Add doxygen-style comments to document all functions and all variables
[OpenSRF.git] / src / libopensrf / log.c
1 /**
2         @file log.c
3         @brief Routines for logging messages.
4 */
5
6 #include <opensrf/log.h>
7
8 /** Pseudo-log type indicating that no previous log type was defined.
9         See also _prevLogType. */
10 #define OSRF_NO_LOG_TYPE -1
11
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;
34
35 /** An id identifying the current transaction.  If defined, it is included into every
36         log message. */
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 */
40
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 );
46
47 /**
48         @brief Reset certain local static variables to their initial values.
49
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)
54 */
55 void osrfLogCleanup( void ) {
56         free(_osrfLogAppname);
57         _osrfLogAppname = NULL;
58         free(_osrfLogFile);
59         _osrfLogFile = NULL;
60         _osrfLogType = OSRF_LOG_TYPE_STDERR;
61 }
62
63
64 /**
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.
69
70         Typically the values for these parameters come from a configuration file.
71
72         There are three valid values for @a type:
73
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
77
78         If @a type has any other value, log messages will be written to standard error.
79
80         The logging type may be set separately by calling osrfLogSetType().  See also
81         osrfLogToStderr() and osrfRestoreLogType().
82
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".
85
86         Here are the valid values for @a maxlevel, with the corresponding macros:
87
88         - 1 OSRF_LOG_ERROR
89         - 2 OSRF_LOG_WARNING
90         - 3 OSRF_LOG_INFO (the default)
91         - 4 OSRF_LOG_DEBUG
92         - 5 OSRF_LOG_INTERNAL
93
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.
98
99         The message level may be set separately by calling osrfLogSetLevel().
100 */
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 );
107 }
108
109 /**
110         @brief Store a copy of a transaction id for future use.
111         @param xid Pointer to the transaction id to be stored.
112 */
113 static void _osrfLogSetXid( const char* xid ) {
114    if(xid) {
115       if(_osrfLogXid) free(_osrfLogXid);
116       _osrfLogXid = strdup(xid);
117    }
118 }
119
120 /**
121         @brief Store an empty string as the transaction id.
122 */
123 void osrfLogClearXid( void ) { _osrfLogSetXid(""); }
124
125 /**
126         @brief Store a transaction id, unless running as a client process.
127         @param xid Pointer to the new transaction id
128 */
129 void osrfLogSetXid(char* xid) {
130    if(!_osrfLogIsClient) _osrfLogSetXid(xid);
131 }
132
133 /**
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
136 */
137 void osrfLogForceXid(char* xid) {
138    _osrfLogSetXid(xid);
139 }
140
141 /**
142         @brief For client processes only: create and store a unique transaction id.
143
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
146         call.
147
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.
151 */
152 void osrfLogMkXid( void ) {
153    if(_osrfLogIsClient) {
154       static int _osrfLogXidInc = 0; /* increments with each new xid for uniqueness */
155       char buf[32];
156       snprintf(buf, sizeof(buf), "%s%d", _osrfLogXidPfx, _osrfLogXidInc);
157       _osrfLogSetXid(buf);
158       _osrfLogXidInc++;
159    }
160 }
161
162 /**
163         @brief Return a pointer to the currently stored transaction id, if any.
164         @return Pointer to the currently stored transaction id.
165
166         If no transaction id has been stored, return NULL.
167 */
168 const char* osrfLogGetXid( void ) {
169    return _osrfLogXid;
170 }
171
172 /**
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.
175
176         The generated prefix concatenates a timestamp (the return from time()) and a process id.
177 */
178 void osrfLogSetIsClient(int is) {
179    _osrfLogIsClient = is;
180    if(!is) return;
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;
185 }
186
187 /**
188         @brief Specify what kind of logging to perform.
189         @param logtype A code indicating the type of logging.
190
191         There are three valid values for @a logtype:
192
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
196
197         If @a logtype has any other value, log messages will be written to standard error.
198
199         This function merely records the log type for future reference.  It does not open
200         or close any files.
201
202         See also osrfLogInit(), osrfLogToStderr() and osrfRestoreLogType().
203
204 */
205 static void osrfLogSetType( int logtype ) {
206
207         switch( logtype )
208         {
209                 case OSRF_LOG_TYPE_FILE :
210                 case OSRF_LOG_TYPE_SYSLOG :
211                 case OSRF_LOG_TYPE_STDERR :
212                         _osrfLogType = logtype;
213                         break;
214                 default :
215                         fprintf(stderr, "Unrecognized log type.  Logging to stderr\n");
216                         _osrfLogType = OSRF_LOG_TYPE_STDERR;
217                         break;
218         }
219 }
220
221 /**
222         @brief Switch the logging output to standard error (but remember where it @em was going).
223
224         See also osrfRestoreLogType().
225 */
226 void osrfLogToStderr( void )
227 {
228         if( OSRF_NO_LOG_TYPE == _prevLogType ) {
229                 _prevLogType = _osrfLogType;
230                 _osrfLogType = OSRF_LOG_TYPE_STDERR;
231         }
232 }
233
234 /**
235         @brief Switch the logging output to wherever it was going before calling osrfLogtoStderr().
236
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.
240 */
241 void osrfRestoreLogType( void )
242 {
243         if( _prevLogType != OSRF_NO_LOG_TYPE ) {
244                 _osrfLogType = _prevLogType;
245                 _prevLogType = OSRF_NO_LOG_TYPE;
246         }
247 }
248
249 /**
250         @brief Store a file name for a log file.
251         @param logfile Pointer to the file name.
252
253         The new file name replaces whatever file name was previously in place, if any.
254
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.
257 */
258 void osrfLogSetFile( const char* logfile ) {
259         if(!logfile) return;
260         if(_osrfLogFile) free(_osrfLogFile);
261         _osrfLogFile = strdup(logfile);
262 }
263
264 /**
265         @brief Enable the issuance of activity log messages.
266
267         By default, activity messages are enabled.  See also osrfLogActivity().
268 */
269 void osrfLogSetActivityEnabled( int enabled ) {
270         _osrfLogActivityEnabled = enabled;
271 }
272
273 /**
274         @brief Store an application name for future use.
275         @param appname Pointer to the application name to be stored.
276
277         The @a appname string prefaces every log message.  The default application name is "osrf".
278 */
279 void osrfLogSetAppname( const char* appname ) {
280         if(!appname) return;
281         if(_osrfLogAppname) free(_osrfLogAppname);
282         _osrfLogAppname = strdup(appname);
283
284         /* if syslogging, re-open the log with the appname */
285         if( _osrfLogType == OSRF_LOG_TYPE_SYSLOG) {
286                 closelog();
287                 openlog(_osrfLogAppname, 0, _osrfLogFacility);
288         }
289 }
290
291 /**
292         @brief Store a facility number for future use.
293         @param facility The facility number to be stored.
294
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.
298 */
299 void osrfLogSetSyslogFacility( int facility ) {
300         _osrfLogFacility = facility;
301 }
302
303 /**
304         @brief Store a facility number for future use for activity messages.
305         @param facility The facility number to be stored.
306
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
310         The facility used for activity messages is separate and distinct from that used for
311         other log messages, and defaults to LOG_LOCAL1.
312  */
313 void osrfLogSetSyslogActFacility( int facility ) {
314         _osrfLogActFacility = facility;
315 }
316
317 /**
318         @brief Set the maximum level of messages to be issued.
319         @param loglevel The maximum message level.
320
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.
325
326         The default message level is OSRF_LOG_INFO.
327 */
328 void osrfLogSetLevel( int loglevel ) {
329         _osrfLogLevel = loglevel;
330 }
331
332 /**
333         @brief Get the current log message level.
334         @return The current log message level.
335
336         See also osrfLogSetLevel().
337  */
338 int osrfLogGetLevel( void ) {
339         return _osrfLogLevel;
340 }
341
342 /**
343         @name Message Logging Functions
344         
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.
348
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.
352
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.
356
357         Depending on the current maximum message level, the message may or may not actually be
358         issued.  See also osrfLogSetLevel().
359 */
360 /*@{*/
361
362 /**
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,
367
368         Tag: "ERR".
369 */
370 void osrfLogError( const char* file, int line, const char* msg, ... ) {
371         if( !msg ) return;
372         if( _osrfLogLevel < OSRF_LOG_ERROR ) return;
373         VA_LIST_TO_STRING( msg );
374         _osrfLogDetail( OSRF_LOG_ERROR, file, line, VA_BUF );
375 }
376
377 /**
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,
382
383         Tag: "WARN".
384  */
385 void osrfLogWarning( const char* file, int line, const char* msg, ... ) {
386         if( !msg ) return;
387         if( _osrfLogLevel < OSRF_LOG_WARNING ) return;
388         VA_LIST_TO_STRING( msg );
389         _osrfLogDetail( OSRF_LOG_WARNING, file, line, VA_BUF );
390 }
391
392 /**
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,
397
398         Tag: "INFO".
399  */
400 void osrfLogInfo( const char* file, int line, const char* msg, ... ) {
401         if( !msg ) return;
402         if( _osrfLogLevel < OSRF_LOG_INFO ) return;
403         VA_LIST_TO_STRING( msg );
404         _osrfLogDetail( OSRF_LOG_INFO, file, line, VA_BUF );
405 }
406
407 /**
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,
412  
413         Tag: "DEBG".
414  */
415 void osrfLogDebug( const char* file, int line, const char* msg, ... ) {
416         if( !msg ) return;
417         if( _osrfLogLevel < OSRF_LOG_DEBUG ) return;
418         VA_LIST_TO_STRING( msg );
419         _osrfLogDetail( OSRF_LOG_DEBUG, file, line, VA_BUF );
420 }
421
422 /**
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,
427
428         Tag: "INT ".
429  */
430 void osrfLogInternal( const char* file, int line, const char* msg, ... ) {
431         if( !msg ) return;
432         if( _osrfLogLevel < OSRF_LOG_INTERNAL ) return;
433         VA_LIST_TO_STRING( msg );
434         _osrfLogDetail( OSRF_LOG_INTERNAL, file, line, VA_BUF );
435 }
436
437 /*@}*/
438
439 /**
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,
444
445         Tag: "ACT".
446
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().
453 */
454 void osrfLogActivity( const char* file, int line, const char* msg, ... ) {
455         if( !msg ) return;
456         if( _osrfLogLevel >= OSRF_LOG_INFO
457                 || ( _osrfLogActivityEnabled && _osrfLogLevel >= OSRF_LOG_ACTIVITY ) )
458         {
459                 VA_LIST_TO_STRING( msg );
460
461                 if( _osrfLogActivityEnabled && _osrfLogLevel >= OSRF_LOG_ACTIVITY )
462                         _osrfLogDetail( OSRF_LOG_ACTIVITY, file, line, VA_BUF );
463
464                 /* also log at info level */
465                 if( _osrfLogLevel >= OSRF_LOG_INFO )
466                         _osrfLogDetail( OSRF_LOG_INFO, file, line, VA_BUF );
467         }
468 }
469
470 /**
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.
476
477         This function is the final common pathway for all messages.
478
479         The @a level parameter determines the tag to be incorporated into the message: "ERR",
480         "WARN", "INFO", "DEBG", "INT " or "ACT".
481
482         The @a filename and @a name identify the location in the application code from whence the
483         message is being issued.
484
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.
487
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.
490 */
491 static void _osrfLogDetail( int level, const char* filename, int line, char* msg ) {
492
493         if(!filename) filename = "";
494
495         char* label = "INFO";           /* level name */
496         int lvl = LOG_INFO;     /* syslog level */
497         int fac = _osrfLogFacility;
498
499         switch( level ) {
500                 case OSRF_LOG_ERROR:            
501                         label = "ERR "; 
502                         lvl = LOG_ERR;
503                         break;
504
505                 case OSRF_LOG_WARNING:  
506                         label = "WARN"; 
507                         lvl = LOG_WARNING;
508                         break;
509
510                 case OSRF_LOG_INFO:             
511                         label = "INFO"; 
512                         lvl = LOG_INFO;
513                         break;
514
515                 case OSRF_LOG_DEBUG:    
516                         label = "DEBG"; 
517                         lvl = LOG_DEBUG;
518                         break;
519
520                 case OSRF_LOG_INTERNAL: 
521                         label = "INT "; 
522                         lvl = LOG_DEBUG;
523                         break;
524
525                 case OSRF_LOG_ACTIVITY: 
526                         label = "ACT"; 
527                         lvl = LOG_INFO;
528                         fac = _osrfLogActFacility;
529                         break;
530         }
531
532    char* xid = (_osrfLogXid) ? _osrfLogXid : "";
533
534    int logtype = _osrfLogType;
535    if( logtype == OSRF_LOG_TYPE_FILE && !_osrfLogFile )
536    {
537            // No log file defined?  Temporarily reroute to stderr
538            logtype = OSRF_LOG_TYPE_STDERR;
539    }
540
541    if( logtype == OSRF_LOG_TYPE_SYSLOG ) {
542                 char buf[1536];  
543                 buf[0] = '\0';
544                 /* give syslog some breathing room, and be cute about it */
545                 strncat(buf, msg, 1535);
546                 buf[1532] = '.';
547                 buf[1533] = '.';
548                 buf[1534] = '.';
549                 buf[1535] = '\0';
550                 syslog( fac | lvl, "[%s:%ld:%s:%d:%s] %s", label, (long) getpid(), filename, line, xid, buf );
551         }
552
553         else if( logtype == OSRF_LOG_TYPE_FILE )
554                 _osrfLogToFile( label, (long) getpid(), filename, line, xid, msg );
555
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 );
558 }
559
560
561 /**
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.
569
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.
572 */
573 static void _osrfLogToFile( const char* label, long pid, const char* filename, int line,
574         const char* xid, const char* msg ) {
575
576         if( !label || !filename || !xid || !msg )
577                 return;           // missing parameter(s)
578
579         if(!_osrfLogFile)
580                 return;           // No log file defined
581
582         if(!_osrfLogAppname)
583                 _osrfLogAppname = strdup("osrf");   // apply default application name
584
585         char datebuf[36];
586         time_t t = time(NULL);
587         struct tm* tms = localtime(&t);
588         strftime(datebuf, sizeof( datebuf ), "%Y-%m-%d %H:%M:%S", tms);
589
590         FILE* file = fopen(_osrfLogFile, "a");
591         if(!file) {
592                 fprintf(stderr,
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 );
596
597                 return;
598         }
599
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));
604
605 }
606
607 /**
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.
611
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.
615
616         Example: "LOCAL3" => LOG_LOCAL3.
617
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.)
621 */
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;
634         }
635         return LOG_LOCAL0;
636 }
637
638