如何将消息记录到通用(更改)文件

时间:2014-03-27 15:48:33

标签: python logging multiprocessing logstash rsyslog

这个问题类似于未答复的rsyslog specific question on Server Fault。我不清楚最好的解决方案是通过已有的软件,如rsyslog或logstash,还是我必须自己构建一些东西。这就是我在这里问的原因。

问题

我有几个并行运行的python进程(由多处理处理)。他们构建需要写入该组的同一日志文件的组。从多个进程记录到同一个文件必须经过某种序列化以避免文件损坏,因此可以想到rsyslog或logstash。

我没有找到的(对于rsyslog和logstash都没有)是如何过滤包含我事先不知道的文件名的字段(或标记或在该系统中可能被调用的任何内容) (包含我无法控制的版本号)并将这些消息写入对应文件。

所以,我知道如何使用动态输出的静态输入滤波器。但我不知道动态输入和动态输出是如何完成的。

我最喜欢的幻想解决方案

在Python应用程序中:

  • 创建一个自定义格式化程序,用于添加包含目标日志文件名称的字段(例如rsyslog的syslogtag)

  • 添加SyslogHandler或与我的记录器类似的东西。

在rsyslog或logstash config中添加类似

的规则
<config of some logging system>
[filterfor] <field> -> write messages containing <value of field> to logfile /path/to/logs/<value of field>.log

进行。

问题

是否可以开箱即用或(在logstash中)使用(尚未编写)插件?

编辑:也许一个例子可以澄清我在寻找什么。

示例日志消息,其中目标在括号中为exapmle:

<group_a> Message that will end up only in "group_a.log"
<group_a> Another Message for "group_a.log"
<group_b> Some interesting message for "group_b.log"
<group_c> Message for "group_c.log"

这些基于匹配名称的消息将最终出现在相应的日志文件中。对于上面的示例,包含其内容的日志文件将是:

/var/log/group_logs/group_a.log
   <group_a> Message that will end up only in "group_a.log"
   <group_a> Another Message for "group_a.log"

/var/log/group_logs/group_b.log
<group_b> Some interesting message for "group_b.log"

/var/log/group_logs/group_c.log
   <group_c> Message for "group_c.log"

因此它可以像正则表达式一样将匹配的名称保存在一个组中,并将其用作文件的名称。

2 个答案:

答案 0 :(得分:1)

以下解决方案适用于logstash(无需插件)。

我将每个流程输出到一个单独的文件,比如/path/logs/process-<unique-process-specific-id>.log。该文件将包含如下行:

<group> <rest of line>

然后你可以使用这个配置:

input {
  file {
    path => "/path/logs/process-*.log"
    start_position => beginning
  }
}

filter {
  grok {
    match => { "message" => "\A(?<group>[^ ]++) (?<rest>.*+)\z" }
  }
}

output {
  file {
    path => "/path/logs/group-%{group}.log"
    message_format => "%{rest}"
  }
}

因此,如果一个进程正在向/path/logs/process-foobar.log写一行,如下所示:

groupA Hello world!

..然后这会生成一个包含内容

的日志文件/path/logs/group-groupA.log
Hello world!

答案 1 :(得分:1)

rsyslog的工作解决方案如下:

  1. 所有日志消息都包含由(任意)开始和结束分隔符分隔的目标文件名的名称。它们必须只包含文件名(在这种情况下,我们使用 [[作为开始和]] 作为结束分隔符)
  2. 将日志消息发送到local0工具,以将其与其他消息分开。
  3. rsyslog配置中的重要部分是:

    $template debugFile,"/var/log/%msg:R,ERE,1,DFLT:\[\[(.*)\]\]--end%.log"
    

    通过正则表达式从消息生成日志文件的绝对路径 - rsyslog团队提供的Regular Expression Checker/Generator在这里可能会有所帮助。

    $template rawFormat,"%msg%\n"
    

    输出模板仅包含原始日志消息(主要是装饰性的)。

    local0.* ?debugFile;rawFormat
    

    将此模板和格式用于发送到local0工具的所有日志。