]> git.sur5r.net Git - openldap/blob - libraries/liblutil/debug.c
updates from HEAD
[openldap] / libraries / liblutil / debug.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10
11 #include <ac/stdarg.h>
12 #include <ac/stdlib.h>
13 #include <ac/string.h>
14 #include <ac/time.h>
15
16 #ifdef LDAP_SYSLOG
17 #include <ac/syslog.h>
18 #endif
19
20 #include "ldap_log.h"
21 #include "ldap_defaults.h"
22 #include "lber.h"
23
24 struct DEBUGLEVEL
25 {
26         char *subsystem;
27         int  level;
28 };
29
30 static struct DEBUGLEVEL **levelArray;
31 static long   numLevels = 0;
32
33 static FILE *log_file = NULL;
34 static int global_level = 0;
35
36 #ifdef LDAP_SYSLOG
37 static int use_syslog = 0;
38
39 static int debug2syslog(int l) {
40         switch (l) {
41         case LDAP_LEVEL_EMERG:  return LOG_EMERG;
42         case LDAP_LEVEL_ALERT:  return LOG_ALERT;
43         case LDAP_LEVEL_CRIT:   return LOG_CRIT;
44         case LDAP_LEVEL_ERR:    return LOG_ERR;
45         case LDAP_LEVEL_WARNING:        return LOG_WARNING;
46         case LDAP_LEVEL_NOTICE: return LOG_NOTICE;
47         case LDAP_LEVEL_INFO:   return LOG_INFO;
48         }
49         return LOG_DEBUG;
50 }
51 #endif
52
53 static char *lutil_levels[] = {"emergency", "alert", "critical",
54                            "error", "warning", "notice",
55                            "information", "entry", "args",
56                            "results", "detail1", "detail2",
57                            NULL};
58
59 int lutil_mnem2level( const char *level )
60 {
61     int i;
62     for( i = 0; lutil_levels[i] != NULL; i++ )
63     {
64         if ( !strcasecmp( level, lutil_levels[i] ) )
65         {
66             return i;
67         }
68     }
69     return 0;
70 }
71
72 static void addSubsys( const char *subsys, int level )
73 {
74         int i, j;
75
76         if ( !strcasecmp( subsys, "global") ) global_level = level;
77
78         for( i = 0; i < numLevels; i++ )
79         {
80                 if ( levelArray[i] == NULL )
81                 {
82                         levelArray[i] = (struct DEBUGLEVEL*)ber_memalloc( sizeof( struct DEBUGLEVEL ) );
83                         levelArray[i]->subsystem = (char*)ber_memalloc( strlen( subsys ) + 1 );
84                         strcpy ( levelArray[i]->subsystem, subsys );
85                         levelArray[i]->level = level;
86                         return;
87                 }
88                 if( !strcasecmp( subsys, levelArray[i]->subsystem ) )
89                 {
90                         levelArray[i]->level = level;
91                         return;
92                 }
93         }
94         levelArray = (struct DEBUGLEVEL**)ber_memrealloc( levelArray, sizeof( struct DEBUGLEVEL* ) * (numLevels + 10) );
95         for( j = numLevels; j < (numLevels + 10); j++ )
96         {
97                 levelArray[j] = NULL;
98         }
99         numLevels += 10;
100         levelArray[i] = (struct DEBUGLEVEL*)ber_memalloc( sizeof( struct DEBUGLEVEL ) );
101         levelArray[i]->subsystem = (char*)ber_memalloc( strlen( subsys ) + 1 );
102         strcpy( levelArray[i]->subsystem, subsys );
103         levelArray[i]->level = level;
104         return;
105 }
106
107 void lutil_set_debug_level( const char* subsys, int level )
108 {
109     addSubsys( subsys, level );
110 }
111
112 int lutil_debug_file( FILE *file )
113 {
114         log_file = file;
115         ber_set_option( NULL, LBER_OPT_LOG_PRINT_FILE, file );
116
117         return 0;
118 }
119
120 void lutil_log_int(
121         FILE* file,
122         const char *subsys, int level,
123         const char *fmt, va_list vl )
124 {
125 #ifdef HAVE_WINSOCK
126         time_t now;
127         struct tm *today;
128 #endif
129         int i;
130
131         if ( levelArray == NULL ) return; /* logging isn't set up */
132
133         /*
134          * Look for the subsystem in the level array.  When we find it,
135          * break out of the loop.
136          */
137         for( i = 0; i < numLevels; i++ ) {
138                 if ( levelArray[i] == NULL ) break; 
139                 if ( ! strcasecmp( levelArray[i]->subsystem, subsys ) ) break;
140         }
141
142         /*
143          * If we didn't find the subsystem, or the set level is less than
144          * the requested output level, don't output it.
145          */
146         if ( (level > global_level) &&
147                 ((i > numLevels ) || (levelArray[i] == NULL) || ( level > levelArray[i]->level )) )
148         {
149                 return;
150         }
151
152 #ifdef LDAP_SYSLOG
153         /* we're configured to use syslog */
154         if( use_syslog ) {
155                 vsyslog( debug2syslog(level), fmt, vl );
156                 return;
157         }
158 #endif
159
160 #if 0
161 #ifdef HAVE_WINSOCK
162         if( log_file == NULL ) {
163                 log_file = fopen( LDAP_RUNDIR LDAP_DIRSEP "openldap.log", "w" );
164
165                 if ( log_file == NULL )
166                         log_file = fopen( "openldap.log", "w" );
167
168                 if ( log_file == NULL )
169                         return;
170
171                 ber_set_option( NULL, LBER_OPT_LOG_PRINT_FILE, log_file );
172         }
173 #endif
174 #endif
175
176         if( file == NULL ) {
177                 /*
178                  * Use stderr unless file was specified via:
179                  *   ber_set_option( NULL, LBER_OPT_LOG_PRINT_FILE, file)
180                  */
181                 file = stderr;
182         }
183
184 #ifdef HAVE_WINSOCK
185         /*
186          * Stick the time in the buffer to output when using Winsock
187          * as NT can't pipe to a timestamp program like Unix can.
188          * This, of course, makes some logs hard to read.
189      */
190         time( &now );
191         today = localtime( &now );
192         fprintf( file, "%4d%02d%02d:%02d:%02d:%02d ",
193                 today->tm_year + 1900, today->tm_mon + 1,
194                 today->tm_mday, today->tm_hour,
195                 today->tm_min, today->tm_sec );
196 #endif
197
198         /*
199          * format the output data.
200          */
201         vfprintf( file, fmt, vl );
202 }
203
204 /*
205  * The primary logging routine.  Takes the subsystem being logged from, the
206  * level of the log output and the format and data.  Send this on to the
207  * internal routine with the print file, if any.
208  */
209 void lutil_log( const char *subsys, int level, const char *fmt, ... )
210 {
211         FILE* outfile = NULL;
212         va_list vl;
213         va_start( vl, fmt );
214         ber_get_option( NULL, LBER_OPT_LOG_PRINT_FILE, &outfile );
215         lutil_log_int( outfile, subsys, level, fmt, vl );
216         va_end( vl );
217 }
218
219 void lutil_log_initialize(int argc, char **argv)
220 {
221     int i;
222     /*
223      * Start by setting the hook for the libraries to use this logging
224      * routine.
225      */
226     ber_set_option( NULL, LBER_OPT_LOG_PROC, (void*)lutil_log_int );
227
228     if ( argc == 0 ) return;
229     /*
230      * Now go through the command line options to set the debugging
231      * levels
232      */
233     for( i = 0; i < argc; i++ )
234     {
235         char *next = argv[i];
236         if ( i < argc-1 && next[0] == '-' && next[1] == 'd' )
237         {
238             char subsys[64];
239             int level;
240             char *optarg = argv[i+1];
241             char *index = strchr( optarg, '=' );
242             if ( index != NULL )
243             {
244                 *index = 0;
245                 strcpy ( subsys, optarg );
246                 level = atoi( index+1 );
247                 if ( level <= 0 ) level = lutil_mnem2level( index + 1 );
248                 lutil_set_debug_level( subsys, level );
249                 *index = '=';
250             }
251             else
252             {
253                 global_level = atoi( optarg );
254                 /* 
255                  * if a negative number was used, make the global level the
256                  * maximum sane level.
257                  */
258                 if ( global_level < 0 ) global_level = 65535;
259             }
260         }
261     }
262 }
263
264 void (lutil_debug)( int debug, int level, const char *fmt, ... )
265 {
266         char buffer[4096];
267         va_list vl;
268
269         if ( !(level & debug ) )
270                 return;
271
272 #ifdef HAVE_WINSOCK
273         if( log_file == NULL ) {
274                 log_file = fopen( LDAP_RUNDIR LDAP_DIRSEP "openldap.log", "w" );
275
276                 if ( log_file == NULL )
277                         log_file = fopen( "openldap.log", "w" );
278
279                 if ( log_file == NULL )
280                         return;
281
282                 ber_set_option( NULL, LBER_OPT_LOG_PRINT_FILE, log_file );
283         }
284 #endif
285         va_start( vl, fmt );
286
287 #ifdef HAVE_VSNPRINTF
288         vsnprintf( buffer, sizeof(buffer), fmt, vl );
289 #else
290         vsprintf( buffer, fmt, vl );
291 #endif
292         buffer[sizeof(buffer)-1] = '\0';
293
294         if( log_file != NULL ) {
295                 fputs( buffer, log_file );
296                 fflush( log_file );
297         }
298
299     fputs( buffer, stderr );
300         va_end( vl );
301 }