Benutzer-Werkzeuge

Webseiten-Werkzeuge


edv:prg:c:example:logging_ext

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 <syslog.h>
// Typ "FILE"
#include <stdio.h>
 
// 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 <sys/debug.h>
// Zeit-Funktionen und Strukturen
#include <time.h>
// Wegen der Funktion "max(int int1, int int2)":
#include <sys/ddi.h>
 
////////////////////////////////////////////////////////////////////////////////
//
// 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
: Jürgen Kreick

EOF

edv/prg/c/example/logging_ext.txt · Zuletzt geändert: 2020/01/11 01:23 von 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki