1 /*
2  * Copyright (C) 2002-2003 Fhg Fokus
3  *
4  * This file is part of SEMS, a free SIP media server.
5  *
6  * SEMS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version. This program is released under
10  * the GPL with the additional exemption that compiling, linking,
11  * and/or using OpenSSL is allowed.
12  *
13  * For a license to use the SEMS software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * SEMS is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27 
28 /** @file log.h */
29 #ifndef _log_h_
30 #define _log_h_
31 
32 #include <sys/types.h>	/* pid_t */
33 #include <stdio.h>
34 #include <unistd.h>	/* getpid() */
35 #include <pthread.h>	/* pthread_self() */
36 #include <execinfo.h>   /* backtrace_symbols() */
37 
38 #ifdef __cplusplus
39 #include <cxxabi.h> /* __cxa_demangle() */
40 #endif
41 
42 
43 #ifdef __cplusplus
44 extern "C" {
45 # if 0
46 }
47 # endif
48 #endif
49 
50 /**
51  * @{ Log levels
52  */
53 enum Log_Level {
54   L_ERR = 0,
55   L_WARN,
56   L_INFO,
57   L_DBG
58 };
59 /** @} */
60 
61 #define FIX_LOG_LEVEL(level) \
62   ((level) < L_ERR ? L_ERR : ((level) > L_DBG ? L_DBG : (level)))
63 
64 #ifdef __cplusplus
65 # ifdef PRETTY_FUNCTION_LOG
66 #  define FUNC_NAME __PRETTY_FUNCTION__
67 # else
68 #  define FUNC_NAME __FUNCTION__
69 #endif
70 #else
71 # define FUNC_NAME __FUNCTION__
72 #endif
73 
74 #ifdef __linux
75 # ifndef _GNU_SOURCE
76 #  define _GNU_SOURCE
77 # endif
78 # include <linux/unistd.h>
79 # include <sys/syscall.h>
80 # define GET_PID() syscall(__NR_gettid)
81 #else
82 # define GET_PID() getpid()
83 #endif
84 
85 #ifdef _DEBUG
86 # ifndef NO_THREADID_LOG
87 #  define GET_TID() pthread_self()
88 #  define LOC_FMT   " [#%lx/%u] [%s, %s:%d]"
89 #  define LOC_DATA  (unsigned long)tid_, pid_, FUNC_NAME, __FILE__, __LINE__
90 # else
91 #  define GET_TID() 0
92 #  define LOC_FMT   " [%u] [%s %s:%d]"
93 #  define LOC_DATA  pid_, FUNC_NAME,  __FILE__, __LINE__
94 # endif
95 #else
96 # define GET_TID()   0
97 # define LOC_FMT   " [%u/%s:%d]"
98 # define LOC_DATA  pid_, __FILE__, __LINE__
99 #endif
100 
101 #ifdef LOG_LOC_DATA_ATEND
102 #define COMPLETE_LOG_FMT "%s: %s" LOC_FMT "\n", log_level2str[level_], msg_, LOC_DATA
103 #else
104 #define COMPLETE_LOG_FMT LOC_FMT " %s: %s" "\n", LOC_DATA, log_level2str[level_], msg_
105 #endif
106 
107 #ifndef LOG_BUFFER_LEN
108 #define LOG_BUFFER_LEN 4096
109 #endif
110 
111 /* The underscores in parameter and local variable names are there to
112    avoid collisions. */
113 #define _LOG(level__, fmt, args...)					\
114   do {									\
115     int level_ = FIX_LOG_LEVEL(level__);				\
116 									\
117     if ((level_) <= log_level) {					\
118       pid_t pid_ = GET_PID();						\
119       pthread_t tid_ = GET_TID();					\
120       char msg_[LOG_BUFFER_LEN];					\
121       int n_ = snprintf(msg_, sizeof(msg_), fmt, ##args);		\
122       if ((n_ < LOG_BUFFER_LEN) && (msg_[n_ - 1] == '\n'))              \
123         msg_[n_ - 1] = '\0';                                            \
124       if (log_stderr) {							\
125 	fprintf(stderr, COMPLETE_LOG_FMT);				\
126 	fflush(stderr);							\
127       }									\
128       run_log_hooks(level_, pid_, tid_, FUNC_NAME, __FILE__, __LINE__, msg_); \
129     }									\
130   } while(0)
131 
132 /**
133  * @{ Logging macros
134  */
135 
136 #define CAT_ERROR(error_category, fmt, args... ) \
137   _LOG(L_ERR, error_category " " fmt, ##args)
138 #define CAT_WARN(error_category, fmt, args... ) \
139 _LOG(L_WARN, error_category " " fmt, ##args)
140 #define CAT_INFO(error_category, fmt, args... ) \
141   _LOG(L_INFO, error_category " " fmt, ##args)
142 #define CAT_DBG(error_category, fmt, args... ) \
143   _LOG(L_DBG, error_category " " fmt, ##args)
144 
145 #define CATEGORIZED_PREFIX    "SNMP:"
146 #define CATEGORY_ERROR      CATEGORIZED_PREFIX "0"
147 #define CATEGORY_WARNING    CATEGORIZED_PREFIX "1"
148 #define CATEGORY_INFO       CATEGORIZED_PREFIX "2"
149 #define CATEGORY_DEBUG      CATEGORIZED_PREFIX "3"
150 
151 #ifdef USE_LOG_CATEGORY_PREFIXES
152 # define ERROR_CATEGORY_EGENERAL CATEGORY_ERROR   ".0" " "
153 # define ERROR_CATEGORY_WGENERAL CATEGORY_WARNING ".0" " "
154 # define ERROR_CATEGORY_IGENERAL CATEGORY_INFO    ".0" " "
155 # define ERROR_CATEGORY_DGENERAL CATEGORY_DEBUG   ".0" " "
156 #else
157 # define ERROR_CATEGORY_EGENERAL
158 # define ERROR_CATEGORY_WGENERAL
159 # define ERROR_CATEGORY_IGENERAL
160 # define ERROR_CATEGORY_DGENERAL
161 #endif
162 
163 #define ERROR(fmt, args...) CAT_ERROR(ERROR_CATEGORY_EGENERAL, fmt, ##args)
164 #define WARN(fmt, args...)  CAT_WARN(ERROR_CATEGORY_WGENERAL, fmt, ##args)
165 #define INFO(fmt, args...)  CAT_INFO(ERROR_CATEGORY_IGENERAL, fmt, ##args)
166 #define DBG(fmt, args...)   CAT_DBG(ERROR_CATEGORY_DGENERAL, fmt, ##args)
167 
168 /** @} */
169 
170 extern int log_level;
171 extern int log_stderr;
172 extern const char* log_level2str[];
173 
174 void init_logging(void);
175 void run_log_hooks(int, pid_t, pthread_t, const char*, const char*, int, char*);
176 
177 #ifndef DISABLE_SYSLOG_LOG
178 int set_syslog_facility(const char*);
179 #endif
180 
181 void log_stacktrace(int ll);
182 
183 #ifdef __cplusplus
184 }
185 #endif
186 
187 #ifdef __cplusplus
188 /* ...only for C++ */
189 #define log_demangled_stacktrace __lds
190 void __lds(int ll, unsigned int max_frames = 63);
191 class AmLoggingFacility;
192 void register_log_hook(AmLoggingFacility*);
193 #endif
194 
195 #endif /* !_log_h_ */
196