📄 log.c
字号:
/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2004 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * log.c - implement logging functions */#include "gwlib.h"#include <limits.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <time.h>#include <stdarg.h>#include <string.h>#ifdef HAVE_EXECINFO_H#include <execinfo.h>#endif#if HAVE_SYSLOG_H#include <syslog.h>#else/* * If we don't have syslog.h, then we'll use the following dummy definitions * to avoid writing #if HAVE_SYSLOG_H everywhere. */enum { LOG_PID, LOG_DAEMON, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR, LOG_ALERT};static void openlog(const char *ident, int option, int facility){}static void syslog(int translog, const char *buf){}static void closelog(void){}#endif/* * List of currently open log files. */#define MAX_LOGFILES 128static struct { FILE *file; int minimum_output_level; char filename[FILENAME_MAX + 1]; /* to allow re-open */ enum excl_state exclusive;} logfiles[MAX_LOGFILES];static int num_logfiles = 0;/* * Mapping array between thread id and logfiles[] index. * This is used for smsc specific logging. */#define THREADTABLE_SIZE 1024static unsigned int thread_to[(long)THREADTABLE_SIZE];/* * Ensure we use the real threadtable slot number to map the thread id * instead of the thread id reported by gwthread_self() */#define thread_slot() \ (gwthread_self() % THREADTABLE_SIZE)/* * List of places that should be logged at debug-level. */#define MAX_LOGGABLE_PLACES (10*1000)static char *loggable_places[MAX_LOGGABLE_PLACES];static int num_places = 0;/* * Reopen/rotate locking things. */static List *writers = NULL;/* * Syslog support. */static int sysloglevel;static int dosyslog = 0;/* * Make sure stderr is included in the list. */static void add_stderr(void){ int i; for (i = 0; i < num_logfiles; ++i) if (logfiles[i].file == stderr) return; logfiles[num_logfiles].file = stderr; logfiles[num_logfiles].minimum_output_level = GW_DEBUG; logfiles[num_logfiles].exclusive = GW_NON_EXCL; ++num_logfiles;}void log_init(void){ unsigned long i; /* default all possible thread to logging index 0, stderr */ for (i = 0; i <= THREADTABLE_SIZE; i++) { thread_to[i] = 0; } add_stderr(); /* initialize rw lock */ if (writers == NULL); writers = list_create();}void log_shutdown(void){ log_close_all(); if (writers != NULL) list_destroy(writers, NULL); writers = NULL;}void log_set_output_level(enum output_level level){ int i; for (i = 0; i < num_logfiles; ++i) { if (logfiles[i].file == stderr) { logfiles[i].minimum_output_level = level; break; } }}void log_set_log_level(enum output_level level){ int i; /* change everything but stderr */ for (i = 0; i < num_logfiles; ++i) { if (logfiles[i].file != stderr) { logfiles[i].minimum_output_level = level; info(0, "Changed logfile `%s' to level `%d'.", logfiles[i].filename, level); } }}void log_set_syslog(const char *ident, int syslog_level){ if (ident == NULL) dosyslog = 0; else { dosyslog = 1; sysloglevel = syslog_level; openlog(ident, LOG_PID, LOG_DAEMON); debug("gwlib.log", 0, "Syslog logging enabled."); }}void log_reopen(void){ int i, j, found; /* * Writer lock. */ if (writers != NULL) { list_lock(writers); /* wait for writers complete */ list_consume(writers); } for (i = 0; i < num_logfiles; ++i) { if (logfiles[i].file != stderr) { found = 0; /* * Reverse seek for allready reopened logfile. * If we find a previous file descriptor for the same file * name, then don't reopen that duplicate, but assign the * file pointer to it. */ for (j = i-1; j >= 0 && found == 0; j--) { if (strcmp(logfiles[i].filename, logfiles[j].filename) == 0) { logfiles[i].file = logfiles[j].file; found = 1; } } if (found) continue; if (logfiles[i].file != NULL) fclose(logfiles[i].file); logfiles[i].file = fopen(logfiles[i].filename, "a"); if (logfiles[i].file == NULL) { error(errno, "Couldn't re-open logfile `%s'.", logfiles[i].filename); } } } /* * Unlock writer. */ if (writers != NULL) list_unlock(writers);}void log_close_all(void){ /* * Writer lock. */ if (writers != NULL) { list_lock(writers); /* wait for writers */ list_consume(writers); } while (num_logfiles > 0) { --num_logfiles; if (logfiles[num_logfiles].file != stderr && logfiles[num_logfiles].file != NULL) fclose(logfiles[num_logfiles].file); logfiles[num_logfiles].file = NULL; } /* * Unlock writer. */ if (writers != NULL) list_unlock(writers); /* close syslog if used */ if (dosyslog) { closelog(); dosyslog = 0; }}int log_open(char *filename, int level, enum excl_state excl){ FILE *f = NULL; int i; if (writers == NULL) writers = list_create(); if (num_logfiles == MAX_LOGFILES) { error(0, "Too many log files already open, not adding `%s'", filename); return -1; } if (strlen(filename) > FILENAME_MAX) { error(0, "Log filename too long: `%s'.", filename); return -1; } /* * Check if the file is already opened for logging. * If there is an open file, then assign the file descriptor * that is already existing for this log file. */ for (i = 0; i < num_logfiles && f == NULL; ++i) { if (strcmp(logfiles[i].filename, filename) == 0) f = logfiles[i].file; } /* if not previously opened, then open it now */ if (f == NULL) { f = fopen(filename, "a"); if (f == NULL) { error(errno, "Couldn't open logfile `%s'.", filename); return -1; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -