1 /*
2 * This file is part of the zlog Library.
3 *
4 * Copyright (C) 2011 by Hardy Simpson <HardySimpson1984@gmail.com>
5 *
6 * Licensed under the LGPL v2.1, see the file COPYING in base directory.
7 */
8
9 #include "fmacros.h"
10
11 #include <sys/types.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <syslog.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <pthread.h>
21
22 #include "rule.h"
23 #include "format.h"
24 #include "buf.h"
25 #include "thread.h"
26 #include "level_list.h"
27 #include "rotater.h"
28 #include "spec.h"
29 #include "conf.h"
30
31 #include "zc_defs.h"
32
33
zlog_rule_profile(zlog_rule_t * a_rule,int flag)34 void zlog_rule_profile(zlog_rule_t * a_rule, int flag)
35 {
36 int i;
37 zlog_spec_t *a_spec;
38
39 zc_assert(a_rule,);
40 zc_profile(flag, "---rule:[%p][%s%c%d]-[%d,%d][%s,%p,%d:%ld*%d~%s][%d][%d][%s:%s:%p];[%p]---",
41 a_rule,
42
43 a_rule->category,
44 a_rule->compare_char,
45 a_rule->level,
46
47 a_rule->file_perms,
48 a_rule->file_open_flags,
49
50 a_rule->file_path,
51 a_rule->dynamic_specs,
52 a_rule->static_fd,
53
54 a_rule->archive_max_size,
55 a_rule->archive_max_count,
56 a_rule->archive_path,
57
58 a_rule->pipe_fd,
59
60 a_rule->syslog_facility,
61
62 a_rule->record_name,
63 a_rule->record_path,
64 a_rule->record_func,
65 a_rule->format);
66
67 if (a_rule->dynamic_specs) {
68 zc_arraylist_foreach(a_rule->dynamic_specs, i, a_spec) {
69 zlog_spec_profile(a_spec, flag);
70 }
71 }
72 return;
73 }
74
75 /*******************************************************************************/
76
zlog_rule_output_static_file_single(zlog_rule_t * a_rule,zlog_thread_t * a_thread)77 static int zlog_rule_output_static_file_single(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
78 {
79 struct stat stb;
80 int do_file_reload = 0;
81 int redo_inode_stat = 0;
82
83 if (zlog_format_gen_msg(a_rule->format, a_thread)) {
84 zc_error("zlog_format_gen_msg fail");
85 return -1;
86 }
87
88 /* check if the output file was changed by an external tool by comparing the inode to our saved off one */
89 if (stat(a_rule->file_path, &stb)) {
90 if (errno != ENOENT) {
91 zc_error("stat fail on [%s], errno[%d]", a_rule->file_path, errno);
92 return -1;
93 } else {
94 do_file_reload = 1;
95 redo_inode_stat = 1; /* we'll have to restat the newly created file to get the inode info */
96 }
97 } else {
98 do_file_reload = (stb.st_ino != a_rule->static_ino || stb.st_dev != a_rule->static_dev);
99 }
100
101 if (do_file_reload) {
102 close(a_rule->static_fd);
103 a_rule->static_fd = open(a_rule->file_path,
104 O_WRONLY | O_APPEND | O_CREAT | a_rule->file_open_flags,
105 a_rule->file_perms);
106 if (a_rule->static_fd < 0) {
107 zc_error("open file[%s] fail, errno[%d]", a_rule->file_path, errno);
108 return -1;
109 }
110
111 /* save off the new dev/inode info from the stat call we already did */
112 if (redo_inode_stat) {
113 if (stat(a_rule->file_path, &stb)) {
114 zc_error("stat fail on new file[%s], errno[%d]", a_rule->file_path, errno);
115 return -1;
116 }
117 }
118 a_rule->static_dev = stb.st_dev;
119 a_rule->static_ino = stb.st_ino;
120 }
121
122 if (write(a_rule->static_fd,
123 zlog_buf_str(a_thread->msg_buf),
124 zlog_buf_len(a_thread->msg_buf)) < 0) {
125 zc_error("write fail, errno[%d]", errno);
126 return -1;
127 }
128
129 /* not so thread safe here, as multiple thread may ++fsync_count at the same time */
130 if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) {
131 a_rule->fsync_count = 0;
132 if (fsync(a_rule->static_fd)) {
133 zc_error("fsync[%d] fail, errno[%d]", a_rule->static_fd, errno);
134 }
135 }
136
137 return 0;
138 }
139
zlog_rule_gen_archive_path(zlog_rule_t * a_rule,zlog_thread_t * a_thread)140 static char * zlog_rule_gen_archive_path(zlog_rule_t *a_rule, zlog_thread_t *a_thread)
141 {
142 int i;
143 zlog_spec_t *a_spec;
144
145 if (!a_rule->archive_specs) return a_rule->archive_path;
146
147 zlog_buf_restart(a_thread->archive_path_buf);
148
149 zc_arraylist_foreach(a_rule->archive_specs, i, a_spec) {
150 if (zlog_spec_gen_archive_path(a_spec, a_thread)) {
151 zc_error("zlog_spec_gen_path fail");
152 return NULL;
153 }
154 }
155
156 zlog_buf_seal(a_thread->archive_path_buf);
157 return zlog_buf_str(a_thread->archive_path_buf);
158 }
159
zlog_rule_output_static_file_rotate(zlog_rule_t * a_rule,zlog_thread_t * a_thread)160 static int zlog_rule_output_static_file_rotate(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
161 {
162 size_t len;
163 struct zlog_stat info;
164 int fd;
165
166 if (zlog_format_gen_msg(a_rule->format, a_thread)) {
167 zc_error("zlog_format_gen_msg fail");
168 return -1;
169 }
170
171 fd = open(a_rule->file_path,
172 a_rule->file_open_flags | O_WRONLY | O_APPEND | O_CREAT, a_rule->file_perms);
173 if (fd < 0) {
174 zc_error("open file[%s] fail, errno[%d]", a_rule->file_path, errno);
175 return -1;
176 }
177
178 len = zlog_buf_len(a_thread->msg_buf);
179 if (write(fd, zlog_buf_str(a_thread->msg_buf), len) < 0) {
180 zc_error("write fail, errno[%d]", errno);
181 close(fd);
182 return -1;
183 }
184
185 if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) {
186 a_rule->fsync_count = 0;
187 if (fsync(fd)) zc_error("fsync[%d] fail, errno[%d]", fd, errno);
188 }
189
190 if (close(fd) < 0) {
191 zc_error("close fail, maybe cause by write, errno[%d]", errno);
192 return -1;
193 }
194
195 if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) {
196 a_rule->fsync_count = 0;
197 if (fsync(a_rule->static_fd)) {
198 zc_error("fsync[%d] fail, errno[%d]", a_rule->static_fd, errno);
199 }
200 }
201
202 if (len > a_rule->archive_max_size) {
203 zc_debug("one msg's len[%ld] > archive_max_size[%ld], no rotate",
204 (long)len, (long)a_rule->archive_max_size);
205 return 0;
206 }
207
208 if (stat(a_rule->file_path, &info)) {
209 zc_warn("stat [%s] fail, errno[%d], maybe in rotating", a_rule->file_path, errno);
210 return 0;
211 }
212
213 /* file not so big, return */
214 if (info.st_size + len < a_rule->archive_max_size) return 0;
215
216 if (zlog_rotater_rotate(zlog_env_conf->rotater,
217 a_rule->file_path, len,
218 zlog_rule_gen_archive_path(a_rule, a_thread),
219 a_rule->archive_max_size, a_rule->archive_max_count)
220 ) {
221 zc_error("zlog_rotater_rotate fail");
222 return -1;
223 } /* success or no rotation do nothing */
224
225 return 0;
226 }
227
228 /* return path success
229 * return NULL fail
230 */
231 #define zlog_rule_gen_path(a_rule, a_thread) do { \
232 int i; \
233 zlog_spec_t *a_spec; \
234 \
235 zlog_buf_restart(a_thread->path_buf); \
236 \
237 zc_arraylist_foreach(a_rule->dynamic_specs, i, a_spec) { \
238 if (zlog_spec_gen_path(a_spec, a_thread)) { \
239 zc_error("zlog_spec_gen_path fail"); \
240 return -1; \
241 } \
242 } \
243 \
244 zlog_buf_seal(a_thread->path_buf); \
245 } while(0)
246
247
zlog_rule_output_dynamic_file_single(zlog_rule_t * a_rule,zlog_thread_t * a_thread)248 static int zlog_rule_output_dynamic_file_single(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
249 {
250 int fd;
251
252 zlog_rule_gen_path(a_rule, a_thread);
253
254 if (zlog_format_gen_msg(a_rule->format, a_thread)) {
255 zc_error("zlog_format_output fail");
256 return -1;
257 }
258
259 fd = open(zlog_buf_str(a_thread->path_buf),
260 a_rule->file_open_flags | O_WRONLY | O_APPEND | O_CREAT, a_rule->file_perms);
261 if (fd < 0) {
262 zc_error("open file[%s] fail, errno[%d]", zlog_buf_str(a_thread->path_buf), errno);
263 return -1;
264 }
265
266 if (write(fd, zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) {
267 zc_error("write fail, errno[%d]", errno);
268 close(fd);
269 return -1;
270 }
271
272 if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) {
273 a_rule->fsync_count = 0;
274 if (fsync(fd)) zc_error("fsync[%d] fail, errno[%d]", fd, errno);
275 }
276
277 if (close(fd) < 0) {
278 zc_error("close fail, maybe cause by write, errno[%d]", errno);
279 return -1;
280 }
281
282 return 0;
283 }
284
zlog_rule_output_dynamic_file_rotate(zlog_rule_t * a_rule,zlog_thread_t * a_thread)285 static int zlog_rule_output_dynamic_file_rotate(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
286 {
287 int fd;
288 char *path;
289 size_t len;
290 struct zlog_stat info;
291
292 zlog_rule_gen_path(a_rule, a_thread);
293
294 if (zlog_format_gen_msg(a_rule->format, a_thread)) {
295 zc_error("zlog_format_output fail");
296 return -1;
297 }
298
299 path = zlog_buf_str(a_thread->path_buf);
300 fd = open(path, a_rule->file_open_flags | O_WRONLY | O_APPEND | O_CREAT, a_rule->file_perms);
301 if (fd < 0) {
302 zc_error("open file[%s] fail, errno[%d]", zlog_buf_str(a_thread->path_buf), errno);
303 return -1;
304 }
305
306 len = zlog_buf_len(a_thread->msg_buf);
307 if (write(fd, zlog_buf_str(a_thread->msg_buf), len) < 0) {
308 zc_error("write fail, errno[%d]", errno);
309 close(fd);
310 return -1;
311 }
312
313 if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) {
314 a_rule->fsync_count = 0;
315 if (fsync(fd)) zc_error("fsync[%d] fail, errno[%d]", fd, errno);
316 }
317
318 if (close(fd) < 0) {
319 zc_error("write fail, maybe cause by write, errno[%d]", errno);
320 return -1;
321 }
322
323 if (len > a_rule->archive_max_size) {
324 zc_debug("one msg's len[%ld] > archive_max_size[%ld], no rotate",
325 (long)len, (long) a_rule->archive_max_size);
326 return 0;
327 }
328
329 if (stat(path, &info)) {
330 zc_warn("stat [%s] fail, errno[%d], maybe in rotating", path, errno);
331 return 0;
332 }
333
334 /* file not so big, return */
335 if (info.st_size + len < a_rule->archive_max_size) return 0;
336
337 if (zlog_rotater_rotate(zlog_env_conf->rotater,
338 path, len,
339 zlog_rule_gen_archive_path(a_rule, a_thread),
340 a_rule->archive_max_size, a_rule->archive_max_count)
341 ) {
342 zc_error("zlog_rotater_rotate fail");
343 return -1;
344 } /* success or no rotation do nothing */
345
346 return 0;
347 }
348
zlog_rule_output_pipe(zlog_rule_t * a_rule,zlog_thread_t * a_thread)349 static int zlog_rule_output_pipe(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
350 {
351 if (zlog_format_gen_msg(a_rule->format, a_thread)) {
352 zc_error("zlog_format_gen_msg fail");
353 return -1;
354 }
355
356 if (write(a_rule->pipe_fd,
357 zlog_buf_str(a_thread->msg_buf),
358 zlog_buf_len(a_thread->msg_buf)) < 0) {
359 zc_error("write fail, errno[%d]", errno);
360 return -1;
361 }
362
363 return 0;
364 }
365
zlog_rule_output_syslog(zlog_rule_t * a_rule,zlog_thread_t * a_thread)366 static int zlog_rule_output_syslog(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
367 {
368 zlog_level_t *a_level;
369
370 if (zlog_format_gen_msg(a_rule->format, a_thread)) {
371 zc_error("zlog_format_gen_msg fail");
372 return -1;
373 }
374
375 /*
376 msg = a_thread->msg_buf->start;
377 msg_len = a_thread->msg_buf->end - a_thread->msg_buf->start;
378 */
379
380 a_level = zlog_level_list_get(zlog_env_conf->levels, a_thread->event->level);
381 zlog_buf_seal(a_thread->msg_buf);
382 syslog(a_rule->syslog_facility | a_level->syslog_level,
383 "%s", zlog_buf_str(a_thread->msg_buf));
384 return 0;
385 }
386
zlog_rule_output_static_record(zlog_rule_t * a_rule,zlog_thread_t * a_thread)387 static int zlog_rule_output_static_record(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
388 {
389 zlog_msg_t msg;
390
391 if (!a_rule->record_func) {
392 zc_error("user defined record funcion for [%s] not set, no output",
393 a_rule->record_name);
394 return -1;
395 }
396
397 if (zlog_format_gen_msg(a_rule->format, a_thread)) {
398 zc_error("zlog_format_gen_msg fail");
399 return -1;
400 }
401 zlog_buf_seal(a_thread->msg_buf);
402
403 msg.buf = zlog_buf_str(a_thread->msg_buf);
404 msg.len = zlog_buf_len(a_thread->msg_buf);
405 msg.path = a_rule->record_path;
406
407 if (a_rule->record_func(&msg)) {
408 zc_error("a_rule->record fail");
409 return -1;
410 }
411 return 0;
412 }
413
zlog_rule_output_dynamic_record(zlog_rule_t * a_rule,zlog_thread_t * a_thread)414 static int zlog_rule_output_dynamic_record(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
415 {
416 zlog_msg_t msg;
417
418 if (!a_rule->record_func) {
419 zc_error("user defined record funcion for [%s] not set, no output",
420 a_rule->record_name);
421 return -1;
422 }
423
424 zlog_rule_gen_path(a_rule, a_thread);
425
426 if (zlog_format_gen_msg(a_rule->format, a_thread)) {
427 zc_error("zlog_format_gen_msg fail");
428 return -1;
429 }
430 zlog_buf_seal(a_thread->msg_buf);
431
432 msg.buf = zlog_buf_str(a_thread->msg_buf);
433 msg.len = zlog_buf_len(a_thread->msg_buf);
434 msg.path = zlog_buf_str(a_thread->path_buf);
435
436 if (a_rule->record_func(&msg)) {
437 zc_error("a_rule->record fail");
438 return -1;
439 }
440 return 0;
441 }
442
zlog_rule_output_stdout(zlog_rule_t * a_rule,zlog_thread_t * a_thread)443 static int zlog_rule_output_stdout(zlog_rule_t * a_rule,
444 zlog_thread_t * a_thread)
445 {
446
447 if (zlog_format_gen_msg(a_rule->format, a_thread)) {
448 zc_error("zlog_format_gen_msg fail");
449 return -1;
450 }
451
452 if (write(STDOUT_FILENO,
453 zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) {
454 zc_error("write fail, errno[%d]", errno);
455 return -1;
456 }
457
458 return 0;
459 }
460
zlog_rule_output_stderr(zlog_rule_t * a_rule,zlog_thread_t * a_thread)461 static int zlog_rule_output_stderr(zlog_rule_t * a_rule,
462 zlog_thread_t * a_thread)
463 {
464
465 if (zlog_format_gen_msg(a_rule->format, a_thread)) {
466 zc_error("zlog_format_gen_msg fail");
467 return -1;
468 }
469
470 if (write(STDERR_FILENO,
471 zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) {
472 zc_error("write fail, errno[%d]", errno);
473 return -1;
474 }
475
476 return 0;
477 }
478 /*******************************************************************************/
syslog_facility_atoi(char * facility)479 static int syslog_facility_atoi(char *facility)
480 {
481 /* guess no unix system will choose -187
482 * as its syslog facility, so it is a safe return value
483 */
484 zc_assert(facility, -187);
485
486 if (STRICMP(facility, ==, "LOG_LOCAL0")) return LOG_LOCAL0;
487 if (STRICMP(facility, ==, "LOG_LOCAL1")) return LOG_LOCAL1;
488 if (STRICMP(facility, ==, "LOG_LOCAL2")) return LOG_LOCAL2;
489 if (STRICMP(facility, ==, "LOG_LOCAL3")) return LOG_LOCAL3;
490 if (STRICMP(facility, ==, "LOG_LOCAL4")) return LOG_LOCAL4;
491 if (STRICMP(facility, ==, "LOG_LOCAL5")) return LOG_LOCAL5;
492 if (STRICMP(facility, ==, "LOG_LOCAL6")) return LOG_LOCAL6;
493 if (STRICMP(facility, ==, "LOG_LOCAL7")) return LOG_LOCAL7;
494 if (STRICMP(facility, ==, "LOG_USER")) return LOG_USER;
495 if (STRICMP(facility, ==, "LOG_AUTHPRIV")) return LOG_AUTHPRIV;
496 if (STRICMP(facility, ==, "LOG_CRON")) return LOG_CRON;
497 if (STRICMP(facility, ==, "LOG_DAEMON")) return LOG_DAEMON;
498 if (STRICMP(facility, ==, "LOG_FTP")) return LOG_FTP;
499 if (STRICMP(facility, ==, "LOG_KERN")) return LOG_KERN;
500 if (STRICMP(facility, ==, "LOG_LPR")) return LOG_LPR;
501 if (STRICMP(facility, ==, "LOG_MAIL")) return LOG_MAIL;
502 if (STRICMP(facility, ==, "LOG_NEWS")) return LOG_NEWS;
503 if (STRICMP(facility, ==, "LOG_SYSLOG")) return LOG_SYSLOG;
504 return LOG_AUTHPRIV;
505
506 zc_error("wrong syslog facility[%s], must in LOG_LOCAL[0-7] or LOG_USER", facility);
507 return -187;
508 }
509
zlog_rule_parse_path(char * path_start,char * path_str,size_t path_size,zc_arraylist_t ** path_specs,int * time_cache_count)510 static int zlog_rule_parse_path(char *path_start, /* start with a " */
511 char *path_str, size_t path_size, zc_arraylist_t **path_specs,
512 int *time_cache_count)
513 {
514 char *p, *q;
515 size_t len;
516 zlog_spec_t *a_spec;
517 zc_arraylist_t *specs;
518
519 p = path_start + 1;
520
521 q = strrchr(p, '"');
522 if (!q) {
523 zc_error("matching \" not found in conf line[%s]", path_start);
524 return -1;
525 }
526 len = q - p;
527 if (len > path_size - 1) {
528 zc_error("file_path too long %ld > %ld", len, path_size - 1);
529 return -1;
530 }
531 memcpy(path_str, p, len);
532
533 /* replace any environment variables like %E(HOME) */
534 if (zc_str_replace_env(path_str, path_size)) {
535 zc_error("zc_str_replace_env fail");
536 return -1;
537 }
538
539 if (strchr(path_str, '%') == NULL) {
540 /* static, no need create specs */
541 return 0;
542 }
543
544 specs = zc_arraylist_new((zc_arraylist_del_fn)zlog_spec_del);
545 if (!path_specs) {
546 zc_error("zc_arraylist_new fail");
547 return -1;
548 }
549
550 for (p = path_str; *p != '\0'; p = q) {
551 a_spec = zlog_spec_new(p, &q, time_cache_count);
552 if (!a_spec) {
553 zc_error("zlog_spec_new fail");
554 goto err;
555 }
556
557 if (zc_arraylist_add(specs, a_spec)) {
558 zc_error("zc_arraylist_add fail");
559 goto err;
560 }
561 }
562
563 *path_specs = specs;
564 return 0;
565 err:
566 if (specs) zc_arraylist_del(specs);
567 if (a_spec) zlog_spec_del(a_spec);
568 return -1;
569 }
570
zlog_rule_new(char * line,zc_arraylist_t * levels,zlog_format_t * default_format,zc_arraylist_t * formats,unsigned int file_perms,size_t fsync_period,int * time_cache_count)571 zlog_rule_t *zlog_rule_new(char *line,
572 zc_arraylist_t *levels,
573 zlog_format_t * default_format,
574 zc_arraylist_t * formats,
575 unsigned int file_perms,
576 size_t fsync_period,
577 int * time_cache_count)
578 {
579 int rc = 0;
580 int nscan = 0;
581 int nread = 0;
582 zlog_rule_t *a_rule;
583
584 char selector[MAXLEN_CFG_LINE + 1];
585 char category[MAXLEN_CFG_LINE + 1];
586 char level[MAXLEN_CFG_LINE + 1];
587
588 char *action;
589 char output[MAXLEN_CFG_LINE + 1];
590 char format_name[MAXLEN_CFG_LINE + 1];
591 char file_path[MAXLEN_CFG_LINE + 1];
592 char archive_max_size[MAXLEN_CFG_LINE + 1];
593 char *file_limit;
594
595 char *p;
596 char *q;
597 size_t len;
598
599 zc_assert(line, NULL);
600 zc_assert(default_format, NULL);
601 zc_assert(formats, NULL);
602
603 a_rule = calloc(1, sizeof(zlog_rule_t));
604 if (!a_rule) {
605 zc_error("calloc fail, errno[%d]", errno);
606 return NULL;
607 }
608
609 a_rule->file_perms = file_perms;
610 a_rule->fsync_period = fsync_period;
611
612 /* line [f.INFO "%H/log/aa.log", 20MB * 12; MyTemplate]
613 * selector [f.INFO]
614 * *action ["%H/log/aa.log", 20MB * 12; MyTemplate]
615 */
616 memset(&selector, 0x00, sizeof(selector));
617 nscan = sscanf(line, "%s %n", selector, &nread);
618 if (nscan != 1) {
619 zc_error("sscanf [%s] fail, selector", line);
620 goto err;
621 }
622 action = line + nread;
623
624 /*
625 * selector [f.INFO]
626 * category [f]
627 * level [.INFO]
628 */
629 memset(category, 0x00, sizeof(category));
630 memset(level, 0x00, sizeof(level));
631 nscan = sscanf(selector, " %[^.].%s", category, level);
632 if (nscan != 2) {
633 zc_error("sscanf [%s] fail, category or level is null",
634 selector);
635 goto err;
636 }
637
638
639 /* check and set category */
640 for (p = category; *p != '\0'; p++) {
641 if ((!isalnum(*p)) && (*p != '_') && (*p != '*') && (*p != '!')) {
642 zc_error("category name[%s] character is not in [a-Z][0-9][_!*]",
643 category);
644 goto err;
645 }
646 }
647
648 /* as one line can't be longer than MAXLEN_CFG_LINE, same as category */
649 strcpy(a_rule->category, category);
650
651 /* check and set level */
652 switch (level[0]) {
653 case '=':
654 /* aa.=debug */
655 a_rule->compare_char = '=';
656 p = level + 1;
657 break;
658 case '!':
659 /* aa.!debug */
660 a_rule->compare_char = '!';
661 p = level + 1;
662 break;
663 case '*':
664 /* aa.* */
665 a_rule->compare_char = '*';
666 p = level;
667 break;
668 default:
669 /* aa.debug */
670 a_rule->compare_char = '.';
671 p = level;
672 break;
673 }
674
675 a_rule->level = zlog_level_list_atoi(levels, p);
676
677 /* level_bit is a bitmap represents which level can be output
678 * 32bytes, [0-255] levels, see level.c
679 * which bit field is 1 means allow output and 0 not
680 */
681 switch (a_rule->compare_char) {
682 case '=':
683 memset(a_rule->level_bitmap, 0x00, sizeof(a_rule->level_bitmap));
684 a_rule->level_bitmap[a_rule->level / 8] |= (1 << (7 - a_rule->level % 8));
685 break;
686 case '!':
687 memset(a_rule->level_bitmap, 0xFF, sizeof(a_rule->level_bitmap));
688 a_rule->level_bitmap[a_rule->level / 8] &= ~(1 << (7 - a_rule->level % 8));
689 break;
690 case '*':
691 memset(a_rule->level_bitmap, 0xFF, sizeof(a_rule->level_bitmap));
692 break;
693 case '.':
694 memset(a_rule->level_bitmap, 0x00, sizeof(a_rule->level_bitmap));
695 a_rule->level_bitmap[a_rule->level / 8] |= ~(0xFF << (8 - a_rule->level % 8));
696 memset(a_rule->level_bitmap + a_rule->level / 8 + 1, 0xFF,
697 sizeof(a_rule->level_bitmap) - a_rule->level / 8 - 1);
698 break;
699 }
700
701 /* action ["%H/log/aa.log", 20MB * 12 ; MyTemplate]
702 * output ["%H/log/aa.log", 20MB * 12]
703 * format [MyTemplate]
704 */
705 memset(output, 0x00, sizeof(output));
706 memset(format_name, 0x00, sizeof(format_name));
707 nscan = sscanf(action, " %[^;];%s", output, format_name);
708 if (nscan < 1) {
709 zc_error("sscanf [%s] fail", action);
710 goto err;
711 }
712
713 /* check and get format */
714 if (STRCMP(format_name, ==, "")) {
715 zc_debug("no format specified, use default");
716 a_rule->format = default_format;
717 } else {
718 int i;
719 int find_flag = 0;
720 zlog_format_t *a_format;
721
722 zc_arraylist_foreach(formats, i, a_format) {
723 if (zlog_format_has_name(a_format, format_name)) {
724 a_rule->format = a_format;
725 find_flag = 1;
726 break;
727 }
728 }
729 if (!find_flag) {
730 zc_error("in conf file can't find format[%s], pls check",
731 format_name);
732 goto err;
733 }
734 }
735
736 /* output [-"%E(HOME)/log/aa.log" , 20MB*12] [>syslog , LOG_LOCAL0 ]
737 * file_path [-"%E(HOME)/log/aa.log" ] [>syslog ]
738 * *file_limit [20MB * 12 ~ "aa.#i.log" ] [LOG_LOCAL0]
739 */
740 memset(file_path, 0x00, sizeof(file_path));
741 nscan = sscanf(output, " %[^,],", file_path);
742 if (nscan < 1) {
743 zc_error("sscanf [%s] fail", action);
744 goto err;
745 }
746
747 file_limit = strchr(output, ',');
748 if (file_limit) {
749 file_limit++; /* skip the , */
750 while( isspace(*file_limit) ) {
751 file_limit++;
752 }
753 }
754
755 p = NULL;
756 switch (file_path[0]) {
757 case '-' :
758 /* sync file each time write log */
759 if (file_path[1] != '"') {
760 zc_error(" - must set before a file output");
761 goto err;
762 }
763
764 /* no need to fsync, as file is opened by O_SYNC, write immediately */
765 a_rule->fsync_period = 0;
766
767 p = file_path + 1;
768 a_rule->file_open_flags = O_SYNC;
769 /* fall through */
770 case '"' :
771 if (!p) p = file_path;
772
773 rc = zlog_rule_parse_path(p, a_rule->file_path, sizeof(a_rule->file_path),
774 &(a_rule->dynamic_specs), time_cache_count);
775 if (rc) {
776 zc_error("zlog_rule_parse_path fail");
777 goto err;
778 }
779
780 if (file_limit) {
781 memset(archive_max_size, 0x00, sizeof(archive_max_size));
782 nscan = sscanf(file_limit, " %[0-9MmKkBb] * %d ~",
783 archive_max_size, &(a_rule->archive_max_count));
784 if (nscan) {
785 a_rule->archive_max_size = zc_parse_byte_size(archive_max_size);
786 }
787 p = strchr(file_limit, '"');
788 if (p) { /* archive file path exist */
789 rc = zlog_rule_parse_path(p,
790 a_rule->archive_path, sizeof(a_rule->file_path),
791 &(a_rule->archive_specs), time_cache_count);
792 if (rc) {
793 zc_error("zlog_rule_parse_path fail");
794 goto err;
795 }
796
797 p = strchr(a_rule->archive_path, '#');
798 if ( (p == NULL) && (
799 (strchr(p, 'r') == NULL) || (strchr(p, 's') == NULL)
800 )
801 ) {
802 zc_error("archive_path must contain #r or #s");
803 goto err;
804 }
805 }
806 }
807
808 /* try to figure out if the log file path is dynamic or static */
809 if (a_rule->dynamic_specs) {
810 if (a_rule->archive_max_size <= 0) {
811 a_rule->output = zlog_rule_output_dynamic_file_single;
812 } else {
813 a_rule->output = zlog_rule_output_dynamic_file_rotate;
814 }
815 } else {
816 struct stat stb;
817
818 if (a_rule->archive_max_size <= 0) {
819 a_rule->output = zlog_rule_output_static_file_single;
820 } else {
821 /* as rotate, so need to reopen everytime */
822 a_rule->output = zlog_rule_output_static_file_rotate;
823 }
824
825 a_rule->static_fd = open(a_rule->file_path,
826 O_WRONLY | O_APPEND | O_CREAT | a_rule->file_open_flags,
827 a_rule->file_perms);
828 if (a_rule->static_fd < 0) {
829 zc_error("open file[%s] fail, errno[%d]", a_rule->file_path, errno);
830 goto err;
831 }
832
833 /* save off the inode information for checking for a changed file later on */
834 if (fstat(a_rule->static_fd, &stb)) {
835 zc_error("stat [%s] fail, errno[%d], failing to open static_fd", a_rule->file_path, errno);
836 goto err;
837 }
838 a_rule->static_dev = stb.st_dev;
839 a_rule->static_ino = stb.st_ino;
840 }
841 break;
842 case '|' :
843 a_rule->pipe_fp = popen(output + 1, "w");
844 if (!a_rule->pipe_fp) {
845 zc_error("popen fail, errno[%d]", errno);
846 goto err;
847 }
848 a_rule->pipe_fd = fileno(a_rule->pipe_fp);
849 if (a_rule->pipe_fd < 0 ) {
850 zc_error("fileno fail, errno[%d]", errno);
851 goto err;
852 }
853 a_rule->output = zlog_rule_output_pipe;
854 break;
855 case '>' :
856 if (STRNCMP(file_path + 1, ==, "syslog", 6)) {
857 a_rule->syslog_facility = syslog_facility_atoi(file_limit);
858 if (a_rule->syslog_facility == -187) {
859 zc_error("-187 get");
860 goto err;
861 }
862 a_rule->output = zlog_rule_output_syslog;
863 openlog(NULL, LOG_NDELAY | LOG_NOWAIT | LOG_PID, LOG_USER);
864 } else if (STRNCMP(file_path + 1, ==, "stdout", 6)) {
865 a_rule->output = zlog_rule_output_stdout;
866 } else if (STRNCMP(file_path + 1, ==, "stderr", 6)) {
867 a_rule->output = zlog_rule_output_stderr;
868 } else {
869 zc_error
870 ("[%s]the string after is not syslog, stdout or stderr", output);
871 goto err;
872 }
873 break;
874 case '$' :
875 sscanf(file_path + 1, "%s", a_rule->record_name);
876
877 if (file_limit) { /* record path exists */
878 p = strchr(file_limit, '"');
879 if (!p) {
880 zc_error("record_path not start with \", [%s]", file_limit);
881 goto err;
882 }
883 p++; /* skip 1st " */
884
885 q = strrchr(p, '"');
886 if (!q) {
887 zc_error("matching \" not found in conf line[%s]", p);
888 goto err;
889 }
890 len = q - p;
891 if (len > sizeof(a_rule->record_path) - 1) {
892 zc_error("record_path too long %ld > %ld", len, sizeof(a_rule->record_path) - 1);
893 goto err;
894 }
895 memcpy(a_rule->record_path, p, len);
896 }
897
898 /* replace any environment variables like %E(HOME) */
899 rc = zc_str_replace_env(a_rule->record_path, sizeof(a_rule->record_path));
900 if (rc) {
901 zc_error("zc_str_replace_env fail");
902 goto err;
903 }
904
905 /* try to figure out if the log file path is dynamic or static */
906 if (strchr(a_rule->record_path, '%') == NULL) {
907 a_rule->output = zlog_rule_output_static_record;
908 } else {
909 zlog_spec_t *a_spec;
910
911 a_rule->output = zlog_rule_output_dynamic_record;
912
913 a_rule->dynamic_specs = zc_arraylist_new((zc_arraylist_del_fn)zlog_spec_del);
914 if (!(a_rule->dynamic_specs)) {
915 zc_error("zc_arraylist_new fail");
916 goto err;
917 }
918 for (p = a_rule->record_path; *p != '\0'; p = q) {
919 a_spec = zlog_spec_new(p, &q, time_cache_count);
920 if (!a_spec) {
921 zc_error("zlog_spec_new fail");
922 goto err;
923 }
924
925 rc = zc_arraylist_add(a_rule->dynamic_specs, a_spec);
926 if (rc) {
927 zlog_spec_del(a_spec);
928 zc_error("zc_arraylist_add fail");
929 goto err;
930 }
931 }
932 }
933 break;
934 default :
935 zc_error("the 1st char[%c] of file_path[%s] is wrong",
936 file_path[0], file_path);
937 goto err;
938 }
939
940 //zlog_rule_profile(a_rule, ZC_DEBUG);
941 return a_rule;
942 err:
943 zlog_rule_del(a_rule);
944 return NULL;
945 }
946
zlog_rule_del(zlog_rule_t * a_rule)947 void zlog_rule_del(zlog_rule_t * a_rule)
948 {
949 zc_assert(a_rule,);
950 if (a_rule->dynamic_specs) {
951 zc_arraylist_del(a_rule->dynamic_specs);
952 a_rule->dynamic_specs = NULL;
953 }
954 if (a_rule->static_fd) {
955 if (close(a_rule->static_fd)) {
956 zc_error("close fail, maybe cause by write, errno[%d]", errno);
957 }
958 }
959 if (a_rule->pipe_fp) {
960 if (pclose(a_rule->pipe_fp) == -1) {
961 zc_error("pclose fail, errno[%d]", errno);
962 }
963 }
964 if (a_rule->archive_specs) {
965 zc_arraylist_del(a_rule->archive_specs);
966 a_rule->archive_specs = NULL;
967 }
968 free(a_rule);
969 zc_debug("zlog_rule_del[%p]", a_rule);
970 return;
971 }
972
973 /*******************************************************************************/
zlog_rule_output(zlog_rule_t * a_rule,zlog_thread_t * a_thread)974 int zlog_rule_output(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
975 {
976 switch (a_rule->compare_char) {
977 case '*' :
978 return a_rule->output(a_rule, a_thread);
979 break;
980 case '.' :
981 if (a_thread->event->level >= a_rule->level) {
982 return a_rule->output(a_rule, a_thread);
983 } else {
984 return 0;
985 }
986 break;
987 case '=' :
988 if (a_thread->event->level == a_rule->level) {
989 return a_rule->output(a_rule, a_thread);
990 } else {
991 return 0;
992 }
993 break;
994 case '!' :
995 if (a_thread->event->level != a_rule->level) {
996 return a_rule->output(a_rule, a_thread);
997 } else {
998 return 0;
999 }
1000 break;
1001 }
1002
1003 return 0;
1004 }
1005
1006 /*******************************************************************************/
zlog_rule_is_wastebin(zlog_rule_t * a_rule)1007 int zlog_rule_is_wastebin(zlog_rule_t * a_rule)
1008 {
1009 zc_assert(a_rule, -1);
1010
1011 if (STRCMP(a_rule->category, ==, "!")) {
1012 return 1;
1013 }
1014
1015 return 0;
1016 }
1017
1018 /*******************************************************************************/
zlog_rule_match_category(zlog_rule_t * a_rule,char * category)1019 int zlog_rule_match_category(zlog_rule_t * a_rule, char *category)
1020 {
1021 zc_assert(a_rule, -1);
1022 zc_assert(category, -1);
1023
1024 if (STRCMP(a_rule->category, ==, "*")) {
1025 /* '*' match anything, so go on */
1026 return 1;
1027 } else if (STRCMP(a_rule->category, ==, category)) {
1028 /* accurate compare */
1029 return 1;
1030 } else {
1031 /* aa_ match aa_xx & aa, but not match aa1_xx */
1032 size_t len;
1033 len = strlen(a_rule->category);
1034
1035 if (a_rule->category[len - 1] == '_') {
1036 if (strlen(category) == len - 1) {
1037 len--;
1038 }
1039
1040 if (STRNCMP(a_rule->category, ==, category, len)) {
1041 return 1;
1042 }
1043 }
1044 }
1045
1046 return 0;
1047 }
1048
1049 /*******************************************************************************/
1050
zlog_rule_set_record(zlog_rule_t * a_rule,zc_hashtable_t * records)1051 int zlog_rule_set_record(zlog_rule_t * a_rule, zc_hashtable_t *records)
1052 {
1053 zlog_record_t *a_record;
1054
1055 if (a_rule->output != zlog_rule_output_static_record
1056 && a_rule->output != zlog_rule_output_dynamic_record) {
1057 return 0; /* fliter, may go through not record rule */
1058 }
1059
1060 a_record = zc_hashtable_get(records, a_rule->record_name);
1061 if (a_record) {
1062 a_rule->record_func = a_record->output;
1063 }
1064 return 0;
1065 }
1066