aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-10-04 11:09:39 +0000
committerChristian Grothoff <christian@grothoff.org>2011-10-04 11:09:39 +0000
commite305c764722394c18d55e084c7be4b64ff799fa4 (patch)
tree24f9dd8cc6f5393a9084d8149e53af5e850b25e7 /src/util
parentba59bf06eefaefa447fbca9059adefe9ac0ef167 (diff)
downloadgnunet-e305c764722394c18d55e084c7be4b64ff799fa4.tar.gz
gnunet-e305c764722394c18d55e084c7be4b64ff799fa4.zip
LRN's big logging rewrite (#1805):
* GNUNET_BOTTOM_LOGLEVEL and GNUNET_TOP_LOGLEVEL set global levels Use bottom level to force logging to be more verbose than configured Use top level to force logging to be less verbose than configured Obviously, bottom <= top * GNUNET_LOG sets per-component levels GNUNET_LOG looks like this: name[/bottom[/top]]/... name starts with a non-digit character, must not include '/' bottom and top must consist only of digits, or be empty a description is only used if it matches the component exactly as a special exception (for now) the name '*' matches any component per-component loglevels override global loglevels global levels override whatever is given via arguments or in config Examples: test_client/8/8/ run test_client with DEBUG level (usually leads to a timeout, by the way) */2/2/core/8/8/transport/4/4 run everything with WARNING, core - with DEBUG, transport - with INFO *//1/peerinfo/4/ run everything with top loglevel ERROR, global/configured bottom loglevel, and peerinfo - with bottom loglevel INFO and global/configured top loglevel statistics/ does nothing * Added GNUNET_ERROR_TYPE_UNSPECIFIED enum value, to hold -1. Its corresponding string is NULL. * Changed the logger calls as Grothoff suggested - to use static int to hold the result of runtime evaluation of logability. Logging can be unconditionally disabled in advance by defining GNUNET_LOG_CALL_STATUS to 0, and enabled in advance by defining it to 1. * Added GNUNET_CULL_LOGGING, which, if defined, completely culls out all logging calls at compile time. * Log definition parsing is only done once, results are cached. * Changed definition format, now it looks like this: [component|*|];[file|*|];[function|*|];[from_line[-to_line]];level/[component...] All field separators are mandatory (but some fields could be empty or be '*'). Line definition must be either empty or "number" or "number-number" Level definition must not be empty, and is a string representation of the level (i.e. DEBUG, WARNING, INFO, etc). Definition entry must end with a slash, whether or not there's another entry after it. File name is matched to the end of __FILE__, which allows file name to match not only the base name, but also directories leading to it. * Removed default WARNING loglevel from program and service utility code. Now they default to NULL (UNSPECIFIED) level, which can be overriden by GNUNET_LOG definition, if no level is specified via config or commandline. Log levels from config or commandline are overriden by GNUNET_FORCE_LOG. If GNUNET_*LOG are undefined, and no levels came from config or commandline, logger internally defaults to WARNING level. Add --enable-logging configure option
Diffstat (limited to 'src/util')
-rw-r--r--src/util/common_logging.c387
-rw-r--r--src/util/program.c4
-rw-r--r--src/util/service.c4
3 files changed, 367 insertions, 28 deletions
diff --git a/src/util/common_logging.c b/src/util/common_logging.c
index ff3ac12ee..16d367de8 100644
--- a/src/util/common_logging.c
+++ b/src/util/common_logging.c
@@ -115,6 +115,11 @@ static char last_bulk_comp[COMP_TRACK_SIZE + 1];
115static char *component; 115static char *component;
116 116
117/** 117/**
118 * Running component (without pid).
119 */
120static char *component_nopid;
121
122/**
118 * Minimum log level. 123 * Minimum log level.
119 */ 124 */
120static enum GNUNET_ErrorType min_level; 125static enum GNUNET_ErrorType min_level;
@@ -127,13 +132,94 @@ static struct CustomLogger *loggers;
127/** 132/**
128 * Number of log calls to ignore. 133 * Number of log calls to ignore.
129 */ 134 */
130static unsigned int skip_log; 135unsigned int skip_log;
131 136
132/** 137/**
133 * File descriptor to use for "stderr", or NULL for none. 138 * File descriptor to use for "stderr", or NULL for none.
134 */ 139 */
135static FILE *GNUNET_stderr; 140static FILE *GNUNET_stderr;
136 141
142/**
143 * Represents a single logging definition
144 */
145struct LogDef
146{
147 /**
148 * Component name. NULL means that this definition matches any component
149 */
150 char *component;
151
152 /**
153 * File name. NULL means that this definition matches any file
154 */
155 char *file;
156
157 /**
158 * Stores strlen(file)
159 */
160 int strlen_file;
161
162 /**
163 * Function name. NULL means that this definition matches any function
164 */
165 char *function;
166
167 /**
168 * Lowest line at which this definition matches.
169 * Defaults to 0. Must be <= to_line.
170 */
171 int from_line;
172
173 /**
174 * Highest line at which this definition matches.
175 * Defaults to INT_MAX. Must be >= from_line.
176 */
177 int to_line;
178
179 /**
180 * Maximal log level allowed for calls that match this definition.
181 * Calls with higher log level will be disabled.
182 * Must be >= 0
183 */
184 int level;
185
186 /**
187 * 1 if this definition comes from GNUNET_FORCE_LOG, which means that it
188 * overrides any configuration options. 0 otherwise.
189 */
190 int force;
191};
192
193/**
194 * Dynamic array of logging definitions
195 */
196struct LogDef *logdefs = NULL;
197
198/**
199 * Allocated size of logdefs array (in units)
200 */
201int logdefs_size = 0;
202
203/**
204 * The number of units used in logdefs array.
205 */
206int logdefs_len = 0;
207
208/**
209 * GNUNET_YES if GNUNET_LOG environment variable is already parsed.
210 */
211int gnunet_log_parsed = GNUNET_NO;
212
213/**
214 * GNUNET_YES if GNUNET_FORCE_LOG environment variable is already parsed.
215 */
216int gnunet_force_log_parsed = GNUNET_NO;
217
218/**
219 * GNUNET_YES if at least one definition with forced == 1 is available.
220 */
221int gnunet_force_log_present = GNUNET_NO;
222
137#ifdef WINDOWS 223#ifdef WINDOWS
138/** 224/**
139 * Contains the number of performance counts per second. 225 * Contains the number of performance counts per second.
@@ -151,6 +237,8 @@ LARGE_INTEGER performance_frequency;
151static enum GNUNET_ErrorType 237static enum GNUNET_ErrorType
152get_type (const char *log) 238get_type (const char *log)
153{ 239{
240 if (log == NULL)
241 return GNUNET_ERROR_TYPE_UNSPECIFIED;
154 if (0 == strcasecmp (log, _("DEBUG"))) 242 if (0 == strcasecmp (log, _("DEBUG")))
155 return GNUNET_ERROR_TYPE_DEBUG; 243 return GNUNET_ERROR_TYPE_DEBUG;
156 if (0 == strcasecmp (log, _("INFO"))) 244 if (0 == strcasecmp (log, _("INFO")))
@@ -163,9 +251,264 @@ get_type (const char *log)
163 return GNUNET_ERROR_TYPE_NONE; 251 return GNUNET_ERROR_TYPE_NONE;
164 return GNUNET_ERROR_TYPE_INVALID; 252 return GNUNET_ERROR_TYPE_INVALID;
165} 253}
254#if !defined(GNUNET_CULL_LOGGING)
255/**
256 * Utility function - reallocates logdefs array to be twice as large.
257 */
258static void
259resize_logdefs ()
260{
261 logdefs_size = (logdefs_size + 1) * 2;
262 logdefs = GNUNET_realloc (logdefs, logdefs_size * sizeof (struct LogDef));
263}
264
265/**
266 * Utility function - adds a parsed definition to logdefs array.
267 *
268 * @param component see struct LogDef, can't be NULL
269 * @param file see struct LogDef, can't be NULL
270 * @param function see struct LogDef, can't be NULL
271 * @param from_line see struct LogDef
272 * @param to_line see struct LogDef
273 * @param level see struct LogDef, must be >= 0
274 * @param force see struct LogDef
275 */
276static void
277add_definition (char *component, char *file, char *function, int from_line, int to_line, int level, int force)
278{
279 if (logdefs_size == logdefs_len)
280 resize_logdefs ();
281 struct LogDef n;
282 memset (&n, 0, sizeof (n));
283 if (strlen (component) > 0 && component[0] != '*')
284 n.component = strdup (component);
285 if (strlen (file) > 0 && file[0] != '*')
286 {
287 n.file = strdup (file);
288 n.strlen_file = strlen (file);
289 }
290 if (strlen (function) > 0 && function[0] != '*')
291 n.function = strdup (function);
292 n.from_line = from_line;
293 n.to_line = to_line;
294 n.level = level;
295 n.force = force;
296 logdefs[logdefs_len++] = n;
297}
298
299
300/**
301 * Decides whether a particular logging call should or should not be allowed
302 * to be made. Used internally by GNUNET_log*()
303 *
304 * @param caller_level loglevel the caller wants to use
305 * @param comp component name the caller uses (NULL means that global
306 * component name is used)
307 * @param file file name containing the logging call, usually __FILE__
308 * @param function function which tries to make a logging call,
309 * usually __FUNCTION__
310 * @param line line at which the call is made, usually __LINE__
311 * @return 0 to disallow the call, 1 to allow it
312 */
313int
314GNUNET_get_log_call_status (int caller_level, const char *comp, const char *file, const char *function, int line)
315{
316 struct LogDef *ld;
317 int i;
318 int force_only;
319 size_t strlen_file;
320 int matches = 0;
321
322 if (comp == NULL)
323 /* Use default component */
324 comp = component_nopid;
325
326 /* We have no definitions to override globally configured log level,
327 * so just use it right away.
328 */
329 if (min_level >= 0 && gnunet_force_log_present == GNUNET_NO)
330 return caller_level <= min_level;
331
332 /* Only look for forced definitions? */
333 force_only = min_level >= 0;
334 strlen_file = strlen (file);
335 for (i = 0; i < logdefs_len; i++)
336 {
337 ld = &logdefs[i];
338 if ((!force_only || ld->force) &&
339 (line >= ld->from_line && line <= ld->to_line) &&
340 (ld->component == NULL || strcmp (comp, ld->component) == 0) &&
341 (ld->file == NULL ||
342 (ld->strlen_file <= strlen_file &&
343 strcmp (&file[strlen_file - ld->strlen_file], ld->file) == 0)) &&
344 (ld->function == NULL || strcmp (function, ld->function) == 0)
345 )
346 {
347 /* This definition matched! */
348 matches += 1;
349 /* And if it allows the call to be made, then we're finished */
350 if (caller_level <= ld->level)
351 return 1;
352 }
353 }
354 /* If some definitions did match, but had too low loglevel to allow logging,
355 * don't check any further.
356 */
357 if (matches > 0)
358 return 0;
359 /* Otherwise use global level, if defined */
360 if (min_level >= 0)
361 return caller_level <= min_level;
362 /* All programs/services previously defaulted to WARNING.
363 * Now WE default to WARNING, and THEY default to NULL.
364 */
365 return caller_level <= GNUNET_ERROR_TYPE_WARNING;
366}
166 367
167 368
168/** 369/**
370 * Utility function - parses a definition
371 *
372 * Definition format:
373 * component;file;function;from_line-to_line;level[/component...]
374 * All entries are mandatory, but may be empty.
375 * Empty entries for component, file and function are treated as
376 * "matches anything".
377 * Empty line entry is treated as "from 0 to INT_MAX"
378 * Line entry with only one line is treated as "this line only"
379 * Entry for level MUST NOT be empty.
380 * Entries for component, file and function that consist of a
381 * single character "*" are treated (at the moment) the same way
382 * empty entries are treated (wildcard matching is not implemented (yet?)).
383 * file entry is matched to the end of __FILE__. That is, it might be
384 * a base name, or a base name with leading directory names (some compilers
385 * define __FILE__ to absolute file path).
386 *
387 * @param constname name of the environment variable from which to get the
388 * string to be parsed
389 * @param force 1 if definitions found in @constname are to be forced
390 * @return number of added definitions
391 */
392static int
393parse_definitions (const char *constname, int force)
394{
395 char *def;
396 const char *tmp;
397 char *comp = NULL;
398 char *file = NULL;
399 char *function = NULL;
400 char *p;
401 char *start;
402 char *t;
403 short state;
404 int level;
405 int from_line, to_line;
406 int counter = 0;
407 int keep_looking = 1;
408 tmp = getenv (constname);
409 if (tmp == NULL)
410 return 0;
411 def = strdup (tmp);
412 level = -1;
413 from_line = 0;
414 to_line = INT_MAX;
415 for (p = def, state = 0, start = def; keep_looking; p++)
416 {
417 switch (p[0])
418 {
419 case ';': /* found a field separator */
420 p[0] = '\0';
421 switch (state)
422 {
423 case 0: /* within a component name */
424 comp = start;
425 break;
426 case 1: /* within a file name */
427 file = start;
428 break;
429 case 2: /* within a function name */
430 /* after a file name there must be a function name */
431 function = start;
432 break;
433 case 3: /* within a from-to line range */
434 if (strlen (start) > 0)
435 {
436 errno = 0;
437 from_line = strtol (start, &t, 10);
438 if (errno != 0 || from_line < 0)
439 {
440 free (def);
441 return counter;
442 }
443 if (t < p && t[0] == '-')
444 {
445 errno = 0;
446 start = t + 1;
447 to_line = strtol (start, &t, 10);
448 if (errno != 0 || to_line < 0 || t != p)
449 {
450 free (def);
451 return counter;
452 }
453 }
454 else /* one number means "match this line only" */
455 to_line = from_line;
456 }
457 else /* default to 0-max */
458 {
459 from_line = 0;
460 to_line = INT_MAX;
461 }
462 break;
463 }
464 start = p + 1;
465 state += 1;
466 break;
467 case '\0': /* found EOL */
468 keep_looking = 0;
469 /* fall through to '/' */
470 case '/': /* found a definition separator */
471 switch (state)
472 {
473 case 4: /* within a log level */
474 p[0] = '\0';
475 state = 0;
476 level = get_type ((const char *) start);
477 if (level == GNUNET_ERROR_TYPE_INVALID || level == GNUNET_ERROR_TYPE_UNSPECIFIED)
478 {
479 free (def);
480 return counter;
481 }
482 add_definition (comp, file, function, from_line, to_line, level, force);
483 counter += 1;
484 start = p + 1;
485 break;
486 default:
487 break;
488 }
489 default:
490 break;
491 }
492 }
493 free (def);
494 return counter;
495}
496
497/**
498 * Utility function - parses GNUNET_LOG and GNUNET_FORCE_LOG.
499 */
500static void
501parse_all_definitions ()
502{
503 if (gnunet_log_parsed == GNUNET_NO)
504 parse_definitions ("GNUNET_LOG", 0);
505 gnunet_log_parsed = GNUNET_YES;
506 if (gnunet_force_log_parsed == GNUNET_NO)
507 gnunet_force_log_present = parse_definitions ("GNUNET_FORCE_LOG", 1) > 0 ? GNUNET_YES : GNUNET_NO;
508 gnunet_force_log_parsed = GNUNET_YES;
509}
510#endif
511/**
169 * Setup logging. 512 * Setup logging.
170 * 513 *
171 * @param comp default component to use 514 * @param comp default component to use
@@ -179,26 +522,24 @@ GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile)
179 FILE *altlog; 522 FILE *altlog;
180 int dirwarn; 523 int dirwarn;
181 char *fn; 524 char *fn;
182 const char *env_loglevel; 525 const char *env_logfile = NULL;
183 int env_minlevel = 0;
184 int env_min_force_level = 100000;
185 526
527 min_level = get_type (loglevel);
528#if !defined(GNUNET_CULL_LOGGING)
529 parse_all_definitions ();
530#endif
186#ifdef WINDOWS 531#ifdef WINDOWS
187 QueryPerformanceFrequency (&performance_frequency); 532 QueryPerformanceFrequency (&performance_frequency);
188#endif 533#endif
189 GNUNET_free_non_null (component); 534 GNUNET_free_non_null (component);
190 GNUNET_asprintf (&component, "%s-%d", comp, getpid ()); 535 GNUNET_asprintf (&component, "%s-%d", comp, getpid ());
191 env_loglevel = getenv ("GNUNET_LOGLEVEL"); 536 GNUNET_free_non_null (component_nopid);
192 if (env_loglevel != NULL) 537 component_nopid = strdup (comp);
193 env_minlevel = get_type (env_loglevel); 538
194 env_loglevel = getenv ("GNUNET_FORCE_LOGLEVEL"); 539 env_logfile = getenv ("GNUNET_FORCE_LOGFILE");
195 if (env_loglevel != NULL) 540 if (env_logfile != NULL)
196 env_min_force_level = get_type (env_loglevel); 541 logfile = env_logfile;
197 min_level = get_type (loglevel); 542
198 if (env_minlevel > min_level)
199 min_level = env_minlevel;
200 if (env_min_force_level < min_level)
201 min_level = env_min_force_level;
202 if (logfile == NULL) 543 if (logfile == NULL)
203 return GNUNET_OK; 544 return GNUNET_OK;
204 fn = GNUNET_STRINGS_filename_expand (logfile); 545 fn = GNUNET_STRINGS_filename_expand (logfile);
@@ -383,13 +724,6 @@ mylog (enum GNUNET_ErrorType kind, const char *comp, const char *message,
383 char *buf; 724 char *buf;
384 va_list vacp; 725 va_list vacp;
385 726
386 if (skip_log > 0)
387 {
388 skip_log--;
389 return;
390 }
391 if ((kind & (~GNUNET_ERROR_TYPE_BULK)) > min_level)
392 return;
393 va_copy (vacp, va); 727 va_copy (vacp, va);
394 size = VSNPRINTF (NULL, 0, message, vacp) + 1; 728 size = VSNPRINTF (NULL, 0, message, vacp) + 1;
395 va_end (vacp); 729 va_end (vacp);
@@ -448,7 +782,7 @@ mylog (enum GNUNET_ErrorType kind, const char *comp, const char *message,
448 * @param ... arguments for format string 782 * @param ... arguments for format string
449 */ 783 */
450void 784void
451GNUNET_log (enum GNUNET_ErrorType kind, const char *message, ...) 785GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...)
452{ 786{
453 va_list va; 787 va_list va;
454 788
@@ -468,12 +802,15 @@ GNUNET_log (enum GNUNET_ErrorType kind, const char *message, ...)
468 * @param ... arguments for format string 802 * @param ... arguments for format string
469 */ 803 */
470void 804void
471GNUNET_log_from (enum GNUNET_ErrorType kind, const char *comp, 805GNUNET_log_from_nocheck (enum GNUNET_ErrorType kind, const char *comp,
472 const char *message, ...) 806 const char *message, ...)
473{ 807{
474 va_list va; 808 va_list va;
475 char comp_w_pid[128]; 809 char comp_w_pid[128];
476 810
811 if (comp == NULL)
812 comp = component_nopid;
813
477 va_start (va, message); 814 va_start (va, message);
478 GNUNET_snprintf (comp_w_pid, sizeof (comp_w_pid), "%s-%d", comp, getpid ()); 815 GNUNET_snprintf (comp_w_pid, sizeof (comp_w_pid), "%s-%d", comp, getpid ());
479 mylog (kind, comp_w_pid, message, va); 816 mylog (kind, comp_w_pid, message, va);
@@ -498,6 +835,8 @@ GNUNET_error_type_to_string (enum GNUNET_ErrorType kind)
498 return _("INFO"); 835 return _("INFO");
499 if ((kind & GNUNET_ERROR_TYPE_DEBUG) > 0) 836 if ((kind & GNUNET_ERROR_TYPE_DEBUG) > 0)
500 return _("DEBUG"); 837 return _("DEBUG");
838 if ((kind & ~GNUNET_ERROR_TYPE_BULK) == 0)
839 return _("NONE");
501 return _("INVALID"); 840 return _("INVALID");
502} 841}
503 842
diff --git a/src/util/program.c b/src/util/program.c
index d89b65a39..b09215343 100644
--- a/src/util/program.c
+++ b/src/util/program.c
@@ -210,7 +210,7 @@ GNUNET_PROGRAM_run (int argc, char *const *argv, const char *binaryName,
210 cnt += sizeof (defoptions) / sizeof (struct GNUNET_GETOPT_CommandLineOption); 210 cnt += sizeof (defoptions) / sizeof (struct GNUNET_GETOPT_CommandLineOption);
211 qsort (allopts, cnt, sizeof (struct GNUNET_GETOPT_CommandLineOption), 211 qsort (allopts, cnt, sizeof (struct GNUNET_GETOPT_CommandLineOption),
212 &cmd_sorter); 212 &cmd_sorter);
213 loglev = GNUNET_strdup ("WARNING"); 213 loglev = NULL;
214 cc.cfgfile = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE); 214 cc.cfgfile = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE);
215 lpfx = GNUNET_strdup (binaryName); 215 lpfx = GNUNET_strdup (binaryName);
216 if (NULL != (spc = strstr (lpfx, " "))) 216 if (NULL != (spc = strstr (lpfx, " ")))
@@ -248,7 +248,7 @@ GNUNET_PROGRAM_run (int argc, char *const *argv, const char *binaryName,
248 /* clean up */ 248 /* clean up */
249 GNUNET_CONFIGURATION_destroy (cfg); 249 GNUNET_CONFIGURATION_destroy (cfg);
250 GNUNET_free_non_null (cc.cfgfile); 250 GNUNET_free_non_null (cc.cfgfile);
251 GNUNET_free (loglev); 251 GNUNET_free_non_null (loglev);
252 GNUNET_free_non_null (logfile); 252 GNUNET_free_non_null (logfile);
253 return GNUNET_OK; 253 return GNUNET_OK;
254} 254}
diff --git a/src/util/service.c b/src/util/service.c
index dc6a7330e..ad74d2786 100644
--- a/src/util/service.c
+++ b/src/util/service.c
@@ -1542,7 +1542,7 @@ GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName,
1542 err = 1; 1542 err = 1;
1543 do_daemonize = 0; 1543 do_daemonize = 0;
1544 logfile = NULL; 1544 logfile = NULL;
1545 loglev = GNUNET_strdup ("WARNING"); 1545 loglev = NULL;
1546 cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE); 1546 cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE);
1547 memset (&sctx, 0, sizeof (sctx)); 1547 memset (&sctx, 0, sizeof (sctx));
1548 sctx.options = opt; 1548 sctx.options = opt;
@@ -1611,7 +1611,7 @@ shutdown:
1611 GNUNET_free_non_null (sctx.addrs); 1611 GNUNET_free_non_null (sctx.addrs);
1612 GNUNET_free_non_null (sctx.addrlens); 1612 GNUNET_free_non_null (sctx.addrlens);
1613 GNUNET_free_non_null (logfile); 1613 GNUNET_free_non_null (logfile);
1614 GNUNET_free (loglev); 1614 GNUNET_free_non_null (loglev);
1615 GNUNET_free (cfg_fn); 1615 GNUNET_free (cfg_fn);
1616 GNUNET_free_non_null (sctx.v4_denied); 1616 GNUNET_free_non_null (sctx.v4_denied);
1617 GNUNET_free_non_null (sctx.v6_denied); 1617 GNUNET_free_non_null (sctx.v6_denied);