log.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:8k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * log.c - implement logging functions
  3.  */
  4. #include <limits.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <errno.h>
  8. #include <time.h>
  9. #include <stdarg.h>
  10. #include <string.h>
  11. #if HAVE_SYSLOG_H
  12. #include <syslog.h>
  13. #else
  14. /*
  15.  * If we don't have syslog.h, then we'll use the following dummy definitions
  16.  * to avoid writing #if HAVE_SYSLOG_H everywhere.
  17.  */
  18. enum {
  19.     LOG_PID, LOG_DAEMON, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR, LOG_ALERT
  20. };
  21. static void openlog(const char *ident, int option, int facility)
  22. {
  23. }
  24. static void syslog(int translog, const char *buf)
  25. {
  26. }
  27. #endif
  28. #include "gwlib.h"
  29. /*
  30.  * List of currently open log files.
  31.  */
  32. #define MAX_LOGFILES 8
  33. static struct {
  34.     FILE *file;
  35.     int minimum_output_level;
  36.     char filename[FILENAME_MAX + 1]; /* to allow re-open */
  37. } logfiles[MAX_LOGFILES];
  38. static int num_logfiles = 0;
  39. /*
  40.  * List of places that should be logged at debug-level.
  41.  */
  42. #define MAX_LOGGABLE_PLACES (10*1000)
  43. static char *loggable_places[MAX_LOGGABLE_PLACES];
  44. static int num_places = 0;
  45. /*
  46.  * Syslog support.
  47.  */
  48. static int sysloglevel;
  49. static int dosyslog = 0;
  50. /*
  51.  * Make sure stderr is included in the list.
  52.  */
  53. static void add_stderr(void) 
  54. {
  55.     int i;
  56.     
  57.     for (i = 0; i < num_logfiles; ++i)
  58. if (logfiles[i].file == stderr)
  59.     return;
  60.     logfiles[num_logfiles].file = stderr;
  61.     logfiles[num_logfiles].minimum_output_level = GW_DEBUG;
  62.     ++num_logfiles;
  63. }
  64. void log_set_output_level(enum output_level level) 
  65. {
  66.     int i;
  67.     
  68.     add_stderr();
  69.     for (i = 0; i < num_logfiles; ++i) {
  70. if (logfiles[i].file == stderr) {
  71.     logfiles[i].minimum_output_level = level;
  72.     break;
  73. }
  74.     }
  75. }
  76. void log_set_syslog(const char *ident, int syslog_level) 
  77. {
  78.     if (ident == NULL)
  79. dosyslog = 0;
  80.     else {
  81. dosyslog = 1;
  82. sysloglevel = syslog_level;
  83. openlog(ident, LOG_PID, LOG_DAEMON);
  84. debug("gwlib.log", 0, "Syslog logging enabled.");
  85.     }
  86. }
  87. void log_reopen(void) 
  88. {
  89. int i;
  90.     for (i = 0; i < num_logfiles; ++i) {
  91. if (logfiles[i].file != stderr) {
  92.     fclose(logfiles[i].file);
  93.     logfiles[i].file = fopen(logfiles[i].filename, "a");
  94.     if (logfiles[i].file == NULL) {
  95. error(errno, "Couldn't re-open logfile `%s'.",
  96.       logfiles[i].filename);
  97.     }
  98. }
  99.     }
  100. }
  101. void log_close_all(void) 
  102. {
  103.     while (num_logfiles > 0) {
  104. --num_logfiles;
  105. if (logfiles[num_logfiles].file != stderr)
  106.     fclose(logfiles[num_logfiles].file);
  107. logfiles[num_logfiles].file = NULL;
  108.     }
  109. }
  110. void log_open(char *filename, int level) 
  111. {
  112.     FILE *f;
  113.     
  114.     add_stderr();
  115.     if (num_logfiles == MAX_LOGFILES) {
  116. error(0, "Too many log files already open, not adding `%s'", 
  117.       filename);
  118. return;
  119.     }
  120.     
  121.     if (strlen(filename) > FILENAME_MAX) {
  122. error(0, "Log filename too long: `%s'.", filename);
  123. return;
  124.     }
  125.     
  126.     f = fopen(filename, "a");
  127.     if (f == NULL) {
  128. error(errno, "Couldn't open logfile `%s'.", filename);
  129. return;
  130.     }
  131.     
  132.     logfiles[num_logfiles].file = f;
  133.     logfiles[num_logfiles].minimum_output_level = level;
  134.     strcpy(logfiles[num_logfiles].filename, filename);
  135.     ++num_logfiles;
  136.     info(0, "Added logfile `%s' with level `%d'.", filename, level);
  137. }
  138. #define FORMAT_SIZE (1024)
  139. static void format(char *buf, int level, const char *place, int e, 
  140.    const char *fmt)
  141. {
  142.     static char *tab[] = {
  143. "DEBUG: ",
  144. "INFO: ",
  145. "WARNING: ",
  146. "ERROR: ",
  147. "PANIC: ",
  148. "LOG: "
  149.     };
  150.     static int tab_size = sizeof(tab) / sizeof(tab[0]);
  151.     time_t t;
  152.     struct tm tm;
  153.     char *p, prefix[1024];
  154.     
  155.     p = prefix;
  156.     time(&t);
  157. #if LOG_TIMESTAMP_LOCALTIME
  158.     tm = gw_localtime(t);
  159. #else
  160.     tm = gw_gmtime(t);
  161. #endif
  162.     sprintf(p, "%04d-%02d-%02d %02d:%02d:%02d ",
  163.     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
  164.     tm.tm_hour, tm.tm_min, tm.tm_sec);
  165.     
  166.     p = strchr(p, '');
  167.     sprintf(p, "[%ld] ", gwthread_self());
  168.     
  169.     p = strchr(p, '');
  170.     if (level < 0 || level >= tab_size)
  171. sprintf(p, "UNKNOWN: ");
  172.     else
  173. sprintf(p, "%s", tab[level]);
  174.     
  175.     p = strchr(p, '');
  176.     if (place != NULL && *place != '')
  177. sprintf(p, "%s: ", place);
  178.     
  179.     if (strlen(prefix) + strlen(fmt) > FORMAT_SIZE / 2) {
  180. sprintf(buf, "%s <OUTPUT message too long>n", prefix);
  181. return;
  182.     }
  183.     
  184.     if (e == 0)
  185. sprintf(buf, "%s%sn", prefix, fmt);
  186.     else
  187. sprintf(buf, "%s%sn%sSystem error %d: %sn",
  188. prefix, fmt, prefix, e, strerror(e));
  189. }
  190. static void output(FILE *f, char *buf, va_list args) 
  191. {
  192.     vfprintf(f, buf, args);
  193.     fflush(f);
  194. }
  195. static void kannel_syslog(char *format, va_list args, int level)
  196. {
  197.     char buf[4096]; /* Trying to syslog more than 4K could be bad */
  198.     int translog;
  199.     
  200.     if (level >= sysloglevel && dosyslog) {
  201. if (args == NULL) {
  202.     strncpy(buf, format, sizeof(buf));
  203.     buf[sizeof(buf) - 1] = '';
  204. } else {
  205.     vsnprintf(buf, sizeof(buf), format, args);
  206.     /* XXX vsnprint not 100% portable */
  207. }
  208. switch(level) {
  209. case GW_DEBUG:
  210.     translog = LOG_DEBUG;
  211.     break;
  212. case GW_INFO:
  213.     translog = LOG_INFO;
  214.     break;
  215. case GW_WARNING:
  216.     translog = LOG_WARNING;
  217.     break;
  218. case GW_ERROR:
  219.     translog = LOG_ERR;
  220.     break;
  221. case GW_PANIC:
  222.     translog = LOG_ALERT;
  223.     break;
  224. default:
  225.     translog = LOG_INFO;
  226.     break;
  227. }
  228. syslog(translog, buf);
  229.     }
  230. }
  231. /*
  232.  * Almost all of the message printing functions are identical, except for
  233.  * the output level they use. This macro contains the identical parts of
  234.  * the functions so that the code needs to exist only once. It's a bit
  235.  * more awkward to edit, but that can't be helped. The "do {} while (0)"
  236.  * construct is a gimmick to be more like a function call in all syntactic
  237.  * situation.
  238.  */
  239. #define FUNCTION_GUTS(level, place) 
  240. do { 
  241.     int i; 
  242.     char buf[FORMAT_SIZE]; 
  243.     va_list args; 
  244.     
  245.     add_stderr(); 
  246.     format(buf, level, place, e, fmt); 
  247.     for (i = 0; i < num_logfiles; ++i) { 
  248. if (level >= logfiles[i].minimum_output_level) { 
  249.     va_start(args, fmt); 
  250.     output(logfiles[i].file, buf, args); 
  251.     va_end(args); 
  252.     } 
  253.     if (dosyslog) { 
  254. va_start(args, fmt); 
  255. kannel_syslog(buf,args,level); 
  256. va_end(args); 
  257.     } 
  258. } while (0)
  259. void gw_panic(int e, const char *fmt, ...) 
  260. {
  261.     FUNCTION_GUTS(GW_PANIC, "");
  262.     exit(EXIT_FAILURE);
  263. }
  264. void error(int e, const char *fmt, ...) 
  265. {
  266.     FUNCTION_GUTS(GW_ERROR, "");
  267. }
  268. void warning(int e, const char *fmt, ...) 
  269. {
  270.     FUNCTION_GUTS(GW_WARNING, "");
  271. }
  272. void info(int e, const char *fmt, ...) 
  273. {
  274.    FUNCTION_GUTS(GW_INFO, "");
  275. }
  276. static int place_matches(const char *place, const char *pat) 
  277. {
  278.     size_t len;
  279.     
  280.     len = strlen(pat);
  281.     if (pat[len-1] == '*')
  282. return (strncasecmp(place, pat, len - 1) == 0);
  283.     return (strcasecmp(place, pat) == 0);
  284. }
  285. static int place_should_be_logged(const char *place) 
  286. {
  287.     int i;
  288.     
  289.     if (num_places == 0)
  290. return 1;
  291.     for (i = 0; i < num_places; ++i) {
  292. if (*loggable_places[i] != '-' && 
  293.     place_matches(place, loggable_places[i]))
  294. return 1;
  295.     }
  296.     return 0;
  297. }
  298. static int place_is_not_logged(const char *place) 
  299. {
  300.     int i;
  301.     
  302.     if (num_places == 0)
  303. return 0;
  304.     for (i = 0; i < num_places; ++i) {
  305. if (*loggable_places[i] == '-' &&
  306.     place_matches(place, loggable_places[i]+1))
  307. return 1;
  308.     }
  309.     return 0;
  310. }
  311. void debug(const char *place, int e, const char *fmt, ...) 
  312. {
  313.     if (place_should_be_logged(place) && place_is_not_logged(place) == 0) {
  314. FUNCTION_GUTS(GW_DEBUG, "");
  315. /*
  316.  * Note: giving `place' to FUNCTION_GUTS makes log lines
  317.       * too long and hard to follow. We'll rely on an external
  318.       * list of what places are used instead of reading them
  319.       * from the log file.
  320.  */
  321.     }
  322. }
  323. void log_set_debug_places(const char *places) 
  324. {
  325.     char *p;
  326.     
  327.     p = strtok(gw_strdup(places), " ,");
  328.     num_places = 0;
  329.     while (p != NULL && num_places < MAX_LOGGABLE_PLACES) {
  330. loggable_places[num_places++] = p;
  331. p = strtok(NULL, " ,");
  332.     }
  333. }