map/das-dn/third_party/zlog/rule.c

1059 lines
26 KiB
C
Raw Normal View History

2024-07-08 10:27:17 +08:00
/*
* This file is part of the zlog Library.
*
* Copyright (C) 2011 by Hardy Simpson <HardySimpson1984@gmail.com>
*
* Licensed under the LGPL v2.1, see the file COPYING in base directory.
*/
#include "fmacros.h"
#include <string.h>
#include <ctype.h>
#include <syslog.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#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;
}