在配置中访问事件数据和字段
Logstash代理是一个包含三个阶段的处理管道:输入 → 过滤 → 输出,输入生成事件,过滤器修改事件,输出将事件发送到其他地方。
所有事件都有属性,例如,apache访问日志包含状态代码(200,404)、请求路径(“/”,“index.html”)、HTTP动作(GET,POST)、客户端IP地址等,Logstash将这些属性称为“字段”。
Logstash中的一些配置选项需要字段的存在来发挥作用,因为输入生成事件,在输入块中没有要衡量的字段 — 他们还不存在!
因为它们依赖于事件和字段,以下配置选项将只在过滤器和输出块中工作。
下面描述的字段引用、sprintf格式和条件在输入块中不起作用。
字段引用
能够通过名称引用字段通常很有用,为此,你可以使用Logstash字段引用语法。
访问字段的语法是[fieldname]
,如果你引用的是顶级字段,你可以省略[]
并简单地使用fieldname
,要引用嵌套字段,需要指定该字段的完整路径:[top-level field][nested field]
。
例如,以下事件有5个顶级字段(agent、ip、request、response、ua)和3个嵌套字段(status、bytes、os)。
{
"agent": "Mozilla/5.0 (compatible; MSIE 9.0)",
"ip": "192.168.24.44",
"request": "/index.html"
"response": {
"status": 200,
"bytes": 52353
},
"ua": {
"os": "Windows 7"
}
}
要引用os
字段,你需要指定[ua][os]
,要引用顶级字段(如request),只需简单的指定字段名。
sprintf格式
字段引用格式也被用在Logstash调用sprintf格式中,这种格式允许你从其他字符串引用字段值,例如,statsd
输出有一个increment
设置,可以根据状态码保存apache日志的计数:
output {
statsd {
increment => "apache.%{[response][status]}"
}
}
类似地,你可以将@timestamp
字段中的时间戳转换为字符串,不是在花括号中指定字段名,而是使用+FORMAT
语法,其中FORMAT
是时间格式。
例如,如果希望使用文件输出根据事件的日期、小时和type
字段写入日志:
output {
file {
path => "/var/log/%{type}.%{+yyyy.MM.dd.HH}"
}
}
条件
有时,你只想在特定条件下过滤或输出事件,为此,你可以使用条件语句。
Logstash中的条件语句的外观和操作方式与编程语言中的相同,条件语句支持if
、else if
和else
语句,并且可以嵌套。
条件语法是:
if EXPRESSION {
...
} else if EXPRESSION {
...
} else {
...
}
表达式是什么?比较测试,布尔逻辑,等等!
你可以使用以下比较运算符:
- 等式:
==
,!=
,<
,>
,<=
,>=
- 正则表达式:
=~
,!~
(检查右边的模式对立左边的字符串值) - 包含:
in
,not in
支持的布尔运算符是:
-
and
,or
,nand
,xor
支持的一元运算符是:
!
表达式可以很长很复杂,表达式可以包含其他表达式,可以用!
来否定表达式,还可以用括号(…)
对它们进行分组。
例如,如果字段action
的值为login
,下面的条件使用mutate过滤器来删除字段secret
:
filter {
if [action] == "login" {
mutate { remove_field => "secret" }
}
}
可以在单个条件中指定多个表达式:
output {
# Send production errors to pagerduty
if [loglevel] == "ERROR" and [deployment] == "production" {
pagerduty {
...
}
}
}
你可以使用in
操作符来测试字段是否包含特定的字符串、键或(对于列表)元素:
filter {
if [foo] in [foobar] {
mutate { add_tag => "field in field" }
}
if [foo] in "foo" {
mutate { add_tag => "field in string" }
}
if "hello" in [greeting] {
mutate { add_tag => "string in field" }
}
if [foo] in ["hello", "world", "foo"] {
mutate { add_tag => "field in list" }
}
if [missing] in [alsomissing] {
mutate { add_tag => "shouldnotexist" }
}
if !("foo" in ["hello", "world"]) {
mutate { add_tag => "shouldexist" }
}
}
你也可以用同样的方式使用not in
条件,例如,当grok成功时,你可以使用not in
只将事件路由到Elasticsearch:
output {
if "_grokparsefailure" not in [tags] {
elasticsearch { ... }
}
}
你可以检查特定字段是否存在,但目前还无法区分不存在的字段和不存在的字段,if [foo]
表达式返回false
时:
- 事件中不存在
[foo]
- 事件中存在
[foo]
,但为false
- 事件中存在
[foo]
,但为null
有关更复杂的示例,请参阅Logstash配置示例。
@metadata字段
在Logstash 1.5和更高版本中,还有一个名为@metadata
的特殊字段,@metadata
的内容在输出时不会是你的任何事件的一部分,这使得它很好地用于条件,或使用字段引用和sprintf格式扩展和构建事件字段。
下面的配置文件将从STDIN生成事件,输入的内容将成为事件中的message
字段,过滤器块中的mutate
事件将添加一些字段,其中一些嵌套在@metadata
字段中。
input { stdin { } }
filter {
mutate { add_field => { "show" => "This data will be in the output" } }
mutate { add_field => { "[@metadata][test]" => "Hello" } }
mutate { add_field => { "[@metadata][no_show]" => "This data will not be in the output" } }
}
output {
if [@metadata][test] == "Hello" {
stdout { codec => rubydebug }
}
}
让我们看看结果是什么:
$ bin/logstash -f ../test.conf
Pipeline main started
asdf
{
"@timestamp" => 2016-06-30T02:42:51.496Z,
"@version" => "1",
"host" => "example.com",
"show" => "This data will be in the output",
"message" => "asdf"
}
输入的“asdf”成为message
字段内容,条件成功地评估了嵌套在@metadata
字段中的test
字段的内容,但是输出没有显示一个名为@metadata
的字段,或者它的内容。
rubydebug
编解码器允许你显示@metadata
字段的内容,如果你添加一个配置标志,metadata => true
:
stdout { codec => rubydebug { metadata => true } }
让我们看看这个更改后的输出是什么样子的:
$ bin/logstash -f ../test.conf
Pipeline main started
asdf
{
"@timestamp" => 2016-06-30T02:46:48.565Z,
"@metadata" => {
"test" => "Hello",
"no_show" => "This data will not be in the output"
},
"@version" => "1",
"host" => "example.com",
"show" => "This data will be in the output",
"message" => "asdf"
}
现在可以看到@metadata
字段及其子字段。
只有rubydebug
编解码器允许显示@metadata
字段的内容。
当你需要一个临时字段但不希望它出现在最终输出中时,请使用@metadata
字段。
也许这个新字段最常见的用例之一是使用date
过滤器并具有一个临时的时间戳。
这个配置文件经过了简化,但是使用了Apache和Nginx web服务器常用的时间戳格式,在过去,你必须自己删除timestamp
字段,然后使用它覆盖@timestamp
字段,对于@metadata
字段,这不再是必要的:
input { stdin { } }
filter {
grok { match => [ "message", "%{HTTPDATE:[@metadata][timestamp]}" ] }
date { match => [ "[@metadata][timestamp]", "dd/MMM/yyyy:HH:mm:ss Z" ] }
}
output {
stdout { codec => rubydebug }
}
注意,在grok
过滤器中的这个配置将提取的日期放入[@metadata][timestamp]
字段中,让我们为这个配置提供一个示例日期字符串,看看会得到什么:
$ bin/logstash -f ../test.conf
Pipeline main started
02/Mar/2014:15:36:43 +0100
{
"@timestamp" => 2014-03-02T14:36:43.000Z,
"@version" => "1",
"host" => "example.com",
"message" => "02/Mar/2014:15:36:43 +0100"
}
就是这样!输出中没有额外的字段,而且配置文件更干净,因为在date
过滤器中进行转换后,不需要删除“ timestamp”字段。
另一个用例是CouchDB更改输入插件(参阅https://github.com/logstash-plugins/logstash-input-couchdb_changes),这个插件自动将CouchDB文档字段元数据捕获到输入插件本身的@metadata
字段中。当事件通过Elasticsearch被索引时,Elasticsearch输出插件允许你指定action
(删除、更新、插入等)和document_id
,如下所示:
output {
elasticsearch {
action => "%{[@metadata][action]}"
document_id => "%{[@metadata][_id]}"
hosts => ["example.com"]
index => "index_name"
protocol => "http"
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。