]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/libtransport/generic_utils.c
added a debug_handler for verbose output
[OpenSRF.git] / src / libtransport / generic_utils.c
1 #include "opensrf/generic_utils.h"
2 #include <stdio.h>
3 #include "pthread.h"
4
5 int _init_log();
6
7 int balance = 0;
8
9 #define LOG_ERROR 1
10 #define LOG_WARNING 2
11 #define LOG_INFO 3
12 #define LOG_DEBUG 4
13
14 void get_timestamp( char buf_25chars[]) {
15         time_t epoch = time(NULL);      
16         char* localtime = strdup( ctime( &epoch ) );
17         strcpy( buf_25chars, localtime );
18         buf_25chars[ strlen(localtime)-1] = '\0'; // remove newline
19         free(localtime);
20 }
21
22
23 inline void* safe_malloc( int size ) {
24         void* ptr = (void*) malloc( size );
25         if( ptr == NULL ) 
26                 fatal_handler("safe_malloc(): Out of Memory" );
27         memset( ptr, 0, size );
28         return ptr;
29 }
30
31 // ---------------------------------------------------------------------------------
32 // Here we define how we want to handle various error levels.
33 // ---------------------------------------------------------------------------------
34
35
36 static FILE* log_file = NULL;
37 static int log_level = -1;
38 pthread_mutex_t mutex;
39
40 void log_free() { if( log_file != NULL ) fclose(log_file ); }
41
42 void fatal_handler( char* msg, ... ) {
43                 
44         char buf[25];
45         memset( buf, 0, 25 );
46         get_timestamp( buf );
47         pid_t  pid = getpid();
48         va_list args;
49
50         if( _init_log() ) {
51
52                 if( log_level < LOG_ERROR )
53                         return;
54
55                 pthread_mutex_lock( &(mutex) );
56                 fprintf( log_file, "[%s %d] [%s] ", buf, pid, "ERR " );
57         
58                 va_start(args, msg);
59                 vfprintf(log_file, msg, args);
60                 va_end(args);
61         
62                 fprintf(log_file, "\n");
63                 fflush( log_file );
64                 pthread_mutex_unlock( &(mutex) );
65
66         }
67         
68         /* also log to stderr  for ERRORS*/
69         fprintf( stderr, "[%s %d] [%s] ", buf, pid, "ERR " );
70         va_start(args, msg);
71         vfprintf(stderr, msg, args);
72         va_end(args);
73         fprintf( stderr, "\n" );
74
75         exit(99);
76 }
77
78 void warning_handler( char* msg, ... ) {
79
80         char buf[25];
81         memset( buf, 0, 25 );
82         get_timestamp( buf );
83         pid_t  pid = getpid();
84         va_list args;
85         
86         if( _init_log() ) {
87
88                 if( log_level < LOG_WARNING )
89                         return;
90
91                 pthread_mutex_lock( &(mutex) );
92                 fprintf( log_file, "[%s %d] [%s] ", buf, pid, "WARN" );
93         
94                 va_start(args, msg);
95                 vfprintf(log_file, msg, args);
96                 va_end(args);
97         
98                 fprintf(log_file, "\n");
99                 fflush( log_file );
100                 pthread_mutex_unlock( &(mutex) );
101
102         } else {
103
104                 fprintf( stderr, "[%s %d] [%s] ", buf, pid, "WARN" );
105                 va_start(args, msg);
106                 vfprintf(stderr, msg, args);
107                 va_end(args);
108                 fprintf( stderr, "\n" );
109         }
110
111 }
112
113 void info_handler( char* msg, ... ) {
114
115         char buf[25];
116         memset( buf, 0, 25 );
117         get_timestamp( buf );
118         pid_t  pid = getpid();
119         va_list args;
120
121         if( _init_log() ) {
122
123                 if( log_level < LOG_INFO )
124                         return;
125                 pthread_mutex_lock( &(mutex) );
126                 fprintf( log_file, "[%s %d] [%s] ", buf, pid, "INFO" );
127
128                 va_start(args, msg);
129                 vfprintf(log_file, msg, args);
130                 va_end(args);
131         
132                 fprintf(log_file, "\n");
133                 fflush( log_file );
134                 pthread_mutex_unlock( &(mutex) );
135
136         } else {
137
138                 fprintf( stderr, "[%s %d] [%s] ", buf, pid, "INFO" );
139                 va_start(args, msg);
140                 vfprintf(stderr, msg, args);
141                 va_end(args);
142                 fprintf( stderr, "\n" );
143                 fflush(stderr);
144
145         }
146 }
147
148
149 void debug_handler( char* msg, ... ) {
150
151         char buf[25];
152         memset( buf, 0, 25 );
153         get_timestamp( buf );
154         pid_t  pid = getpid();
155         va_list args;
156         
157         if( _init_log() ) {
158
159                 if( log_level < LOG_DEBUG )
160                         return;
161
162                 pthread_mutex_lock( &(mutex) );
163                 fprintf( log_file, "[%s %d] [%s] ", buf, pid, "DEBG" );
164         
165                 va_start(args, msg);
166                 vfprintf(log_file, msg, args);
167                 va_end(args);
168         
169                 fprintf(log_file, "\n");
170                 fflush( log_file );
171                 pthread_mutex_unlock( &(mutex) );
172
173         } else {
174
175                 fprintf( stderr, "[%s %d] [%s] ", buf, pid, "DEBG" );
176                 va_start(args, msg);
177                 vfprintf(stderr, msg, args);
178                 va_end(args);
179                 fprintf( stderr, "\n" );
180         }
181
182 }
183
184
185
186 int _init_log() {
187
188         if( log_level != -1 )
189                 return 1;
190
191
192         pthread_mutex_init( &(mutex), NULL );
193
194         /* load the log level setting if we haven't already */
195
196         if( conf_reader == NULL ) {
197                 return 0;
198                 //fprintf( stderr, "No config file specified" );
199         }
200
201         char* log_level_str = config_value( "//log/level");
202         if( log_level_str == NULL ) {
203         //      fprintf( stderr, "No log level specified" );
204                 return 0;
205         }
206         log_level = atoi(log_level_str);
207         free(log_level_str);
208
209         /* see if we have a log file yet */
210         char* f = config_value("//log/file");
211
212         if( f == NULL ) {
213                 // fprintf( stderr, "No log file specified" );
214                 return 0;
215         }
216
217         log_file = fopen( f, "a" );
218         if( log_file == NULL ) {
219                 fprintf( stderr, "Unable to open log file %s for appending\n", f );
220                 return 0;
221         }
222         free(f);
223         return 1;
224                                 
225 }
226
227
228
229 // ---------------------------------------------------------------------------------
230 // Flesh out a ubiqitous growing string buffer
231 // ---------------------------------------------------------------------------------
232
233 growing_buffer* buffer_init(int num_initial_bytes) {
234
235         if( num_initial_bytes > BUFFER_MAX_SIZE ) {
236                 return NULL;
237         }
238
239
240         size_t len = sizeof(growing_buffer);
241
242         growing_buffer* gb = (growing_buffer*) safe_malloc(len);
243
244         gb->n_used = 0;/* nothing stored so far */
245         gb->size = num_initial_bytes;
246         gb->buf = (char *) safe_malloc(gb->size + 1);
247
248         return gb;
249 }
250
251 int buffer_add(growing_buffer* gb, char* data) {
252
253
254         if( ! gb || ! data  ) { return 0; }
255         int data_len = strlen( data );
256
257         if( data_len == 0 ) { return 0; }
258         int total_len = data_len + gb->n_used;
259
260         while( total_len >= gb->size ) {
261                 gb->size *= 2;
262         }
263
264         if( gb->size > BUFFER_MAX_SIZE ) {
265                 warning_handler( "Buffer reached MAX_SIZE of %d", BUFFER_MAX_SIZE );
266                 buffer_free( gb );
267                 return 0;
268         }
269
270         char* new_data = (char*) safe_malloc( gb->size );
271
272         strcpy( new_data, gb->buf );
273         free( gb->buf );
274         gb->buf = new_data;
275
276         strcat( gb->buf, data );
277         gb->n_used = total_len;
278         return total_len;
279 }
280
281
282 int buffer_reset( growing_buffer *gb){
283         if( gb == NULL ) { return 0; }
284         if( gb->buf == NULL ) { return 0; }
285         memset( gb->buf, 0, gb->size );
286         gb->n_used = 0;
287         return 1;
288 }
289
290 int buffer_free( growing_buffer* gb ) {
291         if( gb == NULL ) 
292                 return 0;
293         free( gb->buf );
294         free( gb );
295         return 1;
296 }
297
298 char* buffer_data( growing_buffer *gb) {
299         return strdup( gb->buf );
300 }
301
302
303
304
305
306 // ---------------------------------------------------------------------------------
307 // Config module
308 // ---------------------------------------------------------------------------------
309
310
311 // ---------------------------------------------------------------------------------
312 // Allocate and build the conf_reader.  This only has to happen once in a given
313 // system.  Repeated calls are ignored.
314 // ---------------------------------------------------------------------------------
315 void config_reader_init( char* config_file ) {
316         if( conf_reader == NULL ) {
317
318                 if( config_file == NULL || strlen(config_file) == 0 ) {
319                         fatal_handler( "config_reader_init(): No config file specified" );
320                         return;
321                 }
322
323                 size_t len = sizeof( config_reader );
324                 conf_reader = (config_reader*) safe_malloc( len );
325
326                 conf_reader->config_doc = xmlParseFile( config_file ); 
327                 conf_reader->xpathCx = xmlXPathNewContext( conf_reader->config_doc );
328                 if( conf_reader->xpathCx == NULL ) {
329                         fatal_handler( "config_reader_init(): Unable to create xpath context");
330                         return;
331                 }
332         }
333 }
334
335 char* config_value( const char* xp_query, ... ) {
336
337         if( conf_reader == NULL || xp_query == NULL ) {
338                 fatal_handler( "config_value(): NULL conf_reader or NULL param(s)" );
339                 return NULL;
340         }
341
342         int slen = strlen(xp_query) + 512;/* this is unsafe ... */
343         char xpath_query[ slen ]; 
344         memset( xpath_query, 0, slen );
345         va_list va_args;
346         va_start(va_args, xp_query);
347         vsprintf(xpath_query, xp_query, va_args);
348         va_end(va_args);
349
350
351         char* val;
352         int len = strlen(xpath_query) + 100;
353         char alert_buffer[len];
354         memset( alert_buffer, 0, len );
355
356         // build the xpath object
357         xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST xpath_query, conf_reader->xpathCx );
358
359         if( xpathObj == NULL ) {
360                 sprintf( alert_buffer, "Could not build xpath object: %s", xpath_query );
361                 fatal_handler( alert_buffer );
362                 return NULL;
363         }
364
365
366         if( xpathObj->type == XPATH_NODESET ) {
367
368                 // ----------------------------------------------------------------------------
369                 // Grab nodeset from xpath query, then first node, then first text node and 
370                 // finaly the text node's value
371                 // ----------------------------------------------------------------------------
372                 xmlNodeSet* node_list = xpathObj->nodesetval;
373                 if( node_list == NULL ) {
374                         sprintf( alert_buffer, "Could not build xpath object: %s", xpath_query );
375                         warning_handler(alert_buffer);
376                         return NULL;
377                 }
378
379                 if( node_list->nodeNr == 0 ) {
380                         sprintf( alert_buffer, "Config XPATH query  returned 0 results: %s", xpath_query );
381                         warning_handler(alert_buffer);
382                         return NULL;
383                 }
384
385
386                 xmlNodePtr element_node = *(node_list)->nodeTab;
387                 if( element_node == NULL ) {
388                         sprintf( alert_buffer, "Config XPATH query  returned 0 results: %s", xpath_query );
389                         warning_handler(alert_buffer);
390                         return NULL;
391                 }
392
393                 xmlNodePtr text_node = element_node->children;
394                 if( text_node == NULL ) {
395                         sprintf( alert_buffer, "Config variable has no value: %s", xpath_query );
396                         warning_handler(alert_buffer);
397                         return NULL;
398                 }
399
400                 val = text_node->content;
401                 if( val == NULL ) {
402                         sprintf( alert_buffer, "Config variable has no value: %s", xpath_query );
403                         warning_handler(alert_buffer);
404                         return NULL;
405                 }
406
407
408         } else { 
409                 sprintf( alert_buffer, "Xpath evaluation failed: %s", xpath_query );
410                 warning_handler(alert_buffer);
411                 return NULL;
412         }
413
414         char* value = strdup(val);
415         if( value == NULL ) { warning_handler( "config_value(): Empty config value or Out of Memory!" ); }
416
417         // Free XPATH structures
418         if( xpathObj != NULL ) xmlXPathFreeObject( xpathObj );
419
420         return value;
421 }
422
423
424 void config_reader_free() {
425         if( conf_reader == NULL ) { return; }
426         xmlXPathFreeContext( conf_reader->xpathCx );
427         xmlFreeDoc( conf_reader->config_doc );
428         free( conf_reader );
429         conf_reader = NULL;
430 }