1 #include <opensrf/log.h>
3 #define OSRF_NO_LOG_TYPE -1
5 static int _prevLogType = OSRF_NO_LOG_TYPE;
6 static int _osrfLogType = OSRF_LOG_TYPE_STDERR;
7 static int _osrfLogFacility = LOG_LOCAL0;
8 static int _osrfLogActFacility = LOG_LOCAL1;
9 static char* _osrfLogFile = NULL;
10 static char* _osrfLogAppname = NULL;
11 static int _osrfLogLevel = OSRF_LOG_INFO;
12 static int _osrfLogActivityEnabled = 1;
13 static int _osrfLogIsClient = 0;
15 static char* _osrfLogXid = NULL; /* current xid */
16 static char* _osrfLogXidPfx = NULL; /* xid prefix string */
18 static void osrfLogSetType( int logtype );
19 static void _osrfLogDetail( int level, const char* filename, int line, char* msg );
20 static void _osrfLogToFile( const char* label, long pid, const char* filename, int line,
21 const char* xid, const char* msg );
22 static void _osrfLogSetXid( const char* xid );
24 void osrfLogCleanup( void ) {
25 free(_osrfLogAppname);
26 _osrfLogAppname = NULL;
29 _osrfLogType = OSRF_LOG_TYPE_STDERR;
34 @brief Record some options for later reference by the logging routines.
35 @param type Type of logging; i.e. where the log messages go.
36 @param appname Pointer to the application name (may be NULL).
37 @param maxlevel Which levels of message to issue or suppress.
39 Typically the values for these parameters come from a configuration file.
41 There are three valid values for @a type:
43 - OSRF_LOG_TYPE_FILE -- write messages to a log file
44 - OSRF_LOG_TYPE_SYSLOG -- write messages to the syslog facility
45 - OSRF_LOG_TYPE_STDERR -- write messages to standard error
47 If @a type has any other value, log messages will be written to standard error.
49 The logging type may be set separately by calling osrfLogSetType(). See also
50 osrfLogToStderr() and osrfRestoreLogType().
52 The @a appname string prefaces every log message written to a log file or to standard
53 error. It also identifies the application to the Syslog facility, if the application
54 uses Syslog. The default application name, if not overridden by this function or by
55 osrfLogSetAppname(), is "osrf".
57 Here are the valid values for @a maxlevel, with the corresponding macros:
61 - 3 OSRF_LOG_INFO (the default)
65 With the special exception of activity messages (see osrfLogActivity()), the logging
66 routines will suppress any messages at a level greater than that specified by
67 @a maxlevel. Setting @a maxlevel to zero or less suppresses all levels of message.
68 Setting it to 5 or more enables all levels of message.
70 The message level may be set separately by calling osrfLogSetLevel().
72 void osrfLogInit( int type, const char* appname, int maxlevel ) {
74 if(appname) osrfLogSetAppname(appname);
75 osrfLogSetLevel(maxlevel);
76 if( type == OSRF_LOG_TYPE_SYSLOG )
77 openlog(_osrfLogAppname, 0, _osrfLogFacility );
80 static void _osrfLogSetXid( const char* xid ) {
82 if(_osrfLogXid) free(_osrfLogXid);
83 _osrfLogXid = strdup(xid);
87 void osrfLogClearXid( void ) { _osrfLogSetXid(""); }
88 void osrfLogSetXid(char* xid) {
89 if(!_osrfLogIsClient) _osrfLogSetXid(xid);
91 void osrfLogForceXid(char* xid) {
95 void osrfLogMkXid( void ) {
96 if(_osrfLogIsClient) {
97 static int _osrfLogXidInc = 0; /* increments with each new xid for uniqueness */
99 snprintf(buf, sizeof(buf), "%s%d", _osrfLogXidPfx, _osrfLogXidInc);
105 char* osrfLogGetXid( void ) {
109 void osrfLogSetIsClient(int is) {
110 _osrfLogIsClient = is;
112 /* go ahead and create the xid prefix so it will be consistent later */
113 static char buff[32];
114 snprintf(buff, sizeof(buff), "%d%ld", (int)time(NULL), (long) getpid());
115 _osrfLogXidPfx = buff;
119 @brief Specify what kind of logging to perform.
120 @param logtype A code indicating the type of logging.
122 There are three valid values for @a logtype:
124 - OSRF_LOG_TYPE_FILE -- write messages to a log file
125 - OSRF_LOG_TYPE_SYSLOG -- write messages to the syslog facility
126 - OSRF_LOG_TYPE_STDERR -- write messages to standard error
128 If @a logtype has any other value, log messages will be written to standard error.
130 This function merely records the log type for future reference. It does not open
133 See also osrfLogInit(), osrfLogToStderr() and osrfRestoreLogType().
136 static void osrfLogSetType( int logtype ) {
140 case OSRF_LOG_TYPE_FILE :
141 case OSRF_LOG_TYPE_SYSLOG :
142 case OSRF_LOG_TYPE_STDERR :
143 _osrfLogType = logtype;
146 fprintf(stderr, "Unrecognized log type. Logging to stderr\n");
147 _osrfLogType = OSRF_LOG_TYPE_STDERR;
152 void osrfLogToStderr( void )
154 if( OSRF_NO_LOG_TYPE == _prevLogType ) {
155 _prevLogType = _osrfLogType;
156 _osrfLogType = OSRF_LOG_TYPE_STDERR;
160 void osrfRestoreLogType( void )
162 if( _prevLogType != OSRF_NO_LOG_TYPE ) {
163 _osrfLogType = _prevLogType;
164 _prevLogType = OSRF_NO_LOG_TYPE;
168 void osrfLogSetFile( const char* logfile ) {
170 if(_osrfLogFile) free(_osrfLogFile);
171 _osrfLogFile = strdup(logfile);
174 void osrfLogSetActivityEnabled( int enabled ) {
175 _osrfLogActivityEnabled = enabled;
178 void osrfLogSetAppname( const char* appname ) {
180 if(_osrfLogAppname) free(_osrfLogAppname);
181 _osrfLogAppname = strdup(appname);
183 /* if syslogging, re-open the log with the appname */
184 if( _osrfLogType == OSRF_LOG_TYPE_SYSLOG) {
186 openlog(_osrfLogAppname, 0, _osrfLogFacility);
190 void osrfLogSetSyslogFacility( int facility ) {
191 _osrfLogFacility = facility;
193 void osrfLogSetSyslogActFacility( int facility ) {
194 _osrfLogActFacility = facility;
197 /** Sets the global log level. Any log statements with a higher level
198 * than "level" will not be logged */
199 void osrfLogSetLevel( int loglevel ) {
200 _osrfLogLevel = loglevel;
203 /** Gets the current global log level. **/
204 int osrfLogGetLevel( void ) {
205 return _osrfLogLevel;
208 void osrfLogError( const char* file, int line, const char* msg, ... ) {
210 if( _osrfLogLevel < OSRF_LOG_ERROR ) return;
211 VA_LIST_TO_STRING( msg );
212 _osrfLogDetail( OSRF_LOG_ERROR, file, line, VA_BUF );
215 void osrfLogWarning( const char* file, int line, const char* msg, ... ) {
217 if( _osrfLogLevel < OSRF_LOG_WARNING ) return;
218 VA_LIST_TO_STRING( msg );
219 _osrfLogDetail( OSRF_LOG_WARNING, file, line, VA_BUF );
222 void osrfLogInfo( const char* file, int line, const char* msg, ... ) {
224 if( _osrfLogLevel < OSRF_LOG_INFO ) return;
225 VA_LIST_TO_STRING( msg );
226 _osrfLogDetail( OSRF_LOG_INFO, file, line, VA_BUF );
229 void osrfLogDebug( const char* file, int line, const char* msg, ... ) {
231 if( _osrfLogLevel < OSRF_LOG_DEBUG ) return;
232 VA_LIST_TO_STRING( msg );
233 _osrfLogDetail( OSRF_LOG_DEBUG, file, line, VA_BUF );
236 void osrfLogInternal( const char* file, int line, const char* msg, ... ) {
238 if( _osrfLogLevel < OSRF_LOG_INTERNAL ) return;
239 VA_LIST_TO_STRING( msg );
240 _osrfLogDetail( OSRF_LOG_INTERNAL, file, line, VA_BUF );
243 void osrfLogActivity( const char* file, int line, const char* msg, ... ) {
245 if( _osrfLogLevel >= OSRF_LOG_INFO
246 || ( _osrfLogActivityEnabled && _osrfLogLevel >= OSRF_LOG_ACTIVITY ) )
248 VA_LIST_TO_STRING( msg );
250 if( _osrfLogActivityEnabled && _osrfLogLevel >= OSRF_LOG_ACTIVITY )
251 _osrfLogDetail( OSRF_LOG_ACTIVITY, file, line, VA_BUF );
253 /* also log at info level */
254 if( _osrfLogLevel >= OSRF_LOG_INFO )
255 _osrfLogDetail( OSRF_LOG_INFO, file, line, VA_BUF );
260 @brief Issue a log message.
261 @param level The message level.
262 @param filename The name of the source file from whence the message is issued.
263 @param line The line number from whence the message is issued.
264 @param msg The text of the message.
266 This function is the final common pathway for all messages.
268 The @a level parameter determines the tag to be incorporated into the message: "ERR",
269 "WARN", "INFO", "DEBG", "INT " or "ACT".
271 The @a filename and @a name identify the location in the application code from whence the
272 message is being issued.
274 Here we format the message and route it to the appropriate output destination, depending
275 on the current setting of _osrfLogType: Syslog, a log file, or standard error.
277 static void _osrfLogDetail( int level, const char* filename, int line, char* msg ) {
279 if(!filename) filename = "";
281 char* label = "INFO"; /* level name */
282 int lvl = LOG_INFO; /* syslog level */
283 int fac = _osrfLogFacility;
291 case OSRF_LOG_WARNING:
306 case OSRF_LOG_INTERNAL:
311 case OSRF_LOG_ACTIVITY:
314 fac = _osrfLogActFacility;
318 char* xid = (_osrfLogXid) ? _osrfLogXid : "";
320 int logtype = _osrfLogType;
321 if( logtype == OSRF_LOG_TYPE_FILE && !_osrfLogFile )
323 // No log file defined? Temporarily reroute to stderr
324 logtype = OSRF_LOG_TYPE_STDERR;
327 if( logtype == OSRF_LOG_TYPE_SYSLOG ) {
330 /* give syslog some breathing room, and be cute about it */
331 strncat(buf, msg, 1535);
336 syslog( fac | lvl, "[%s:%ld:%s:%d:%s] %s", label, (long) getpid(), filename, line, xid, buf );
339 else if( logtype == OSRF_LOG_TYPE_FILE )
340 _osrfLogToFile( label, (long) getpid(), filename, line, xid, msg );
342 else if( logtype == OSRF_LOG_TYPE_STDERR )
343 fprintf( stderr, "[%s:%ld:%s:%d:%s] %s\n", label, (long) getpid(), filename, line, xid, msg );
348 @brief Write a message to a log file.
349 @param label The message type: "ERR", "WARN", etc..
350 @param pid The process id.
351 @param filename Name of the source file from whence the message was issued.
352 @param line Line number from whence the message was issued.
353 @param xid Transaction id (or an empty string if there is no transaction).
354 @param msg Message text.
356 Open the log file named by _osrfLogFile, in append mode; write the message; close the
357 file. If unable to open the log file, write the message to standard error.
359 static void _osrfLogToFile( const char* label, long pid, const char* filename, int line,
360 const char* xid, const char* msg ) {
362 if( !label || !filename || !xid || !msg )
363 return; // missing parameter(s)
366 return; // No log file defined
369 _osrfLogAppname = strdup("osrf"); // apply default application name
372 time_t t = time(NULL);
373 struct tm* tms = localtime(&t);
374 strftime(datebuf, sizeof( datebuf ), "%Y-%m-%d %H:%M:%S", tms);
376 FILE* file = fopen(_osrfLogFile, "a");
379 "Unable to fopen log file %s for writing; logging to standard error\n", _osrfLogFile);
380 fprintf(stderr, "%s %s [%s:%ld:%s:%d:%s] %s\n",
381 _osrfLogAppname, datebuf, label, (long) getpid(), filename, line, xid, msg );
386 fprintf(file, "%s %s [%s:%ld:%s:%d:%s] %s\n",
387 _osrfLogAppname, datebuf, label, (long) getpid(), filename, line, xid, msg );
388 if( fclose(file) != 0 )
389 fprintf( stderr, "Error closing log file: %s", strerror(errno));
393 int osrfLogFacilityToInt( const char* facility ) {
394 if(!facility) return LOG_LOCAL0;
395 if(strlen(facility) < 6) return LOG_LOCAL0;
396 switch( facility[5] ) {
397 case '0': return LOG_LOCAL0;
398 case '1': return LOG_LOCAL1;
399 case '2': return LOG_LOCAL2;
400 case '3': return LOG_LOCAL3;
401 case '4': return LOG_LOCAL4;
402 case '5': return LOG_LOCAL5;
403 case '6': return LOG_LOCAL6;
404 case '7': return LOG_LOCAL7;