📄 log.c
字号:
logfiles[num_logfiles].file = f; logfiles[num_logfiles].minimum_output_level = level; logfiles[num_logfiles].exclusive = excl; strcpy(logfiles[num_logfiles].filename, filename); ++num_logfiles; info(0, "Added logfile `%s' with level `%d'.", filename, level); return (num_logfiles - 1);}#define FORMAT_SIZE (1024)static void format(char *buf, int level, const char *place, int e, const char *fmt, int with_timestamp){ static char *tab[] = { "DEBUG: ", "INFO: ", "WARNING: ", "ERROR: ", "PANIC: ", "LOG: " }; static int tab_size = sizeof(tab) / sizeof(tab[0]); time_t t; struct tm tm; char *p, prefix[1024]; long tid, pid; p = prefix; if (with_timestamp) { time(&t);#if LOG_TIMESTAMP_LOCALTIME tm = gw_localtime(t);#else tm = gw_gmtime(t);#endif sprintf(p, "%04d-%02d-%02d %02d:%02d:%02d ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); p = strchr(p, '\0'); } gwthread_self_ids(&tid, &pid); sprintf(p, "[%ld] [%ld] ", pid, tid); p = strchr(p, '\0'); if (level < 0 || level >= tab_size) sprintf(p, "UNKNOWN: "); else sprintf(p, "%s", tab[level]); p = strchr(p, '\0'); if (place != NULL && *place != '\0') sprintf(p, "%s: ", place); if (strlen(prefix) + strlen(fmt) > FORMAT_SIZE / 2) { sprintf(buf, "%s <OUTPUT message too long>\n", prefix); return; } if (e == 0) sprintf(buf, "%s%s\n", prefix, fmt); else sprintf(buf, "%s%s\n%sSystem error %d: %s\n", prefix, fmt, prefix, e, strerror(e));}static void PRINTFLIKE(2,0) output(FILE *f, char *buf, va_list args) { vfprintf(f, buf, args); fflush(f);}static void PRINTFLIKE(1,0) kannel_syslog(char *format, va_list args, int level){ char buf[4096]; /* Trying to syslog more than 4K could be bad */ int translog; if (level >= sysloglevel && dosyslog) { if (args == NULL) { strncpy(buf, format, sizeof(buf)); buf[sizeof(buf) - 1] = '\0'; } else { vsnprintf(buf, sizeof(buf), format, args); /* XXX vsnprint not 100% portable */ } switch(level) { case GW_DEBUG: translog = LOG_DEBUG; break; case GW_INFO: translog = LOG_INFO; break; case GW_WARNING: translog = LOG_WARNING; break; case GW_ERROR: translog = LOG_ERR; break; case GW_PANIC: translog = LOG_ALERT; break; default: translog = LOG_INFO; break; } syslog(translog, "%s", buf); }}/* * Almost all of the message printing functions are identical, except for * the output level they use. This macro contains the identical parts of * the functions so that the code needs to exist only once. It's a bit * more awkward to edit, but that can't be helped. The "do {} while (0)" * construct is a gimmick to be more like a function call in all syntactic * situation. */#define FUNCTION_GUTS(level, place) \ do { \ int i; \ char buf[FORMAT_SIZE]; \ va_list args; \ \ format(buf, level, place, err, fmt, 1); \ if (writers != NULL) { \ list_lock(writers); \ list_add_producer(writers); \ list_unlock(writers); \ } \ for (i = 0; i < num_logfiles; ++i) { \ if (logfiles[i].exclusive == GW_NON_EXCL && \ level >= logfiles[i].minimum_output_level && \ logfiles[i].file != NULL) { \ va_start(args, fmt); \ output(logfiles[i].file, buf, args); \ va_end(args); \ } \ } \ if (writers != NULL) \ list_remove_producer(writers); \ if (dosyslog) { \ format(buf, level, place, err, fmt, 0); \ va_start(args, fmt); \ kannel_syslog(buf,args,level); \ va_end(args); \ } \ } while (0)#define FUNCTION_GUTS_EXCL(level, place) \ do { \ char buf[FORMAT_SIZE]; \ va_list args; \ \ format(buf, level, place, err, fmt, 1); \ if (writers != NULL) { \ list_lock(writers); \ list_add_producer(writers); \ list_unlock(writers); \ } \ if (logfiles[e].exclusive == GW_EXCL && \ level >= logfiles[e].minimum_output_level && \ logfiles[e].file != NULL) { \ va_start(args, fmt); \ output(logfiles[e].file, buf, args); \ va_end(args); \ } \ if (writers != NULL) \ list_remove_producer(writers); \ } while (0)static void PRINTFLIKE(2,3) gw_panic_output(int err, const char *fmt, ...){ FUNCTION_GUTS(GW_PANIC, "");}void gw_panic(int err, const char *fmt, ...){ /* * we don't want PANICs to spread accross smsc logs, so * this will be always within the main core log. */ FUNCTION_GUTS(GW_PANIC, "");#ifdef HAVE_BACKTRACE { void *stack_frames[50]; size_t size, i; char **strings; size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*)); strings = backtrace_symbols(stack_frames, size); if (strings) { for (i = 0; i < size; i++) gw_panic_output(0, "%s", strings[i]); } else { /* hmm, no memory available */ for (i = 0; i < size; i++) gw_panic_output(0, "%p", stack_frames[i]); } /* * Note: we don't free 'strings' array because gw_free could panic's and we * have endless loop with SEGFAULT at the end. And this doesn't care * us in any case, because we are panic's and exiting immediately. (alex) */ }#endif#ifdef SEGFAULT_PANIC *((char*)0) = 0;#endif exit(EXIT_FAILURE);}void error(int err, const char *fmt, ...) { int e; if ((e = thread_to[thread_slot()])) { FUNCTION_GUTS_EXCL(GW_ERROR, ""); } else { FUNCTION_GUTS(GW_ERROR, ""); }}void warning(int err, const char *fmt, ...) { int e; if ((e = thread_to[thread_slot()])) { FUNCTION_GUTS_EXCL(GW_WARNING, ""); } else { FUNCTION_GUTS(GW_WARNING, ""); }}void info(int err, const char *fmt, ...) { int e; if ((e = thread_to[thread_slot()])) { FUNCTION_GUTS_EXCL(GW_INFO, ""); } else { FUNCTION_GUTS(GW_INFO, ""); }}static int place_matches(const char *place, const char *pat) { size_t len; len = strlen(pat); if (pat[len-1] == '*') return (strncasecmp(place, pat, len - 1) == 0); return (strcasecmp(place, pat) == 0);}static int place_should_be_logged(const char *place) { int i; if (num_places == 0) return 1; for (i = 0; i < num_places; ++i) { if (*loggable_places[i] != '-' && place_matches(place, loggable_places[i])) return 1; } return 0;}static int place_is_not_logged(const char *place) { int i; if (num_places == 0) return 0; for (i = 0; i < num_places; ++i) { if (*loggable_places[i] == '-' && place_matches(place, loggable_places[i]+1)) return 1; } return 0;}void debug(const char *place, int err, const char *fmt, ...) { int e; if (place_should_be_logged(place) && place_is_not_logged(place) == 0) { /* * Note: giving `place' to FUNCTION_GUTS makes log lines * too long and hard to follow. We'll rely on an external * list of what places are used instead of reading them * from the log file. */ if ((e = thread_to[thread_slot()])) { FUNCTION_GUTS_EXCL(GW_DEBUG, ""); } else { FUNCTION_GUTS(GW_DEBUG, ""); } }}void log_set_debug_places(const char *places) { char *p; p = strtok(gw_strdup(places), " ,"); num_places = 0; while (p != NULL && num_places < MAX_LOGGABLE_PLACES) { loggable_places[num_places++] = p; p = strtok(NULL, " ,"); }}void log_thread_to(unsigned int idx){ long thread_id = thread_slot(); if (idx > 0) info(0, "Logging thread `%ld' to logfile `%s' with level `%d'.", thread_id, logfiles[idx].filename, logfiles[idx].minimum_output_level); thread_to[thread_id] = idx;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -