Line | Count | Source |
1 | | /* |
2 | | * debug print |
3 | | * |
4 | | * Copyright (C) 2001-2003 FhG Fokus |
5 | | * |
6 | | * This file is part of opensips, a free SIP server. |
7 | | * |
8 | | * opensips is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU General Public License as published by |
10 | | * the Free Software Foundation; either version 2 of the License, or |
11 | | * (at your option) any later version |
12 | | * |
13 | | * opensips is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU General Public License |
19 | | * along with this program; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | */ |
22 | | |
23 | | /*! |
24 | | * \file |
25 | | * \brief OpenSIPS Debug console print functions |
26 | | */ |
27 | | |
28 | | #include "dprint.h" |
29 | | #include "log_interface.h" |
30 | | #include "globals.h" |
31 | | #include "pt.h" |
32 | | |
33 | | #include <stdarg.h> |
34 | | #include <stdio.h> |
35 | | #include <strings.h> |
36 | | |
37 | | #if !defined(HOST_NAME_MAX) |
38 | | #define HOST_NAME_MAX 255 |
39 | | #endif |
40 | | |
41 | | /* used internally by the log interface */ |
42 | | typedef void (*log_print_pre_fmt_f)(log_print_f gen_print_func, int log_level, |
43 | | int facility, const char *module, const char *func, |
44 | | char *stderr_plain_fmt, char *syslog_plain_fmt, char *format, va_list ap); |
45 | | |
46 | | struct log_consumer_t { |
47 | | str name; |
48 | | log_print_f gen_print_func; |
49 | | log_print_pre_fmt_f pre_fmt_print_func; |
50 | | int level_filter; |
51 | | int muted; |
52 | | }; |
53 | | |
54 | | static int log_level_holder = L_NOTICE; |
55 | | enum log_format stderr_log_format = LOG_FORMAT_PLAIN; |
56 | | enum log_format syslog_log_format = LOG_FORMAT_PLAIN; |
57 | | |
58 | | /* shared holder with the globally set log_level */ |
59 | | static int *log_level_global = NULL; |
60 | | |
61 | | /* current logging level for this process */ |
62 | | int *log_level = &log_level_holder; |
63 | | char *log_prefix = ""; |
64 | | |
65 | | /* used when resetting the logging level of this process */ |
66 | | static int *default_log_level; |
67 | | |
68 | | static char *log_json_buf = NULL; |
69 | | int log_json_buf_size = 6144; |
70 | | static char *log_msg_buf = NULL; |
71 | | int log_msg_buf_size = 4096; |
72 | | /* seconds between two logs of the same LMR_* call site */ |
73 | | int log_ratelimit_period = 1; |
74 | | |
75 | | str log_cee_hostname; |
76 | | |
77 | | static void stderr_dprint(int log_level, int facility, const char *module, const char *func, |
78 | | char *format, va_list ap); |
79 | | static void syslog_dprint(int log_level, int facility, const char *module, const char *func, |
80 | | char *format, va_list ap); |
81 | | |
82 | | static void stderr_pre_fmt_func(log_print_f gen_print_func, int log_level, |
83 | | int facility, const char *module, const char *func, |
84 | | char *stderr_plain_fmt, char *syslog_plain_fmt, char *format, va_list ap); |
85 | | static void syslog_pre_fmt_func(log_print_f gen_print_func, int log_level, |
86 | | int facility, const char *module, const char *func, |
87 | | char *stderr_plain_fmt, char *syslog_plain_fmt, char *format, va_list ap); |
88 | | |
89 | | /* static consumer table to be used until a shm one is alloc'ed; |
90 | | * only stderror is enabled initially */ |
91 | | static struct log_consumer_t default_log_consumers[2] ={ |
92 | | {str_init(STDERR_CONSUMER_NAME), stderr_dprint, stderr_pre_fmt_func, 0, 0}, |
93 | | {str_init(SYSLOG_CONSUMER_NAME), syslog_dprint, syslog_pre_fmt_func, 0, 1} |
94 | | }; |
95 | | |
96 | | struct log_consumer_t *log_consumers = default_log_consumers; |
97 | | int log_consumers_no = 2; |
98 | | |
99 | | int log_event_enabled = 0; |
100 | | int log_event_level_filter = 0; |
101 | | static str evi_log_name = str_init("E_CORE_LOG"); |
102 | | static event_id_t evi_log_id; |
103 | | |
104 | | static char* str_fac[]={"LOG_AUTH","LOG_CRON","LOG_DAEMON", |
105 | | "LOG_KERN","LOG_LOCAL0","LOG_LOCAL1", |
106 | | "LOG_LOCAL2","LOG_LOCAL3","LOG_LOCAL4","LOG_LOCAL5", |
107 | | "LOG_LOCAL6","LOG_LOCAL7","LOG_LPR","LOG_MAIL", |
108 | | "LOG_NEWS","LOG_USER","LOG_UUCP", |
109 | | #ifndef __OS_solaris |
110 | | "LOG_AUTHPRIV","LOG_FTP","LOG_SYSLOG", |
111 | | #endif |
112 | | 0}; |
113 | | static int int_fac[]={LOG_AUTH , LOG_CRON , LOG_DAEMON , |
114 | | LOG_KERN , LOG_LOCAL0 , LOG_LOCAL1 , |
115 | | LOG_LOCAL2 , LOG_LOCAL3 , LOG_LOCAL4 , LOG_LOCAL5 , |
116 | | LOG_LOCAL6 , LOG_LOCAL7 , LOG_LPR , LOG_MAIL , |
117 | | LOG_NEWS , LOG_USER , LOG_UUCP |
118 | | #ifndef __OS_solaris |
119 | | ,LOG_AUTHPRIV,LOG_FTP,LOG_SYSLOG |
120 | | #endif |
121 | | }; |
122 | | |
123 | | char ctime_buf[256]; |
124 | | |
125 | | int str2facility(char *s) |
126 | 0 | { |
127 | 0 | int i; |
128 | |
|
129 | 0 | for( i=0; str_fac[i] ; i++) { |
130 | 0 | if (!strcasecmp(s,str_fac[i])) |
131 | 0 | return int_fac[i]; |
132 | 0 | } |
133 | 0 | return -1; |
134 | 0 | } |
135 | | |
136 | | |
137 | | int dp_my_pid(void) |
138 | 0 | { |
139 | 0 | return my_pid(); |
140 | 0 | } |
141 | | |
142 | | int parse_log_format(str *format) |
143 | 0 | { |
144 | 0 | if (str_match(format, (&str_init(LOG_PLAIN_NAME)))) |
145 | 0 | return LOG_FORMAT_PLAIN; |
146 | 0 | else if (str_match(format, (&str_init(LOG_JSON_NAME)))) |
147 | 0 | return LOG_FORMAT_JSON; |
148 | 0 | else if (str_match(format, (&str_init(LOG_JSON_CEE_NAME)))) |
149 | 0 | return LOG_FORMAT_JSON_CEE; |
150 | 0 | else |
151 | 0 | return -1; |
152 | 0 | } |
153 | | |
154 | | void stderr_dprint_tmp(char *format, ...) |
155 | 0 | { |
156 | 0 | va_list ap; |
157 | |
|
158 | 0 | va_start(ap, format); |
159 | 0 | vfprintf(stderr,format,ap); |
160 | 0 | fflush(stderr); |
161 | 0 | va_end(ap); |
162 | 0 | } |
163 | | |
164 | | int init_log_cee_hostname(void) |
165 | 0 | { |
166 | 0 | struct addrinfo hints, *info = NULL; |
167 | 0 | char hostname[HOST_NAME_MAX+1]; |
168 | 0 | int rc; |
169 | 0 | str cname; |
170 | |
|
171 | 0 | if (log_cee_hostname.s) |
172 | 0 | return 0; |
173 | | |
174 | 0 | gethostname (hostname, HOST_NAME_MAX); |
175 | |
|
176 | 0 | memset(&hints, 0, sizeof hints); |
177 | 0 | hints.ai_family = AF_UNSPEC; |
178 | 0 | hints.ai_socktype = SOCK_STREAM; |
179 | 0 | hints.ai_flags = AI_CANONNAME; |
180 | |
|
181 | 0 | rc = getaddrinfo(hostname, 0, &hints, &info); |
182 | 0 | if (!rc && info) { |
183 | 0 | init_str(&cname, info->ai_canonname); |
184 | 0 | if (pkg_str_dup(&log_cee_hostname, &cname) < 0) { |
185 | 0 | LM_ERR("no more pkg memory\n"); |
186 | 0 | freeaddrinfo(info); |
187 | 0 | return -1; |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | 0 | if (info) |
192 | 0 | freeaddrinfo(info); |
193 | |
|
194 | 0 | return 0; |
195 | 0 | } |
196 | | |
197 | | #define append_string(_d,_s,_len) \ |
198 | 0 | do{\ |
199 | 0 | memcpy((_d),(_s),(_len));\ |
200 | 0 | (_d) += (_len);\ |
201 | 0 | len += (_len);\ |
202 | 0 | }while(0) |
203 | | |
204 | | #define append_string_st(_d,_s) \ |
205 | 0 | do{\ |
206 | 0 | memcpy((_d),(_s),sizeof(_s) - 1);\ |
207 | 0 | (_d) += sizeof(_s) - 1;\ |
208 | 0 | len += sizeof(_s) - 1;\ |
209 | 0 | }while(0) |
210 | | |
211 | 0 | #define S_LEN(_s) (sizeof(_s) - 1) |
212 | | |
213 | | #define DP_JSON_TIME_KEY "{\"time\": \"" |
214 | | #define DP_JSON_PID_KEY "\", \"pid\": " |
215 | | #define DP_JSON_LEVEL_KEY ", \"level\": \"" |
216 | | #define DP_JSON_MODULE_KEY "\", \"module\": \"" |
217 | | #define DP_JSON_FUNC_KEY "\", \"function\": \"" |
218 | | #define DP_JSON_PREFIX_KEY "\", \"prefix\": \"" |
219 | | #define DP_JSON_MSG_KEY "\", \"message\": \"" |
220 | | |
221 | | #define DP_JSON_CEE_AT_PREFIX "@cee: " |
222 | | #define DP_JSON_CEE_TIME_KEY "{\"time\": \"" |
223 | | #define DP_JSON_CEE_PID_KEY "\", \"proc\": {\"id\": \"" |
224 | | #define DP_JSON_CEE_LEVEL_KEY "\"}, \"pri\": \"" |
225 | | #define DP_JSON_CEE_MODULE_KEY "\", \"subsys\": \"" |
226 | | #define DP_JSON_CEE_FUNC_KEY "\", \"native\": {\"function\": \"" |
227 | | #define DP_JSON_CEE_PREFIX_KEY "\", \"log_prefix\": \"" |
228 | | #define DP_JSON_CEE_PREFIX_O_KEY "\", \"native\": {\"log_prefix\": \"" |
229 | | #define DP_JSON_CEE_MSG_B_KEY "\"}, \"msg\": \"" |
230 | | #define DP_JSON_CEE_MSG_KEY "\", \"msg\": \"" |
231 | | #define DP_JSON_CEE_PNAME_KEY "\", \"pname\": \"" |
232 | | #define DP_JSON_CEE_PNAME_VAL "opensips" |
233 | | #define DP_JSON_CEE_HOST_KEY "\", \"hostname\": \"" |
234 | | |
235 | | #define DP_JSON_MSG_END "\"}" |
236 | | |
237 | | static int log_escape_json_buf(char *src, int src_len, char *dst, int dst_max_len) |
238 | 0 | { |
239 | 0 | int i, j = 0; |
240 | 0 | int rlen = 0; |
241 | | |
242 | | /* calculate the required length in the dst buffer */ |
243 | 0 | for (i=0; i<src_len; i++) { |
244 | 0 | rlen++; |
245 | |
|
246 | 0 | switch (src[i]) { |
247 | 0 | case '\\': |
248 | 0 | case '\"': |
249 | 0 | case '\b': |
250 | 0 | case '\f': |
251 | 0 | case '\n': |
252 | 0 | case '\r': |
253 | 0 | case '\t': |
254 | 0 | rlen++; /* +1 for the backslash */ |
255 | 0 | break; |
256 | 0 | default: |
257 | 0 | if (src[i] < 32) |
258 | 0 | rlen += 6; /* +6 for \uXXXX */ |
259 | 0 | } |
260 | 0 | } |
261 | | |
262 | 0 | if (rlen>dst_max_len) { |
263 | 0 | stderr_dprint_tmp_err("buffer too small! needed: %d\n", rlen); |
264 | 0 | return -1; |
265 | 0 | } else if (rlen == src_len) { |
266 | | /* nothing needs to be escaped */ |
267 | 0 | memcpy(dst, src, src_len); |
268 | 0 | return src_len; |
269 | 0 | } |
270 | | |
271 | 0 | for (i=0; i<src_len; i++) { |
272 | 0 | if (src[i] > 31 && src[i] != '\\' && src[i] != '\"') { |
273 | 0 | dst[j++] = src[i]; |
274 | 0 | } else { |
275 | 0 | dst[j++] = '\\'; |
276 | |
|
277 | 0 | switch (src[i]) { |
278 | 0 | case '\\': |
279 | 0 | dst[j++] = '\\'; |
280 | 0 | break; |
281 | 0 | case '\"': |
282 | 0 | dst[j++] = '\"'; |
283 | 0 | break; |
284 | 0 | case '\b': |
285 | 0 | dst[j++] = 'b'; |
286 | 0 | break; |
287 | 0 | case '\f': |
288 | 0 | dst[j++] = 'f'; |
289 | 0 | break; |
290 | 0 | case '\n': |
291 | 0 | dst[j++] = 'n'; |
292 | 0 | break; |
293 | 0 | case '\r': |
294 | 0 | dst[j++] = 'r'; |
295 | 0 | break; |
296 | 0 | case '\t': |
297 | 0 | dst[j++] = 't'; |
298 | 0 | break; |
299 | 0 | default: |
300 | | /* escape and print as unicode codepoint */ |
301 | 0 | sprintf(dst+j, "u%04x", src[i]); |
302 | 0 | j += 5; |
303 | 0 | } |
304 | 0 | } |
305 | 0 | } |
306 | | |
307 | 0 | return j; |
308 | 0 | } |
309 | | |
310 | | enum log_json_format { |
311 | | LOG_JSON_SCHEMA_BASIC, |
312 | | LOG_JSON_SCHEMA_CEE, |
313 | | LOG_JSON_SCHEMA_CEE_PREFIX /* for syslog, JSON prefixed with "@cee: " */ |
314 | | }; |
315 | | |
316 | | static int log_print_json(str *buf, enum log_json_format json_fmt, char *time, |
317 | | int pid, char *prefix, const char *level, const char *module, const char *func, |
318 | | char *format, va_list ap) |
319 | 0 | { |
320 | 0 | char *p, *tmp; |
321 | 0 | int len = 0, rlen; |
322 | 0 | int l; |
323 | |
|
324 | 0 | if (json_fmt > LOG_JSON_SCHEMA_BASIC) { |
325 | 0 | rlen = S_LEN(DP_JSON_CEE_PNAME_KEY) + (log_name ? strlen(log_name) : |
326 | 0 | S_LEN(DP_JSON_CEE_PNAME_VAL)) + S_LEN(DP_JSON_CEE_HOST_KEY) + |
327 | 0 | log_cee_hostname.len + S_LEN(DP_JSON_MSG_END) + 1; |
328 | |
|
329 | 0 | if (json_fmt == LOG_JSON_SCHEMA_CEE_PREFIX) |
330 | 0 | len = S_LEN(DP_JSON_CEE_AT_PREFIX); |
331 | |
|
332 | 0 | len += S_LEN(DP_JSON_CEE_TIME_KEY) + strlen(time) + |
333 | 0 | S_LEN(DP_JSON_CEE_PID_KEY) + INT2STR_MAX_LEN + |
334 | 0 | S_LEN(DP_JSON_CEE_LEVEL_KEY) + strlen(level) + |
335 | 0 | (module && func ? |
336 | 0 | S_LEN(DP_JSON_CEE_MODULE_KEY) + strlen(module) + |
337 | 0 | S_LEN(DP_JSON_CEE_FUNC_KEY) + strlen(func) : 0) + |
338 | 0 | S_LEN(DP_JSON_CEE_PREFIX_O_KEY) + strlen(prefix) + |
339 | 0 | S_LEN(DP_JSON_MSG_KEY) + rlen; |
340 | 0 | } else { |
341 | 0 | rlen = S_LEN(DP_JSON_MSG_END) + 1; |
342 | |
|
343 | 0 | len = S_LEN(DP_JSON_TIME_KEY) + strlen(time) + S_LEN(DP_JSON_PID_KEY) + |
344 | 0 | INT2STR_MAX_LEN + S_LEN(DP_JSON_LEVEL_KEY) + strlen(level) + |
345 | 0 | (module && func ? S_LEN(DP_JSON_MODULE_KEY) + strlen(module) + |
346 | 0 | S_LEN(DP_JSON_FUNC_KEY) + strlen(func) : 0) + |
347 | 0 | S_LEN(DP_JSON_PREFIX_KEY) + strlen(prefix) + |
348 | 0 | S_LEN(DP_JSON_CEE_MSG_B_KEY) + rlen; |
349 | 0 | } |
350 | |
|
351 | 0 | if (len >= buf->len) { |
352 | 0 | stderr_dprint_tmp_err("buffer too small! needed: %d\n", len); |
353 | 0 | return -1; |
354 | 0 | } |
355 | | |
356 | 0 | len = 0; |
357 | 0 | p = buf->s; |
358 | |
|
359 | 0 | if (json_fmt > LOG_JSON_SCHEMA_BASIC) { |
360 | 0 | if (json_fmt == LOG_JSON_SCHEMA_CEE_PREFIX) |
361 | 0 | append_string_st(p, DP_JSON_CEE_AT_PREFIX); |
362 | |
|
363 | 0 | append_string_st(p, DP_JSON_CEE_TIME_KEY); |
364 | 0 | append_string(p, time, strlen(time)); |
365 | |
|
366 | 0 | append_string_st(p, DP_JSON_CEE_PID_KEY); |
367 | 0 | tmp = int2str(pid, &l); |
368 | 0 | append_string(p, tmp, l); |
369 | |
|
370 | 0 | append_string_st(p, DP_JSON_CEE_LEVEL_KEY); |
371 | 0 | append_string(p, level, strlen(level)); |
372 | |
|
373 | 0 | if (module && func) { |
374 | 0 | append_string_st(p, DP_JSON_CEE_MODULE_KEY); |
375 | 0 | append_string(p, module, strlen(module)); |
376 | |
|
377 | 0 | append_string_st(p, DP_JSON_CEE_FUNC_KEY); |
378 | 0 | append_string(p, func, strlen(func)); |
379 | 0 | } |
380 | |
|
381 | 0 | if (strlen(prefix) != 0) { |
382 | 0 | if (module && func) |
383 | 0 | append_string_st(p, DP_JSON_CEE_PREFIX_KEY); |
384 | 0 | else |
385 | 0 | append_string_st(p, DP_JSON_CEE_PREFIX_O_KEY); |
386 | 0 | append_string(p, prefix, strlen(prefix)-1/*skip the ':'*/); |
387 | 0 | } |
388 | |
|
389 | 0 | if ((module && func) || strlen(prefix) != 0) |
390 | 0 | append_string_st(p, DP_JSON_CEE_MSG_B_KEY); |
391 | 0 | else |
392 | 0 | append_string_st(p, DP_JSON_CEE_MSG_KEY); |
393 | 0 | } else { |
394 | 0 | append_string_st(p, DP_JSON_TIME_KEY); |
395 | 0 | append_string(p, time, strlen(time)); |
396 | |
|
397 | 0 | append_string_st(p, DP_JSON_PID_KEY); |
398 | 0 | tmp = int2str(pid, &l); |
399 | 0 | append_string(p, tmp, l); |
400 | |
|
401 | 0 | append_string_st(p, DP_JSON_LEVEL_KEY); |
402 | 0 | append_string(p, level, strlen(level)); |
403 | |
|
404 | 0 | if (module && func) { |
405 | 0 | append_string_st(p, DP_JSON_MODULE_KEY); |
406 | 0 | append_string(p, module, strlen(module)); |
407 | |
|
408 | 0 | append_string_st(p, DP_JSON_FUNC_KEY); |
409 | 0 | append_string(p, func, strlen(func)); |
410 | 0 | } |
411 | |
|
412 | 0 | if (strlen(prefix) != 0) { |
413 | 0 | append_string_st(p, DP_JSON_PREFIX_KEY); |
414 | 0 | append_string(p, prefix, strlen(prefix)-1/*skip the ':'*/); |
415 | 0 | } |
416 | |
|
417 | 0 | append_string_st(p, DP_JSON_MSG_KEY); |
418 | 0 | } |
419 | |
|
420 | 0 | l = vsnprintf(log_msg_buf, log_msg_buf_size, format, ap); |
421 | 0 | if (l < 0) { |
422 | 0 | stderr_dprint_tmp_err("vsnprintf() failed!\n"); |
423 | 0 | return -1; |
424 | 0 | } |
425 | 0 | if (l >= log_msg_buf_size) { |
426 | 0 | stderr_dprint_tmp_err("warning: buffer too small, log message truncated\n"); |
427 | 0 | l = log_msg_buf_size; |
428 | 0 | } |
429 | |
|
430 | 0 | l = log_escape_json_buf(log_msg_buf, l, p, |
431 | 0 | buf->len - len - rlen - 1); |
432 | 0 | if (l < 0) { |
433 | 0 | stderr_dprint_tmp_err("failed to escape log message!\n"); |
434 | 0 | return -1; |
435 | 0 | } |
436 | | |
437 | 0 | p += l; |
438 | 0 | len += l; |
439 | |
|
440 | 0 | if (json_fmt == LOG_JSON_SCHEMA_BASIC) { |
441 | 0 | append_string_st(p, DP_JSON_MSG_END); |
442 | 0 | } else { |
443 | 0 | append_string_st(p, DP_JSON_CEE_PNAME_KEY); |
444 | 0 | if (log_name) |
445 | 0 | append_string(p, log_name, strlen(log_name)); |
446 | 0 | else |
447 | 0 | append_string_st(p, DP_JSON_CEE_PNAME_VAL); |
448 | |
|
449 | 0 | append_string_st(p, DP_JSON_CEE_HOST_KEY); |
450 | 0 | append_string(p, log_cee_hostname.s, log_cee_hostname.len); |
451 | |
|
452 | 0 | append_string_st(p, DP_JSON_MSG_END); |
453 | 0 | } |
454 | |
|
455 | 0 | *p = '\0'; |
456 | |
|
457 | 0 | return len; |
458 | 0 | } |
459 | | |
460 | | static void stderr_dprint(int log_level, int facility, const char *module, const char *func, |
461 | | char *format, va_list ap) |
462 | 0 | { |
463 | 0 | char *time; |
464 | 0 | int pid; |
465 | 0 | char *prefix; |
466 | 0 | int len; |
467 | 0 | str buf = {log_json_buf, log_json_buf_size}; |
468 | |
|
469 | 0 | if (stderr_log_format != LOG_FORMAT_PLAIN) { |
470 | 0 | time = va_arg(ap, char *); |
471 | 0 | pid = va_arg(ap, int); |
472 | 0 | prefix = va_arg(ap, char *); |
473 | 0 | if (module && func) |
474 | 0 | va_arg(ap, char *); |
475 | |
|
476 | 0 | if ((len = log_print_json(&buf, stderr_log_format==LOG_FORMAT_JSON_CEE ? |
477 | 0 | LOG_JSON_SCHEMA_CEE : LOG_JSON_SCHEMA_BASIC, |
478 | 0 | time, pid, prefix, dp_log_level_str(log_level), module, func, |
479 | 0 | format, ap)) < 0) { |
480 | 0 | stderr_dprint_tmp_err("failed to print JSON log!\n"); |
481 | 0 | return; |
482 | 0 | } |
483 | | |
484 | 0 | fprintf(stderr, "%.*s\n", len, log_json_buf); |
485 | 0 | fflush(stderr); |
486 | 0 | } else { |
487 | 0 | vfprintf(stderr,format,ap); |
488 | 0 | fflush(stderr); |
489 | 0 | } |
490 | 0 | } |
491 | | |
492 | | static void syslog_dprint(int log_level, int facility, const char *module, const char *func, |
493 | | char *format, va_list ap) |
494 | 0 | { |
495 | 0 | int level; |
496 | 0 | char *time; |
497 | 0 | int pid; |
498 | 0 | char *prefix; |
499 | 0 | int len; |
500 | 0 | str buf = {log_json_buf, log_json_buf_size}; |
501 | |
|
502 | 0 | switch (log_level) { |
503 | 0 | case L_ALERT: |
504 | 0 | level = LOG_ALERT; |
505 | 0 | break; |
506 | 0 | case L_CRIT: |
507 | 0 | level = LOG_CRIT; |
508 | 0 | break; |
509 | 0 | case L_ERR: |
510 | 0 | level = LOG_ERR; |
511 | 0 | break; |
512 | 0 | case L_WARN: |
513 | 0 | level = LOG_WARNING; |
514 | 0 | break; |
515 | 0 | case L_NOTICE: |
516 | 0 | level = LOG_NOTICE; |
517 | 0 | break; |
518 | 0 | case L_INFO: |
519 | 0 | level = LOG_INFO; |
520 | 0 | break; |
521 | 0 | case L_DBG: |
522 | 0 | default: |
523 | 0 | level = LOG_DEBUG; |
524 | 0 | } |
525 | | |
526 | 0 | if (syslog_log_format != LOG_FORMAT_PLAIN) { |
527 | 0 | time = va_arg(ap, char *); |
528 | 0 | pid = va_arg(ap, int); |
529 | 0 | prefix = va_arg(ap, char *); |
530 | 0 | if (module && func) |
531 | 0 | va_arg(ap, char *); |
532 | |
|
533 | 0 | if ((len = log_print_json(&buf, syslog_log_format==LOG_FORMAT_JSON_CEE ? |
534 | 0 | LOG_JSON_SCHEMA_CEE_PREFIX : LOG_JSON_SCHEMA_BASIC, |
535 | 0 | time, pid, prefix, dp_log_level_str(log_level), module, func, |
536 | 0 | format, ap)) < 0) { |
537 | 0 | stderr_dprint_tmp_err("failed to print JSON log!\n"); |
538 | 0 | return; |
539 | 0 | } |
540 | | |
541 | 0 | syslog(level|facility, "%.*s\n", len, log_json_buf); |
542 | 0 | } else { |
543 | | /* skip the time and pid arguments from va_list */ |
544 | 0 | va_arg(ap, char *); |
545 | 0 | va_arg(ap, int); |
546 | |
|
547 | 0 | vsyslog(level|facility, format, ap); |
548 | 0 | } |
549 | 0 | } |
550 | | |
551 | | static str evi_time_str = str_init("time"); |
552 | | static str evi_pid_str = str_init("pid"); |
553 | | static str evi_level_str = str_init("level"); |
554 | | static str evi_module_str = str_init("module"); |
555 | | static str evi_func_str = str_init("function"); |
556 | | static str evi_prefix_str = str_init("prefix"); |
557 | | static str evi_msg_str = str_init("message"); |
558 | | |
559 | | static void event_dprint(int level, int facility, const char *module, const char *func, |
560 | | char *format, va_list ap) |
561 | 0 | { |
562 | 0 | evi_params_p list = NULL; |
563 | 0 | str s; |
564 | 0 | int n; |
565 | 0 | int suppressed; |
566 | |
|
567 | 0 | suppressed = pt[process_no].suppress_log_event; |
568 | |
|
569 | 0 | if (suppressed) |
570 | 0 | return; |
571 | | |
572 | 0 | pt[process_no].suppress_log_event = 1; |
573 | |
|
574 | 0 | if (!evi_probe_event(evi_log_id)) { |
575 | 0 | pt[process_no].suppress_log_event = suppressed; |
576 | 0 | return; |
577 | 0 | } |
578 | | |
579 | 0 | if (!(list = evi_get_params())) { |
580 | 0 | pt[process_no].suppress_log_event = suppressed; |
581 | 0 | return; |
582 | 0 | } |
583 | | |
584 | 0 | init_str(&s, dp_time()); |
585 | 0 | if (evi_param_add_str(list, &evi_time_str, &s)) { |
586 | 0 | LM_ERR("unable to add event parameter\n"); |
587 | 0 | goto end_free; |
588 | 0 | } |
589 | 0 | n = dp_my_pid(); |
590 | 0 | if (evi_param_add_int(list, &evi_pid_str, &n)) { |
591 | 0 | LM_ERR("unable to add event parameter\n"); |
592 | 0 | goto end_free; |
593 | 0 | } |
594 | 0 | init_str(&s, dp_log_level_str(level)); |
595 | 0 | if (evi_param_add_str(list, &evi_level_str, &s)) { |
596 | 0 | LM_ERR("unable to add event parameter\n"); |
597 | 0 | goto end_free; |
598 | 0 | } |
599 | | |
600 | 0 | if (module && func) { |
601 | 0 | init_str(&s, module); |
602 | 0 | if (evi_param_add_str(list, &evi_module_str, &s)) { |
603 | 0 | LM_ERR("unable to add event parameter\n"); |
604 | 0 | goto end_free; |
605 | 0 | } |
606 | 0 | init_str(&s, func); |
607 | 0 | if (evi_param_add_str(list, &evi_func_str, &s)) { |
608 | 0 | LM_ERR("unable to add event parameter\n"); |
609 | 0 | goto end_free; |
610 | 0 | } |
611 | 0 | } |
612 | | |
613 | 0 | init_str(&s, log_prefix); |
614 | 0 | if (s.len) { |
615 | 0 | if (evi_param_add_str(list, &evi_prefix_str, &s)) { |
616 | 0 | LM_ERR("unable to add event parameter\n"); |
617 | 0 | goto end_free; |
618 | 0 | } |
619 | 0 | } |
620 | | |
621 | 0 | s.len = vsnprintf(log_msg_buf, log_msg_buf_size, format, ap); |
622 | 0 | if (s.len < 0) { |
623 | 0 | LM_ERR("vsnprintf() failed!\n"); |
624 | 0 | goto end_free; |
625 | 0 | } |
626 | 0 | if (s.len>=log_msg_buf_size) { |
627 | 0 | LM_WARN("log message truncated\n"); |
628 | 0 | s.len = log_msg_buf_size; |
629 | 0 | } |
630 | | |
631 | | /* try to strip \n from the end of the "message" param */ |
632 | 0 | if (log_msg_buf[s.len-1] == '\n') { |
633 | 0 | log_msg_buf[s.len-1] = '\0'; |
634 | 0 | s.len--; |
635 | 0 | } |
636 | |
|
637 | 0 | s.s = log_msg_buf; |
638 | 0 | if (evi_param_add_str(list, &evi_msg_str, &s)) { |
639 | 0 | LM_ERR("unable to add event parameter\n"); |
640 | 0 | goto end_free; |
641 | 0 | } |
642 | | |
643 | 0 | if (evi_raise_event(evi_log_id, list)) { |
644 | 0 | LM_ERR("unable to raise '%.*s' event\n", |
645 | 0 | evi_log_name.len, evi_log_name.s); |
646 | 0 | } |
647 | |
|
648 | 0 | pt[process_no].suppress_log_event = suppressed; |
649 | |
|
650 | 0 | return; |
651 | 0 | end_free: |
652 | 0 | evi_free_params(list); |
653 | 0 | pt[process_no].suppress_log_event = suppressed; |
654 | 0 | } |
655 | | |
656 | | /* generic consumer that registers to the log interface */ |
657 | | static void gen_consumer_pre_fmt_func(log_print_f gen_print_func, int log_level, |
658 | | int facility, const char *module, const char *func, |
659 | | char *stderr_plain_fmt, char *syslog_plain_fmt, char *format, va_list ap) |
660 | 0 | { |
661 | | /* skip the time, pid, prefix and function arguments from va_list */ |
662 | 0 | va_arg(ap, char *); |
663 | 0 | va_arg(ap, int); |
664 | 0 | va_arg(ap, char *); |
665 | 0 | if (module && func) |
666 | 0 | va_arg(ap, char *); |
667 | |
|
668 | 0 | gen_print_func(log_level, facility, module, func, format, ap); |
669 | 0 | } |
670 | | |
671 | | static void stderr_pre_fmt_func(log_print_f gen_print_func, int log_level, |
672 | | int facility, const char *module, const char *func, |
673 | | char *stderr_plain_fmt, char *syslog_plain_fmt, char *format, va_list ap) |
674 | 0 | { |
675 | 0 | char *fmt = stderr_log_format == LOG_FORMAT_PLAIN ? stderr_plain_fmt : format; |
676 | |
|
677 | 0 | gen_print_func(log_level, facility, module, func, fmt, ap); |
678 | 0 | } |
679 | | |
680 | | static void syslog_pre_fmt_func(log_print_f gen_print_func, int log_level, |
681 | | int facility, const char *module, const char *func, |
682 | | char *stderr_plain_fmt, char *syslog_plain_fmt, char *format, va_list ap) |
683 | 0 | { |
684 | 0 | char *fmt = syslog_log_format == LOG_FORMAT_PLAIN ? syslog_plain_fmt : format; |
685 | |
|
686 | 0 | gen_print_func(log_level, facility, module, func, fmt, ap); |
687 | 0 | } |
688 | | |
689 | | void dprint(int log_level, int facility, const char *module, const char *func, |
690 | | char *stderr_fmt, char *syslog_fmt, char *format, ...) |
691 | 0 | { |
692 | 0 | va_list ap, ap_copy; |
693 | 0 | int i; |
694 | |
|
695 | 0 | va_start(ap, format); |
696 | |
|
697 | 0 | for (i=0; i<log_consumers_no; i++) |
698 | 0 | if (!log_consumers[i].muted && (!log_consumers[i].level_filter || |
699 | 0 | log_consumers[i].level_filter >= log_level)) { |
700 | 0 | va_copy(ap_copy, ap); |
701 | 0 | log_consumers[i].pre_fmt_print_func(log_consumers[i].gen_print_func, |
702 | 0 | log_level, facility, module, func, stderr_fmt, syslog_fmt, |
703 | 0 | format, ap_copy); |
704 | 0 | va_end(ap_copy); |
705 | 0 | } |
706 | |
|
707 | 0 | va_end(ap); |
708 | 0 | } |
709 | | |
710 | | int register_log_consumer(char *name, log_print_f print_func, |
711 | | int level_filter, int muted) |
712 | 0 | { |
713 | 0 | if (log_consumers_no == MAX_LOG_CONS_NO) { |
714 | 0 | LM_ERR("Maximum number of logging consumers already registered\n"); |
715 | 0 | return -1; |
716 | 0 | } |
717 | | |
718 | 0 | init_str(&log_consumers[log_consumers_no].name, name); |
719 | 0 | log_consumers[log_consumers_no].gen_print_func = print_func; |
720 | 0 | log_consumers[log_consumers_no].pre_fmt_print_func = gen_consumer_pre_fmt_func; |
721 | 0 | log_consumers[log_consumers_no].level_filter = level_filter; |
722 | 0 | log_consumers[log_consumers_no].muted = muted; |
723 | |
|
724 | 0 | log_consumers_no++; |
725 | |
|
726 | 0 | return 0; |
727 | 0 | } |
728 | | |
729 | | int init_log_json_buf(int realloc_buf) |
730 | 0 | { |
731 | 0 | if (realloc_buf && log_json_buf) { |
732 | 0 | log_json_buf = pkg_realloc(log_json_buf, log_json_buf_size+1); |
733 | 0 | if (!log_json_buf) { |
734 | 0 | LM_ERR("no pkg memory left\n"); |
735 | 0 | return -1; |
736 | 0 | } |
737 | 0 | } else if (!log_json_buf) { |
738 | 0 | log_json_buf = pkg_malloc(log_json_buf_size+1); |
739 | 0 | if (!log_json_buf) { |
740 | 0 | LM_ERR("no pkg memory left\n"); |
741 | 0 | return -1; |
742 | 0 | } |
743 | 0 | } |
744 | | |
745 | 0 | return 0; |
746 | 0 | } |
747 | | |
748 | | int init_log_msg_buf(int realloc_buf) |
749 | 0 | { |
750 | 0 | if (realloc_buf && log_msg_buf) { |
751 | 0 | log_msg_buf = pkg_realloc(log_msg_buf, log_msg_buf_size+1); |
752 | 0 | if (!log_msg_buf) { |
753 | 0 | LM_ERR("no pkg memory left\n"); |
754 | 0 | return -1; |
755 | 0 | } |
756 | 0 | } else if (!log_msg_buf) { |
757 | 0 | log_msg_buf = pkg_malloc(log_msg_buf_size+1); |
758 | 0 | if (!log_msg_buf) { |
759 | 0 | LM_ERR("no pkg memory left\n"); |
760 | 0 | return -1; |
761 | 0 | } |
762 | 0 | } |
763 | | |
764 | 0 | return 0; |
765 | 0 | } |
766 | | |
767 | | /* replaces the default consumer table with a shm allocated one */ |
768 | | int init_log_cons_shm_table(void) |
769 | 0 | { |
770 | 0 | struct log_consumer_t *cons; |
771 | |
|
772 | 0 | cons = shm_malloc(MAX_LOG_CONS_NO * sizeof(struct log_consumer_t)); |
773 | 0 | if (!cons) { |
774 | 0 | LM_ERR("no more shm memory\n"); |
775 | 0 | return -1; |
776 | 0 | } |
777 | 0 | memset(cons, 0, MAX_LOG_CONS_NO * sizeof(struct log_consumer_t)); |
778 | |
|
779 | 0 | cons[0] = log_consumers[0]; |
780 | 0 | cons[1] = log_consumers[1]; |
781 | |
|
782 | 0 | log_consumers = cons; |
783 | |
|
784 | 0 | return 0; |
785 | 0 | } |
786 | | |
787 | | void cleanup_log_cons_shm_table(void) |
788 | 0 | { |
789 | 0 | struct log_consumer_t *cons = log_consumers; |
790 | |
|
791 | 0 | log_consumers = default_log_consumers; |
792 | 0 | log_consumers_no = 2; |
793 | | |
794 | | /* even if we are reusing the static default_log_consumers table, |
795 | | * inherit the latest settings for the consumers */ |
796 | 0 | log_consumers[0].level_filter = cons[0].level_filter; |
797 | 0 | log_consumers[0].muted = cons[0].muted; |
798 | |
|
799 | 0 | log_consumers[1].level_filter = cons[1].level_filter; |
800 | 0 | log_consumers[1].muted = cons[1].muted; |
801 | |
|
802 | 0 | shm_free(cons); |
803 | 0 | } |
804 | | |
805 | | int init_log_event_cons(void) |
806 | 0 | { |
807 | 0 | evi_log_id = evi_publish_event(evi_log_name); |
808 | 0 | if (evi_log_id == EVI_ERROR) { |
809 | 0 | LM_ERR("cannot register '%.*s' event\n", |
810 | 0 | evi_log_name.len, evi_log_name.s); |
811 | 0 | return -1; |
812 | 0 | } |
813 | | |
814 | 0 | log_msg_buf = pkg_malloc(log_msg_buf_size+1); |
815 | 0 | if (!log_msg_buf) { |
816 | 0 | LM_ERR("no pkg memory left\n"); |
817 | 0 | return -1; |
818 | 0 | } |
819 | | |
820 | 0 | if (register_log_consumer(EVENT_CONSUMER_NAME, event_dprint, |
821 | 0 | log_event_level_filter, 1) < 0) { |
822 | 0 | LM_ERR("Failed to register 'event' log consumer\n"); |
823 | 0 | return -1; |
824 | 0 | } |
825 | | |
826 | 0 | return 0; |
827 | 0 | } |
828 | | |
829 | | static struct log_consumer_t *get_log_consumer_by_name(str *name) |
830 | 0 | { |
831 | 0 | int i; |
832 | |
|
833 | 0 | for (i=0; i<log_consumers_no; i++) |
834 | 0 | if (str_match(&log_consumers[i].name, name)) |
835 | 0 | return log_consumers+i; |
836 | | |
837 | 0 | return NULL; |
838 | 0 | } |
839 | | |
840 | | int set_log_consumer_level_filter(str *name, int level) |
841 | 0 | { |
842 | 0 | struct log_consumer_t *cons; |
843 | |
|
844 | 0 | cons = get_log_consumer_by_name(name); |
845 | 0 | if (!cons) { |
846 | 0 | LM_ERR("Unknown consumer: %.*s\n", name->len, name->s); |
847 | 0 | return -1; |
848 | 0 | } |
849 | | |
850 | 0 | cons->level_filter = level; |
851 | |
|
852 | 0 | return 0; |
853 | 0 | } |
854 | | |
855 | | int get_log_consumer_level_filter(str *name, int *level_filter) |
856 | 0 | { |
857 | 0 | struct log_consumer_t *cons; |
858 | |
|
859 | 0 | cons = get_log_consumer_by_name(name); |
860 | 0 | if (!cons) { |
861 | 0 | LM_ERR("Unknown consumer: %.*s\n", name->len, name->s); |
862 | 0 | return -1; |
863 | 0 | } |
864 | | |
865 | 0 | *level_filter = cons->level_filter; |
866 | |
|
867 | 0 | return 0; |
868 | 0 | } |
869 | | |
870 | | int set_log_consumer_mute_state(str *name, int state) |
871 | 0 | { |
872 | 0 | struct log_consumer_t *cons; |
873 | |
|
874 | 0 | cons = get_log_consumer_by_name(name); |
875 | 0 | if (!cons) { |
876 | 0 | LM_ERR("Unknown consumer: %.*s\n", name->len, name->s); |
877 | 0 | return -1; |
878 | 0 | } |
879 | | |
880 | 0 | cons->muted = state; |
881 | |
|
882 | 0 | return 0; |
883 | 0 | } |
884 | | |
885 | | int get_log_consumer_mute_state(str *name, int *state) |
886 | 0 | { |
887 | 0 | struct log_consumer_t *cons; |
888 | |
|
889 | 0 | cons = get_log_consumer_by_name(name); |
890 | 0 | if (!cons) { |
891 | 0 | LM_ERR("Unknown consumer: %.*s\n", name->len, name->s); |
892 | 0 | return -1; |
893 | 0 | } |
894 | | |
895 | 0 | *state = cons->muted; |
896 | |
|
897 | 0 | return 0; |
898 | 0 | } |
899 | | |
900 | | int set_log_event_cons_cfg_state(void) |
901 | 0 | { |
902 | 0 | if (set_log_consumer_mute_state(&str_init(EVENT_CONSUMER_NAME), |
903 | 0 | !log_event_enabled) < 0) { |
904 | 0 | LM_ERR("Failed to set mute state for event consumer\n"); |
905 | 0 | return -1; |
906 | 0 | } |
907 | | |
908 | 0 | return 0; |
909 | 0 | } |
910 | | |
911 | | void distroy_log_event_cons(void) |
912 | 0 | { |
913 | 0 | set_log_consumer_mute_state(&str_init(EVENT_CONSUMER_NAME), 1); |
914 | 0 | } |
915 | | |
916 | | int init_log_level(void) |
917 | 0 | { |
918 | 0 | log_level = &pt[process_no].log_level; |
919 | 0 | default_log_level = &pt[process_no].default_log_level; |
920 | |
|
921 | 0 | if (process_no==0) { |
922 | | /* this is done only by the first process */ |
923 | 0 | log_level_global = (int*)shm_malloc(sizeof(int)); |
924 | 0 | if (log_level_global==NULL) { |
925 | 0 | LM_ERR("Failed to allocate shm memory for global log_level\n"); |
926 | 0 | return -1; |
927 | 0 | } |
928 | 0 | *log_level_global = log_level_holder; |
929 | 0 | } |
930 | | |
931 | 0 | *log_level = *log_level_global; |
932 | 0 | *default_log_level = *log_level_global; |
933 | |
|
934 | 0 | return 0; |
935 | 0 | } |
936 | | |
937 | | /* call before pt is freed */ |
938 | | void cleanup_log_level(void) |
939 | 0 | { |
940 | 0 | static int my_log_level; |
941 | |
|
942 | 0 | my_log_level = *log_level; |
943 | 0 | log_level = &my_log_level; |
944 | 0 | } |
945 | | |
946 | | |
947 | | void reset_proc_log_level(void) |
948 | 0 | { |
949 | | /* Before init_log_level() runs - e.g. from a module's mod_init(), which |
950 | | * is invoked well before init_multi_proc_support() - default_log_level |
951 | | * is still NULL, so fall back to the value logging started with. */ |
952 | 0 | if (!default_log_level) { |
953 | 0 | *log_level = log_level_holder; |
954 | 0 | return; |
955 | 0 | } |
956 | | |
957 | 0 | *log_level = *default_log_level; |
958 | 0 | } |
959 | | |
960 | | /* |
961 | | * set the (default) log level of a given process |
962 | | * |
963 | | * Note: the index param is not validated! |
964 | | */ |
965 | | void __set_proc_log_level(int proc_idx, int level) |
966 | 0 | { |
967 | | /* The process table is allocated by init_multi_proc_support(), which runs |
968 | | * after init_modules() - so pt is NULL during every module's mod_init(). |
969 | | * There is only one process at that point and log_level already points at |
970 | | * the static holder, so honour the request instead of crashing. */ |
971 | 0 | if (!pt) { |
972 | 0 | *log_level = level; |
973 | 0 | return; |
974 | 0 | } |
975 | | |
976 | 0 | pt[proc_idx].log_level = level; |
977 | 0 | } |
978 | | |
979 | | void __set_proc_default_log_level(int proc_idx, int level) |
980 | 0 | { |
981 | | /* see __set_proc_log_level() - pt does not exist yet during mod_init() */ |
982 | 0 | if (!pt) { |
983 | 0 | log_level_holder = level; |
984 | 0 | return; |
985 | 0 | } |
986 | | |
987 | 0 | pt[proc_idx].default_log_level = level; |
988 | 0 | } |
989 | | |
990 | | /* set the current and default log levels for all OpenSIPS processes */ |
991 | | void set_global_log_level(int level) |
992 | 0 | { |
993 | 0 | int i; |
994 | |
|
995 | 0 | for (i = 0; i < counted_max_processes; i++) { |
996 | 0 | __set_proc_default_log_level(i, level); |
997 | 0 | __set_proc_log_level(i, level); |
998 | 0 | } |
999 | | |
1000 | | /* allocated by init_log_level(); before that there is nothing shared to |
1001 | | * update, and counted_max_processes is still 0 so the loop above was a |
1002 | | * no-op - apply the level to this process instead */ |
1003 | 0 | if (!log_level_global) { |
1004 | 0 | __set_proc_default_log_level(0, level); |
1005 | 0 | __set_proc_log_level(0, level); |
1006 | 0 | return; |
1007 | 0 | } |
1008 | | |
1009 | 0 | *log_level_global = level; |
1010 | 0 | } |
1011 | | |
1012 | | /* set the log level of the current process */ |
1013 | | void set_proc_log_level(int level) |
1014 | 0 | { |
1015 | 0 | __set_proc_log_level(process_no, level); |
1016 | 0 | } |
1017 | | |
1018 | | void suppress_proc_log_event(void) |
1019 | 0 | { |
1020 | | /* no process table yet (mod_init) - nothing to suppress, and the event |
1021 | | * consumer it guards is not running either */ |
1022 | 0 | if (!pt) |
1023 | 0 | return; |
1024 | | |
1025 | 0 | pt[process_no].suppress_log_event = 1; |
1026 | 0 | } |
1027 | | |
1028 | | void reset_proc_log_event(void) |
1029 | 0 | { |
1030 | 0 | if (!pt) |
1031 | 0 | return; |
1032 | | |
1033 | 0 | pt[process_no].suppress_log_event = 0; |
1034 | 0 | } |