/* * This file is part of the zlog Library. * * Copyright (C) 2011 by Hardy Simpson * * Licensed under the LGPL v2.1, see the file COPYING in base directory. */ #include "fmacros.h" #include #include #include #include #include #include #include #include #include #include #include "rule.h" #include "format.h" #include "buf.h" #include "thread.h" #include "level_list.h" #include "rotater.h" #include "spec.h" #include "conf.h" #include "zc_defs.h" void zlog_rule_profile(zlog_rule_t * a_rule, int flag) { int i; zlog_spec_t *a_spec; zc_assert(a_rule,); zc_profile(flag, "---rule:[%p][%s%c%d]-[%d,%d][%s,%p,%d:%ld*%d~%s][%d][%d][%s:%s:%p];[%p]---", a_rule, a_rule->category, a_rule->compare_char, a_rule->level, a_rule->file_perms, a_rule->file_open_flags, a_rule->file_path, a_rule->dynamic_specs, a_rule->static_fd, a_rule->archive_max_size, a_rule->archive_max_count, a_rule->archive_path, a_rule->pipe_fd, a_rule->syslog_facility, a_rule->record_name, a_rule->record_path, a_rule->record_func, a_rule->format); if (a_rule->dynamic_specs) { zc_arraylist_foreach(a_rule->dynamic_specs, i, a_spec) { zlog_spec_profile(a_spec, flag); } } return; } /*******************************************************************************/ static int zlog_rule_output_static_file_single(zlog_rule_t * a_rule, zlog_thread_t * a_thread) { struct stat stb; int do_file_reload = 0; int redo_inode_stat = 0; if (zlog_format_gen_msg(a_rule->format, a_thread)) { zc_error("zlog_format_gen_msg fail"); return -1; } /* check if the output file was changed by an external tool by comparing the inode to our saved off one */ if (stat(a_rule->file_path, &stb)) { if (errno != ENOENT) { zc_error("stat fail on [%s], errno[%d]", a_rule->file_path, errno); return -1; } else { do_file_reload = 1; redo_inode_stat = 1; /* we'll have to restat the newly created file to get the inode info */ } } else { do_file_reload = (stb.st_ino != a_rule->static_ino || stb.st_dev != a_rule->static_dev); } if (do_file_reload) { close(a_rule->static_fd); a_rule->static_fd = open(a_rule->file_path, O_WRONLY | O_APPEND | O_CREAT | a_rule->file_open_flags, a_rule->file_perms); if (a_rule->static_fd < 0) { zc_error("open file[%s] fail, errno[%d]", a_rule->file_path, errno); return -1; } /* save off the new dev/inode info from the stat call we already did */ if (redo_inode_stat) { if (stat(a_rule->file_path, &stb)) { zc_error("stat fail on new file[%s], errno[%d]", a_rule->file_path, errno); return -1; } } a_rule->static_dev = stb.st_dev; a_rule->static_ino = stb.st_ino; } if (write(a_rule->static_fd, zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) { zc_error("write fail, errno[%d]", errno); return -1; } /* not so thread safe here, as multiple thread may ++fsync_count at the same time */ if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) { a_rule->fsync_count = 0; if (fsync(a_rule->static_fd)) { zc_error("fsync[%d] fail, errno[%d]", a_rule->static_fd, errno); } } return 0; } static char * zlog_rule_gen_archive_path(zlog_rule_t *a_rule, zlog_thread_t *a_thread) { int i; zlog_spec_t *a_spec; if (!a_rule->archive_specs) return a_rule->archive_path; zlog_buf_restart(a_thread->archive_path_buf); zc_arraylist_foreach(a_rule->archive_specs, i, a_spec) { if (zlog_spec_gen_archive_path(a_spec, a_thread)) { zc_error("zlog_spec_gen_path fail"); return NULL; } } zlog_buf_seal(a_thread->archive_path_buf); return zlog_buf_str(a_thread->archive_path_buf); } static int zlog_rule_output_static_file_rotate(zlog_rule_t * a_rule, zlog_thread_t * a_thread) { size_t len; struct zlog_stat info; int fd; if (zlog_format_gen_msg(a_rule->format, a_thread)) { zc_error("zlog_format_gen_msg fail"); return -1; } fd = open(a_rule->file_path, a_rule->file_open_flags | O_WRONLY | O_APPEND | O_CREAT, a_rule->file_perms); if (fd < 0) { zc_error("open file[%s] fail, errno[%d]", a_rule->file_path, errno); return -1; } len = zlog_buf_len(a_thread->msg_buf); if (write(fd, zlog_buf_str(a_thread->msg_buf), len) < 0) { zc_error("write fail, errno[%d]", errno); close(fd); return -1; } if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) { a_rule->fsync_count = 0; if (fsync(fd)) zc_error("fsync[%d] fail, errno[%d]", fd, errno); } if (close(fd) < 0) { zc_error("close fail, maybe cause by write, errno[%d]", errno); return -1; } if (len > a_rule->archive_max_size) { zc_debug("one msg's len[%ld] > archive_max_size[%ld], no rotate", (long)len, (long)a_rule->archive_max_size); return 0; } if (stat(a_rule->file_path, &info)) { zc_warn("stat [%s] fail, errno[%d], maybe in rotating", a_rule->file_path, errno); return 0; } /* file not so big, return */ if (info.st_size + len < a_rule->archive_max_size) return 0; if (zlog_rotater_rotate(zlog_env_conf->rotater, a_rule->file_path, len, zlog_rule_gen_archive_path(a_rule, a_thread), a_rule->archive_max_size, a_rule->archive_max_count) ) { zc_error("zlog_rotater_rotate fail"); return -1; } /* success or no rotation do nothing */ return 0; } /* return path success * return NULL fail */ #define zlog_rule_gen_path(a_rule, a_thread) do { \ int i; \ zlog_spec_t *a_spec; \ \ zlog_buf_restart(a_thread->path_buf); \ \ zc_arraylist_foreach(a_rule->dynamic_specs, i, a_spec) { \ if (zlog_spec_gen_path(a_spec, a_thread)) { \ zc_error("zlog_spec_gen_path fail"); \ return -1; \ } \ } \ \ zlog_buf_seal(a_thread->path_buf); \ } while(0) static int zlog_rule_output_dynamic_file_single(zlog_rule_t * a_rule, zlog_thread_t * a_thread) { int fd; zlog_rule_gen_path(a_rule, a_thread); if (zlog_format_gen_msg(a_rule->format, a_thread)) { zc_error("zlog_format_output fail"); return -1; } fd = open(zlog_buf_str(a_thread->path_buf), a_rule->file_open_flags | O_WRONLY | O_APPEND | O_CREAT, a_rule->file_perms); if (fd < 0) { zc_error("open file[%s] fail, errno[%d]", zlog_buf_str(a_thread->path_buf), errno); return -1; } if (write(fd, zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) { zc_error("write fail, errno[%d]", errno); close(fd); return -1; } if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) { a_rule->fsync_count = 0; if (fsync(fd)) zc_error("fsync[%d] fail, errno[%d]", fd, errno); } if (close(fd) < 0) { zc_error("close fail, maybe cause by write, errno[%d]", errno); return -1; } return 0; } static int zlog_rule_output_dynamic_file_rotate(zlog_rule_t * a_rule, zlog_thread_t * a_thread) { int fd; char *path; size_t len; struct zlog_stat info; zlog_rule_gen_path(a_rule, a_thread); if (zlog_format_gen_msg(a_rule->format, a_thread)) { zc_error("zlog_format_output fail"); return -1; } path = zlog_buf_str(a_thread->path_buf); fd = open(path, a_rule->file_open_flags | O_WRONLY | O_APPEND | O_CREAT, a_rule->file_perms); if (fd < 0) { zc_error("open file[%s] fail, errno[%d]", zlog_buf_str(a_thread->path_buf), errno); return -1; } len = zlog_buf_len(a_thread->msg_buf); if (write(fd, zlog_buf_str(a_thread->msg_buf), len) < 0) { zc_error("write fail, errno[%d]", errno); close(fd); return -1; } if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) { a_rule->fsync_count = 0; if (fsync(fd)) zc_error("fsync[%d] fail, errno[%d]", fd, errno); } if (close(fd) < 0) { zc_error("write fail, maybe cause by write, errno[%d]", errno); return -1; } if (len > a_rule->archive_max_size) { zc_debug("one msg's len[%ld] > archive_max_size[%ld], no rotate", (long)len, (long) a_rule->archive_max_size); return 0; } if (stat(path, &info)) { zc_warn("stat [%s] fail, errno[%d], maybe in rotating", path, errno); return 0; } /* file not so big, return */ if (info.st_size + len < a_rule->archive_max_size) return 0; if (zlog_rotater_rotate(zlog_env_conf->rotater, path, len, zlog_rule_gen_archive_path(a_rule, a_thread), a_rule->archive_max_size, a_rule->archive_max_count) ) { zc_error("zlog_rotater_rotate fail"); return -1; } /* success or no rotation do nothing */ return 0; } static int zlog_rule_output_pipe(zlog_rule_t * a_rule, zlog_thread_t * a_thread) { if (zlog_format_gen_msg(a_rule->format, a_thread)) { zc_error("zlog_format_gen_msg fail"); return -1; } if (write(a_rule->pipe_fd, zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) { zc_error("write fail, errno[%d]", errno); return -1; } return 0; } static int zlog_rule_output_syslog(zlog_rule_t * a_rule, zlog_thread_t * a_thread) { zlog_level_t *a_level; if (zlog_format_gen_msg(a_rule->format, a_thread)) { zc_error("zlog_format_gen_msg fail"); return -1; } /* msg = a_thread->msg_buf->start; msg_len = a_thread->msg_buf->end - a_thread->msg_buf->start; */ a_level = zlog_level_list_get(zlog_env_conf->levels, a_thread->event->level); zlog_buf_seal(a_thread->msg_buf); syslog(a_rule->syslog_facility | a_level->syslog_level, "%s", zlog_buf_str(a_thread->msg_buf)); return 0; } static int zlog_rule_output_static_record(zlog_rule_t * a_rule, zlog_thread_t * a_thread) { zlog_msg_t msg; if (!a_rule->record_func) { zc_error("user defined record funcion for [%s] not set, no output", a_rule->record_name); return -1; } if (zlog_format_gen_msg(a_rule->format, a_thread)) { zc_error("zlog_format_gen_msg fail"); return -1; } zlog_buf_seal(a_thread->msg_buf); msg.buf = zlog_buf_str(a_thread->msg_buf); msg.len = zlog_buf_len(a_thread->msg_buf); msg.path = a_rule->record_path; if (a_rule->record_func(&msg)) { zc_error("a_rule->record fail"); return -1; } return 0; } static int zlog_rule_output_dynamic_record(zlog_rule_t * a_rule, zlog_thread_t * a_thread) { zlog_msg_t msg; if (!a_rule->record_func) { zc_error("user defined record funcion for [%s] not set, no output", a_rule->record_name); return -1; } zlog_rule_gen_path(a_rule, a_thread); if (zlog_format_gen_msg(a_rule->format, a_thread)) { zc_error("zlog_format_gen_msg fail"); return -1; } zlog_buf_seal(a_thread->msg_buf); msg.buf = zlog_buf_str(a_thread->msg_buf); msg.len = zlog_buf_len(a_thread->msg_buf); msg.path = zlog_buf_str(a_thread->path_buf); if (a_rule->record_func(&msg)) { zc_error("a_rule->record fail"); return -1; } return 0; } static int zlog_rule_output_stdout(zlog_rule_t * a_rule, zlog_thread_t * a_thread) { if (zlog_format_gen_msg(a_rule->format, a_thread)) { zc_error("zlog_format_gen_msg fail"); return -1; } if (write(STDOUT_FILENO, zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) { zc_error("write fail, errno[%d]", errno); return -1; } return 0; } static int zlog_rule_output_stderr(zlog_rule_t * a_rule, zlog_thread_t * a_thread) { if (zlog_format_gen_msg(a_rule->format, a_thread)) { zc_error("zlog_format_gen_msg fail"); return -1; } if (write(STDERR_FILENO, zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) { zc_error("write fail, errno[%d]", errno); return -1; } return 0; } /*******************************************************************************/ static int syslog_facility_atoi(char *facility) { /* guess no unix system will choose -187 * as its syslog facility, so it is a safe return value */ zc_assert(facility, -187); if (STRICMP(facility, ==, "LOG_LOCAL0")) return LOG_LOCAL0; if (STRICMP(facility, ==, "LOG_LOCAL1")) return LOG_LOCAL1; if (STRICMP(facility, ==, "LOG_LOCAL2")) return LOG_LOCAL2; if (STRICMP(facility, ==, "LOG_LOCAL3")) return LOG_LOCAL3; if (STRICMP(facility, ==, "LOG_LOCAL4")) return LOG_LOCAL4; if (STRICMP(facility, ==, "LOG_LOCAL5")) return LOG_LOCAL5; if (STRICMP(facility, ==, "LOG_LOCAL6")) return LOG_LOCAL6; if (STRICMP(facility, ==, "LOG_LOCAL7")) return LOG_LOCAL7; if (STRICMP(facility, ==, "LOG_USER")) return LOG_USER; if (STRICMP(facility, ==, "LOG_AUTHPRIV")) return LOG_AUTHPRIV; if (STRICMP(facility, ==, "LOG_CRON")) return LOG_CRON; if (STRICMP(facility, ==, "LOG_DAEMON")) return LOG_DAEMON; if (STRICMP(facility, ==, "LOG_FTP")) return LOG_FTP; if (STRICMP(facility, ==, "LOG_KERN")) return LOG_KERN; if (STRICMP(facility, ==, "LOG_LPR")) return LOG_LPR; if (STRICMP(facility, ==, "LOG_MAIL")) return LOG_MAIL; if (STRICMP(facility, ==, "LOG_NEWS")) return LOG_NEWS; if (STRICMP(facility, ==, "LOG_SYSLOG")) return LOG_SYSLOG; return LOG_AUTHPRIV; zc_error("wrong syslog facility[%s], must in LOG_LOCAL[0-7] or LOG_USER", facility); return -187; } static int zlog_rule_parse_path(char *path_start, /* start with a " */ char *path_str, size_t path_size, zc_arraylist_t **path_specs, int *time_cache_count) { char *p, *q; size_t len; zlog_spec_t *a_spec; zc_arraylist_t *specs; p = path_start + 1; q = strrchr(p, '"'); if (!q) { zc_error("matching \" not found in conf line[%s]", path_start); return -1; } len = q - p; if (len > path_size - 1) { zc_error("file_path too long %ld > %ld", len, path_size - 1); return -1; } memcpy(path_str, p, len); /* replace any environment variables like %E(HOME) */ if (zc_str_replace_env(path_str, path_size)) { zc_error("zc_str_replace_env fail"); return -1; } if (strchr(path_str, '%') == NULL) { /* static, no need create specs */ return 0; } specs = zc_arraylist_new((zc_arraylist_del_fn)zlog_spec_del); if (!path_specs) { zc_error("zc_arraylist_new fail"); return -1; } for (p = path_str; *p != '\0'; p = q) { a_spec = zlog_spec_new(p, &q, time_cache_count); if (!a_spec) { zc_error("zlog_spec_new fail"); goto err; } if (zc_arraylist_add(specs, a_spec)) { zc_error("zc_arraylist_add fail"); goto err; } } *path_specs = specs; return 0; err: if (specs) zc_arraylist_del(specs); if (a_spec) zlog_spec_del(a_spec); return -1; } zlog_rule_t *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) { int rc = 0; int nscan = 0; int nread = 0; zlog_rule_t *a_rule; char selector[MAXLEN_CFG_LINE + 1]; char category[MAXLEN_CFG_LINE + 1]; char level[MAXLEN_CFG_LINE + 1]; char *action; char output[MAXLEN_CFG_LINE + 1]; char format_name[MAXLEN_CFG_LINE + 1]; char file_path[MAXLEN_CFG_LINE + 1]; char archive_max_size[MAXLEN_CFG_LINE + 1]; char *file_limit; char *p; char *q; size_t len; zc_assert(line, NULL); zc_assert(default_format, NULL); zc_assert(formats, NULL); a_rule = calloc(1, sizeof(zlog_rule_t)); if (!a_rule) { zc_error("calloc fail, errno[%d]", errno); return NULL; } a_rule->file_perms = file_perms; a_rule->fsync_period = fsync_period; /* line [f.INFO "%H/log/aa.log", 20MB * 12; MyTemplate] * selector [f.INFO] * *action ["%H/log/aa.log", 20MB * 12; MyTemplate] */ memset(&selector, 0x00, sizeof(selector)); nscan = sscanf(line, "%s %n", selector, &nread); if (nscan != 1) { zc_error("sscanf [%s] fail, selector", line); goto err; } action = line + nread; /* * selector [f.INFO] * category [f] * level [.INFO] */ memset(category, 0x00, sizeof(category)); memset(level, 0x00, sizeof(level)); nscan = sscanf(selector, " %[^.].%s", category, level); if (nscan != 2) { zc_error("sscanf [%s] fail, category or level is null", selector); goto err; } /* check and set category */ for (p = category; *p != '\0'; p++) { if ((!isalnum(*p)) && (*p != '_') && (*p != '-') && (*p != '*') && (*p != '!')) { zc_error("category name[%s] character is not in [a-Z][0-9][_!*-]", category); goto err; } } /* as one line can't be longer than MAXLEN_CFG_LINE, same as category */ strcpy(a_rule->category, category); /* check and set level */ switch (level[0]) { case '=': /* aa.=debug */ a_rule->compare_char = '='; p = level + 1; break; case '!': /* aa.!debug */ a_rule->compare_char = '!'; p = level + 1; break; case '*': /* aa.* */ a_rule->compare_char = '*'; p = level; break; default: /* aa.debug */ a_rule->compare_char = '.'; p = level; break; } a_rule->level = zlog_level_list_atoi(levels, p); /* level_bit is a bitmap represents which level can be output * 32bytes, [0-255] levels, see level.c * which bit field is 1 means allow output and 0 not */ switch (a_rule->compare_char) { case '=': memset(a_rule->level_bitmap, 0x00, sizeof(a_rule->level_bitmap)); a_rule->level_bitmap[a_rule->level / 8] |= (1 << (7 - a_rule->level % 8)); break; case '!': memset(a_rule->level_bitmap, 0xFF, sizeof(a_rule->level_bitmap)); a_rule->level_bitmap[a_rule->level / 8] &= ~(1 << (7 - a_rule->level % 8)); break; case '*': memset(a_rule->level_bitmap, 0xFF, sizeof(a_rule->level_bitmap)); break; case '.': memset(a_rule->level_bitmap, 0x00, sizeof(a_rule->level_bitmap)); a_rule->level_bitmap[a_rule->level / 8] |= ~(0xFF << (8 - a_rule->level % 8)); memset(a_rule->level_bitmap + a_rule->level / 8 + 1, 0xFF, sizeof(a_rule->level_bitmap) - a_rule->level / 8 - 1); break; } /* action ["%H/log/aa.log", 20MB * 12 ; MyTemplate] * output ["%H/log/aa.log", 20MB * 12] * format [MyTemplate] */ memset(output, 0x00, sizeof(output)); memset(format_name, 0x00, sizeof(format_name)); nscan = sscanf(action, " %[^;];%s", output, format_name); if (nscan < 1) { zc_error("sscanf [%s] fail", action); goto err; } /* check and get format */ if (STRCMP(format_name, ==, "")) { zc_debug("no format specified, use default"); a_rule->format = default_format; } else { int i; int find_flag = 0; zlog_format_t *a_format; zc_arraylist_foreach(formats, i, a_format) { if (zlog_format_has_name(a_format, format_name)) { a_rule->format = a_format; find_flag = 1; break; } } if (!find_flag) { zc_error("in conf file can't find format[%s], pls check", format_name); goto err; } } /* output [-"%E(HOME)/log/aa.log" , 20MB*12] [>syslog , LOG_LOCAL0 ] * file_path [-"%E(HOME)/log/aa.log" ] [>syslog ] * *file_limit [20MB * 12 ~ "aa.#i.log" ] [LOG_LOCAL0] */ memset(file_path, 0x00, sizeof(file_path)); nscan = sscanf(output, " %[^,],", file_path); if (nscan < 1) { zc_error("sscanf [%s] fail", action); goto err; } file_limit = strchr(output, ','); if (file_limit) { file_limit++; /* skip the , */ while( isspace(*file_limit) ) { file_limit++; } } p = NULL; switch (file_path[0]) { case '-' : /* sync file each time write log */ if (file_path[1] != '"') { zc_error(" - must set before a file output"); goto err; } /* no need to fsync, as file is opened by O_SYNC, write immediately */ a_rule->fsync_period = 0; p = file_path + 1; a_rule->file_open_flags = O_SYNC; /* fall through */ case '"' : if (!p) p = file_path; rc = zlog_rule_parse_path(p, a_rule->file_path, sizeof(a_rule->file_path), &(a_rule->dynamic_specs), time_cache_count); if (rc) { zc_error("zlog_rule_parse_path fail"); goto err; } if (file_limit) { memset(archive_max_size, 0x00, sizeof(archive_max_size)); nscan = sscanf(file_limit, " %[0-9MmKkBb] * %d ~", archive_max_size, &(a_rule->archive_max_count)); if (nscan) { a_rule->archive_max_size = zc_parse_byte_size(archive_max_size); } p = strchr(file_limit, '"'); if (p) { /* archive file path exist */ rc = zlog_rule_parse_path(p, a_rule->archive_path, sizeof(a_rule->file_path), &(a_rule->archive_specs), time_cache_count); if (rc) { zc_error("zlog_rule_parse_path fail"); goto err; } p = strchr(a_rule->archive_path, '#'); if ( (p == NULL) || ((strchr(p, 'r') == NULL) && (strchr(p, 's') == NULL))) { zc_error("archive_path must contain #r or #s"); goto err; } } } /* try to figure out if the log file path is dynamic or static */ if (a_rule->dynamic_specs) { if (a_rule->archive_max_size <= 0) { a_rule->output = zlog_rule_output_dynamic_file_single; } else { a_rule->output = zlog_rule_output_dynamic_file_rotate; } } else { struct stat stb; if (a_rule->archive_max_size <= 0) { a_rule->output = zlog_rule_output_static_file_single; } else { /* as rotate, so need to reopen everytime */ a_rule->output = zlog_rule_output_static_file_rotate; } a_rule->static_fd = open(a_rule->file_path, O_WRONLY | O_APPEND | O_CREAT | a_rule->file_open_flags, a_rule->file_perms); if (a_rule->static_fd < 0) { zc_error("open file[%s] fail, errno[%d]", a_rule->file_path, errno); goto err; } /* save off the inode information for checking for a changed file later on */ if (fstat(a_rule->static_fd, &stb)) { zc_error("stat [%s] fail, errno[%d], failing to open static_fd", a_rule->file_path, errno); goto err; } if (a_rule->archive_max_size > 0) { close(a_rule->static_fd); a_rule->static_fd = -1; } a_rule->static_dev = stb.st_dev; a_rule->static_ino = stb.st_ino; } break; case '|' : a_rule->pipe_fp = popen(output + 1, "w"); if (!a_rule->pipe_fp) { zc_error("popen fail, errno[%d]", errno); goto err; } a_rule->pipe_fd = fileno(a_rule->pipe_fp); if (a_rule->pipe_fd < 0 ) { zc_error("fileno fail, errno[%d]", errno); goto err; } a_rule->output = zlog_rule_output_pipe; break; case '>' : if (STRNCMP(file_path + 1, ==, "syslog", 6)) { a_rule->syslog_facility = syslog_facility_atoi(file_limit); if (a_rule->syslog_facility == -187) { zc_error("-187 get"); goto err; } a_rule->output = zlog_rule_output_syslog; openlog(NULL, LOG_NDELAY | LOG_NOWAIT | LOG_PID, LOG_USER); } else if (STRNCMP(file_path + 1, ==, "stdout", 6)) { a_rule->output = zlog_rule_output_stdout; } else if (STRNCMP(file_path + 1, ==, "stderr", 6)) { a_rule->output = zlog_rule_output_stderr; } else { zc_error ("[%s]the string after is not syslog, stdout or stderr", output); goto err; } break; case '$' : sscanf(file_path + 1, "%s", a_rule->record_name); if (file_limit) { /* record path exists */ p = strchr(file_limit, '"'); if (!p) { zc_error("record_path not start with \", [%s]", file_limit); goto err; } p++; /* skip 1st " */ q = strrchr(p, '"'); if (!q) { zc_error("matching \" not found in conf line[%s]", p); goto err; } len = q - p; if (len > sizeof(a_rule->record_path) - 1) { zc_error("record_path too long %ld > %ld", len, sizeof(a_rule->record_path) - 1); goto err; } memcpy(a_rule->record_path, p, len); } /* replace any environment variables like %E(HOME) */ rc = zc_str_replace_env(a_rule->record_path, sizeof(a_rule->record_path)); if (rc) { zc_error("zc_str_replace_env fail"); goto err; } /* try to figure out if the log file path is dynamic or static */ if (strchr(a_rule->record_path, '%') == NULL) { a_rule->output = zlog_rule_output_static_record; } else { zlog_spec_t *a_spec; a_rule->output = zlog_rule_output_dynamic_record; a_rule->dynamic_specs = zc_arraylist_new((zc_arraylist_del_fn)zlog_spec_del); if (!(a_rule->dynamic_specs)) { zc_error("zc_arraylist_new fail"); goto err; } for (p = a_rule->record_path; *p != '\0'; p = q) { a_spec = zlog_spec_new(p, &q, time_cache_count); if (!a_spec) { zc_error("zlog_spec_new fail"); goto err; } rc = zc_arraylist_add(a_rule->dynamic_specs, a_spec); if (rc) { zlog_spec_del(a_spec); zc_error("zc_arraylist_add fail"); goto err; } } } break; default : zc_error("the 1st char[%c] of file_path[%s] is wrong", file_path[0], file_path); goto err; } return a_rule; err: zlog_rule_del(a_rule); return NULL; } void zlog_rule_del(zlog_rule_t * a_rule) { zc_assert(a_rule,); if (a_rule->dynamic_specs) { zc_arraylist_del(a_rule->dynamic_specs); a_rule->dynamic_specs = NULL; } if (a_rule->static_fd > 0) { if (close(a_rule->static_fd)) { zc_error("close fail, maybe cause by write, errno[%d]", errno); } } if (a_rule->pipe_fp) { if (pclose(a_rule->pipe_fp) == -1) { zc_error("pclose fail, errno[%d]", errno); } } if (a_rule->archive_specs) { zc_arraylist_del(a_rule->archive_specs); a_rule->archive_specs = NULL; } zc_debug("zlog_rule_del[%p]", a_rule); free(a_rule); return; } /*******************************************************************************/ int zlog_rule_output(zlog_rule_t * a_rule, zlog_thread_t * a_thread) { switch (a_rule->compare_char) { case '*' : return a_rule->output(a_rule, a_thread); break; case '.' : if (a_thread->event->level >= a_rule->level) { return a_rule->output(a_rule, a_thread); } else { return 0; } break; case '=' : if (a_thread->event->level == a_rule->level) { return a_rule->output(a_rule, a_thread); } else { return 0; } break; case '!' : if (a_thread->event->level != a_rule->level) { return a_rule->output(a_rule, a_thread); } else { return 0; } break; } return 0; } /*******************************************************************************/ int zlog_rule_is_wastebin(zlog_rule_t * a_rule) { zc_assert(a_rule, -1); if (STRCMP(a_rule->category, ==, "!")) { return 1; } return 0; } /*******************************************************************************/ int zlog_rule_match_category(zlog_rule_t * a_rule, char *category) { zc_assert(a_rule, -1); zc_assert(category, -1); if (STRCMP(a_rule->category, ==, "*")) { /* '*' match anything, so go on */ return 1; } else if (STRCMP(a_rule->category, ==, category)) { /* accurate compare */ return 1; } else { /* aa_ match aa_xx & aa, but not match aa1_xx */ size_t len; len = strlen(a_rule->category); if (a_rule->category[len - 1] == '_') { if (strlen(category) == len - 1) { len--; } if (STRNCMP(a_rule->category, ==, category, len)) { return 1; } } } return 0; } /*******************************************************************************/ int zlog_rule_set_record(zlog_rule_t * a_rule, zc_hashtable_t *records) { zlog_record_t *a_record; if (a_rule->output != zlog_rule_output_static_record && a_rule->output != zlog_rule_output_dynamic_record) { return 0; /* fliter, may go through not record rule */ } a_record = zc_hashtable_get(records, a_rule->record_name); if (a_record) { a_rule->record_func = a_record->output; } return 0; }