• Elasticsearch:从 Elastic Stack 中的时间戳谈开去


    时间戳,也就是 timestamp, 它在许多的事件中,特别是时序数据中是一个不可少的字段。它记录事件或文档的时间。在我们对数据可视化时,也是非常重要的一个字段。针对时序时间,在我们对数据创建 index patterns 或者 date views 时,我们需要选择时间戳的字段。由于 @ 符号的排序比较靠前,所以通常 timestamp 的字段名称被定义为 @timestamp,这样在我们的 Kibana 可视化中,我们永远可以看到 @timestamp 处于列表的前段,无论你有多少个字段:

    在今天的文章中,我特别地来讲述一下 @timestamp 这个字段。

    把一个时间字段变成为 @timestamp 字段 

    在许多的事件中,结构化后的时间字段的名称并不是 @timestamp,而是 timestamp,或者 DOB (date of birth)等这样的字段名称。为了能够使得一下 dashboard 或可视化能够正常地显示我们的数据,我们一种解决方案就是把这些字段的只转化到 @timestamp 这个字段上。在我之前的文章 “Logstash:Logstash 入门教程 (二)” 就有一个使用案例。我们创建如下的 Logstash 配置文件:

    weblog.conf

    1. input {
    2. tcp {
    3. port => 9900
    4. }
    5. }
    6. filter {
    7. grok {
    8. match => { "message" => "%{COMBINEDAPACHELOG}" }
    9. }
    10. mutate {
    11. convert => {
    12. "bytes" => "integer"
    13. }
    14. }
    15. geoip {
    16. source => "[source][address]"
    17. target => "geoip"
    18. }
    19. useragent {
    20. source => "agent"
    21. target => "useragent"
    22. }
    23. }
    24. output {
    25. stdout { }
    26. }

    请注意这个是针对 Elastic Stack 8.x 的配置。针对 Elastic Stack 7.x 的配置如下:

    1. input {
    2. tcp {
    3. port => 9900
    4. }
    5. }
    6. filter {
    7. grok {
    8. match => { "message" => "%{COMBINEDAPACHELOG}" }
    9. }
    10. geoip {
    11. source => "clientip"
    12. }
    13. useragent {
    14. source => "agent"
    15. target => "useragent"
    16. }
    17. }
    18. output {
    19. stdout { }
    20. }

    我们按照如下的方法来启动 Logstash:

    1. $ pwd
    2. /Users/liuxg/elastic/logstash-8.3.3
    3. $ ./bin/logstash -f weblog.conf

    然后,我们在另外一个 terminal 中打入如下的命令:

    head -n 1 weblog-sample.log | nc localhost 9900
    1. $ pwd
    2. /Users/liuxg/demos/logstash
    3. $ ls weblog-sample.log
    4. weblog-sample.log
    5. $ head -n 1 weblog-sample.log | nc localhost 9900

    我们可以看到如下的输出:

    显然在上面有两个时间戳:timestamp 及 @timestamp。它们表达的意思是不一样的。我们希望的是 @timestamp 时间是事件发生的时间,也就是 timestamp 所表达的时间。在这个时候,我们可以使用 date 过滤器来完成:

    weblog.conf

    1. input {
    2. tcp {
    3. port => 9900
    4. }
    5. }
    6. filter {
    7. grok {
    8. match => { "message" => "%{COMBINEDAPACHELOG}" }
    9. }
    10. mutate {
    11. convert => {
    12. "bytes" => "integer"
    13. }
    14. }
    15. geoip {
    16. source => "[source][address]"
    17. target => "geoip"
    18. }
    19. useragent {
    20. source => "agent"
    21. target => "useragent"
    22. }
    23. date {
    24. match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
    25. }
    26. }
    27. output {
    28. stdout { }
    29. }

    我们重新运行一下 Logstash。这次我们发现:

    由于添加了 date 过滤器,所以 timestamp 及 @timestamp 现在是一致的了。

    为时间添加时间戳

    针对一些事件由于一些原因,可能在日志本身中不含有时间戳这些字段。我们可以使用 Beats 或者 client API 的方式采集数据。如果我们想针对这些事件添加时间戳,我们可以通过添加事件采集时的时间为时间的时间。我们可以通过 ingest pipeline 的元数据来进行添加。比如,我们先创建一个如下的 pipeline:

    1. PUT _ingest/pipeline/add-timestamp
    2. {
    3. "processors": [
    4. {
    5. "set": {
    6. "field": "@timestamp",
    7. "value": "{{_ingest.timestamp}}"
    8. }
    9. }
    10. ]
    11. }

    然后我们可以通过如下的方式来进行写入文档:

    1. PUT my-index/_doc/1?pipeline=add-timestamp
    2. {
    3. "event": "This is xiaoguo from Elastic"
    4. }

    我们通过如下的方式来进行查看:

    GET my-index/_search

     

    1. {
    2. "took": 0,
    3. "timed_out": false,
    4. "_shards": {
    5. "total": 1,
    6. "successful": 1,
    7. "skipped": 0,
    8. "failed": 0
    9. },
    10. "hits": {
    11. "total": {
    12. "value": 1,
    13. "relation": "eq"
    14. },
    15. "max_score": 1,
    16. "hits": [
    17. {
    18. "_index": "my-index",
    19. "_id": "1",
    20. "_score": 1,
    21. "_source": {
    22. "@timestamp": "2022-08-11T07:01:53.400148840Z",
    23. "event": "This is xiaoguo from Elastic"
    24. }
    25. }
    26. ]
    27. }
    28. }

    我们可以看到一条被添加的字段叫做 @timestamp,而它的时间就是 ingest pipeline 被调用的时间。

    在上面,我们看到 Logstash 中的 date 过滤器,可以把我们的一个时间戳字段的内容复制到 @timestamp 这个字段。事实上,date processor 也可以做同样的事情。我们使用如下的例子:

    1. PUT my-index/_doc/1?pipeline=add-timestamp
    2. {
    3. "event": "This is xiaoguo from Elastic",
    4. "@timestamp": "2012-12-05"
    5. }

    在上面,我们添加一个叫做 @timestamp 的字段。执行完上面的命令后,我们可以看到如下的内容被写入到 Elasticsearch 文档中:

    GET my-index/_search?filter_path=hits.hits._source
    1. {
    2. "hits": {
    3. "hits": [
    4. {
    5. "_source": {
    6. "@timestamp": "2022-08-11T07:08:46.191688712Z",
    7. "DOB": "2012-12-05",
    8. "event": "This is xiaoguo from Elastic"
    9. }
    10. }
    11. ]
    12. }
    13. }

    很显然上面的 @timestamp 是 ingest pipeline 调用时的时间。这个在我们的时间使用中,可能不是我们需要的。我们更希望上面的 DOB(date of birth)的时间成为我们的时间戳的时间。我们可以借助于 date processor。我们对 pipeline 进行重新修改:

    1. PUT _ingest/pipeline/add-timestamp
    2. {
    3. "processors": [
    4. {
    5. "set": {
    6. "field": "@timestamp",
    7. "value": "{{_ingest.timestamp}}"
    8. }
    9. },
    10. {
    11. "date": {
    12. "field": "DOB",
    13. "formats": ["yyyy-MM-dd"]
    14. }
    15. }
    16. ]
    17. }

    我们再次执行上面的写入命令:

    1. PUT my-index/_doc/1?pipeline=add-timestamp
    2. {
    3. "event": "This is xiaoguo from Elastic",
    4. "DOB": "2012-12-05"
    5. }

    我们做如下的查询:

    GET my-index/_search?filter_path=hits.hits._source
    1. {
    2. "hits": {
    3. "hits": [
    4. {
    5. "_source": {
    6. "@timestamp": "2012-12-05T00:00:00.000Z",
    7. "DOB": "2012-12-05",
    8. "event": "This is xiaoguo from Elastic"
    9. }
    10. }
    11. ]
    12. }
    13. }

    很显然,这次的 @timestamp 和 DOB 两个字段的时间是一致的,尽管在之前的 set processor 中我们把它设置为 ingest pipeline 执行的时间。

    时间格式转换

    在我的一个私信中,有个开发者问我如何把不同时间格式的字段统一起来,这样显得好看一些。目前看来,Logstash 的 date 过滤器没有这个功能,但是 date processor 倒是有一个输出格式的定义。我们尝试如下的方法:

    1. PUT _ingest/pipeline/add-timestamp
    2. {
    3. "processors": [
    4. {
    5. "date": {
    6. "field": "DOB",
    7. "formats": [
    8. "strict_date_optional_time_nanos"
    9. ],
    10. "output_format": "yyyy-MM-dd"
    11. }
    12. }
    13. ]
    14. }
    15. PUT my-index/_doc/1?pipeline=add-timestamp
    16. {
    17. "event": "This is xiaoguo from Elastic",
    18. "DOB": "2099-05-05T16:21:15.000000Z"
    19. }

    在上面,我们创建了一个 pipeline,并写入一个文档。我们希望的时间格式是:

    GET my-index/_search?filter_path=hits.hits._source
    1. {
    2. "hits": {
    3. "hits": [
    4. {
    5. "_source": {
    6. "@timestamp": "2099-05-05",
    7. "DOB": "2099-05-05T16:21:15.000000Z",
    8. "event": "This is xiaoguo from Elastic"
    9. }
    10. }
    11. ]
    12. }
    13. }

    我们也可以选择不同格式,比如:

    1. PUT _ingest/pipeline/add-timestamp
    2. {
    3. "processors": [
    4. {
    5. "date": {
    6. "field": "DOB",
    7. "formats": [
    8. "strict_date_optional_time_nanos"
    9. ],
    10. "output_format": "basic_date"
    11. }
    12. }
    13. ]
    14. }

    在上面,basic_date 及 strict_date_optional_time_nanos 可以在地址找到它们的定义。运行完上面的 pipeline后,我们再次写入文档:

    1. PUT my-index/_doc/1?pipeline=add-timestamp
    2. {
    3. "event": "This is xiaoguo from Elastic",
    4. "DOB": "2099-05-05T16:21:15.000000Z"
    5. }

    我们得到如下的结果:

    1. {
    2. "hits": {
    3. "hits": [
    4. {
    5. "_source": {
    6. "@timestamp": "20990505",
    7. "DOB": "2099-05-05T16:21:15.000000Z",
    8. "event": "This is xiaoguo from Elastic"
    9. }
    10. }
    11. ]
    12. }
    13. }
  • 相关阅读:
    web前端面试高频考点——Vue组件间的通信及高级特性(多种组件间的通信、自定义v-model、nextTick、插槽)
    JavaScript的懒加载处理
    图像处理入门:从平滑到面积测量的C++实践指南
    Au NPs/FA/PAMAM-DOX 金纳米粒子/叶酸/聚酰胺-胺型树枝状高分子修饰阿霉素的研究
    Prometheus + grafana 的监控平台部署
    强缓存和协商缓存
    CPP 核心编程4-重载递增运算符
    dubbo是如何实现可扩展的?(二)
    ZYNQ实验--裸机程序固化
    Auto.js 清除指定应用缓存
  • 原文地址:https://blog.csdn.net/UbuntuTouch/article/details/126282040