====== logging_ext ======
FIXME: Da sich viele Teile der Funktionssignatur wiederholen und aus den Makros/Konstanten bestehen, ist es sinnvoll für die DebugLevel %%LOG_DEBUG%%, %%LOG_INFO%%, %%LOG_WARNING%% und %%LOG_ERR%% Makros um die Funktionen logLog(), logLogRC(), logLogRC_SQL(), logEntry(), logExit() und logExitRC() zu definieren.\\ Diese Makros sollen die Parameter %%logLevel%% (%%LOG_DEBUG%%/%%LOG_INFO%%/%%LOG_WARNING%%/%%LOG_ERR%%), %%modulName%% (%%__FILE__%%), %%lineNumber%% (%%__LINE__%%) und %%functName%% (%%__func__%%) kapseln.\\ Als Namen für diese Makros könnte man z.B. %%LOG_LOG_DEBUG()%%/%%LOG_LOG_INFO()%%/%%LOG_LOG_WARNING()%%/%%LOG_LOG_ERR()%% verwenden.
Logging-Modul - nützliche Log-Funktionen.
**logging_ext.h**:
/*********************************************************************
*
* Autor: Jürgen Kreick
* Version: 1.0.0 vom 10.09.2010
*
**********************************************************************
*
* Achtung! Dieses Modul (in der aktuellen Version) ist nicht reenterable!
*
* Für MultiThreaded Betrieb nur bedingt geeignet!
*
**********************************************************************
*
* Hinweise zum Modul/Quelltext: Keine aktuellen Hinweise.
*
**********************************************************************
*
* Release Notes:
*
* Ver 1.0.0 (vom 10.09.2010):
* Die erste Version des Moduls. Umfasst (nach außen) folgende Funktionen:
* logInit(), logDone(), logLog(), logLogRC(), logLogRC_SQL(),
* logEntry(), logExit(), logExitRC(), logErrorMsgFatal().
*
**********************************************************************/
#ifndef logging_ext_h_H
#define logging_ext_h_H
// Wegen LogLevel (soll einheitlich zu Syslog bleiben)
#include
// Typ "FILE"
#include
// Standard-LogLevel:
#define LOGLEVEL_STD 5
// Zur Abgrenzung (und Plausibilitätspruefung): der gleiche Wert wie der min./max. LogLevel
#define LOGLEVEL_MIN 0
#define LOGLEVEL_MAX 7
// Rückgabewerte:
#define RC_OK 0
#define RC_ERR -1
// Status zum LogFile (Extension für den FileNamen) dranhängen
#define LOGSTATUS_RUN "RUN"
#define LOGSTATUS_CLOSE "CLOSED"
// Vordefinierte (ungültige) LogFile-IDs:
#define LOGFILE_NOFILE 0
#define LOGFILE_ERROR -2
// Vordefinierte LogFile-Texte:
#define LOGTXT_FUNCTION_ENTRY "FUNCTION ENTRY"
#define LOGTXT_FUNCTION_EXIT "FUNCTION EXIT"
// Datums- und Zeitformat:
// Achtung!
// Makros LOG_?????_FORMAT_MEM sollen genauen Speicherbedarf (in Zeichen) für
// die entsprechenden LOG_?????_FORMAT widerspiegeln! Sie werden für die
// Deklaration von String-Buffern genutzt.
// Das ist nicht etwa die Länge des LOG_?????_FORMAT-Strings, sondern die Länge
// des Strings, der durch das sprintf(LOG_?????_FORMAT, ...) erzeugt wird.
// Wird hier ein zu kleiner Wert derfiniert, führt es zum BufferOverflow.
// Datum JJJJ-MM-TT
#define LOG_DATUM_FORMAT "%04d-%02d-%02d"
#define LOG_DATUM_FORMAT_MEM 10
// Zeit SS-MM-ss
#define LOG_ZEIT_FORMAT "%02d-%02d-%02d"
#define LOG_ZEIT_FORMAT_MEM 8
// ******************** Prototypen ****************************************
// logInit() wird ein Mal pro LogFile aufgerufen und legt dabei das LogFile an.
// (Beim allerersten Aufruf wird zusätzlich das gesamte Log-Modul initialisiert.)
//
// Parameter:
//
// Es gibt 2 Varianten des Aufrufs:
//
// 1) Die logInit() generiert den FileNamen des LogFiles automatisch aus dem
// Namen des Programms (char *progName), des aktuellen Datums und der
// aktuellen Uhrzeit und legt es im angegebenen Ordner (char *loggingPath)
// an. Der Parameter "char *logPathFileName" soll dabei NULL bleiben.
//
// 2) Die logInit() übernimmt den FileNamen des LogFiles samt Pfad aus dem
// Parameter "char *logPathFileName" und fügt lediglich die Endung
// beispielsweise ".RUN" bzw. ".CLOSED" hinzu.
//
// In beiden Fällen wird die Endung über den Parameter "char *extRun" und
// "char *extClosed" bestimmt.
//
// char *loggingPath : Verzeichnis, in dem das LogFile angelegt werden soll
// char *progName : Anfang des Dateinamens
// char *logPathFileName : Entweder NULL (Kein konkretes File),
// oder kompletter (mit Pfad) FileName
// char *extRun : Entweder NULL (Keine Erweiterung des FileNamens),
// oder eine Erweiterung, z.B. "RUN".
// Diese wird am Ende des FileNamens angehängt.
// char *extClosed : Entweder NULL (Keine Erweiterung des FileNamens),
// oder eine Erweiterung, z.B. "CLOSED".
// Diese bekommt das File nachdem die logDone(logFileID)
// aufgerufen wird (normalerweise beim Programmende).
// int threadNum : Falls mehrere Thread in separate LogFiles schreiben sollen,
// hier die Thread-Nummer, sonst 0
// int logLevelMax : Bis zu welchem LogLevel die Ausgabe erfolgen soll. (Alle
// niedrigeren LogLevel werden mitgeloggt.)
// Dateiname wird nach dem Schema "progName.JJJJ-MM-TT.SS-MM-ss.PID.ThreadNr.log.Status" gebildet.
//
// Rückgabewert: die "int logFileID" - sie wird bei allen Logging Funktionen
// (innerhalb dieses Moduls) als Bezug auf das konkrete LogFile verwendet.
// Bei Fehlern wird LOGFILE_ERROR als Rückgabewert zurück gegeben.
int logInit (const char *loggingPath, const char *progName, const char *logPathFileName, const char *extRun, const char *extClosed, int threadNum, int logLevelMax);
// logDone() schließt das über die logFileID referenziertes LogFile und ändert
// dessen Status (den letzten Teil des Namen von ".RUN" auf ".CLOSED").
// Mit dem Parameter 0 aufgerufen schließt sie alle LogFiles.
void logDone (int logFileID);
// Allgemeine Logging-Funktion.
//
// Parameter:
// int logLevel : Unter welchem LogLevel soll die Ausgabe erfolgen. Falls
// "logLevel" den "logLevelMax" beim Aufruf von logInit()
// überschreitet, erfolgt keine Ausgabe.
// int logFileID : Die LogFile-Referenz - das Ergebniss von logInit()
// char *modulName : Modul-Name, das die Ausgabe produziert. In meisten Fällen
// wird als Makro __FILE__ übergeben.
// int lineNumber : Zeilennummer, die die Ausgabe produziert. In meisten Fällen
// wird als Makro __LINE__ übergeben.
// char *functName : Name der Funktion, die die Ausgabe produziert. In meisten
// Fällen wird als Makro __func__ übergeben.
// char *text : Die eigentliche Log-Ausgabe.
//
// Rückgabewert: Erfolg (Ausgabe erfolgreich) / Misserfolg (Ausgabe nicht erfolgrei oder LogLevel zu niedrig).
int logLog (int logLevel, int logFileID, const char *modulName, int lineNumber, const char *functName, const char *text);
//
// Das gleiche wie oben, nur mit Angabe von RC (ReturnCode)
//
// Parameter: wie oben, jedoch ein Parameter zusätzlich:
// int rc : ReturnCode, wird hinter dem "text" ausgegeben.
int logLogRC (int logLevel, int logFileID, const char *modulName, int lineNumber, const char *functName, const char *text, int rc);
//
// Das gleiche wie oben, nur für SQL
//
// Diese Funktion kann nach jeder DB-Operation aufgerufen werden
// (insbesondere falls der SQL-Code nicht RC_DB_OK ist).
//
// Parameter: wie oben, jedoch ein Parameter zusätzlich:
// const char *sql : Der SQL selbst.
int logLogRC_SQL (int logLevel, int logFileID, const char *modulName, int lineNumber, const char *functName, const char *text, const char *sql, int rc_SQL);
// Logging-Funktionen zum Markieren der Ein- und Ausstiegsstelle in den Funktionen.
//
// Parameter: wie oben.
int logEntry (int logLevel, int logFileID, const char *modulName, const char *functName);
int logExit (int logLevel, int logFileID, const char *modulName, const char *functName);
// ...und für Exit mit ReturnCode
int logExitRC (int logLevel, int logFileID, const char *modulName, const char *functName, int rc);
// Bei Fatalfehler wird eine Fehlermeldung auf "stderr" ausgegeben und die gesamte Anwendung mit exit(exitCode) unterbrochen.
//
// Parameter: wie oben.
void logErrorMsgFatal (int exitCode, const char *modulName, int lineNumber, const char *functName, const char * fehlermeldung);
/* Everything else goes here */
#endif
// EOF
**logging_ext.c**:
#include "logging_ext.h"
// Makro ASSERT()
#include
// Zeit-Funktionen und Strukturen
#include
// Wegen der Funktion "max(int int1, int int2)":
#include
////////////////////////////////////////////////////////////////////////////////
//
// Zur Info: LogLevel aus syslog.h
// LOG_EMERG 0 /* system is unusable */
// LOG_ALERT 1 /* action must be taken immediately */
// LOG_CRIT 2 /* critical conditions */
// LOG_ERR 3 /* error conditions */
// LOG_WARNING 4 /* warning conditions */
// LOG_NOTICE 5 /* normal but signification condition */
// LOG_INFO 6 /* informational */
// LOG_DEBUG 7 /* debug-level messages */
//
////////////////////////////////////////////////////////////////////////////////
// LogLevel als String für die Ausgabe im LogFile:
#define LOG_STR_EMERG "EMERGENCY"
#define LOG_STR_ALERT "ALERT"
#define LOG_STR_CRIT "CRITICAL"
#define LOG_STR_ERR "ERROR"
#define LOG_STR_WARNING "WARNING"
#define LOG_STR_NOTICE "NOTICE"
#define LOG_STR_INFO "INFO"
#define LOG_STR_DEBUG "DEBUG"
// Restliche Konstanten:
#define TMP_STR_LEN_MAX 8191
#define FILENAME_LEN_MAX 8191
// So viele LogFiles parallel kann dieses Modul verwalten
#define AKTIVE_LOGFILES_MAX 64
// Status
#define LOGFILE_AKTIVE 1
#define LOGFILE_FREE 0
// Ausgabeformat in der Funktion logLogRC()
#define LOG_RC_FORMAT "%s (RC = %d)"
// Ausgabeformat in der Funktion logExitRC()
#define LOG_EXIT_RC_FORMAT "%s (RC = %d)"
// Ausgabeformat in der Funktion logLogRC_SQL()
#define LOG_RC_SQL_FORMAT "SQL: '%s;' %s (SQL-CODE = %d)"
// Vordefinierte LogFile-Meldungen:
#define LOGTXT_TEXT_TOO_LONG "Log-Ausgabe ist zu lang"
// ******************** lokale Strukturen ****************************************
// Steuerstruktur für alle LogFiles
typedef struct
{
int id; // logische Nummer eines Log-Files
int active; // 1 = aktiv, 0 = frei
int logLevel; // bis zu welchem LogLevel loggen
int thread; // falls mehrere Thread aktiv sind, Thread-Nummer, sonst 0
FILE *logFile; // FileDescriptor
char fileNameRun [FILENAME_LEN_MAX + 1]; // FileName im aktiven Zustand (mit .RUN am Ende)
char fileNameClose [FILENAME_LEN_MAX + 1]; // FileName im inaktiven Zustand (mit .CLOSED am Ende)
} LOGFILE_CONTROL;
// ******************** lokale Variablen ****************************************
// Zähler für momentan aktive LogFiles.
// Solange die "initLogFileCtl(0)" nicht aufgerufen wurde (anfängliche Initialisierung),
// bleibt "countAktiveLogFiles" im Fehlerzustand und hindert jegliche weitere Funktion
// des Moduls.
int countAktiveLogFiles = LOGFILE_ERROR;
int myPID = -1; // eigene Prozess-ID (Bestandteil des Namens des LogFiles)
int threaded = 0; // Soviele Ausgaben erfolgen in den Threads (parallel).
LOGFILE_CONTROL logFileCtl [AKTIVE_LOGFILES_MAX + 1]; // Steuerstrukturen für alle LogFiles (Element 0 unbenutzt)
char *logLevel2String [] =
{
LOG_STR_EMERG, // 0 "EMERGENCY"
LOG_STR_ALERT, // 1 "ALERT"
LOG_STR_CRIT, // 2 "CRITICAL"
LOG_STR_ERR, // 3 "ERROR"
LOG_STR_WARNING, // 4 "WARNING"
LOG_STR_NOTICE, // 5 "NOTICE"
LOG_STR_INFO, // 6 "INFO"
LOG_STR_DEBUG // 7 "DEBUG"
};
// ******************** interne Funktionen ****************************************
void initLogFileCtl (int id) // initialisiert eine logFileCtl[id], falls id = 0 - gesamte Struktur
{
// Die ID darf nur zwischen 0 und AKTIVE_LOGFILES_MAX bewegen (beide einschließlich)
ASSERT((id >= 0) && (id <= AKTIVE_LOGFILES_MAX));
if (id == 0) // Gesamte Struktur initialisieren
{
// Diese Initialisierung findet nur ein Mal statt - beim Start der Anwendung
ASSERT(countAktiveLogFiles == LOGFILE_ERROR); // Die Struktur darf noch nicht initialisiert sein
memset(&logFileCtl, 0x00, sizeof(logFileCtl));
countAktiveLogFiles = 0;
threaded = 0;
myPID = getpid(); // eigene Prozess-ID
}
else // Eine einzelne Komponente initialisieren
{
ASSERT(countAktiveLogFiles >= 0); // Die Struktur muss bereits initialisiert sein
memset(&(logFileCtl[id]), 0x00, sizeof(logFileCtl[0])); // nur eine logFileCtl[id] initialisieren
} // if
} // initLogFileCtl()
int getNewLogFileCtl ()
{
int rc = LOGFILE_ERROR;
register int i;
for (i = 1; i <= AKTIVE_LOGFILES_MAX; i++) // durch die ganze Tabelle
{
if (!(logFileCtl[i].active)) // Noch nicht aktiv?
{
rc = i; // ID merken
break; // Keine weitere Suche
} // if
} // for
if ((rc <= 0) || (rc > AKTIVE_LOGFILES_MAX)) rc = LOGFILE_ERROR;
if (rc > 0) initLogFileCtl(rc); // ID initialisieren
return rc; // ID zurueck, oder -2 (LOGFILE_ERROR) wenn nichts passendes gefunden
} // getNewLogFileCtl()
void getCurrentDateAndTime (char *currentDate, const char *formatDate, char *currentTime, const char *formatTime)
{
// ----- Achtung! Mehrere returns innerhalb der Funktion ------------------------------
time_t aktSekunden;
struct tm *aktZeit;
if (!currentDate) return;
if (!formatDate) return;
if (!currentTime) return;
if (!formatTime) return;
time(&aktSekunden); // aktuelle Zeit holen
aktZeit = localtime(&aktSekunden); // auf Komponenten zerlegen
// Achtung! sprintf() ist unsicher!
// Es findet hier keine Prüfung statt, ob in "currentTime" und "currentDate" genug Platz vorhanden ist!
sprintf(currentTime, formatTime, aktZeit->tm_hour, aktZeit->tm_min, aktZeit->tm_sec); // Uhrzeit
sprintf(currentDate, formatDate, aktZeit->tm_year + 1900, aktZeit->tm_mon + 1, aktZeit->tm_mday); // Datum
} // getCurrentDateAndTime()
// Diese Funktion berechnet wieviele Stellen (samt '-' bei negativen) eine Ganzzahl im String-Format belegt.
int intlen (int zahl)
{
int len = 0;
// Initialisierungswert
if (zahl < 1) len = 1; // Bei 0 wird nicht gezählt, bei negativen eine Stelle dazu wegen Vorzeichen.
else len = 0;
zahl = abs(zahl);
while (zahl > 0)
{
zahl = zahl / 10; // Um eine Stelle kürzen
len++; // Eine Stelle dazu zählen
} // while
return len;
} // intlen()
// ******************** export-Funktionen ****************************************
int logInit (const char *loggingPath, const char *progName, const char *logPathFileName, const char *extRun, const char *extClosed, int threadNum, int logLevelMax)
{
int rc = RC_OK;
int logFileID = LOGFILE_ERROR;
FILE *logFile = NULL;
char fileName [FILENAME_LEN_MAX + 1];
char strZeit [LOG_ZEIT_FORMAT_MEM + 1];
char strDatum [LOG_DATUM_FORMAT_MEM + 1];
int logFileNameReserve = 0;
memset(fileName, '\0', sizeof(fileName));
memset(strZeit, '\0', sizeof(strZeit));
memset(strDatum, '\0', sizeof(strDatum));
if (countAktiveLogFiles == LOGFILE_ERROR) initLogFileCtl(0); // D.h. nur beim ersten Aufruf initialisieren.
if ((logFileID = getNewLogFileCtl()) > 0) rc = RC_OK; // wenn eine neue ID erteilt wurde
else rc = RC_ERR; // keine neue ID verfügbar
if (!rc)
{
if (logLevelMax < LOGLEVEL_MIN) logLevelMax = LOGLEVEL_MIN;
if (logLevelMax > LOGLEVEL_MAX) logLevelMax = LOGLEVEL_MAX;
logFileCtl[logFileID].id = logFileID; // Struktur ausfüllen
if (logPathFileName) // Falls ein konkreter FileName vorgegeben wurde, diesen als Basis verwenden.
{
// Die Verlängerung des FileNamens (logFileNameReserve) berechnen.
if (extRun && extClosed) logFileNameReserve = max(strlen(extRun), strlen(extClosed)) + 1; // 1 für das '.'-Zeichen
else if (extRun) logFileNameReserve = strlen(extRun) + 1;
else if (extClosed) logFileNameReserve = strlen(extClosed) + 1;
else logFileNameReserve = 0; // Keine Endungen
strlcpy(fileName, logPathFileName, sizeof(fileName) - logFileNameReserve); // Den FileNamen übernehmen
}
else // Den FileNamen selbstständig generieren.
{
getCurrentDateAndTime(strDatum, LOG_DATUM_FORMAT, strZeit, LOG_ZEIT_FORMAT);
snprintf(fileName, sizeof(fileName), "%s/%s.%s.%s.%d.%d.log", loggingPath, progName, strDatum, strZeit, myPID, threadNum); // StammName
} // if
// Den kompletten FileNamen bilden - für den RUN-Zustand.
if (extRun) snprintf(logFileCtl[logFileID].fileNameRun, sizeof(logFileCtl[0].fileNameRun), "%s.%s", fileName, extRun);
else strlcpy(logFileCtl[logFileID].fileNameRun, fileName, sizeof(logFileCtl[0].fileNameRun));
// Den kompletten FileNamen bilden - für den CLOSED-Zustand.
if (extClosed) snprintf(logFileCtl[logFileID].fileNameClose, sizeof(logFileCtl[0].fileNameClose), "%s.%s", fileName, extClosed);
else strlcpy(logFileCtl[logFileID].fileNameClose, fileName, sizeof(logFileCtl[0].fileNameClose));
logFile = fopen(logFileCtl[logFileID].fileNameRun, "w"); // zum Schreiben öffnen
if (logFile)
{
if (setvbuf(logFile, NULL, _IOLBF, TMP_STR_LEN_MAX + 1) != 0) // Zeilenbuffer anlegen
{
fclose(logFile); // Bei mißerfolg.
logFile = NULL;
} // if
} // if
if (logFile) logFileCtl[logFileID].logFile = logFile; // Falls geöffnet, den FileHandle zuweisen...
else logFileCtl[logFileID].logFile = stderr; // ...sonst "stderr"-Handle
logFileCtl[logFileID].logLevel = logLevelMax; // Den "persönlichen" LogLevel merken.
logFileCtl[logFileID].thread = threadNum; // Thread-Nummer merken.
if (logFile) logFileCtl[logFileID].active = LOGFILE_AKTIVE; // auf aktiv setzen
else rc = RC_ERR;
if (logFileCtl[logFileID].active == LOGFILE_AKTIVE) // Falls ein aktives LogFile dazu gekommen...
{
countAktiveLogFiles++; // ... eins dazu zählen.
if (logFileCtl[logFileID].thread > 0) threaded++; // Es ist also mit paralleler Ausgabe zu rechnen.
} // if
} // if
if (!rc) rc = logFileID;
else rc = LOGFILE_ERROR;
return rc; // LogFile-ID
} // logInit()
void logDone (int logFileID)
{
// ----- Achtung! Mehrere returns innerhalb der Funktion ------------------------------
if (logFileID == 0)
{
int i;
for (i = 1; i <= AKTIVE_LOGFILES_MAX; i++) logDone(i); // Alle LogFiles schließen
return;
} // if
if ((logFileID < 1) || (logFileID > AKTIVE_LOGFILES_MAX)) return; // ID ist nicht plausibel
if (logFileCtl[logFileID].active != LOGFILE_AKTIVE) return; // ID ist nicht aktiv
// Ab hier Files schließen und die ID deaktivieren.
if (logFileCtl[logFileID].logFile) fflush(logFileCtl[logFileID].logFile);
if (logFileCtl[logFileID].logFile == stderr) logFileCtl[logFileID].logFile = NULL; // Bei "stderr" keine weiteren Aktivitäten.
if (logFileCtl[logFileID].logFile) fclose(logFileCtl[logFileID].logFile);
logFileCtl[logFileID].logFile = NULL;
// Wechsel vom RUN- zum CLOSED-Zustand.
rename(logFileCtl[logFileID].fileNameRun, logFileCtl[logFileID].fileNameClose); // Log-File umbenennen
logFileCtl[logFileID].active = LOGFILE_FREE; // nicht mehr aktiv
if (logFileCtl[logFileID].thread) threaded--; // Um einen Thread weniger.
if (threaded < 0) threaded = 0; // Darf nicht negativ sein (dürfte eigentlich nicht vorkommen).
logFileCtl[logFileID].thread = 0;
countAktiveLogFiles--;
if (countAktiveLogFiles < 0) countAktiveLogFiles = 0; // Darf nicht negativ sein (dürfte eigentlich nicht vorkommen).
} // logDone()
int logLog (int logLevel, int logFileID, const char *modulName, int lineNumber, const char *functName, const char *text)
{
int rc = RC_OK;
int logFileIdLogLevel = 0;
char strZeit [LOG_ZEIT_FORMAT_MEM + 1];
char strDatum [LOG_DATUM_FORMAT_MEM + 1];
memset(strZeit, '\0', sizeof(strZeit));
memset(strDatum, '\0', sizeof(strDatum));
// Ist die logFileID plausibel?
if ((logFileID < 1) || (logFileID > AKTIVE_LOGFILES_MAX)) rc = RC_ERR; // ID ist nicht plausibel
if ((logLevel < LOGLEVEL_MIN) || (logLevel > LOGLEVEL_MAX)) rc = RC_ERR; // LogLevel ist nicht plausibel
if (rc) logFileID = 0; // damit durch fehlerhafte logFileID kein Segmentation Fault ausgelöst wird
// ist die logFileID aktiv?
if (!rc) if (logFileCtl[logFileID].active != LOGFILE_AKTIVE) rc = RC_ERR; // ID ist nicht plausibel
logFileIdLogLevel = logFileCtl[logFileID].logLevel;
if (!rc && (logLevel <= logFileIdLogLevel)) // Ausgabe in LogFile nur wenn der LogLevel passt.
{
getCurrentDateAndTime(strDatum, LOG_DATUM_FORMAT, strZeit, LOG_ZEIT_FORMAT);
// Die Ausgabe ins LogFile abhängig vom zur logFileID gehörenden logLevel schreiben:
// Log-Ausgabe für logEntry() / logExit() / logExitRC() (mit "modulName" und "functName")
if (lineNumber == -1) fprintf(logFileCtl[logFileID].logFile, "%s %s %s: %s:%s(): %s\n", strDatum, strZeit, logLevel2String[logLevel], modulName ? modulName : "NOMODUL(NULL-POINTER)", functName ? functName : "NOFUNKT(NULL-POINTER)", text ? text : "NOTEXT(NULL-POINTER)");
// Log-Ausgabe für logLevel = LOG_DEBUG (und evtl. höher) erfolgt mit "modulName", "lineNumber", und "functName" (alle Angaben)
else if (logFileIdLogLevel >= LOG_DEBUG) fprintf(logFileCtl[logFileID].logFile, "%s %s %s: %s[%d]:%s(): %s\n", strDatum, strZeit, logLevel2String[logLevel], modulName ? modulName : "NOMODUL(NULL-POINTER)", lineNumber, functName ? functName : "NOFUNKT(NULL-POINTER)", text ? text : "NOTEXT(NULL-POINTER)");
// Log-Ausgabe für logLevel = LOG_INFO (und evtl. höher) erfolgt nur mit "functName"
else if (logFileIdLogLevel >= LOG_INFO) fprintf(logFileCtl[logFileID].logFile, "%s %s %s: %s(): %s\n", strDatum, strZeit, logLevel2String[logLevel], functName ? functName : "NOFUNKT(NULL-POINTER)", text ? text : "NOTEXT(NULL-POINTER)");
// allgemeine Log-Ausgabe (nur mit Zeitstempel)
else fprintf(logFileCtl[logFileID].logFile, "%s %s %s: %s\n", strDatum, strZeit, logLevel2String[logLevel], text ? text : "NOTEXT(NULL-POINTER)");
if (threaded) fflush(logFileCtl[logFileID].logFile); // Bei mehreren Threads sofort wegschreiben.
} // if
return rc;
} // logLog()
int logLogRC (int logLevel, int logFileID, const char *modulName, int lineNumber, const char *functName, const char *text, int rc)
{
char logStr [TMP_STR_LEN_MAX + 1];
memset(logStr, '\0', sizeof(logStr));
if ((strlen(text) + intlen(rc) + strlen(LOG_RC_FORMAT)) > TMP_STR_LEN_MAX) strcpy(logStr, LOGTXT_TEXT_TOO_LONG); // Ausgabe-String zu lang.
else sprintf(logStr, LOG_RC_FORMAT, text, rc); // Achtung! sprintf() ist unsicher!
return logLog(logLevel, logFileID, modulName, lineNumber, functName, logStr);
} // logLogRC()
int logLogRC_SQL (int logLevel, int logFileID, const char *modulName, int lineNumber, const char *functName, const char *text, const char *sql, int rc_SQL)
{
char logStr [TMP_STR_LEN_MAX + 1];
memset(logStr, '\0', sizeof(logStr));
if ((strlen(sql) + strlen(text) + intlen(rc_SQL) + strlen(LOG_RC_SQL_FORMAT)) > TMP_STR_LEN_MAX) strcpy(logStr, LOGTXT_TEXT_TOO_LONG); // Ausgabe-String zu lang.
else sprintf(logStr, LOG_RC_SQL_FORMAT, sql, text, rc_SQL); // Achtung! sprintf() ist unsicher!
return logLog(logLevel, logFileID, modulName, lineNumber, functName, logStr);
} // logLogRC_SQL()
int logEntry (int logLevel, int logFileID, const char *modulName, const char *functName)
{
return logLog(logLevel, logFileID, modulName, -1, functName, LOGTXT_FUNCTION_ENTRY);
} // logEntry()
int logExit (int logLevel, int logFileID, const char *modulName, const char *functName)
{
return logLog(logLevel, logFileID, modulName, -1, functName, LOGTXT_FUNCTION_EXIT);
} // logExit()
int logExitRC (int logLevel, int logFileID, const char *modulName, const char *functName, int rc)
{
char logStr [TMP_STR_LEN_MAX + 1];
memset(logStr, '\0', sizeof(logStr));
sprintf(logStr, LOG_EXIT_RC_FORMAT, LOGTXT_FUNCTION_EXIT, rc); // Achtung! sprintf() ist unsicher!
// Unbedingt darauf achten, daß "logStr" für die Ausgabe groß genug ist!
return logLog(logLevel, logFileID, modulName, -1, functName, logStr);
} // logExitRC()
void logErrorMsgFatal (int exitCode, const char *modulName, int lineNumber, const char *functName, const char * fehlermeldung)
{
fprintf(stderr, "\n%%s[%d]:%s(): FATAL ERROR: [%s]\n", modulName ? modulName : "NOMODUL(NULL-POINTER)", lineNumber, functName ? functName : "NOFUNKT(NULL-POINTER)", fehlermeldung ? fehlermeldung : "(undefinierte Fehlermeldung)");
fprintf(stderr, "Die Ausfuehrung wird mit ExitCode = [%d] abgebrochen.\n\n", exitCode);
fflush(stderr);
fflush(stdout);
exit(exitCode);
} // errorMsgFatal()
// EOF
----
Stand: 10.09.2010\\
--- //[[feedback.jk-wiki@kreick.de|: Jürgen Kreick]]//
EOF