14fdf06fbcedce037a5ba45245f7814fa2c6f5b1
[OpenSRF.git] / src / libopensrf / log.c
1 #include <opensrf/log.h>
2
3 #define OSRF_NO_LOG_TYPE -1
4
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;
14
15 static char* _osrfLogXid            = NULL; /* current xid */
16 static char* _osrfLogXidPfx         = NULL; /* xid prefix string */
17
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* msg, ... );
21 static void _osrfLogSetXid( const char* xid );
22
23 #define OSRF_LOG_GO(f,li,m,l)   \
24         if(!m) return;          \
25         VA_LIST_TO_STRING(m);   \
26         _osrfLogDetail( l, f, li, VA_BUF );
27
28 void osrfLogCleanup( void ) {
29         free(_osrfLogAppname);
30         _osrfLogAppname = NULL;
31         free(_osrfLogFile);
32         _osrfLogFile = NULL;
33         _osrfLogType = OSRF_LOG_TYPE_STDERR;
34 }
35
36
37 void osrfLogInit( int type, const char* appname, int maxlevel ) {
38         osrfLogSetType(type);
39         if(appname) osrfLogSetAppname(appname);
40         osrfLogSetLevel(maxlevel);
41         if( type == OSRF_LOG_TYPE_SYSLOG ) 
42                 openlog(_osrfLogAppname, 0, _osrfLogFacility );
43 }
44
45 static void _osrfLogSetXid( const char* xid ) {
46    if(xid) {
47       if(_osrfLogXid) free(_osrfLogXid);
48       _osrfLogXid = strdup(xid);
49    }
50 }
51
52 void osrfLogClearXid( void ) { _osrfLogSetXid(""); }
53 void osrfLogSetXid(char* xid) {
54    if(!_osrfLogIsClient) _osrfLogSetXid(xid);
55 }
56 void osrfLogForceXid(char* xid) {
57    _osrfLogSetXid(xid);
58 }
59
60 void osrfLogMkXid( void ) {
61    if(_osrfLogIsClient) {
62       static int _osrfLogXidInc = 0; /* increments with each new xid for uniqueness */
63       char buf[32];
64       snprintf(buf, sizeof(buf), "%s%d", _osrfLogXidPfx, _osrfLogXidInc);
65       _osrfLogSetXid(buf);
66       _osrfLogXidInc++;
67    }
68 }
69
70 char* osrfLogGetXid( void ) {
71    return _osrfLogXid;
72 }
73
74 void osrfLogSetIsClient(int is) {
75    _osrfLogIsClient = is;
76    if(!is) return;
77    /* go ahead and create the xid prefix so it will be consistent later */
78    static char buff[32];
79    snprintf(buff, sizeof(buff), "%d%ld", (int)time(NULL), (long) getpid());
80    _osrfLogXidPfx = buff;
81 }
82
83 /** Sets the type of logging to perform.  See log types */
84 static void osrfLogSetType( int logtype ) {
85
86         switch( logtype )
87         {
88                 case OSRF_LOG_TYPE_FILE :
89                 case OSRF_LOG_TYPE_SYSLOG :
90                 case OSRF_LOG_TYPE_STDERR :
91                         _osrfLogType = logtype;
92                         break;
93                 default :
94                         fprintf(stderr, "Unrecognized log type.  Logging to stderr\n");
95                         _osrfLogType = OSRF_LOG_TYPE_STDERR;
96                         break;
97         }
98 }
99
100 void osrfLogToStderr( void )
101 {
102         if( OSRF_NO_LOG_TYPE == _prevLogType ) {
103                 _prevLogType = _osrfLogType;
104                 _osrfLogType = OSRF_LOG_TYPE_STDERR;
105         }
106 }
107
108 void osrfRestoreLogType( void )
109 {
110         if( _prevLogType != OSRF_NO_LOG_TYPE ) {
111                 _osrfLogType = _prevLogType;
112                 _prevLogType = OSRF_NO_LOG_TYPE;
113         }
114 }
115
116 void osrfLogSetFile( const char* logfile ) {
117         if(!logfile) return;
118         if(_osrfLogFile) free(_osrfLogFile);
119         _osrfLogFile = strdup(logfile);
120 }
121
122 void osrfLogSetActivityEnabled( int enabled ) {
123         _osrfLogActivityEnabled = enabled;
124 }
125
126 void osrfLogSetAppname( const char* appname ) {
127         if(!appname) return;
128         if(_osrfLogAppname) free(_osrfLogAppname);
129         _osrfLogAppname = strdup(appname);
130
131         /* if syslogging, re-open the log with the appname */
132         if( _osrfLogType == OSRF_LOG_TYPE_SYSLOG) {
133                 closelog();
134                 openlog(_osrfLogAppname, 0, _osrfLogFacility);
135         }
136 }
137
138 void osrfLogSetSyslogFacility( int facility ) {
139         _osrfLogFacility = facility;
140 }
141 void osrfLogSetSyslogActFacility( int facility ) {
142         _osrfLogActFacility = facility;
143 }
144
145 /** Sets the global log level.  Any log statements with a higher level
146  * than "level" will not be logged */
147 void osrfLogSetLevel( int loglevel ) {
148         _osrfLogLevel = loglevel;
149 }
150
151 /** Gets the current global log level. **/
152 int osrfLogGetLevel( void ) {
153         return _osrfLogLevel;
154 }
155
156 void osrfLogError( const char* file, int line, const char* msg, ... ) 
157         { OSRF_LOG_GO(file, line, msg, OSRF_LOG_ERROR); }
158 void osrfLogWarning( const char* file, int line, const char* msg, ... ) 
159         { OSRF_LOG_GO(file, line, msg, OSRF_LOG_WARNING); }
160 void osrfLogInfo( const char* file, int line, const char* msg, ... ) 
161         { OSRF_LOG_GO(file, line, msg, OSRF_LOG_INFO); }
162 void osrfLogDebug( const char* file, int line, const char* msg, ... ) 
163         { OSRF_LOG_GO(file, line, msg, OSRF_LOG_DEBUG); }
164 void osrfLogInternal( const char* file, int line, const char* msg, ... ) 
165         { OSRF_LOG_GO(file, line, msg, OSRF_LOG_INTERNAL); }
166 void osrfLogActivity( const char* file, int line, const char* msg, ... ) { 
167         OSRF_LOG_GO(file, line, msg, OSRF_LOG_ACTIVITY); 
168         _osrfLogDetail( OSRF_LOG_INFO, file, line, VA_BUF ); /* also log at info level */
169 }
170
171 /** Actually does the logging */
172 static void _osrfLogDetail( int level, const char* filename, int line, char* msg ) {
173
174         if( level == OSRF_LOG_ACTIVITY && ! _osrfLogActivityEnabled ) return;
175         if( level > _osrfLogLevel ) return;
176         if(!msg) return;
177         if(!filename) filename = "";
178
179         char* label = "INFO";           /* level name */
180         int lvl = LOG_INFO;     /* syslog level */
181         int fac = _osrfLogFacility;
182
183         switch( level ) {
184                 case OSRF_LOG_ERROR:            
185                         label = "ERR "; 
186                         lvl = LOG_ERR;
187                         break;
188
189                 case OSRF_LOG_WARNING:  
190                         label = "WARN"; 
191                         lvl = LOG_WARNING;
192                         break;
193
194                 case OSRF_LOG_INFO:             
195                         label = "INFO"; 
196                         lvl = LOG_INFO;
197                         break;
198
199                 case OSRF_LOG_DEBUG:    
200                         label = "DEBG"; 
201                         lvl = LOG_DEBUG;
202                         break;
203
204                 case OSRF_LOG_INTERNAL: 
205                         label = "INT "; 
206                         lvl = LOG_DEBUG;
207                         break;
208
209                 case OSRF_LOG_ACTIVITY: 
210                         label = "ACT"; 
211                         lvl = LOG_INFO;
212                         fac = _osrfLogActFacility;
213                         break;
214         }
215
216    char* xid = (_osrfLogXid) ? _osrfLogXid : "";
217
218    int logtype = _osrfLogType;
219    if( logtype == OSRF_LOG_TYPE_FILE && !_osrfLogFile )
220    {
221            // No log file defined?  Temporarily reroute to stderr
222            logtype = OSRF_LOG_TYPE_STDERR;
223    }
224
225    if( logtype == OSRF_LOG_TYPE_SYSLOG ) {
226                 char buf[1536];  
227                 buf[0] = '\0';
228                 /* give syslog some breathing room, and be cute about it */
229                 strncat(buf, msg, 1535);
230                 buf[1532] = '.';
231                 buf[1533] = '.';
232                 buf[1534] = '.';
233                 buf[1535] = '\0';
234                 syslog( fac | lvl, "[%s:%ld:%s:%d:%s] %s", label, (long) getpid(), filename, line, xid, buf );
235         }
236
237         else if( logtype == OSRF_LOG_TYPE_FILE )
238                 _osrfLogToFile( "[%s:%ld:%s:%d:%s] %s", label, (long) getpid(), filename, line, xid, msg );
239
240         else if( logtype == OSRF_LOG_TYPE_STDERR )
241                 fprintf( stderr, "[%s:%ld:%s:%d:%s] %s\n", label, (long) getpid(), filename, line, xid, msg );
242 }
243
244
245 static void _osrfLogToFile( const char* msg, ... ) {
246
247         if(!msg) return;
248         if(!_osrfLogFile) return;
249         VA_LIST_TO_STRING(msg);
250
251         if(!_osrfLogAppname) _osrfLogAppname = strdup("osrf");
252
253         char datebuf[36];
254         time_t t = time(NULL);
255         struct tm* tms = localtime(&t);
256         strftime(datebuf, sizeof( datebuf ), "%Y-%m-%d %H:%M:%S", tms);
257
258         FILE* file = fopen(_osrfLogFile, "a");
259         if(!file) {
260                 fprintf(stderr,
261                         "Unable to fopen log file %s for writing; logging to standard error\n", _osrfLogFile);
262                 fprintf(stderr, "%s %s %s\n", _osrfLogAppname, datebuf, VA_BUF );
263
264                 return;
265         }
266
267         fprintf(file, "%s %s %s\n", _osrfLogAppname, datebuf, VA_BUF );
268         if( fclose(file) != 0 ) 
269                 fprintf( stderr, "Error closing log file: %s", strerror(errno));
270
271 }
272
273
274 int osrfLogFacilityToInt( char* facility ) {
275         if(!facility) return LOG_LOCAL0;
276         if(strlen(facility) < 6) return LOG_LOCAL0;
277         switch( facility[5] ) {
278                 case '0': return LOG_LOCAL0;
279                 case '1': return LOG_LOCAL1;
280                 case '2': return LOG_LOCAL2;
281                 case '3': return LOG_LOCAL3;
282                 case '4': return LOG_LOCAL4;
283                 case '5': return LOG_LOCAL5;
284                 case '6': return LOG_LOCAL6;
285                 case '7': return LOG_LOCAL7;
286         }
287         return LOG_LOCAL0;
288 }
289
290