- 运维
- 配置管理
- 后端
【免费下载链接】salt
Software to automate the management and configuration of infrastructure and applications at scale.
导读
Salt 为 syslog-ng 日志服务提供了一对配套的执行模块与状态模块:执行模块 salt/modules/syslog_ng.py 负责生成配置、校验语法、查询版本/模块/统计信息,以及启动、停止、重载服务;状态模块 salt/states/syslog_ng.py 则把上述能力包装为可在 SLS 中直接使用的状态。本文基于 syslog-ng 官方使用教程 与该模块源码、单元测试,完整讲解如何从 YAML 描述生成 syslog-ng 配置(包括 source、destination、filter、parser、rewrite、template、log 路径与 junction 分支),如何用module.run编排初始化步骤,以及如何通过config_test、version、modules、stats等命令对实例进行诊断——读完即可在 Salt 环境中落地一套「配置即代码」的 syslog-ng 管理方案。
模块定位与适用场景
syslog-ng 是通用的日志采集与转发守护进程,Salt 的 syslog_ng 模块(salt.modules.syslog_ng)提供如下能力(对应源码中的公开函数):
- 生成配置:
config、write_version、write_config、set_config_file、set_binary_path、set_parameters - 诊断查询:
config_test(语法检查)、version(版本号)、modules(可用模块)、stats(运行统计)、get_config_file - 服务控制:
start、stop、reload_(通过__func_alias__对外暴露为reload)
模块声明(模块 docstring)说明了关键背景:syslog-ng 可以通过包管理器或源码方式安装;当从源码安装时,syslog-ng与syslog-ng-ctl两个二进制不在PATH中,用户需要用syslog_ng.set_binary_path指定 sbin 目录,用syslog_ng.set_config_file指定配置文件位置,否则模块会使用默认配置路径/etc/syslog-ng.conf(模块源码中的模块级常量__SYSLOG_NG_CONFIG_FILE)。模块仅依赖cmd,支持所有平台(salt/modules/syslog_ng.py模块头部:platform: all)。
值得注意的是,执行模块中若干函数(config、set_binary_path、set_config_file、start、stop、reload_、write_config、write_version)的 docstring 都注明「intended to be used from the state module / from states」,即它们的典型用法是经由状态模块或module.run调用,而不是直接在命令行单独执行;从源码结构看,这些函数返回的是带name、result、changes、comment字段的状态字典(_format_state_result),天然适配 Salt 的状态执行模型。
配置生成机制:从 YAML 到 syslog-ng 语法的配置树
config函数是整个生成能力的核心。它接收一个name(语句 ID 或<statement_type>.<id>形式)和一份已解析的 YAML 结构config,通过_build_config_tree构建内存中的配置树,再经_render_configuration渲染为 syslog-ng 的文本语法(salt/modules/syslog_ng.py#L644-L675)。
从源码看,配置树由一组职责分明的类构成(salt/modules/syslog_ng.py#L92-L398),它们与 syslog-ng 配置语法逐层对应:
| 类 | 对应语法元素 | 典型实例 |
|---|---|---|
Statement/NamedStatement/UnnamedStatement | 语句(statement) | source s_local {...};、log {...};、options {...}; |
GivenStatement | 原样输出的文本片段 | 配置注释、已有配置片段 |
Option | 语句内部的一个选项 | file(...)、tcp(...)、udp(...) |
SimpleParameter/TypedParameter | 选项的参数 | '/var/log/messages'、ip(127.0.0.1) |
SimpleParameterValue/TypedParameterValue | 带类型参数的取值 | ip(0.0.0.0)中的0.0.0.0、tls(key_file(...) cert_file(...)) |
Argument | 类型参数的最内层取值 | key_file的值 |
渲染时由Buildable.build递归调用子对象的build方法,配合模块级的_INDENT/_INDENT_STEP(4 空格缩进)生成层级缩进文本。例如source s_localhost { tcp(ip(127.0.0.1), port(1233)); };的缩进即由此产生。
模块内部的 YAML 解析路径(_parse_statement→_create_and_add_option→_create_and_add_parameters→_parse_typed_parameter/_parse_typed_parameter_typed_value)对配置做了三类识别:
_is_reference:值为字符串的{type: id}形式,解析为对已定义语句的引用(如source: s_localhost);_is_inline_definition:值为列表的单键字典,解析为内联匿名语句(如destination: [file: [...]]);_is_junction:键为junction的字典,按 channel 拆分为多个分支(_add_junction)。
_is_statement_unnamed把log、channel、junction、options判定为无名语句,渲染时不带 ID;其余语句(source、destination、filter、parser、rewrite、template等)则为具名语句。
测试如何验证生成逻辑
仓库中的单元测试(tests/unit/states/test_syslog_ng.py)逐一对各类语句的生成结果做了断言,例如test_generate_source_config验证file(...)源码生成、test_generate_log_config验证带 junction/channel 的 log 路径、test_generate_short_form_statement验证source.s_gsoc短形式;test_generate_given_config验证config.<id>形式的原样文本输出。此外 tests/pytests/unit/modules/test_syslog_ng.py 用 Mock 模拟cmd.run_all,验证version对syslog-ng -V首行syslog-ng 3.6.0alpha0的版本解析、modules对Available-Modules行的提取、config_test对--syntax-only [--cfgfile=...]参数拼装,以及指定 sbin 目录时会把该目录追加进PATH环境变量(_run_command_in_extended_path)。
状态与执行函数参考
syslog_ng.config:生成语句
config(name, config, write=True)要求两个参数:
name:Salt 文档的 ID,或<statement类型>.<id>形式;config:解析后的 YAML 结构;write(可选):为True时写入配置文件,否则只返回生成结果。
write=True时会调用_write_config以追加模式写入__SYSLOG_NG_CONFIG_FILE(默认/etc/syslog-ng.conf);在 test 模式下(__opts__["test"]为真)只返回注释说明将写入的内容而不落盘。返回字典中changes.new携带新生成的配置文本。
CLI 直接调用示例(模块 docstring 给出):
salt '*' syslog_ng.config name='s_local' config="[{'tcp':[{'ip':'127.0.0.1'},{'port':1233}]}]"初始化函数:set_binary_path、set_config_file、set_parameters、write_version
set_binary_path(name):设置syslog-ng与syslog-ng-ctl二进制所在目录。包管理器安装时无需调用;源码安装时必用,例如salt '*' syslog_ng.set_binary_path name=/usr/sbin。set_config_file(name):设置配置文件路径,例如salt '*' syslog_ng.set_config_file name=/etc/syslog-ng。注意模块默认值就是/etc/syslog-ng.conf,且源码演示示例中混用了目录与文件两种写法,实操时应以完整文件路径为准。get_config_file():返回当前配置的配置文件路径。set_parameters(version=None, binary_path=None, config_file=None):一次完成上述设置;其中version参数会调用_determine_config_version从syslog-ng -V输出中解析出形如3.6的大版本号并写入配置。write_version(name):删除旧的配置文件、重建新文件,写入@version: <name>行,并前置一行 Salt 生成的头部注释#Generated by Salt on <时间戳>(__SALT_GENERATED_CONFIG_HEADER)。它依赖_write_config的追加写与os.remove实现「先清空再重建」。
服务控制:start、stop、reload
start(...):带完整参数列表(user、group、chroot、caps、no_caps、pidfile、enable_core、fd_limit、verbose、debug、trace、yydebug、persist_file、control、worker_threads),通过_add_cli_param/_add_boolean_cli_param拼装 CLI 参数,最后总是附加--cfgfile=<__SYSLOG_NG_CONFIG_FILE>;若设置了二进制路径则以os.path.join(__SYSLOG_NG_BINARY_PATH, "syslog-ng")作为命令。测试test_started_state_generate_valid_cli_command验证了started(user="joe", group="users", enable_core=True)生成的命令以syslog-ng --user=joe --group=users --enable-core --cfgfile=/etc/syslog-ng.conf结尾。返回结果中changes.new为完整命令行。stop(name=None):用ps.pgrep(pattern="syslog-ng")找 PID,再用ps.pkill("syslog-ng")结束进程;未运行时报Syslog-ng is not running。reload_(name):执行syslog-ng-ctl reload(设置了二进制路径时用该目录下的syslog-ng-ctl),retcode == 0视为成功。
模块 docstring 明确提示:如果目标系统上有 Salt 的 service 模块可用,服务启停应优先使用 service 模块;这些函数是 service 模块不可用时的替代方案。
诊断函数:config_test、version、modules、stats
config_test(syslog_ng_sbin_dir=None, cfgfile=None):以syslog-ng --syntax-only [--cfgfile=<file>]对配置文件做语法检查,返回retcode/stdout/stderr字典。可用于部署前校验生成的配置。version(syslog_ng_sbin_dir=None):解析syslog-ng -V输出第一行(格式如syslog-ng 3.6.0alpha0),取第二个字段作为版本号返回。modules(syslog_ng_sbin_dir=None):同样读取syslog-ng -V输出,提取Available-Modules行后的模块列表(测试样例为syslogformat,json-plugin,basicfuncs,...等逗号分隔串)。stats(syslog_ng_sbin_dir=None):执行syslog-ng-ctl stats,返回统计输出(测试样例展示了SourceName;SourceId;...分号分隔的统计表格,包含各 source/destination 的 processed 计数)。
这些函数均通过_run_command→__salt__"cmd.run_all"执行,并捕获CommandExecutionError返回retcode=-1。当传入syslog_ng_sbin_dir时,会临时把该目录并入PATH(_run_command_in_extended_path)。
状态模块用法
状态模块(salt/states/syslog_ng.py)是对执行模块的薄封装,提供四个状态函数:
syslog_ng.config(name, config, write=True):生成配置语句;syslog_ng.stopped(name=None):停止 syslog-ng;syslog_ng.started(...):按参数启动 syslog-ng;syslog_ng.reloaded(name):重载配置。
状态模块 docstring 说明:service 模块不可用的系统才需要started/stopped/reloaded;配置生成能力则始终可用。完整的配置生成细节见 syslog-ng 使用教程(下文即其核心内容)。
YAML 配置语法详解
语句的两种声明形式
syslog_ng.config要求name与config两个参数,name决定生成的语句名,config持有 YAML 结构。以下两种形式等价:
短形式(ID 中直接带类型前缀):
source.s_localhost: syslog_ng.config: - config: - tcp: - ip: "127.0.0.1" - port: 1233长形式(config 中显式声明类型):
s_localhost: syslog_ng.config: - config: source: - tcp: - ip: "127.0.0.1" - port: 1233短形式需要更少输入,二者生成完全相同的配置文本。配置内容用列表与字典组合表达,从源码解析逻辑看,列表中的每个字典项都会被_create_and_add_option展开为语句内的一个Option。
引号规则
YAML 与生成配置之间存在引号转义约定(教程原文的规则):
- 若生成的配置中需要
"string"(双引号),YAML 中应写'"string"'; - 若生成的配置中需要
'string'(单引号),YAML 中应写"'string'"。
例如文件路径:
- file: '"/var/log/apache/access.log"'生成结果中的写法因「简单参数 vs 类型参数」而异(见下文示例):作为简单参数时保留引号成为"/var/log/apache/access.log",作为类型参数值(如ip(...)的值)时引号由_is_simple_type判定、按值类型直接输出。字符串'yes'、'no'等也会按此规则输出。
完整实战示例:端到端生成配置
教程给出了一个完整的 SLS 示例,覆盖初始化、全局选项、source/destination/log 与注释写入:
# 设置配置文件位置 set_location: module.run: - name: syslog_ng.set_config_file - m_name: "/home/tibi/install/syslog-ng/etc/syslog-ng.conf" # syslog-ng 与 syslog-ng-ctl 二进制所在目录;若已在 PATH 中则无需此项 set_bin_path: module.run: - name: syslog_ng.set_binary_path - m_name: "/home/tibi/install/syslog-ng/sbin" # 写入文件头几行,同时清空原有内容 write_version: module.run: - name: syslog_ng.write_version - m_name: "3.6" # 更短的写法:一次设置上述变量 set_variables: module.run: - name: syslog_ng.set_parameters - version: "3.6" - binary_path: "/home/tibi/install/syslog-ng/sbin" - config_file: "/home/tibi/install/syslog-ng/etc/syslog-ng.conf" # 全局选项 options.global_options: syslog_ng.config: - config: - time_reap: 30 - mark_freq: 10 - keep_hostname: "yes" source.s_localhost: syslog_ng.config: - config: - tcp: - ip: "127.0.0.1" - port: 1233 destination.d_log_server: syslog_ng.config: - config: - tcp: - "127.0.0.1" - port: 1234 log.l_log_to_central_server: syslog_ng.config: - config: - source: s_localhost - destination: d_log_server some_comment: module.run: - name: syslog_ng.write_config - config: | # Multi line # comment # 另一种写法:把注释/已有片段作为 config 语句 config.other_comment_form: syslog_ng.config: - config: | # Multi line # comment执行后生成的文件(教程原文,含 Salt 生成头部与版本行):
#Generated by Salt on 2014-08-18 00:11:11 @version: 3.6 options { time_reap( 30 ); mark_freq( 10 ); keep_hostname( yes ); }; source s_localhost { tcp( ip( 127.0.0.1 ), port( 1233 ) ); }; destination d_log_server { tcp( 127.0.0.1, port( 1234 ) ); }; log { source( s_localhost ); destination( d_log_server ); }; # Multi line # comment # Multi line # comment注意几点实现细节:
log语句是无名语句,l_log_to_central_server这类 ID 只相当于注释;source/destination的引用写法source: s_localhost被_is_reference识别并渲染为source(s_localhost);。- 注释写入有两种途径:
module.run调write_config(追加原样文本),或config.<name>形式走GivenStatement(_build_config_tree对type_ == "config"分支直接以原样字符串构建)。 - 从
_write_config的实现看,配置以追加模式写入;因此典型的初始化流程是先用write_version清空重建,再逐条追加各语句。
更多语句生成示例(含源码解析佐证)
以下示例取自教程的 Examples 章节,同时对应 tests/unit/states/test_syslog_ng.py 中的测试用例,可对照验证。
简单 source(file)
目标配置:
source s_tail { file( "/var/log/apache/access.log", follow_freq(1), flags(no-parse, validate-utf8) ); };对应 YAML(三种等价写法之一):
s_tail: syslog_ng.config: - config: source: - file: - file: '"/var/log/apache/access.log"' - follow_freq: 1 - flags: - no-parse - validate-utf8复杂 source(tcp + ip/port/flags)
s_gsoc2014: syslog_ng.config: - config: source: - tcp: - ip: 0.0.0.0 - port: 1234 - flags: no-parse生成:
source s_gsoc2014 { tcp( ip("0.0.0.0"), port(1234), flags(no-parse) ); };filter
f_json: syslog_ng.config: - config: filter: - match: - '"@json:"'生成:
filter f_json { match( "@json:" ); };template
t_demo_filetemplate: syslog_ng.config: - config: template: - template: - '"$ISODATE $HOST $MSG\n"' - template_escape: - "no"生成:
template t_demo_filetemplate { template( "$ISODATE $HOST $MSG " ); template_escape( no ); };rewrite
r_set_message_to_MESSAGE: syslog_ng.config: - config: rewrite: - set: - '"${.json.message}"' - value: '"$MESSAGE"'生成:
rewrite r_set_message_to_MESSAGE { set( "${.json.message}", value("$MESSAGE") ); };全局 options
global_options: syslog_ng.config: - config: options: - time_reap: 30 - mark_freq: 10 - keep_hostname: "yes"生成:
options { time_reap(30); mark_freq(10); keep_hostname(yes); };log 路径与 junction 分支
这是最能体现 YAML 表达力的例子——把分支日志处理(JSON 与非 JSON 分流)表达为junction+channel,每个 channel 内再组合 filter/parser/rewrite/destination:
l_gsoc2014: syslog_ng.config: - config: log: - source: s_gsoc2014 - junction: - channel: - filter: f_json - parser: p_json - rewrite: r_set_json_tag - rewrite: r_set_message_to_MESSAGE - destination: - file: - '"/tmp/json-input.log"' - template: t_gsoc2014 - flags: final - channel: - filter: f_not_json - parser: - syslog-parser: [] - rewrite: r_set_syslog_tag - flags: final - destination: - file: - "/tmp/all.log" - template: t_gsoc2014对应生成的目标配置:
log { source(s_gsoc2014); junction { channel { filter(f_json); parser(p_json); rewrite(r_set_json_tag); rewrite(r_set_message_to_MESSAGE); destination { file( "/tmp/json-input.log", template(t_gsoc2014) ); }; flags(final); }; channel { filter(f_not_json); parser { syslog-parser( ); }; rewrite(r_set_syslog_tag); flags(final); }; }; destination { file( "/tmp/all.log", template(t_gsoc2014) ); }; };该示例与测试用例LOG_1_CONFIG/test_generate_log_config完全对应:源码中_parse_log_statement逐项判定引用(source: s_gsoc2014)、junction(键为junction)、内联定义(值为列表的键,如destination下的file),空值列表(syslog-parser: [])则渲染为空参数选项。
版本与二进制路径的处理细节
从源码可以确认几个易踩坑的行为:
set_parameters的version参数并不会直接使用传入值,而是调用_determine_config_version(__SYSLOG_NG_BINARY_PATH)重新解析syslog-ng -V输出:统计前两个.出现的位置截取主版本号(如3.6),失败则取前 3 个字符。因此若二进制路径未设置且syslog-ng不在PATH中,version解析可能失败——设置参数时务必保证路径正确。start在设置了二进制路径时拼接__SYSLOG_NG_BINARY_PATH/syslog-ng,未设置时直接使用syslog-ng;两种情况下__opts__["test"]都为真时只返回「将要启动的命令」而不真正执行。- 所有命令均以
python_shell=False执行,避免 shell 注入;自定义环境变量中PATH会经过salt.utils.stringutils.to_str与salt.utils.data.decode规范化。
小结:一套可落地的 syslog-ng 管理方案
综合教程、执行模块与状态模块源码以及两类单元测试,可以总结出推荐的落地顺序:
- 用
module.run+syslog_ng.set_parameters(或分别set_binary_path+set_config_file)初始化二进制路径与配置文件; - 用
module.run+syslog_ng.write_version清空旧配置并写入@version头; - 依次用
syslog_ng.config(状态形式或短/长 YAML 两种写法)生成options、source、destination、filter、parser、rewrite、template、log(含 junction/channel)等语句; - 用
syslog_ng.write_config或config.<name>追加注释与既有片段; - 部署前用
syslog_ng.config_test做语法校验,用syslog_ng.version/modules/stats诊断实例; - 用
syslog_ng.reloaded/started/stopped控制服务生命周期(系统有 service 模块时优先用 service)。
该模块把 syslog-ng 复杂的文本语法抽象为 YAML 数据驱动,同时保留了「原样文本」逃生通道(config语句与GivenStatement),既适合全量模板化,也适合渐进式迁移存量配置。需要进一步阅读的仓库资源包括:执行模块源码、状态模块源码、官方使用教程、状态单元测试、执行模块单元测试。
- 运维
- 配置管理
- 后端
【免费下载链接】salt
Software to automate the management and configuration of infrastructure and applications at scale.
相关推荐
Salt 执行模块 npm 完全指南:用 SaltStack 自动化管理 NPM 包的生命周期
Salt 执行模块 npm 完全指南:用 SaltStack 自动化管理 NPM 包的生命周期 本指南围绕 Salt 执行模块 npm (源码位于 salt/m
运维配置管理后端Salt 之 win_pki 执行模块:基于 PowerShell PKI 的 Windows 证书全生命周期管理
Salt 之 win_pki 执行模块:基于 PowerShell PKI 的 Windows 证书全生命周期管理 导读 salt.modules.win_pk
运维配置管理后端Salt Windows 服务管理完全指南:win_service 执行模块与 service 状态编排实战
Salt Windows 服务管理完全指南:win_service 执行模块与 service 状态编排实战 导读 Windows 服务(Services)是
运维配置管理后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考