在Debian运维中,syslog-ng默认配置几乎对所有日志来者不拒,从内核消息到应用调试信息一股脑全部写入文件,导致日志文件迅速膨胀到几十GB甚至更大,磁盘告警频发、日志检索效率极低、故障排查时淹没在无关信息中。解决这个问题的核心就是收紧过滤规则,按来源、级别、模式三个维度建立精确的过滤策略,把真正有用的日志留下,把噪声挡在门外。下面直接给你一套完整的操作方案和原理拆解。

一、为什么syslog-ng默认配置会制造"日志洪流"

Debian自带的syslog-ng配置文件通常位于/etc/syslog-ng/syslog-ng.conf,默认的source和destination设置非常宽泛。比如常见的默认规则长这样:

source s_src {
    system();
    internal();
};

destination d_all {
    file("/var/log/syslog");
};

log {
    source(s_src);
    destination(d_all);
};

这段配置的意思是:系统所有来源的日志(包括内核、守护进程、内部消息)全部写到/var/log/syslog。问题在于,它没有做任何级别过滤和来源区分。你的cron每分钟打一条info,sshd每次连接都记录,甚至某些应用程序的debug级别日志也全部涌入。在生产服务器上,这种配置一周就能把日志文件撑到上百GB。

二、理解syslog-ng的过滤三要素

要精准控制日志,必须搞清楚三个核心概念:过滤器(filter)、日志级别(level)、来源设施(facility)。

syslog-ng的过滤器语法用match和not match组合。match表示匹配则通过,not match表示不匹配则通过。常见的日志级别从高到低是:emerg、alert、crit、err、warning、notice、info、debug。一般生产环境建议最低记录到warning或notice级别,debug级别在排查问题时才临时开启。

设施(facility)则标识日志来源,比如auth是认证相关、kern是内核、daemon是后台守护进程、mail是邮件服务、cron是定时任务。通过设施过滤,你可以把不同类型的日志分流到不同文件。

三、实战:构建分级过滤规则

下面是一套经过验证的生产级配置方案,直接替换或修改/etc/syslog-ng/syslog-ng.conf中的log段落:

# 定义过滤器
filter f_emergency { level(emerg); };
filter f_critical { level(crit..emerg); };
filter f_error { level(err..emerg); };
filter f_warning { level(warning..emerg); };
filter f_info { level(info..emerg); };
filter f_debug { level(debug..emerg); };

filter f_auth { facility(auth); };
filter f_authpriv { facility(authpriv); };
filter f_cron { facility(cron); };
filter f_daemon { facility(daemon); };
filter f_kern { facility(kern); };
filter f_mail { facility(mail); };
filter f_user { facility(user); };

filter f_no_debug { not level(debug); };
filter f_no_info { not level(info); };

# 定义日志路径
destination d_emergency { file("/var/log/emergency.log"); };
destination d_critical { file("/var/log/critical.log"); };
destination d_error { file("/var/log/error.log"); };
destination d_warning { file("/var/log/warning.log"); };
destination d_info { file("/var/log/info.log"); };
destination d_auth { file("/var/log/auth.log"); };
destination d_cron { file("/var/log/cron.log"); };
destination d_daemon { file("/var/log/daemon.log"); };
destination d_kern { file("/var/log/kern.log"); };
destination d_mail { file("/var/log/mail.log"); };
destination d_user { file("/var/log/user.log"); };
destination d_debug { file("/var/log/debug.log"); };

# 组合日志规则
log {
    source(s_src);
    filter(f_emergency);
    destination(d_emergency);
};

log {
    source(s_src);
    filter(f_critical);
    destination(d_critical);
};

log {
    source(s_src);
    filter(f_error);
    destination(d_error);
};

log {
    source(s_src);
    filter(f_warning);
    destination(d_warning);
};

log {
    source(s_src);
    filter(f_auth);
    destination(d_auth);
};

log {
    source(s_src);
    filter(f_authpriv);
    destination(d_auth);
};

log {
    source(s_src);
    filter(f_cron);
    destination(d_cron);
};

log {
    source(s_src);
    filter(f_daemon);
    destination(d_daemon);
};

log {
    source(s_src);
    filter(f_kern);
    destination(d_kern);
};

log {
    source(s_src);
    filter(f_mail);
    destination(d_mail);
};

log {
    source(s_src);
    filter(f_user);
    destination(d_user);
};

# 通用info及以上级别(排除debug)
log {
    source(s_src);
    filter(f_no_debug);
    destination(d_info);
};

# debug级别单独存放,生产环境可注释掉
# log {
#     source(s_src);
#     filter(f_debug);
#     destination(d_debug);
# };

这套配置的逻辑是:紧急和错误级别的日志单独成文件,方便监控告警系统抓取;按设施分类让不同类型的日志各归其位;通用info日志排除debug噪声。你会发现/var/log/syslog不再被塞满,每个文件都有明确的用途。

四、用正则表达式做更精细的过滤

有时候光靠级别和设施还不够,比如你想过滤掉某个特定应用产生的大量重复日志,或者只保留包含特定关键字的条目。这时候用regexp匹配就很有效:

# 过滤掉包含"health check OK"的冗余日志
filter f_no_health_check {
    not match("health check OK" type(string));
};

# 只保留包含"connection refused"的sshd日志
filter f_ssh_refused {
    match("sshd.*connection refused" type(pcre));
};

log {
    source(s_src);
    filter(f_auth);
    filter(f_ssh_refused);
    destination(d_auth);
};

pcre类型支持Perl兼容正则,功能最强。但要注意,正则匹配会消耗更多CPU资源,在高并发日志场景下慎用。建议只在特定规则上使用,不要全局应用。

五、配合logrotate防止日志文件失控

过滤规则收紧后,日志增长速度会大幅下降,但仍然需要logrotate做轮转和压缩。Debian默认的/etc/logrotate.d/syslog-ng配置通常是这样的:

/var/log/syslog
{
    rotate 7
    daily
    missingok
    notifempty
    compress
    delaycompress
    postrotate
        /usr/sbin/syslog-ng-ctl reopen
    endscript
}

你需要为每个新创建的日志文件添加对应的logrotate规则,或者直接用通配符:

/var/log/*.log
{
    rotate 14
    daily
    missingok
    notifempty
    compress
    delaycompress
    sharedscripts
    postrotate
        /usr/sbin/syslog-ng-ctl reopen
    endscript
}

rotate 14表示保留14天,daily每天轮转,compress压缩旧日志。这样即使某个文件偶尔暴增,也不会长期占用磁盘。

六、验证配置和排错技巧

修改完syslog-ng.conf后,千万不要直接重启服务,先用语法检查:

syslog-ng -s

如果输出显示"Configuration check successful",说明语法没问题。然后用systemctl reload syslog-ng平滑重载配置,避免中断日志采集。

如果发现某条规则没生效,用以下命令实时查看syslog-ng的内部日志:

journalctl -u syslog-ng -f

或者直接查看/var/log/syslog中是否出现预期的日志条目。如果过滤太严格导致某些重要日志被丢弃,逐步放宽filter条件,不要一次性全部放开。

七、进阶:用syslog-ng的channel和parser做结构化处理

对于更复杂的场景,比如需要把JSON格式的应用日志解析成结构化字段,syslog-ng提供了parser功能。先定义parser:

parser p_json {
    json-parser(prefix(".json."));
};

然后在log规则中引用:

log {
    source(s_src);
    parser(p_json);
    filter(f_error);
    destination(d_error);
};

这样error.log中的每条记录都会带有.json.字段前缀的结构化数据,后续可以用ELK或者其他日志分析平台直接索引,排查效率翻倍。

八、常见误区和注意事项

第一个误区是把所有日志都设为warning以上,觉得"越少越好"。但实际上某些info级别的日志(比如用户登录成功记录、服务启动确认)在审计和合规场景下是必须保留的。过滤规则要根据业务需求定制,不能一刀切。

第二个误区是忽略了internal()消息源。syslog-ng的internal()会产生自身运行状态日志,如果不单独处理,这些内部消息也会混入业务日志。建议单独建一个文件:

log {
    source(s_internal);
    destination(d_internal);
};

destination d_internal {
    file("/var/log/syslog-ng-internal.log");
};

第三个注意点是性能。每增加一条filter规则,syslog-ng都要对每条日志做一次匹配判断。规则数量控制在20条以内通常不会有明显性能影响,超过50条就需要评估是否用外部工具(如rsyslog的omprog模块)做预处理。

总结来说,Debian上syslog-ng的日志洪流问题本质上是默认配置"不做筛选"导致的。通过分级过滤、设施分流、正则精筛、logrotate轮转四步组合拳,你可以把日志总量压缩70%以上,同时确保关键信息一个不丢。这不是什么高深技术,而是运维基本功,值得每个Debian管理员花半小时认真配置一次。