Kannel: Open Source WAP and SMS gateway  svn-r5262
log.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * log.c - implement logging functions
59  */
60 
61 #include "gwlib.h"
62 #include <limits.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <errno.h>
66 #include <time.h>
67 #include <stdarg.h>
68 #include <string.h>
69 #include <ctype.h>
70 
71 #ifdef HAVE_EXECINFO_H
72 #include <execinfo.h>
73 #endif
74 
75 #if HAVE_SYSLOG_H
76 #ifdef __sun__
77 #include <syslog.h>
78 
79 typedef struct _code {
80  char *c_name;
81  int c_val;
82 } CODE;
83 
84 CODE facilitynames[] = {
85  { "auth", LOG_AUTH },
86 /* { "authpriv", LOG_AUTHPRIV }, */
87  { "cron", LOG_CRON },
88  { "daemon", LOG_DAEMON },
89 /* { "ftp", LOG_FTP }, */
90  { "kern", LOG_KERN },
91  { "lpr", LOG_LPR },
92  { "mail", LOG_MAIL },
93 /* { "mark", INTERNAL_MARK }, */ /* INTERNAL */
94  { "news", LOG_NEWS },
95  { "security", LOG_AUTH }, /* DEPRECATED */
96  { "syslog", LOG_SYSLOG },
97  { "user", LOG_USER },
98  { "uucp", LOG_UUCP },
99  { "local0", LOG_LOCAL0 },
100  { "local1", LOG_LOCAL1 },
101  { "local2", LOG_LOCAL2 },
102  { "local3", LOG_LOCAL3 },
103  { "local4", LOG_LOCAL4 },
104  { "local5", LOG_LOCAL5 },
105  { "local6", LOG_LOCAL6 },
106  { "local7", LOG_LOCAL7 },
107  { NULL, -1 }
108 };
109 
110 #else
111 #define SYSLOG_NAMES
112 #include <syslog.h>
113 #endif
114 
115 /*
116  * Decode the syslog name to its int value
117  */
118 static int decode(char *name)
119 {
120  register CODE *c;
121  CODE *facilities = facilitynames;
122 
123  if (isdigit(*name)) {
124  return (atoi(name));
125  }
126  for (c = facilities; c->c_name; c++) {
127  if (!strcasecmp(name, c->c_name)) {
128  return (c->c_val);
129  }
130  }
131  return LOG_DAEMON;
132 }
133 
134 #else
135 
136 /*
137  * If we don't have syslog.h, then we'll use the following dummy definitions
138  * to avoid writing #if HAVE_SYSLOG_H everywhere.
139  */
140 
141 enum {
143 };
144 
145 static int decode(char *name)
146 {
147  return LOG_DAEMON;
148 }
149 
150 static void openlog(const char *ident, int option, int facility)
151 {
152 }
153 
154 static void syslog(int translog, const char *msg, ...)
155 {
156 }
157 
158 static void closelog(void)
159 {
160 }
161 #endif
162 
163 
164 /*
165  * List of currently open log files.
166  */
167 #define MAX_LOGFILES 128
168 static struct {
169  FILE *file;
171  char filename[FILENAME_MAX + 1]; /* to allow re-open */
174 static int num_logfiles = 0;
175 
176 
177 /*
178  * Mapping array between thread id and logfiles[] index.
179  * This is used for smsc specific logging.
180  */
181 #define THREADTABLE_SIZE 1024
182 static unsigned int thread_to[(long)THREADTABLE_SIZE];
183 
184 
185 /*
186  * Ensure we use the real threadtable slot number to map the thread id
187  * instead of the thread id reported by gwthread_self()
188  */
189 #define thread_slot() \
190  (gwthread_self() % THREADTABLE_SIZE)
191 
192 
193 /*
194  * List of places that should be logged at debug-level.
195  */
196 #define MAX_LOGGABLE_PLACES (10*1000)
198 static int num_places = 0;
199 
200 
201 /*
202  * Reopen/rotate locking things.
203  */
204 static RWLock rwlock;
205 
206 /*
207  * Syslog support.
208  */
209 static int sysloglevel;
211 static int dosyslog = 0;
212 
213 /*
214  * Make sure stderr is included in the list.
215  */
216 static void add_stderr(void)
217 {
218  int i;
219 
220  for (i = 0; i < num_logfiles; ++i)
221  if (logfiles[i].file == stderr)
222  return;
223  logfiles[num_logfiles].file = stderr;
224  logfiles[num_logfiles].minimum_output_level = GW_DEBUG;
225  logfiles[num_logfiles].exclusive = GW_NON_EXCL;
226  ++num_logfiles;
227 }
228 
229 
230 void log_init(void)
231 {
232  unsigned long i;
233 
234  /* Initialize rwlock */
235  gw_rwlock_init_static(&rwlock);
236 
237  /* default all possible thread to logging index 0, stderr */
238  for (i = 0; i < THREADTABLE_SIZE; i++) {
239  thread_to[i] = 0;
240  }
241 
242  add_stderr();
243 }
244 
245 void log_shutdown(void)
246 {
247  log_close_all();
248  /* destroy rwlock */
249  gw_rwlock_destroy(&rwlock);
250 }
251 
252 
254 {
255  int i;
256 
257  for (i = 0; i < num_logfiles; ++i) {
258  if (logfiles[i].file == stderr) {
259  logfiles[i].minimum_output_level = level;
260  break;
261  }
262  }
263 }
264 
266 {
267  int i;
268 
269  /* change everything but stderr */
270  for (i = 0; i < num_logfiles; ++i) {
271  if (logfiles[i].file != stderr) {
272  logfiles[i].minimum_output_level = level;
273  info(0, "Changed logfile `%s' to level `%d'.", logfiles[i].filename, level);
274  }
275  }
276 }
277 
278 void log_set_syslog_facility(char *facility)
279 {
280  if (facility != NULL)
281  syslogfacility = decode(facility);
282 }
283 
284 void log_set_syslog(const char *ident, int syslog_level)
285 {
286  if (ident == NULL)
287  dosyslog = 0;
288  else {
289  dosyslog = 1;
290  sysloglevel = syslog_level;
291  openlog(ident, LOG_PID, syslogfacility);
292  debug("gwlib.log", 0, "Syslog logging enabled.");
293  }
294 }
295 
296 
297 void log_reopen(void)
298 {
299  int i, j, found;
300 
301  /*
302  * Writer lock.
303  */
304  gw_rwlock_wrlock(&rwlock);
305 
306  for (i = 0; i < num_logfiles; ++i) {
307  if (logfiles[i].file != stderr) {
308  found = 0;
309 
310  /*
311  * Reverse seek for allready reopened logfile.
312  * If we find a previous file descriptor for the same file
313  * name, then don't reopen that duplicate, but assign the
314  * file pointer to it.
315  */
316  for (j = i-1; j >= 0 && found == 0; j--) {
317  if (strcmp(logfiles[i].filename, logfiles[j].filename) == 0) {
318  logfiles[i].file = logfiles[j].file;
319  found = 1;
320  }
321  }
322  if (found)
323  continue;
324  if (logfiles[i].file != NULL)
325  fclose(logfiles[i].file);
326  logfiles[i].file = fopen(logfiles[i].filename, "a");
327  if (logfiles[i].file == NULL) {
328  error(errno, "Couldn't re-open logfile `%s'.",
329  logfiles[i].filename);
330  }
331  }
332  }
333 
334  /*
335  * Unlock writer.
336  */
337  gw_rwlock_unlock(&rwlock);
338 }
339 
340 
341 void log_close_all(void)
342 {
343  /*
344  * Writer lock.
345  */
346  gw_rwlock_wrlock(&rwlock);
347 
348  while (num_logfiles > 0) {
349  --num_logfiles;
350  if (logfiles[num_logfiles].file != stderr && logfiles[num_logfiles].file != NULL) {
351  int i;
352  /* look for the same filename and set file to NULL */
353  for (i = num_logfiles - 1; i >= 0; i--) {
354  if (strcmp(logfiles[num_logfiles].filename, logfiles[i].filename) == 0)
355  logfiles[i].file = NULL;
356  }
357  fclose(logfiles[num_logfiles].file);
358  logfiles[num_logfiles].file = NULL;
359  }
360  }
361 
362  /*
363  * Unlock writer.
364  */
365  gw_rwlock_unlock(&rwlock);
366 
367  /* close syslog if used */
368  if (dosyslog) {
369  closelog();
370  dosyslog = 0;
371  }
372 }
373 
374 
375 int log_open(char *filename, int level, enum excl_state excl)
376 {
377  FILE *f = NULL;
378  int i;
379 
380  gw_rwlock_wrlock(&rwlock);
381 
382  if (num_logfiles == MAX_LOGFILES) {
383  gw_rwlock_unlock(&rwlock);
384  error(0, "Too many log files already open, not adding `%s'",
385  filename);
386  return -1;
387  }
388 
389  if (strlen(filename) > FILENAME_MAX) {
390  gw_rwlock_unlock(&rwlock);
391  error(0, "Log filename too long: `%s'.", filename);
392  return -1;
393  }
394 
395  /*
396  * Check if the file is already opened for logging.
397  * If there is an open file, then assign the file descriptor
398  * that is already existing for this log file.
399  */
400  for (i = 0; i < num_logfiles && f == NULL; ++i) {
401  if (strcmp(logfiles[i].filename, filename) == 0)
402  f = logfiles[i].file;
403  }
404 
405  /* if not previously opened, then open it now */
406  if (f == NULL) {
407  f = fopen(filename, "a");
408  if (f == NULL) {
409  gw_rwlock_unlock(&rwlock);
410  error(errno, "Couldn't open logfile `%s'.", filename);
411  return -1;
412  }
413  }
414 
415  logfiles[num_logfiles].file = f;
416  logfiles[num_logfiles].minimum_output_level = level;
417  logfiles[num_logfiles].exclusive = excl;
418  strcpy(logfiles[num_logfiles].filename, filename);
419  ++num_logfiles;
420  i = num_logfiles - 1;
421  gw_rwlock_unlock(&rwlock);
422 
423  info(0, "Added logfile `%s' with level `%d'.", filename, level);
424 
425  return i;
426 }
427 
428 
429 #define FORMAT_SIZE (1024)
430 static void format(char *buf, int level, const char *place, int e,
431  const char *fmt, int with_timestamp_and_pid)
432 {
433  static char *tab[] = {
434  "DEBUG: ",
435  "INFO: ",
436  "WARNING: ",
437  "ERROR: ",
438  "PANIC: ",
439  "LOG: "
440  };
441  static int tab_size = sizeof(tab) / sizeof(tab[0]);
442  time_t t;
443  struct tm tm;
444  char *p, prefix[1024];
445  long tid, pid;
446 
447  p = prefix;
448 
449  if (with_timestamp_and_pid) {
450  time(&t);
451 #if LOG_TIMESTAMP_LOCALTIME
452  tm = gw_localtime(t);
453 #else
454  tm = gw_gmtime(t);
455 #endif
456  sprintf(p, "%04d-%02d-%02d %02d:%02d:%02d ",
457  tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
458  tm.tm_hour, tm.tm_min, tm.tm_sec);
459 
460  p = strchr(p, '\0');
461 
462  /* print PID and thread ID */
463  gwthread_self_ids(&tid, &pid);
464  sprintf(p, "[%ld] [%ld] ", pid, tid);
465  } else {
466  /* thread ID only */
467  tid = gwthread_self();
468  sprintf(p, "[%ld] ", tid);
469  }
470 
471  p = strchr(p, '\0');
472  if (level < 0 || level >= tab_size)
473  sprintf(p, "UNKNOWN: ");
474  else
475  sprintf(p, "%s", tab[level]);
476 
477  p = strchr(p, '\0');
478  if (place != NULL && *place != '\0')
479  sprintf(p, "%s: ", place);
480 
481  if (strlen(prefix) + strlen(fmt) > FORMAT_SIZE / 2) {
482  sprintf(buf, "%s <OUTPUT message too long>\n", prefix);
483  return;
484  }
485 
486  if (e == 0)
487  sprintf(buf, "%s%s\n", prefix, fmt);
488  else
489  sprintf(buf, "%s%s\n%sSystem error %d: %s\n",
490  prefix, fmt, prefix, e, strerror(e));
491 }
492 
493 
494 static void PRINTFLIKE(2,0) output(FILE *f, char *buf, va_list args)
495 {
496  vfprintf(f, buf, args);
497  fflush(f);
498 }
499 
500 
501 static void PRINTFLIKE(1,0) kannel_syslog(char *format, va_list args, int level)
502 {
503  char buf[4096]; /* Trying to syslog more than 4K could be bad */
504  int translog;
505 
506  if (level >= sysloglevel && dosyslog) {
507  vsnprintf(buf, sizeof(buf), format, args);
508  /* XXX vsnprint not 100% portable */
509 
510  switch(level) {
511  case GW_DEBUG:
512  translog = LOG_DEBUG;
513  break;
514  case GW_INFO:
515  translog = LOG_INFO;
516  break;
517  case GW_WARNING:
518  translog = LOG_WARNING;
519  break;
520  case GW_ERROR:
521  translog = LOG_ERR;
522  break;
523  case GW_PANIC:
524  translog = LOG_ALERT;
525  break;
526  default:
527  translog = LOG_INFO;
528  break;
529  }
530  syslog(translog, "%s", buf);
531  }
532 }
533 
534 
535 /*
536  * Almost all of the message printing functions are identical, except for
537  * the output level they use. This macro contains the identical parts of
538  * the functions so that the code needs to exist only once. It's a bit
539  * more awkward to edit, but that can't be helped. The "do {} while (0)"
540  * construct is a gimmick to be more like a function call in all syntactic
541  * situation.
542  */
543 
544 #define FUNCTION_GUTS(level, place) \
545  do { \
546  int i; \
547  int formatted = 0; \
548  char buf[FORMAT_SIZE]; \
549  va_list args; \
550  \
551  gw_rwlock_rdlock(&rwlock); \
552  for (i = 0; i < num_logfiles; ++i) { \
553  if (logfiles[i].exclusive == GW_NON_EXCL && \
554  level >= logfiles[i].minimum_output_level && \
555  logfiles[i].file != NULL) { \
556  if (!formatted) { \
557  format(buf, level, place, err, fmt, 1); \
558  formatted = 1; \
559  } \
560  va_start(args, fmt); \
561  output(logfiles[i].file, buf, args); \
562  va_end(args); \
563  } \
564  } \
565  gw_rwlock_unlock(&rwlock); \
566  if (dosyslog) { \
567  format(buf, level, place, err, fmt, 0); \
568  va_start(args, fmt); \
569  kannel_syslog(buf,args,level); \
570  va_end(args); \
571  } \
572  } while (0)
573 
574 #define FUNCTION_GUTS_EXCL(level, place) \
575  do { \
576  char buf[FORMAT_SIZE]; \
577  va_list args; \
578  \
579  gw_rwlock_rdlock(&rwlock); \
580  if (logfiles[e].exclusive == GW_EXCL && \
581  level >= logfiles[e].minimum_output_level && \
582  logfiles[e].file != NULL) { \
583  format(buf, level, place, err, fmt, 1); \
584  va_start(args, fmt); \
585  output(logfiles[e].file, buf, args); \
586  va_end(args); \
587  } \
588  gw_rwlock_unlock(&rwlock); \
589  } while (0)
590 
591 
592 #ifdef HAVE_BACKTRACE
593 static void PRINTFLIKE(2,3) gw_panic_output(int err, const char *fmt, ...)
594 {
595  FUNCTION_GUTS(GW_PANIC, "");
596 }
597 #endif
598 
599 void gw_backtrace(void **stack_frames, size_t size, int lock)
600 {
601 #if HAVE_BACKTRACE
602  void *frames[50];
603  size_t i;
604  char **strings;
605 
606  if (stack_frames == NULL) {
607  stack_frames = frames;
608  size = backtrace(stack_frames, sizeof(frames) / sizeof(void*));
609  }
610 
611  strings = backtrace_symbols(stack_frames, size);
612 
613  if (strings) {
614  for (i = 0; i < size; i++)
615  gw_panic_output(0, "%s", strings[i]);
616  }
617  else { /* hmm, no memory available */
618  for (i = 0; i < size; i++)
619  gw_panic_output(0, "%p", stack_frames[i]);
620  }
621 
622  /*
623  * Note: we must call gw_native_free directly because if gw_free points to gw_check_free we could
624  * panic's and we have endless loop with SEGFAULT at the end.
625  */
626  gw_native_free(strings);
627 #endif
628 }
629 
630 void gw_panic(int err, const char *fmt, ...)
631 {
632  /*
633  * we don't want PANICs to spread accross smsc logs, so
634  * this will be always within the main core log.
635  */
636  FUNCTION_GUTS(GW_PANIC, "");
637 
638  gw_backtrace(NULL, 0, 0);
639 
640 #ifdef SEGFAULT_PANIC
641  *((char*)0) = 0;
642 #endif
643 
644  exit(EXIT_FAILURE);
645 }
646 
647 
648 void error(int err, const char *fmt, ...)
649 {
650  int e;
651 
652  if ((e = thread_to[thread_slot()])) {
654  } else {
655  FUNCTION_GUTS(GW_ERROR, "");
656  }
657 }
658 
659 
660 void warning(int err, const char *fmt, ...)
661 {
662  int e;
663 
664  if ((e = thread_to[thread_slot()])) {
666  } else {
668  }
669 }
670 
671 
672 void info(int err, const char *fmt, ...)
673 {
674  int e;
675 
676  if ((e = thread_to[thread_slot()])) {
678  } else {
679  FUNCTION_GUTS(GW_INFO, "");
680  }
681 }
682 
683 
684 static int place_matches(const char *place, const char *pat)
685 {
686  size_t len;
687 
688  len = strlen(pat);
689  if (pat[len-1] == '*')
690  return (strncasecmp(place, pat, len - 1) == 0);
691 
692  return (strcasecmp(place, pat) == 0);
693 }
694 
695 
696 static int place_should_be_logged(const char *place)
697 {
698  int i;
699 
700  if (num_places == 0)
701  return 1;
702  for (i = 0; i < num_places; ++i) {
703  if (*loggable_places[i] != '-' &&
704  place_matches(place, loggable_places[i]))
705  return 1;
706  }
707  return 0;
708 }
709 
710 
711 static int place_is_not_logged(const char *place)
712 {
713  int i;
714 
715  if (num_places == 0)
716  return 0;
717  for (i = 0; i < num_places; ++i) {
718  if (*loggable_places[i] == '-' &&
719  place_matches(place, loggable_places[i]+1))
720  return 1;
721  }
722  return 0;
723 }
724 
725 
726 void debug(const char *place, int err, const char *fmt, ...)
727 {
728  int e;
729 
730  if (place_should_be_logged(place) && place_is_not_logged(place) == 0) {
731  /*
732  * Note: giving `place' to FUNCTION_GUTS makes log lines
733  * too long and hard to follow. We'll rely on an external
734  * list of what places are used instead of reading them
735  * from the log file.
736  */
737  if ((e = thread_to[thread_slot()])) {
739  } else {
740  FUNCTION_GUTS(GW_DEBUG, "");
741  }
742  }
743 }
744 
745 
746 void log_set_debug_places(const char *places)
747 {
748  char *p;
749 
750  p = strtok(gw_strdup(places), " ,");
751  num_places = 0;
752  while (p != NULL && num_places < MAX_LOGGABLE_PLACES) {
753  loggable_places[num_places++] = p;
754  p = strtok(NULL, " ,");
755  }
756 }
757 
758 
759 void log_thread_to(int idx)
760 {
761  long thread_id = thread_slot();
762 
763  if (idx > 0) {
764  info(0, "Logging thread `%ld' to logfile `%s' with level `%d'.",
765  thread_id, logfiles[idx].filename, logfiles[idx].minimum_output_level);
766  thread_to[thread_id] = idx;
767  } else if (idx != 0 && num_logfiles > 0) {
768  warning(0, "Logging thread `%ld' to logfile `%s' with level `%d'.",
769  thread_id, logfiles[0].filename, logfiles[0].minimum_output_level);
770  }
771 }
void error(int err, const char *fmt,...)
Definition: log.c:648
void info(int err, const char *fmt,...)
Definition: log.c:672
void log_set_debug_places(const char *places)
Definition: log.c:746
void log_shutdown(void)
Definition: log.c:245
int size
Definition: wsasm.c:84
void gw_backtrace(void **stack_frames, size_t size, int lock)
Definition: log.c:599
long gwthread_self(void)
void gw_native_free(void *ptr)
Definition: gwmem-native.c:123
static struct @66 logfiles[MAX_LOGFILES]
Definition: log.c:142
static int dosyslog
Definition: log.c:211
#define MAX_LOGFILES
Definition: log.c:167
struct tm gw_gmtime(time_t t)
Definition: protected.c:137
static int num_places
Definition: log.c:198
void log_reopen(void)
Definition: log.c:297
#define FUNCTION_GUTS_EXCL(level, place)
Definition: log.c:574
void gw_rwlock_destroy(RWLock *lock)
Definition: gw-rwlock.c:112
int gw_rwlock_wrlock(RWLock *lock)
Definition: gw-rwlock.c:177
void log_init(void)
Definition: log.c:230
#define THREADTABLE_SIZE
Definition: log.c:181
static unsigned int thread_to[(long) THREADTABLE_SIZE]
Definition: log.c:182
#define lock(c)
Definition: counter.c:89
static void openlog(const char *ident, int option, int facility)
Definition: log.c:150
static char * loggable_places[MAX_LOGGABLE_PLACES]
Definition: log.c:197
void gwthread_self_ids(long *tid, long *pid)
int minimum_output_level
Definition: log.c:170
void log_thread_to(int idx)
Definition: log.c:759
FILE * file
Definition: log.c:169
static struct pid_list * found
static RWLock rwlock
Definition: log.c:204
output_level
Definition: log.h:68
static int num_logfiles
Definition: log.c:174
void log_close_all(void)
Definition: log.c:341
void gw_panic(int err, const char *fmt,...)
Definition: log.c:630
#define MAX_LOGGABLE_PLACES
Definition: log.c:196
void log_set_output_level(enum output_level level)
Definition: log.c:253
static int sysloglevel
Definition: log.c:209
#define FORMAT_SIZE
Definition: log.c:429
static int decode(char *name)
Definition: log.c:145
static void closelog(void)
Definition: log.c:158
Definition: log.h:69
Definition: log.h:69
Definition: log.c:142
void log_set_log_level(enum output_level level)
Definition: log.c:265
static void PRINTFLIKE(2, 0)
Definition: log.c:494
int gw_rwlock_unlock(RWLock *lock)
Definition: gw-rwlock.c:155
char * name
Definition: smsc_cimd2.c:212
void warning(int err, const char *fmt,...)
Definition: log.c:660
void log_set_syslog_facility(char *facility)
Definition: log.c:278
char filename[FILENAME_MAX+1]
Definition: log.c:171
static int place_matches(const char *place, const char *pat)
Definition: log.c:684
void log_set_syslog(const char *ident, int syslog_level)
Definition: log.c:284
Definition: log.h:69
unsigned char * option
Definition: test_cimd2.c:1000
static void add_stderr(void)
Definition: log.c:216
static void syslog(int translog, const char *msg,...)
Definition: log.c:154
int log_open(char *filename, int level, enum excl_state excl)
Definition: log.c:375
static void format(char *buf, int level, const char *place, int e, const char *fmt, int with_timestamp_and_pid)
Definition: log.c:430
static int place_is_not_logged(const char *place)
Definition: log.c:711
Definition: log.h:69
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
Definition: log.c:142
struct tm gw_localtime(time_t t)
Definition: protected.c:121
#define thread_slot()
Definition: log.c:189
excl_state
Definition: log.h:73
Definition: log.c:142
void gw_rwlock_init_static(RWLock *lock)
Definition: gw-rwlock.c:96
Definition: log.c:142
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
#define FUNCTION_GUTS(level, place)
Definition: log.c:544
enum excl_state exclusive
Definition: log.c:172
static int syslogfacility
Definition: log.c:210
Definition: log.h:69
static int place_should_be_logged(const char *place)
Definition: log.c:696
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.