3 @brief Routines for logging messages.
6 #include <opensrf/log.h>
8 /** Pseudo-log type indicating that no previous log type was defined.
9 See also _prevLogType. */
10 #define OSRF_NO_LOG_TYPE -1
12 /** Stores a log type during temporary redirections to standard error. */
13 static int _prevLogType = OSRF_NO_LOG_TYPE;
14 /** Defines the destination of log messages: standard error, a log file, or Syslog. */
15 static int _osrfLogType = OSRF_LOG_TYPE_STDERR;
16 /** Defines the Syslog facility number used for log messages other than activity messages.
17 Defaults to LOG_LOCAL0. */
18 static int _osrfLogFacility = LOG_LOCAL0;
19 /** Defines the Syslog facility number used for activity messages. Defaults to LOG_LOCAL1. */
20 static int _osrfLogActFacility = LOG_LOCAL1;
21 /** Name of the log file. */
22 static char* _osrfLogFile = NULL;
23 /** Application name. This string will preface every log message. */
24 static char* _osrfLogAppname = NULL;
25 static char* _osrfLogTag = NULL;
26 /** Maximum message level. Messages of higher levels will be suppressed.
27 Default: OSRF_LOG_INFO. */
28 static int _osrfLogLevel = OSRF_LOG_INFO;
29 /** Boolean. If true, activity message are enabled. Default: true. */
30 static int _osrfLogActivityEnabled = 1;
31 /** Boolean. If true, the current process is a client; otherwise it's a server. Clients and
32 servers have different options with regard to transaction ids. See osrfLogSetXid(),
33 osrfLogForceXid(), and osrfLogMkXid(). Default: false. */
34 static int _osrfLogIsClient = 0;
36 /** An id identifying the current transaction. If defined, it is included into every
38 static char* _osrfLogXid = NULL; /* current xid */
39 /** A prefix used to generate transaction ids. It incorporates a timestamp and a process id. */
40 static char* _osrfLogXidPfx = NULL; /* xid prefix string */
42 static void osrfLogSetType( int logtype );
43 static void _osrfLogDetail( int level, const char* filename, int line, char* msg );
44 static void _osrfLogToFile( const char* label, long pid, const char* filename, int line,
45 const char* xid, const char* msg );
46 static void _osrfLogSetXid( const char* xid );
49 @brief Reset certain local static variables to their initial values.
51 Of the various static variables, we here reset only three:
52 - application name (deleted)
53 - file name of log file (deleted)
54 - log type (reset to OSRF_LOG_TYPE_STDERR)
56 void osrfLogCleanup( void ) {
60 free(_osrfLogAppname);
61 _osrfLogAppname = NULL;
64 _osrfLogType = OSRF_LOG_TYPE_STDERR;
69 @brief Record some options for later reference by the logging routines.
70 @param type Type of logging; i.e. where the log messages go.
71 @param appname Pointer to the application name (may be NULL).
72 @param maxlevel Which levels of message to issue or suppress.
74 Typically the values for these parameters come from a configuration file.
76 There are three valid values for @a type:
78 - OSRF_LOG_TYPE_FILE -- write messages to a log file
79 - OSRF_LOG_TYPE_SYSLOG -- write messages to the syslog facility
80 - OSRF_LOG_TYPE_STDERR -- write messages to standard error
82 If @a type has any other value, log messages will be written to standard error.
84 The logging type may be set separately by calling osrfLogSetType(). See also
85 osrfLogToStderr() and osrfRestoreLogType().
87 The @a appname string prefaces every log message. The default application name, if
88 not overridden by this function or by osrfLogSetAppname(), is "osrf".
90 Here are the valid values for @a maxlevel, with the corresponding macros:
94 - 3 OSRF_LOG_INFO (the default)
98 With the special exception of activity messages (see osrfLogActivity()), the logging
99 routines will suppress any messages at a level greater than that specified by
100 @a maxlevel. Setting @a maxlevel to zero or less suppresses all levels of message.
101 Setting it to 5 or more enables all levels of message.
103 The message level may be set separately by calling osrfLogSetLevel().
105 void osrfLogInit( int type, const char* appname, int maxlevel ) {
106 osrfLogSetType(type);
107 if(appname) osrfLogSetAppname(appname);
108 osrfLogSetLevel(maxlevel);
109 if( type == OSRF_LOG_TYPE_SYSLOG )
110 openlog(_osrfLogAppname, 0, _osrfLogFacility );
114 @brief Store a copy of a transaction id for future use.
115 @param xid Pointer to the transaction id to be stored.
117 static void _osrfLogSetXid( const char* xid ) {
119 if(_osrfLogXid) free(_osrfLogXid);
120 _osrfLogXid = strdup(xid);
125 @brief Store an empty string as the transaction id.
127 void osrfLogClearXid( void ) { _osrfLogSetXid(""); }
130 @brief Store a transaction id, unless running as a client process.
131 @param xid Pointer to the new transaction id
133 void osrfLogSetXid(const char* xid) {
134 if(!_osrfLogIsClient) _osrfLogSetXid(xid);
138 @brief Store a transaction id for future use, whether running as a client or as a server.
139 @param xid Pointer to the new transaction id
141 void osrfLogForceXid(const char* xid) {
146 @brief For client processes only: create and store a unique transaction id.
148 The generated transaction id concatenates a prefix (which must have been generated
149 previously by osrfLogSetIsClient()) and a sequence number that is incremented on each
152 Since the various pieces of the transaction id are of variable length, and not separated
153 by any non-numeric characters, the result is not guaranteed to be unique. However
154 collisions should be rare.
156 void osrfLogMkXid( void ) {
157 if(_osrfLogIsClient) {
158 static int _osrfLogXidInc = 0; /* increments with each new xid for uniqueness */
160 snprintf(buf, sizeof(buf), "%s%d", _osrfLogXidPfx, _osrfLogXidInc);
167 @brief Return a pointer to the currently stored transaction id, if any.
168 @return Pointer to the currently stored transaction id.
170 If no transaction id has been stored, return NULL.
172 const char* osrfLogGetXid( void ) {
177 @brief Note whether the current process is a client; if so, generate a transaction prefix.
178 @param is A boolean; true means the current process is a client, false means it isn't.
180 The generated prefix concatenates a timestamp (the return from time()) and a process id.
182 void osrfLogSetIsClient(int is) {
183 _osrfLogIsClient = is;
185 /* go ahead and create the xid prefix so it will be consistent later */
186 static char buff[32];
187 snprintf(buff, sizeof(buff), "%d%ld", (int)time(NULL), (long) getpid());
188 _osrfLogXidPfx = buff;
192 @brief Specify what kind of logging to perform.
193 @param logtype A code indicating the type of logging.
195 There are three valid values for @a logtype:
197 - OSRF_LOG_TYPE_FILE -- write messages to a log file
198 - OSRF_LOG_TYPE_SYSLOG -- write messages to the syslog facility
199 - OSRF_LOG_TYPE_STDERR -- write messages to standard error
201 If @a logtype has any other value, log messages will be written to standard error.
203 This function merely records the log type for future reference. It does not open
206 See also osrfLogInit(), osrfLogToStderr() and osrfRestoreLogType().
209 static void osrfLogSetType( int logtype ) {
213 case OSRF_LOG_TYPE_FILE :
214 case OSRF_LOG_TYPE_SYSLOG :
215 case OSRF_LOG_TYPE_STDERR :
216 _osrfLogType = logtype;
219 fprintf(stderr, "Unrecognized log type. Logging to stderr\n");
220 _osrfLogType = OSRF_LOG_TYPE_STDERR;
226 @brief Switch the logging output to standard error (but remember where it @em was going).
228 See also osrfRestoreLogType().
230 void osrfLogToStderr( void )
232 if( OSRF_NO_LOG_TYPE == _prevLogType ) {
233 _prevLogType = _osrfLogType;
234 _osrfLogType = OSRF_LOG_TYPE_STDERR;
239 @brief Switch the logging output to wherever it was going before calling osrfLogtoStderr().
241 By using osrfRestoreLogType together with osrfRestoreLogType(), an application can
242 temporarily redirect log messages to standard error, either for an interactive
243 session or for debugging, and later revert to the original log output.
245 void osrfRestoreLogType( void )
247 if( _prevLogType != OSRF_NO_LOG_TYPE ) {
248 _osrfLogType = _prevLogType;
249 _prevLogType = OSRF_NO_LOG_TYPE;
254 @brief Store a file name for a log file.
255 @param logfile Pointer to the file name.
257 The new file name replaces whatever file name was previously in place, if any.
259 This function does not affect the logging type. The choice of file name makes a
260 difference only when the logging type is OSRF_LOG_TYPE_FILE.
262 void osrfLogSetFile( const char* logfile ) {
264 if(_osrfLogFile) free(_osrfLogFile);
265 _osrfLogFile = strdup(logfile);
269 @brief Enable the issuance of activity log messages.
271 By default, activity messages are enabled. See also osrfLogActivity().
273 void osrfLogSetActivityEnabled( int enabled ) {
274 _osrfLogActivityEnabled = enabled;
278 @brief Store an application name for future use.
279 @param appname Pointer to the application name to be stored.
281 The @a appname string prefaces every log message. The default application name is "osrf".
283 void osrfLogSetAppname( const char* appname ) {
288 snprintf(buf, sizeof(buf), "%s/%s", appname, _osrfLogTag);
290 snprintf(buf, sizeof(buf), "%s", appname);
293 if(_osrfLogAppname) free(_osrfLogAppname);
294 _osrfLogAppname = strdup(buf);
296 /* if syslogging, re-open the log with the appname */
297 if( _osrfLogType == OSRF_LOG_TYPE_SYSLOG) {
299 openlog(_osrfLogAppname, 0, _osrfLogFacility);
304 @brief Store a facility number for future use.
305 @param facility The facility number to be stored.
307 A facility is a small integer passed to the Syslog system to characterize the source
308 of a message. The value of this integer is typically derived from a configuration file.
309 If not otherwise specified, it defaults to LOG_LOCAL0.
311 void osrfLogSetSyslogFacility( int facility ) {
312 _osrfLogFacility = facility;
316 @brief Store an arbitrary program name tag for future use.
317 @param logtag The string to be stored.
319 A log tag is a short string that is appended to the appname
320 we log under. This can be used to segregate logs from different
321 users in, for instance, rsyslogd.
324 void osrfLogSetLogTag( const char* logtag ) {
325 if (logtag) _osrfLogTag = strdup(logtag);
329 @brief Store a facility number for future use for activity messages.
330 @param facility The facility number to be stored.
332 A facility is a small integer passed to the Syslog system to characterize the source
333 of a message. The value of this integer is typically derived from a configuration file.
335 The facility used for activity messages is separate and distinct from that used for
336 other log messages, and defaults to LOG_LOCAL1.
338 void osrfLogSetSyslogActFacility( int facility ) {
339 _osrfLogActFacility = facility;
343 @brief Set the maximum level of messages to be issued.
344 @param loglevel The maximum message level.
346 A log message will be issued only if its level is less than or equal to this maximum.
347 For example, if @a loglevel is set to OSRF_LOG_INFO, then the logging routines will
348 issue information messages, warning messages, and error messages, but not debugging
349 messages or internal messages.
351 The default message level is OSRF_LOG_INFO.
353 void osrfLogSetLevel( int loglevel ) {
354 _osrfLogLevel = loglevel;
358 @brief Get the current log message level.
359 @return The current log message level.
361 See also osrfLogSetLevel().
363 int osrfLogGetLevel( void ) {
364 return _osrfLogLevel;
368 @name Message Logging Functions
370 These five functions are the most widely used of the logging routines. They all work
371 the same way, differing only in the levels of the messages they log, and in the tags
372 they use within those messages to indicate the message level.
374 The first two parameters define the location in the source code where the function is
375 called: the name of the source file and the line number. In practice these are normally
376 provided through use of the OSRF_LOG_MARK macro.
378 The third parameter is a printf-style format string, which will be expanded to form the
379 message text. Subsequent parameters, if any, will be formatted and inserted into the
380 expanded message text.
382 Depending on the current maximum message level, the message may or may not actually be
383 issued. See also osrfLogSetLevel().
388 @brief Log an error message.
389 @param file The file name of the source code calling the function.
390 @param line The line number of the source code calling the function.
391 @param msg A printf-style format string that will be expanded to form the message text,
395 void osrfLogError( const char* file, int line, const char* msg, ... ) {
397 if( _osrfLogLevel < OSRF_LOG_ERROR ) return;
398 VA_LIST_TO_STRING( msg );
399 _osrfLogDetail( OSRF_LOG_ERROR, file, line, VA_BUF );
403 @brief Log a warning message.
404 @param file The file name of the source code calling the function.
405 @param line The line number of the source code calling the function.
406 @param msg A printf-style format string that will be expanded to form the message text,
410 void osrfLogWarning( const char* file, int line, const char* msg, ... ) {
412 if( _osrfLogLevel < OSRF_LOG_WARNING ) return;
413 VA_LIST_TO_STRING( msg );
414 _osrfLogDetail( OSRF_LOG_WARNING, file, line, VA_BUF );
418 @brief Log an informational message.
419 @param file The file name of the source code calling the function.
420 @param line The line number of the source code calling the function.
421 @param msg A printf-style format string that will be expanded to form the message text,
425 void osrfLogInfo( const char* file, int line, const char* msg, ... ) {
427 if( _osrfLogLevel < OSRF_LOG_INFO ) return;
428 VA_LIST_TO_STRING( msg );
429 _osrfLogDetail( OSRF_LOG_INFO, file, line, VA_BUF );
433 @brief Log a debug message.
434 @param file The file name of the source code calling the function.
435 @param line The line number of the source code calling the function.
436 @param msg A printf-style format string that will be expanded to form the message text,
440 void osrfLogDebug( const char* file, int line, const char* msg, ... ) {
442 if( _osrfLogLevel < OSRF_LOG_DEBUG ) return;
443 VA_LIST_TO_STRING( msg );
444 _osrfLogDetail( OSRF_LOG_DEBUG, file, line, VA_BUF );
448 @brief Log an internal message.
449 @param file The file name of the source code calling the function.
450 @param line The line number of the source code calling the function.
451 @param msg A printf-style format string that will be expanded to form the message text,
455 void osrfLogInternal( const char* file, int line, const char* msg, ... ) {
457 if( _osrfLogLevel < OSRF_LOG_INTERNAL ) return;
458 VA_LIST_TO_STRING( msg );
459 _osrfLogDetail( OSRF_LOG_INTERNAL, file, line, VA_BUF );
465 @brief Issue activity log message.
466 @param file The file name of the source code calling the function.
467 @param line The line number of the source code calling the function.
468 @param msg A printf-style format string that will be expanded to form the message text,
472 Activity messages behave like informational messages, with the following differences:
473 - They are tagged "ACT" instead of "INFO";
474 - Though enabled by default, they may be disabled by a previous call to
475 osrfLogSetActivityEnabled();
476 - When Syslog is in use, they are assigned a separate facility number, which defaults
477 to LOG_LOCAL1 instead of LOG_LOCAL0. See also osrfLogSetSyslogActFacility().
479 void osrfLogActivity( const char* file, int line, const char* msg, ... ) {
481 if( _osrfLogLevel >= OSRF_LOG_INFO
482 || ( _osrfLogActivityEnabled && _osrfLogLevel >= OSRF_LOG_ACTIVITY ) )
484 VA_LIST_TO_STRING( msg );
486 if( _osrfLogActivityEnabled && _osrfLogLevel >= OSRF_LOG_ACTIVITY )
487 _osrfLogDetail( OSRF_LOG_ACTIVITY, file, line, VA_BUF );
489 /* also log at info level */
490 if( _osrfLogLevel >= OSRF_LOG_INFO )
491 _osrfLogDetail( OSRF_LOG_INFO, file, line, VA_BUF );
496 @brief Issue a log message.
497 @param level The message level.
498 @param filename The name of the source file from whence the message is issued.
499 @param line The line number from whence the message is issued.
500 @param msg The text of the message.
502 This function is the final common pathway for all messages.
504 The @a level parameter determines the tag to be incorporated into the message: "ERR",
505 "WARN", "INFO", "DEBG", "INT " or "ACT".
507 The @a filename and @a name identify the location in the application code from whence the
508 message is being issued.
510 Here we format the message and route it to the appropriate output destination, depending
511 on the current setting of _osrfLogType: Syslog, a log file, or standard error.
513 If the logging type has been set to OSRF_LOG_TYPE_FILE, but no file name has been
514 defined for the log file, the message is written to standard error.
516 static void _osrfLogDetail( int level, const char* filename, int line, char* msg ) {
518 if(!filename) filename = "";
520 char* label = "INFO"; /* level name */
521 int lvl = LOG_INFO; /* syslog level */
522 int fac = _osrfLogFacility;
530 case OSRF_LOG_WARNING:
545 case OSRF_LOG_INTERNAL:
550 case OSRF_LOG_ACTIVITY:
553 fac = _osrfLogActFacility;
557 char* xid = (_osrfLogXid) ? _osrfLogXid : "";
559 int logtype = _osrfLogType;
560 if( logtype == OSRF_LOG_TYPE_FILE && !_osrfLogFile )
562 // No log file defined? Temporarily reroute to stderr
563 logtype = OSRF_LOG_TYPE_STDERR;
566 if( logtype == OSRF_LOG_TYPE_SYSLOG ) {
569 /* give syslog some breathing room, and be cute about it */
570 strncat(buf, msg, 1535);
575 syslog( fac | lvl, "[%s:%ld:%s:%d:%s] %s", label, (long) getpid(), filename, line, xid, buf );
578 else if( logtype == OSRF_LOG_TYPE_FILE )
579 _osrfLogToFile( label, (long) getpid(), filename, line, xid, msg );
581 else if( logtype == OSRF_LOG_TYPE_STDERR )
582 fprintf( stderr, "[%s:%ld:%s:%d:%s] %s\n", label, (long) getpid(), filename, line, xid, msg );
587 @brief Write a message to a log file.
588 @param label The message type: "ERR", "WARN", etc..
589 @param pid The process id.
590 @param filename Name of the source file from whence the message was issued.
591 @param line Line number from whence the message was issued.
592 @param xid Transaction id (or an empty string if there is no transaction).
593 @param msg Message text.
595 Open the log file named by _osrfLogFile, in append mode; write the message; close the
596 file. If unable to open the log file, write the message to standard error.
598 static void _osrfLogToFile( const char* label, long pid, const char* filename, int line,
599 const char* xid, const char* msg ) {
601 if( !label || !filename || !xid || !msg )
602 return; // missing parameter(s)
605 return; // No log file defined
608 _osrfLogAppname = strdup("osrf"); // apply default application name
611 time_t t = time(NULL);
612 struct tm* tms = localtime(&t);
613 strftime(datebuf, sizeof( datebuf ), "%Y-%m-%d %H:%M:%S", tms);
615 FILE* file = fopen(_osrfLogFile, "a");
618 "Unable to fopen log file %s for writing; logging to standard error\n", _osrfLogFile);
619 fprintf(stderr, "%s %s [%s:%ld:%s:%d:%s] %s\n",
620 _osrfLogAppname, datebuf, label, (long) getpid(), filename, line, xid, msg );
625 fprintf(file, "%s %s [%s:%ld:%s:%d:%s] %s\n",
626 _osrfLogAppname, datebuf, label, (long) getpid(), filename, line, xid, msg );
627 if( fclose(file) != 0 )
628 fprintf( stderr, "Error closing log file: %s", strerror(errno));
633 @brief Translate a character string to a facility number for Syslog.
634 @param facility The string to be translated.
635 @return An integer in the range 0 through 7.
637 Take the sixth character (counting from 1). If it's a digit in the range '0' through '7',
638 return the corresponding value: LOG_LOCAL0, LOG_LOCAL1, etc... Otherwise -- or if the
639 string isn't long enough -- return LOG_LOCAL0 as a default.
641 Example: "LOCAL3" => LOG_LOCAL3.
643 (Syslog uses the LOG_LOCALx macros to designate different kinds of locally defined
644 facilities that may issue messages. Depending on the configuration, Syslog mey handle
645 messages from different facilities differently.)
647 int osrfLogFacilityToInt( const char* facility ) {
648 if(!facility) return LOG_LOCAL0;
649 if(strlen(facility) < 6) return LOG_LOCAL0;
650 switch( facility[5] ) {
651 case '0': return LOG_LOCAL0;
652 case '1': return LOG_LOCAL1;
653 case '2': return LOG_LOCAL2;
654 case '3': return LOG_LOCAL3;
655 case '4': return LOG_LOCAL4;
656 case '5': return LOG_LOCAL5;
657 case '6': return LOG_LOCAL6;
658 case '7': return LOG_LOCAL7;