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