7.5. 使用名称的 Pipe 替换日志文件
许多管理员想要通过日志数据进行一些特殊配置或操作,例如配置日志以仅记录特定事件。这无法使用标准的 Directory 服务器日志文件配置文件属性,但通过将日志数据发送到命名管道,然后使用另一个脚本来处理数据。对日志使用命名管道简化了这些特殊任务,如下所示:
- 记录某些事件,如来自特定用户或 IP 地址的绑定尝试或连接失败
- 与特定正则表达式模式匹配的日志记录条目
- 将日志保持到特定的长度(仅限最后的几行)
- 在事件发生时发送通知(如电子邮件)
使用管道替换日志文件可提高性能,特别是对于具有高操作率的服务器。
命名管道与使用脚本从日志中提取数据,因为日志缓冲区中如何处理数据。
如果日志缓冲了,服务器性能很好,但重要的数据不会在事件发生后马上写入磁盘(日志文件)。如果服务器崩溃出现问题,则在将数据写入磁盘之前,它可能会在数据写入磁盘前崩溃 - 也没有用于提取脚本的数据。
如果没有缓冲日志[1]写入操作会在磁盘中清除到磁盘,从而导致大量磁盘 I/O 和性能下降。
使用管道替换日志磁盘文件具有缓冲优势,因为管道读取的脚本可以将内存中传入的日志数据(通过简单脚本无法缓冲)。
第 9.4 节 “ds-logpipe.py” 中涵盖了脚本的用法和选项详情。基本格式为: ds-logpipe.py
/path/to/named_pipe--userpipe_user--maxlinesnumber--serverpidfilefile.pid--serverpidPID--servertimeout --plugin=/path/to/plugin.pypluginfile.arg=value
7.5.1. 使用 Named Pipe 进行日志记录
Directory 服务器实例可以通过运行命名管道日志脚本并提供管道的名称,即可将命名管道用于其日志记录。(如果服务器已在运行,则必须重新打开日志,但不需要配置。)
# ds-logpipe.py /var/log/dirsrv/slapd-example/access
以这种方式运行 ds-logpipe.py
具有简单且不需要更改目录服务器配置的优点。这可用于快速调试或监控,特别是在查找特定类型的事件时。
如果 Directory 服务器实例经常或永久使用命名的管道而不是记录一个真实文件,那么可以重新配置实例以创建管道并将其用于记录(与日志文件默认这样做)。
需要为实例配置配置三个内容:
-
要使用的日志文件必须改为管道(
nsslapd-*log
,其中 * 可访问、错误或审核)[2],根据所配置的日志类型而定。 -
应禁用缓冲,因为脚本已经缓冲了日志条目(
nsslapd-*log-logbuffering
) -
日志轮转应该被禁用,因此服务器不会尝试轮转命名管道(
nsslapd-*log-maxlogsperdir
、nsslapd-*log-logpirationtime
、nsslapd-*log-logrotation
)
这些配置更改可以在 Directory Server 控制台中或使用 ldapmodify
进行。
例如,这会切换日志 来访问。pipe
:
# ldapmodify -D "cn=Directory Manager" -W -p 389 -h server.example.com -x
dn: cn=config
changetype: modify
replace: nsslapd-accesslog
nsslapd-accesslog: /var/log/dirsrv/slapd-instance/access.pipe
-
replace: nsslapd-accesslog-logbuffering
nsslapd-accesslog-logbuffering: off
-
replace: nsslapd-accesslog-maxlogsperdir
nsslapd-accesslog-maxlogsperdir: 1
-
replace: nsslapd-accesslog-logexpirationtime
nsslapd-accesslog-logexpirationtime: -1
-
replace: nsslapd-accesslog-logrotationtime
nsslapd-accesslog-logrotationtime: -1
进行这些更改可让服务器关闭当前日志文件并立即切换到命名管道。这对调试正在运行的服务器以及特定消息的日志输出非常有用。
7.5.2. 使用服务器启动 Named Pipe
命名的管道可以通过编辑实例的 init 脚本配置文件来启动和关闭 Directory Server 实例。
命名 pipe 脚本必须在实例的 dse.ldif
文件中特别配置,然后才能在服务器启动时调用。
打开服务器系统的实例配置文件。
/etc/sysconfig/dirsrv-instance_name
警告不要编辑
/etc/sysconfig/dirsrv
文件。在文件的末尾,会有一个包含以下内容的行:
# Put custom instance specific settings below here.
在该行的下面,插入
ds-logpipe.py
命令以在服务器启动时启动。例如:# only keep the last 1000 lines of the error log python /usr/bin/ds-logpipe.py /var/log/dirsrv/slapd-example/errors.pipe -m 1000 -u dirsrv -s /var/run/dirsrv/slapd-example.pid > /var/log/dirsrv/slapd-example/errors & # only log failed binds python /usr/bin/ds-logpipe.py /var/log/dirsrv/slapd-example/access.pipe -u dirsrv -s /var/run/dirsrv/slapd-example.pid --plugin=/usr/share/dirsrv/data/failedbinds.py failedbinds.logfile=/var/log/dirsrv/slapd-example/access.failedbinds &
注意-s
选项指定要将其 PID 写入的 .pid 文件,并将脚本设置为在服务器进程启动和停止。
7.5.3. 使用带有 Named Pipe Log 的插件
可以调用插件来从命名管道读取日志数据,并在其上执行一些操作。使用带有命名 pipe log 脚本的插件有一些注意事项:
- 对于从命名管道读取的每一行调用插件函数。
-
插件功能必须是 Python 脚本,且必须以
.py
结尾。 - 所有插件参数都会在命令行中传递给命名 pipe log 脚本。
- 可以针对加载插件时指定预协作功能。
- 可以为脚本退出时调用 post-operation 功能。
7.5.3.1. 使用 Named Pipe Log Script 载入插件
有两个选项 ds-logpipe.py
用于插件:
-
plugin
选项提供插件文件的路径(必须是 Python 脚本,且必须以.py
结尾)。 -
plugin.arg 选项将插件参数传递给命名的管道日志脚本。插件文件名(没有
.py
扩展名)是 插件,且插件中允许的任何参数都可以是 arg。
例如:
ds-logpipe.py /var/log/dirsrc/slapd-example/errors.pipe --plugin=/usr/share/dirsrv/data/example-funct.py example-funct.regex="warning"
> warnings.txt
如果为同一参数传递多个值,则它们将转换为插件字典中的值列表。例如,此脚本为 arg1
提供两个值:
--plugin=/path/to/pluginname.py pluginname.arg1=foo pluginname.arg1=bar pluginname.arg2=baz
在插件中,这会转换为:
{'arg1': ['foo', 'bar'], 'arg2': 'baz'}
这是一个 Python 字典
对象,具有两个键。第一个键是字符串 arg1
,其值是一个 Python 列表对象,它包含两个元素,即字符串 foo
和 bar
。第二个键是字符串 arg2
,其值是字符串 baz
。如果参数只有一个值,它将保留为简单字符串。单个参数名称的多个值将转换为字符串列表。
7.5.3.2. 写入插件以用于 Named Pipe 日志转发脚本
ds-logpipe.py
命令需要最多有三个插件: 插件()、
pre()
和 post
()。
任何与 ds-logpipe.py
命令一起使用的插件都必须指定 插件
功能。
插件()
功能针对日志数据中的每一行执行,而在脚本启动和停止时 预()
和 post()
函数将运行。
每个函数都可以定义任何参数,然后使用 plugin.arg 选项将这些参数传递给脚本。另外,每个函数都可以自行定义返回值和操作。
例 7.8. 简单 Named Pipe Log Plug-in
def pre(myargs): retval = True myarg = myargs['argname'] if isinstance(myarg, list): # handle list of values else: # handle single value if bad_problem: retval = False return retval def plugin(line): retval = True # do something with line if something_is_bogus: retval = False return retval def post(): # no arguments # do something # no return value