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 /** Maximum message level. Messages of higher levels will be suppressed.
26 Default: OSRF_LOG_INFO. */
27 static int _osrfLogLevel = OSRF_LOG_INFO;
28 /** Boolean. If true, activity message are enabled. Default: true. */
29 static int _osrfLogActivityEnabled = 1;
30 /** Boolean. If true, the current process is a client; otherwise it's a server. Clients and
31 servers have different options with regard to transaction ids. See osrfLogSetXid(),
32 osrfLogForceXid(), and osrfLogMkXid(). Default: false. */
33 static int _osrfLogIsClient = 0;
35 /** An id identifying the current transaction. If defined, it is included into every
37 static char* _osrfLogXid = NULL; /* current xid */
38 /** A prefix used to generate transaction ids. It incorporates a timestamp and a process id. */
39 static char* _osrfLogXidPfx = NULL; /* xid prefix string */
41 static void osrfLogSetType( int logtype );
42 static void _osrfLogDetail( int level, const char* filename, int line, char* msg );
43 static void _osrfLogToFile( const char* label, long pid, const char* filename, int line,
44 const char* xid, const char* msg );
45 static void _osrfLogSetXid( const char* xid );
48 @brief Reset certain local static variables to their initial values.
50 Of the various static variables, we here reset only three:
51 - application name (deleted)
52 - file name of log file (deleted)
53 - log type (reset to OSRF_LOG_TYPE_STDERR)
55 void osrfLogCleanup( void ) {
56 free(_osrfLogAppname);
57 _osrfLogAppname = NULL;
60 _osrfLogType = OSRF_LOG_TYPE_STDERR;
65 @brief Record some options for later reference by the logging routines.
66 @param type Type of logging; i.e. where the log messages go.
67 @param appname Pointer to the application name (may be NULL).
68 @param maxlevel Which levels of message to issue or suppress.
70 Typically the values for these parameters come from a configuration file.
72 There are three valid values for @a type:
74 - OSRF_LOG_TYPE_FILE -- write messages to a log file
75 - OSRF_LOG_TYPE_SYSLOG -- write messages to the syslog facility
76 - OSRF_LOG_TYPE_STDERR -- write messages to standard error
78 If @a type has any other value, log messages will be written to standard error.
80 The logging type may be set separately by calling osrfLogSetType(). See also
81 osrfLogToStderr() and osrfRestoreLogType().
83 The @a appname string prefaces every log message. The default application name, if
84 not overridden by this function or by osrfLogSetAppname(), is "osrf".
86 Here are the valid values for @a maxlevel, with the corresponding macros:
90 - 3 OSRF_LOG_INFO (the default)
94 With the special exception of activity messages (see osrfLogActivity()), the logging
95 routines will suppress any messages at a level greater than that specified by
96 @a maxlevel. Setting @a maxlevel to zero or less suppresses all levels of message.
97 Setting it to 5 or more enables all levels of message.
99 The message level may be set separately by calling osrfLogSetLevel().
101 void osrfLogInit( int type, const char* appname, int maxlevel ) {
102 osrfLogSetType(type);
103 if(appname) osrfLogSetAppname(appname);
104 osrfLogSetLevel(maxlevel);
105 if( type == OSRF_LOG_TYPE_SYSLOG )
106 openlog(_osrfLogAppname, 0, _osrfLogFacility );
110 @brief Store a copy of a transaction id for future use.
111 @param xid Pointer to the transaction id to be stored.
113 static void _osrfLogSetXid( const char* xid ) {
115 if(_osrfLogXid) free(_osrfLogXid);
116 _osrfLogXid = strdup(xid);
121 @brief Store an empty string as the transaction id.
123 void osrfLogClearXid( void ) { _osrfLogSetXid(""); }
126 @brief Store a transaction id, unless running as a client process.
127 @param xid Pointer to the new transaction id
129 void osrfLogSetXid(char* xid) {
130 if(!_osrfLogIsClient) _osrfLogSetXid(xid);
134 @brief Store a transaction id for future use, whether running as a client or as a server.
135 @param xid Pointer to the new transaction id
137 void osrfLogForceXid(char* xid) {
142 @brief For client processes only: create and store a unique transaction id.
144 The generated transaction id concatenates a prefix (which must have been generated
145 previously by osrfLogSetIsClient()) and a sequence number that is incremented on each
148 Since the various pieces of the transaction id are of variable length, and not separated
149 by any non-numeric characters, the result is not guaranteed to be unique. However
150 collisions should be rare.
152 void osrfLogMkXid( void ) {
153 if(_osrfLogIsClient) {
154 static int _osrfLogXidInc = 0; /* increments with each new xid for uniqueness */
156 snprintf(buf, sizeof(buf), "%s%d", _osrfLogXidPfx, _osrfLogXidInc);
163 @brief Return a pointer to the currently stored transaction id, if any.
164 @return Pointer to the currently stored transaction id.
166 If no transaction id has been stored, return NULL.
168 const char* osrfLogGetXid( void ) {
173 @brief Note whether the current process is a client; if so, generate a transaction prefix.
174 @param is A boolean; true means the current process is a client, false means it isn't.
176 The generated prefix concatenates a timestamp (the return from time()) and a process id.
178 void osrfLogSetIsClient(int is) {
179 _osrfLogIsClient = is;
181 /* go ahead and create the xid prefix so it will be consistent later */
182 static char buff[32];
183 snprintf(buff, sizeof(buff), "%d%ld", (int)time(NULL), (long) getpid());
184 _osrfLogXidPfx = buff;
188 @brief Specify what kind of logging to perform.
189 @param logtype A code indicating the type of logging.
191 There are three valid values for @a logtype:
193 - OSRF_LOG_TYPE_FILE -- write messages to a log file
194 - OSRF_LOG_TYPE_SYSLOG -- write messages to the syslog facility
195 - OSRF_LOG_TYPE_STDERR -- write messages to standard error
197 If @a logtype has any other value, log messages will be written to standard error.
199 This function merely records the log type for future reference. It does not open
202 See also osrfLogInit(), osrfLogToStderr() and osrfRestoreLogType().
205 static void osrfLogSetType( int logtype ) {
209 case OSRF_LOG_TYPE_FILE :
210 case OSRF_LOG_TYPE_SYSLOG :
211 case OSRF_LOG_TYPE_STDERR :
212 _osrfLogType = logtype;
215 fprintf(stderr, "Unrecognized log type. Logging to stderr\n");
216 _osrfLogType = OSRF_LOG_TYPE_STDERR;
222 @brief Switch the logging output to standard error (but remember where it @em was going).
224 See also osrfRestoreLogType().
226 void osrfLogToStderr( void )
228 if( OSRF_NO_LOG_TYPE == _prevLogType ) {
229 _prevLogType = _osrfLogType;
230 _osrfLogType = OSRF_LOG_TYPE_STDERR;
235 @brief Switch the logging output to wherever it was going before calling osrfLogtoStderr().
237 By using osrfRestoreLogType together with osrfRestoreLogType(), an application can
238 temporarily redirect log messages to standard error, either for an interactive
239 session or for debugging, and later revert to the original log output.
241 void osrfRestoreLogType( void )
243 if( _prevLogType != OSRF_NO_LOG_TYPE ) {
244 _osrfLogType = _prevLogType;
245 _prevLogType = OSRF_NO_LOG_TYPE;
250 @brief Store a file name for a log file.
251 @param logfile Pointer to the file name.
253 The new file name replaces whatever file name was previously in place, if any.
255 This function does not affect the logging type. The choice of file name makes a
256 difference only when the logging type is OSRF_LOG_TYPE_FILE.
258 void osrfLogSetFile( const char* logfile ) {
260 if(_osrfLogFile) free(_osrfLogFile);
261 _osrfLogFile = strdup(logfile);
265 @brief Enable the issuance of activity log messages.
267 By default, activity messages are enabled. See also osrfLogActivity().
269 void osrfLogSetActivityEnabled( int enabled ) {
270 _osrfLogActivityEnabled = enabled;
274 @brief Store an application name for future use.
275 @param appname Pointer to the application name to be stored.
277 The @a appname string prefaces every log message. The default application name is "osrf".
279 void osrfLogSetAppname( const char* appname ) {
281 if(_osrfLogAppname) free(_osrfLogAppname);
282 _osrfLogAppname = strdup(appname);
284 /* if syslogging, re-open the log with the appname */
285 if( _osrfLogType == OSRF_LOG_TYPE_SYSLOG) {
287 openlog(_osrfLogAppname, 0, _osrfLogFacility);
292 @brief Store a facility number for future use.
293 @param facility The facility number to be stored.
295 A facility is a small integer passed to the Syslog system to characterize the source
296 of a message. The value of this integer is typically derived from a configuration file.
297 If not otherwise specified, it defaults to LOG_LOCAL0.
299 void osrfLogSetSyslogFacility( int facility ) {
300 _osrfLogFacility = facility;
304 @brief Store a facility number for future use for activity messages.
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.
310 The facility used for activity messages is separate and distinct from that used for
311 other log messages, and defaults to LOG_LOCAL1.
313 void osrfLogSetSyslogActFacility( int facility ) {
314 _osrfLogActFacility = facility;
318 @brief Set the maximum level of messages to be issued.
319 @param loglevel The maximum message level.
321 A log message will be issued only if its level is less than or equal to this maximum.
322 For example, if @a loglevel is set to OSRF_LOG_INFO, then the logging routines will
323 issue information messages, warning messages, and error messages, but not debugging
324 messages or internal messages.
326 The default message level is OSRF_LOG_INFO.
328 void osrfLogSetLevel( int loglevel ) {
329 _osrfLogLevel = loglevel;
333 @brief Get the current log message level.
334 @return The current log message level.
336 See also osrfLogSetLevel().
338 int osrfLogGetLevel( void ) {
339 return _osrfLogLevel;
343 @name Message Logging Functions
345 These five functions are the most widely used of the logging routines. They all work
346 the same way, differing only in the levels of the messages they log, and in the tags
347 they use within those messages to indicate the message level.
349 The first two parameters define the location in the source code where the function is
350 called: the name of the source file and the line number. In practice these are normally
351 provided through use of the OSRF_LOG_MARK macro.
353 The third parameter is a printf-style format string, which will be expanded to form the
354 message text. Subsequent parameters, if any, will be formatted and inserted into the
355 expanded message text.
357 Depending on the current maximum message level, the message may or may not actually be
358 issued. See also osrfLogSetLevel().
363 @brief Log an error message.
364 @param file The file name of the source code calling the function.
365 @param line The line number of the source code calling the function.
366 @param msg A printf-style format string that will be expanded to form the message text,
370 void osrfLogError( const char* file, int line, const char* msg, ... ) {
372 if( _osrfLogLevel < OSRF_LOG_ERROR ) return;
373 VA_LIST_TO_STRING( msg );
374 _osrfLogDetail( OSRF_LOG_ERROR, file, line, VA_BUF );
378 @brief Log a warning message.
379 @param file The file name of the source code calling the function.
380 @param line The line number of the source code calling the function.
381 @param msg A printf-style format string that will be expanded to form the message text,
385 void osrfLogWarning( const char* file, int line, const char* msg, ... ) {
387 if( _osrfLogLevel < OSRF_LOG_WARNING ) return;
388 VA_LIST_TO_STRING( msg );
389 _osrfLogDetail( OSRF_LOG_WARNING, file, line, VA_BUF );
393 @brief Log an informational message.
394 @param file The file name of the source code calling the function.
395 @param line The line number of the source code calling the function.
396 @param msg A printf-style format string that will be expanded to form the message text,
400 void osrfLogInfo( const char* file, int line, const char* msg, ... ) {
402 if( _osrfLogLevel < OSRF_LOG_INFO ) return;
403 VA_LIST_TO_STRING( msg );
404 _osrfLogDetail( OSRF_LOG_INFO, file, line, VA_BUF );
408 @brief Log a debug message.
409 @param file The file name of the source code calling the function.
410 @param line The line number of the source code calling the function.
411 @param msg A printf-style format string that will be expanded to form the message text,
415 void osrfLogDebug( const char* file, int line, const char* msg, ... ) {
417 if( _osrfLogLevel < OSRF_LOG_DEBUG ) return;
418 VA_LIST_TO_STRING( msg );
419 _osrfLogDetail( OSRF_LOG_DEBUG, file, line, VA_BUF );
423 @brief Log an internal message.
424 @param file The file name of the source code calling the function.
425 @param line The line number of the source code calling the function.
426 @param msg A printf-style format string that will be expanded to form the message text,
430 void osrfLogInternal( const char* file, int line, const char* msg, ... ) {
432 if( _osrfLogLevel < OSRF_LOG_INTERNAL ) return;
433 VA_LIST_TO_STRING( msg );
434 _osrfLogDetail( OSRF_LOG_INTERNAL, file, line, VA_BUF );
440 @brief Issue activity log message.
441 @param file The file name of the source code calling the function.
442 @param line The line number of the source code calling the function.
443 @param msg A printf-style format string that will be expanded to form the message text,
447 Activity messages behave like informational messages, with the following differences:
448 - They are tagged "ACT" instead of "INFO";
449 - Though enabled by default, they may be disabled by a previous call to
450 osrfLogSetActivityEnabled();
451 - When Syslog is in use, they are assigned a separate facility number, which defaults
452 to LOG_LOCAL1 instead of LOG_LOCAL0. See also osrfLogSetSyslogActFacility().
454 void osrfLogActivity( const char* file, int line, const char* msg, ... ) {
456 if( _osrfLogLevel >= OSRF_LOG_INFO
457 || ( _osrfLogActivityEnabled && _osrfLogLevel >= OSRF_LOG_ACTIVITY ) )
459 VA_LIST_TO_STRING( msg );
461 if( _osrfLogActivityEnabled && _osrfLogLevel >= OSRF_LOG_ACTIVITY )
462 _osrfLogDetail( OSRF_LOG_ACTIVITY, file, line, VA_BUF );
464 /* also log at info level */
465 if( _osrfLogLevel >= OSRF_LOG_INFO )
466 _osrfLogDetail( OSRF_LOG_INFO, file, line, VA_BUF );
471 @brief Issue a log message.
472 @param level The message level.
473 @param filename The name of the source file from whence the message is issued.
474 @param line The line number from whence the message is issued.
475 @param msg The text of the message.
477 This function is the final common pathway for all messages.
479 The @a level parameter determines the tag to be incorporated into the message: "ERR",
480 "WARN", "INFO", "DEBG", "INT " or "ACT".
482 The @a filename and @a name identify the location in the application code from whence the
483 message is being issued.
485 Here we format the message and route it to the appropriate output destination, depending
486 on the current setting of _osrfLogType: Syslog, a log file, or standard error.
488 If the logging type has been set to OSRF_LOG_TYPE_FILE, but no file name has been
489 defined for the log file, the message is written to standard error.
491 static void _osrfLogDetail( int level, const char* filename, int line, char* msg ) {
493 if(!filename) filename = "";
495 char* label = "INFO"; /* level name */
496 int lvl = LOG_INFO; /* syslog level */
497 int fac = _osrfLogFacility;
505 case OSRF_LOG_WARNING:
520 case OSRF_LOG_INTERNAL:
525 case OSRF_LOG_ACTIVITY:
528 fac = _osrfLogActFacility;
532 char* xid = (_osrfLogXid) ? _osrfLogXid : "";
534 int logtype = _osrfLogType;
535 if( logtype == OSRF_LOG_TYPE_FILE && !_osrfLogFile )
537 // No log file defined? Temporarily reroute to stderr
538 logtype = OSRF_LOG_TYPE_STDERR;
541 if( logtype == OSRF_LOG_TYPE_SYSLOG ) {
544 /* give syslog some breathing room, and be cute about it */
545 strncat(buf, msg, 1535);
550 syslog( fac | lvl, "[%s:%ld:%s:%d:%s] %s", label, (long) getpid(), filename, line, xid, buf );
553 else if( logtype == OSRF_LOG_TYPE_FILE )
554 _osrfLogToFile( label, (long) getpid(), filename, line, xid, msg );
556 else if( logtype == OSRF_LOG_TYPE_STDERR )
557 fprintf( stderr, "[%s:%ld:%s:%d:%s] %s\n", label, (long) getpid(), filename, line, xid, msg );
562 @brief Write a message to a log file.
563 @param label The message type: "ERR", "WARN", etc..
564 @param pid The process id.
565 @param filename Name of the source file from whence the message was issued.
566 @param line Line number from whence the message was issued.
567 @param xid Transaction id (or an empty string if there is no transaction).
568 @param msg Message text.
570 Open the log file named by _osrfLogFile, in append mode; write the message; close the
571 file. If unable to open the log file, write the message to standard error.
573 static void _osrfLogToFile( const char* label, long pid, const char* filename, int line,
574 const char* xid, const char* msg ) {
576 if( !label || !filename || !xid || !msg )
577 return; // missing parameter(s)
580 return; // No log file defined
583 _osrfLogAppname = strdup("osrf"); // apply default application name
586 time_t t = time(NULL);
587 struct tm* tms = localtime(&t);
588 strftime(datebuf, sizeof( datebuf ), "%Y-%m-%d %H:%M:%S", tms);
590 FILE* file = fopen(_osrfLogFile, "a");
593 "Unable to fopen log file %s for writing; logging to standard error\n", _osrfLogFile);
594 fprintf(stderr, "%s %s [%s:%ld:%s:%d:%s] %s\n",
595 _osrfLogAppname, datebuf, label, (long) getpid(), filename, line, xid, msg );
600 fprintf(file, "%s %s [%s:%ld:%s:%d:%s] %s\n",
601 _osrfLogAppname, datebuf, label, (long) getpid(), filename, line, xid, msg );
602 if( fclose(file) != 0 )
603 fprintf( stderr, "Error closing log file: %s", strerror(errno));
608 @brief Translate a character string to a facility number for Syslog.
609 @param facility The string to be translated.
610 @return An integer in the range 0 through 7.
612 Take the sixth character (counting from 1). If it's a digit in the range '0' through '7',
613 return the corresponding value: LOG_LOCAL0, LOG_LOCAL1, etc... Otherwise -- or if the
614 string isn't long enough -- return LOG_LOCAL0 as a default.
616 Example: "LOCAL3" => LOG_LOCAL3.
618 (Syslog uses the LOG_LOCALx macros to designate different kinds of locally defined
619 facilities that may issue messages. Depending on the configuration, Syslog mey handle
620 messages from different facilities differently.)
622 int osrfLogFacilityToInt( const char* facility ) {
623 if(!facility) return LOG_LOCAL0;
624 if(strlen(facility) < 6) return LOG_LOCAL0;
625 switch( facility[5] ) {
626 case '0': return LOG_LOCAL0;
627 case '1': return LOG_LOCAL1;
628 case '2': return LOG_LOCAL2;
629 case '3': return LOG_LOCAL3;
630 case '4': return LOG_LOCAL4;
631 case '5': return LOG_LOCAL5;
632 case '6': return LOG_LOCAL6;
633 case '7': return LOG_LOCAL7;