3 @brief Routines for logging messages.
6 #include <opensrf/log.h>
8 #define OSRF_NO_LOG_TYPE -1
10 static int _prevLogType = OSRF_NO_LOG_TYPE;
11 static int _osrfLogType = OSRF_LOG_TYPE_STDERR;
12 static int _osrfLogFacility = LOG_LOCAL0;
13 static int _osrfLogActFacility = LOG_LOCAL1;
14 static char* _osrfLogFile = NULL;
15 static char* _osrfLogAppname = NULL;
16 static int _osrfLogLevel = OSRF_LOG_INFO;
17 static int _osrfLogActivityEnabled = 1;
18 static int _osrfLogIsClient = 0;
20 static char* _osrfLogXid = NULL; /* current xid */
21 static char* _osrfLogXidPfx = NULL; /* xid prefix string */
23 static void osrfLogSetType( int logtype );
24 static void _osrfLogDetail( int level, const char* filename, int line, char* msg );
25 static void _osrfLogToFile( const char* label, long pid, const char* filename, int line,
26 const char* xid, const char* msg );
27 static void _osrfLogSetXid( const char* xid );
30 @brief Reset certain static variables to their initial values.
32 Of the various static variables, we here reset only three:
33 - application name (deleted)
34 - file name of log file (deleted)
35 - log type (reset to OSRF_LOG_TYPE_STDERR)
37 void osrfLogCleanup( void ) {
38 free(_osrfLogAppname);
39 _osrfLogAppname = NULL;
42 _osrfLogType = OSRF_LOG_TYPE_STDERR;
47 @brief Record some options for later reference by the logging routines.
48 @param type Type of logging; i.e. where the log messages go.
49 @param appname Pointer to the application name (may be NULL).
50 @param maxlevel Which levels of message to issue or suppress.
52 Typically the values for these parameters come from a configuration file.
54 There are three valid values for @a type:
56 - OSRF_LOG_TYPE_FILE -- write messages to a log file
57 - OSRF_LOG_TYPE_SYSLOG -- write messages to the syslog facility
58 - OSRF_LOG_TYPE_STDERR -- write messages to standard error
60 If @a type has any other value, log messages will be written to standard error.
62 The logging type may be set separately by calling osrfLogSetType(). See also
63 osrfLogToStderr() and osrfRestoreLogType().
65 The @a appname string prefaces every log message written to a log file or to standard
66 error. It also identifies the application to the Syslog facility, if the application
67 uses Syslog. The default application name, if not overridden by this function or by
68 osrfLogSetAppname(), is "osrf".
70 Here are the valid values for @a maxlevel, with the corresponding macros:
74 - 3 OSRF_LOG_INFO (the default)
78 With the special exception of activity messages (see osrfLogActivity()), the logging
79 routines will suppress any messages at a level greater than that specified by
80 @a maxlevel. Setting @a maxlevel to zero or less suppresses all levels of message.
81 Setting it to 5 or more enables all levels of message.
83 The message level may be set separately by calling osrfLogSetLevel().
85 void osrfLogInit( int type, const char* appname, int maxlevel ) {
87 if(appname) osrfLogSetAppname(appname);
88 osrfLogSetLevel(maxlevel);
89 if( type == OSRF_LOG_TYPE_SYSLOG )
90 openlog(_osrfLogAppname, 0, _osrfLogFacility );
94 @brief Store a copy of a transaction id for future use.
95 @param xid Pointer to the transaction id to be stored.
97 static void _osrfLogSetXid( const char* xid ) {
99 if(_osrfLogXid) free(_osrfLogXid);
100 _osrfLogXid = strdup(xid);
105 @brief Store an empty string as the transaction id.
107 void osrfLogClearXid( void ) { _osrfLogSetXid(""); }
110 @brief Store a transaction id, unless running as a client process.
111 @param xid Pointer to the new transaction id
113 void osrfLogSetXid(char* xid) {
114 if(!_osrfLogIsClient) _osrfLogSetXid(xid);
118 @brief Store a transaction id, unconditionally, for future use.
119 @param xid Pointer to the new transaction id
121 void osrfLogForceXid(char* xid) {
126 @brief For client processes only: create and store a unique transaction id.
128 The generated transaction id concatenates a prefix (which must have been generated
129 previously by osrfLogSetIsClient()) and a sequence number that is incremented on each
132 Since the various pieces of the transaction id are of variable length, and not separated
133 by any non-numeric characters, the result is not guaranteed to be unique. However
134 collisions should be rare.
136 void osrfLogMkXid( void ) {
137 if(_osrfLogIsClient) {
138 static int _osrfLogXidInc = 0; /* increments with each new xid for uniqueness */
140 snprintf(buf, sizeof(buf), "%s%d", _osrfLogXidPfx, _osrfLogXidInc);
147 @brief Return a pointer to the currently stored transaction id, if any.
148 @return Pointer to the currently stored transaction id.
150 If no transaction id has been stored, return NULL.
152 const char* osrfLogGetXid( void ) {
157 @brief Note whether the current process is a client; if so, generate a transaction prefix.
158 @param is A boolean; true means the current process is a client, false means it isn't.
160 The generated prefix concatenates a timestamp (the return from time()) and a process id.
162 void osrfLogSetIsClient(int is) {
163 _osrfLogIsClient = is;
165 /* go ahead and create the xid prefix so it will be consistent later */
166 static char buff[32];
167 snprintf(buff, sizeof(buff), "%d%ld", (int)time(NULL), (long) getpid());
168 _osrfLogXidPfx = buff;
172 @brief Specify what kind of logging to perform.
173 @param logtype A code indicating the type of logging.
175 There are three valid values for @a logtype:
177 - OSRF_LOG_TYPE_FILE -- write messages to a log file
178 - OSRF_LOG_TYPE_SYSLOG -- write messages to the syslog facility
179 - OSRF_LOG_TYPE_STDERR -- write messages to standard error
181 If @a logtype has any other value, log messages will be written to standard error.
183 This function merely records the log type for future reference. It does not open
186 See also osrfLogInit(), osrfLogToStderr() and osrfRestoreLogType().
189 static void osrfLogSetType( int logtype ) {
193 case OSRF_LOG_TYPE_FILE :
194 case OSRF_LOG_TYPE_SYSLOG :
195 case OSRF_LOG_TYPE_STDERR :
196 _osrfLogType = logtype;
199 fprintf(stderr, "Unrecognized log type. Logging to stderr\n");
200 _osrfLogType = OSRF_LOG_TYPE_STDERR;
205 void osrfLogToStderr( void )
207 if( OSRF_NO_LOG_TYPE == _prevLogType ) {
208 _prevLogType = _osrfLogType;
209 _osrfLogType = OSRF_LOG_TYPE_STDERR;
213 void osrfRestoreLogType( void )
215 if( _prevLogType != OSRF_NO_LOG_TYPE ) {
216 _osrfLogType = _prevLogType;
217 _prevLogType = OSRF_NO_LOG_TYPE;
221 void osrfLogSetFile( const char* logfile ) {
223 if(_osrfLogFile) free(_osrfLogFile);
224 _osrfLogFile = strdup(logfile);
227 void osrfLogSetActivityEnabled( int enabled ) {
228 _osrfLogActivityEnabled = enabled;
231 void osrfLogSetAppname( const char* appname ) {
233 if(_osrfLogAppname) free(_osrfLogAppname);
234 _osrfLogAppname = strdup(appname);
236 /* if syslogging, re-open the log with the appname */
237 if( _osrfLogType == OSRF_LOG_TYPE_SYSLOG) {
239 openlog(_osrfLogAppname, 0, _osrfLogFacility);
243 void osrfLogSetSyslogFacility( int facility ) {
244 _osrfLogFacility = facility;
246 void osrfLogSetSyslogActFacility( int facility ) {
247 _osrfLogActFacility = facility;
250 /** Sets the global log level. Any log statements with a higher level
251 * than "level" will not be logged */
252 void osrfLogSetLevel( int loglevel ) {
253 _osrfLogLevel = loglevel;
256 /** Gets the current global log level. **/
257 int osrfLogGetLevel( void ) {
258 return _osrfLogLevel;
261 void osrfLogError( const char* file, int line, const char* msg, ... ) {
263 if( _osrfLogLevel < OSRF_LOG_ERROR ) return;
264 VA_LIST_TO_STRING( msg );
265 _osrfLogDetail( OSRF_LOG_ERROR, file, line, VA_BUF );
268 void osrfLogWarning( const char* file, int line, const char* msg, ... ) {
270 if( _osrfLogLevel < OSRF_LOG_WARNING ) return;
271 VA_LIST_TO_STRING( msg );
272 _osrfLogDetail( OSRF_LOG_WARNING, file, line, VA_BUF );
275 void osrfLogInfo( const char* file, int line, const char* msg, ... ) {
277 if( _osrfLogLevel < OSRF_LOG_INFO ) return;
278 VA_LIST_TO_STRING( msg );
279 _osrfLogDetail( OSRF_LOG_INFO, file, line, VA_BUF );
282 void osrfLogDebug( const char* file, int line, const char* msg, ... ) {
284 if( _osrfLogLevel < OSRF_LOG_DEBUG ) return;
285 VA_LIST_TO_STRING( msg );
286 _osrfLogDetail( OSRF_LOG_DEBUG, file, line, VA_BUF );
289 void osrfLogInternal( const char* file, int line, const char* msg, ... ) {
291 if( _osrfLogLevel < OSRF_LOG_INTERNAL ) return;
292 VA_LIST_TO_STRING( msg );
293 _osrfLogDetail( OSRF_LOG_INTERNAL, file, line, VA_BUF );
296 void osrfLogActivity( const char* file, int line, const char* msg, ... ) {
298 if( _osrfLogLevel >= OSRF_LOG_INFO
299 || ( _osrfLogActivityEnabled && _osrfLogLevel >= OSRF_LOG_ACTIVITY ) )
301 VA_LIST_TO_STRING( msg );
303 if( _osrfLogActivityEnabled && _osrfLogLevel >= OSRF_LOG_ACTIVITY )
304 _osrfLogDetail( OSRF_LOG_ACTIVITY, file, line, VA_BUF );
306 /* also log at info level */
307 if( _osrfLogLevel >= OSRF_LOG_INFO )
308 _osrfLogDetail( OSRF_LOG_INFO, file, line, VA_BUF );
313 @brief Issue a log message.
314 @param level The message level.
315 @param filename The name of the source file from whence the message is issued.
316 @param line The line number from whence the message is issued.
317 @param msg The text of the message.
319 This function is the final common pathway for all messages.
321 The @a level parameter determines the tag to be incorporated into the message: "ERR",
322 "WARN", "INFO", "DEBG", "INT " or "ACT".
324 The @a filename and @a name identify the location in the application code from whence the
325 message is being issued.
327 Here we format the message and route it to the appropriate output destination, depending
328 on the current setting of _osrfLogType: Syslog, a log file, or standard error.
330 static void _osrfLogDetail( int level, const char* filename, int line, char* msg ) {
332 if(!filename) filename = "";
334 char* label = "INFO"; /* level name */
335 int lvl = LOG_INFO; /* syslog level */
336 int fac = _osrfLogFacility;
344 case OSRF_LOG_WARNING:
359 case OSRF_LOG_INTERNAL:
364 case OSRF_LOG_ACTIVITY:
367 fac = _osrfLogActFacility;
371 char* xid = (_osrfLogXid) ? _osrfLogXid : "";
373 int logtype = _osrfLogType;
374 if( logtype == OSRF_LOG_TYPE_FILE && !_osrfLogFile )
376 // No log file defined? Temporarily reroute to stderr
377 logtype = OSRF_LOG_TYPE_STDERR;
380 if( logtype == OSRF_LOG_TYPE_SYSLOG ) {
383 /* give syslog some breathing room, and be cute about it */
384 strncat(buf, msg, 1535);
389 syslog( fac | lvl, "[%s:%ld:%s:%d:%s] %s", label, (long) getpid(), filename, line, xid, buf );
392 else if( logtype == OSRF_LOG_TYPE_FILE )
393 _osrfLogToFile( label, (long) getpid(), filename, line, xid, msg );
395 else if( logtype == OSRF_LOG_TYPE_STDERR )
396 fprintf( stderr, "[%s:%ld:%s:%d:%s] %s\n", label, (long) getpid(), filename, line, xid, msg );
401 @brief Write a message to a log file.
402 @param label The message type: "ERR", "WARN", etc..
403 @param pid The process id.
404 @param filename Name of the source file from whence the message was issued.
405 @param line Line number from whence the message was issued.
406 @param xid Transaction id (or an empty string if there is no transaction).
407 @param msg Message text.
409 Open the log file named by _osrfLogFile, in append mode; write the message; close the
410 file. If unable to open the log file, write the message to standard error.
412 static void _osrfLogToFile( const char* label, long pid, const char* filename, int line,
413 const char* xid, const char* msg ) {
415 if( !label || !filename || !xid || !msg )
416 return; // missing parameter(s)
419 return; // No log file defined
422 _osrfLogAppname = strdup("osrf"); // apply default application name
425 time_t t = time(NULL);
426 struct tm* tms = localtime(&t);
427 strftime(datebuf, sizeof( datebuf ), "%Y-%m-%d %H:%M:%S", tms);
429 FILE* file = fopen(_osrfLogFile, "a");
432 "Unable to fopen log file %s for writing; logging to standard error\n", _osrfLogFile);
433 fprintf(stderr, "%s %s [%s:%ld:%s:%d:%s] %s\n",
434 _osrfLogAppname, datebuf, label, (long) getpid(), filename, line, xid, msg );
439 fprintf(file, "%s %s [%s:%ld:%s:%d:%s] %s\n",
440 _osrfLogAppname, datebuf, label, (long) getpid(), filename, line, xid, msg );
441 if( fclose(file) != 0 )
442 fprintf( stderr, "Error closing log file: %s", strerror(errno));
446 int osrfLogFacilityToInt( const char* facility ) {
447 if(!facility) return LOG_LOCAL0;
448 if(strlen(facility) < 6) return LOG_LOCAL0;
449 switch( facility[5] ) {
450 case '0': return LOG_LOCAL0;
451 case '1': return LOG_LOCAL1;
452 case '2': return LOG_LOCAL2;
453 case '3': return LOG_LOCAL3;
454 case '4': return LOG_LOCAL4;
455 case '5': return LOG_LOCAL5;
456 case '6': return LOG_LOCAL6;
457 case '7': return LOG_LOCAL7;