Systemd不支持按日志级别直接重定向,需脚本区分stdout/stderr输出、service配置StandardOutput=journal、再通过journalbeat/fluent-bit等采集器转发至日志中心。

Systemd 本身不支持直接将 StandardOutput 按“分类”(如 info/warn/error)重定向到外部日志中心,它只提供统一的流捕获机制(stdout/stderr),日志分级需由应用自身或中间层完成。真正可行的路径是:让 Shell 脚本规范输出 + 利用 Systemd 的日志转发能力 + 借助外部日志代理(如 rsyslog、journalbeat 或 fluent-bit)对接日志中心。
1. Shell 脚本需主动区分输出级别并写入标准流
Systemd 不解析日志内容,但会原样保留 stdout 和 stderr 的归属。惯例是:
- info/debug 类消息走 stdout
- warning/error/fatal 类消息走 stderr
例如,在脚本中这样写:
#!/bin/bash echo "Starting backup task..." # → stdout → journal's INFO level (by default) logger -t "mybackup" "Config loaded" # 可选:用 logger 写入 journal,带标识 echo "Disk space low, continuing..." >&2 # → stderr → journal's WARNING (systemd treats stderr as higher priority) exit 1 >&2 # → stderr → journal's ERR
2. 在 .service 文件中配置 StandardOutput 和 StandardError
明确指定输出去向为 journal(推荐),而非文件或 null:
[Service] Type=oneshot ExecStart=/opt/scripts/backup.sh StandardOutput=journal StandardError=journal # 可选:添加日志标识,便于后续过滤 SyslogIdentifier=mybackup
⚠️ 注意:StandardOutput=file:/path 会绕过 journal,失去结构化日志能力,不建议用于对接日志中心。
3. 启用 journal 远程转发或使用日志采集器
Systemd journal 支持两种主流对接方式:
-
本地 journalbeat / fluent-bit:监听
/run/systemd/journal/socket或读取 journal 文件,按SyslogIdentifier、PRIORITY、CODE_FILE等字段提取并打标,再发往 Elasticsearch / Loki / Splunk -
rsyslog + imjournal:启用
imjournal模块,将 journal 条目转成 syslog 格式,再通过omelasticsearch或omfwd发送;需在/etc/rsyslog.d/10-journal.conf中配置$IMJournalStateFile和过滤规则
示例(fluent-bit 过滤器片段):
[FILTER]
Name kubernetes
Match systemd.journal.*
Merge_Log On
Keep_Log Off
K8S-Logging.Parser On
<p>[FILTER]
Name modify
Match systemd.journal.*
Add app_name mybackup
Add log_source systemd</p>4. (可选)增强日志结构化:在脚本中输出 JSON 行
若日志中心支持 JSON 解析(如 Loki、ES),可在脚本中直接输出结构化行:
echo '{"level":"info","msg":"task started","ts":"'"$(date -Iseconds)"'"}'
echo '{"level":"error","msg":"permission denied","path":"/data"}' >&2配合 fluent-bit 的 parser json 插件,可自动提取 level 字段,用于日志中心告警或着色。
关键不在 Systemd 的 StandardOutput 属性本身,而在于整个链路的设计:脚本负责语义分级 → Systemd 统一收拢 → 外部采集器负责识别、丰富、路由。跳过任何一环都难以实现可靠分类。











