重写从另一台机器通过 syslog 接收到的日志

重写从另一台机器通过 syslog 接收到的日志

我有一台机器 A,它是 pfsense 安装,它通过 syslog 将日志发送到 Ubuntu 机器。Ubuntu 机器必须重写日志,例如替换主机名并稍微更改格式。

格式一般如下

Mar  7 00:05:32 hostname service: field1 field2 field3 field4 field5 field6 field7

我希望可以重写主机名、服务和更改字段的顺序,并过滤掉某个字段中具有某个值的消息,因为它们并不有趣。

经过过滤和处理后,消息应被写入磁盘的日志文件中,并通过 syslog 发送到另一台机器。

现在,日志记录部分很简单 - 只需设置 rsyslogd 来接受传入消息并转发它们。但是,我在重写部分有点卡住了。我并不依赖 rsyslogd;任何类似 syslog 的守护进程都可以。

答案1

这个问题有点模糊,但我会尝试提出一个可能的解决方案。重写消息rsyslog提供了许多模块,其中之一是mmfields. 它会根据某个字符分割传入的消息(仅字符)字段然后允许访问这些字段。对于类似这样的消息

a=1 b=two c=3 d=four

分隔符将为空白,然后可以通过、、和访问字段。不幸的是,第一个字段 ( ) 始终为空,因为消息前面有一个空格,而这将是第一个字段。因此,对于上述消息,我们得到、 、、和。$!f2$!f3$!f4$!f5$!f1$!f1==""$!f2=="a=1"$!f3=="b=two"$!f4=="c=3"$!f5=="d=four"

rsyslog与其他船舶消息修改模块也是,但由于缺乏进一步的细节,我选择了这个。将以下文件存储为/etc/rsyslog.d/10-so.conf。根据所需的执行顺序更改名称,但保留.conf扩展名。

# Load the "Message Modification" module "mmfields" to split
# incoming messages into fields at a certain separator:
module(load="mmfields")

# Format used for messages that are forwarded to another host.
# The fields are re-ordered and field #3 is omitted.
template(name="rewrite_forward" type="list") {
    constant(value="<")
    property(name="pri")
    constant(value=">")
    property(name="timestamp" dateFormat="rfc3339")
    constant(value=" ")
    property(name="hostname")
    constant(value=" ")
    property(name="syslogtag")
    constant(value=" ")
    property(name="$!f4")
    constant(value=" ")
    property(name="$!f2")
    constant(value=" ")
    property(name="$!f5")
}

# Format used for messages that are written to a local logfile.
# The format is almost the same as above, but lacks the priority,
# uses a different timestamp format, and ends with a "\n" as this
# is suitable for messages printed to a logfile.
template(name="rewrite_file" type="list") {
    property(name="timestamp")
    constant(value=" ")
    property(name="hostname")
    constant(value=" ")
    property(name="syslogtag")
    constant(value=" ")
    property(name="$!f4")
    constant(value=" ")
    property(name="$!f2")
    constant(value=" ")
    property(name="$!f5")
    constant(value="\n")
}

if ( $programname == "so" ) then {

    # split message into fields at (exactly) one space character.
    # The "fields" can then be referred to as "$!f1", "$!f2", ..., "$!fN".
    # Note that "$!f1" will always be an empty string because the message
    # usually starts with a blank and that is considered to be the first
    # field. 
    action( type="mmfields" 
            separator=" " 
    )

    # If the second field is the string "b=2", then go ahead and log and
    # forward the message. Change the condition to your liking.
    if ($!f3 == "b=2") then {

        # write rewritten logmessage to local file
        action( type     = "omfile"
                file     = "/var/log/so-rewrite-fields.log"
                template = "rewrite_file"
        )

        # just for reference: write the unmodified message to the
        # very same logfile. Drop this for actual processing. It 
        # serves just as a debugging aid.
        action( type = "omfile"
                file = "/var/log/so-rewrite-fields.log"
        )

        # forward rewritten message to another host
        action( type = "omfwd"  
                target   = "127.0.0.1"  # change to actual destination
                port     = "514"        # change to actual destination
                protocol = "udp"        # change to actual destination
                template = "rewrite_forward"
        )

    }

    # no further processing:
    stop
}

重新启动rsyslog(通过sudo systemctl restart rsyslog.service)并尝试:

# A message that won't be logged because `$!f3 != "b=2"`:
logger -t so --id=$$ "a=1 b=3 txt=Hello number=$RANDOM"

# A message that will be logged because `$!f3 == "b=2"`:
logger -t so --id=$$ "a=1 b=2 txt=Hello number=$RANDOM"

第二条语句的输出logger将是:

Mar 14 21:40:34 stratum9 so[3533]: txt=Hello a=1 number=6484        # rewritten msg
Mar 14 21:40:34 stratum9 so[3533]: a=1 b=2 txt=Hello number=6484    # original msg

要更改主机名,只需替换

constant(value=" ")
property(name="hostname")
constant(value=" ")

在模板中

constant(value=" fromElsewhere ")

要更改 syslogtag(你所说的服务), 代替

    constant(value=" ")
    property(name="syslogtag")
    constant(value=" ")

constant(value=" otherService: ")

输出将是:

Mar 14 22:05:51 fromElsewhere otherService: txt=Hello a=1 number=11763   # rewritten
Mar 14 22:05:51 stratum9 so[3533]: a=1 b=2 txt=Hello number=11763       # original

这里了解更多消息属性。

请注意我的方法(mmfields) 依赖于字段始终具有相同的顺序,并且不容易允许重写消息,例如a=1 b=2b=1 a=2重新排序和更改键值对)。为此,另一个模块可能更合适。

答案2

据我所知,这可以通过使用 logstash elasticsearch 和 Kibana 来实现。我正在尝试做同样的事情,并且通过设置 elk stack 或多或少取得了成功。然后使用 logstash 中的 grok 过滤器将系统日志消息分解为不同的字段,并使用这些字段匹配模式并发送警报。看看这个指导它可能会给你一些关于从哪里开始的答案。

这种设置已经内置了针对 mysql 日志、apache 或 nginx 日志等内容的过滤器。下面是好的概述elk stack 的功能和架构。希望这对您有所帮助。

相关内容