日志切分处理

Loggie可使用normalize interceptor来进行日志的切分和处理,将日志数据进行结构化的提取,同时可以对提取后的字段进行处理。
建议先了解Loggie内部日志数据schema设计

需求场景

最主要的是对日志进行切分解析提取和处理。

比如以下日志:

  1. 01-Dec-2021 03:13:58.298 INFO [main] Starting service [Catalina]

我们可能会需要将其中的日期、日志级别解析出来,最终形成:

  1. {
  2. "time": "01-Dec-2021 03:13:58.298",
  3. "level": "INFO",
  4. "message": "[main] Starting service [Catalina]"
  5. }

这种结构化的数据,存储的时候便于过滤查询,或者根据日志里的时间来排序,而不是采集的时间戳,或者根据日志级别进行一些过滤,可以方便查询到ERROR级别的日志等等。
当然不仅仅是像以上tomcat的运维类日志,还有诸如业务的一些订单等等日志,都有类似的需求和使用场景。

功能

目前已经支持的功能有:

  • regex: 正则切分提取日志
  • jsonDecode: 解析提取json格式的日志
  • split: 通过分隔符来提取日志
  • add/rename/drop/copy/underRoot指定字段
  • convert类型转换
  • timestamp: 转换指定字段的时间格式

normalize可以配置内部的processor顺序执行。

配置示例

日志切分处理在Loggie Agent端或者Loggie中转机侧均可,取决于我们是否需要中转机,以及希望日志处理这种CPU密集型的计算是分布在Agent上,由各个节点承担,还是希望在中转机集群中集中进行。

下面以采集tomcat服务的标准输出和access日志为例,展示如何对标准输出格式进行处理和access日志进行字段切分。

简单起见,示例使用CRD实例配置下发在Agent,同时使用dev sink直接输出处理结果展示。

sink

创建如下的sink用于演示,将采集处理后的日志打印在所属节点Loggie的日志中。

Example

  1. apiVersion: loggie.io/v1beta1
  2. kind: Sink
  3. metadata:
  4. name: default
  5. spec:
  6. sink: |
  7. type: dev
  8. printEvents: true
  9. codec:
  10. type: json
  11. pretty: true

interceptor

根据实际环境创建如下的interceptor。

Example

docker

  1. apiVersion: loggie.io/v1beta1
  2. kind: Interceptor
  3. metadata:
  4. name: tomcat
  5. spec:
  6. interceptors: |
  7. - type: normalize
  8. name: stdproc
  9. belongTo: ["stdout"]
  10. processors:
  11. - jsonDecode: ~
  12. - drop:
  13. targets: ["stream", "time", "body"]
  14. - rename:
  15. convert:
  16. - from: "log"
  17. to: "message"
  18. - type: normalize
  19. name: accproc
  20. belongTo: ["access"]
  21. processors:
  22. - regex:
  23. pattern: '(?<ip>\S+) (?<id>\S+) (?<u>\S+) (?<time>\[.*?\]) (?<url>\".*?\") (?<status>\S+) (?<size>\S+)'

containerd

  1. apiVersion: loggie.io/v1beta1
  2. kind: Interceptor
  3. metadata:
  4. name: tomcat
  5. spec:
  6. interceptors: |
  7. - type: normalize
  8. name: stdproc
  9. belongTo: ["stdout"]
  10. processors:
  11. - split:
  12. separator: ' '
  13. max: 4
  14. keys: ["time", "std", "F", "message"]
  15. - drop:
  16. targets: ["time", "std", "F", "body"]
  17. - type: normalize
  18. name: accproc
  19. belongTo: ["access"]
  20. processors:
  21. - regex:
  22. pattern: '(?<ip>\S+) (?<id>\S+) (?<u>\S+) (?<time>\[.*?\]) (?<url>\".*?\") (?<status>\S+) (?<size>\S+)'

如果使用docker运行时,默认采集的标准输出为json格式。
类似:

  1. {
  2. "log":"I0610 08:29:07.698664 Waiting for caches to sync\n",
  3. "stream":"stderr",
  4. "time":"2021-06-10T08:29:07.698731204Z"
  5. }

我们需要将json格式的原始日志解析,一般还需要drop streamtime字段,并将其中的log字段key改为和其他格式一致的body或者message

使用filesource采集后,在Loggie里的原始格式为:

  1. "body": '"log":"I0610 08:29:07.698664 Waiting for caches to sync\n","stream":"stderr", "time":"2021-06-10T08:29:07.698731204Z"'
  2. ...

可在normalize interceptors里,配置以下processor:

  1. jsonDecode:
    解析并提取字段,将Loggie里存储的日志格式变成:

    1. "body": '"log":"I0610 08:29:07.698664 Waiting for caches to sync\n","stream":"stderr", "time":"2021-06-10T08:29:07.698731204Z"'
    2. "log": "I0610 08:29:07.698664 Waiting for caches to sync\n"
    3. "stream":"stderr"
    4. "time":"2021-06-10T08:29:07.698731204Z"
    5. ...
  2. drop:
    bodystreamtime丢弃。(body为内置字段表示原始日志数据,仅能丢弃,不能修改)

  3. rename:
    log改名为统一的字段比如message

最终发送的日志格式变成:

  1. "message": "I0610 08:29:07.698664 Waiting for caches to sync\n"
  2. ...

在runtime为containerd时,原始日志如下所示:

  1. 2021-12-01T03:13:58.298476921Z stderr F INFO [main] Starting service [Catalina]

会默认加上类似2021-12-01T03:13:58.298476921Z stderr F的前缀,一般我们并不需要这个日志,发送的时候只保留后面数据。
和docker的方式类似,我们可以配置split等方式来切分处理。

另外,由于stdout的日志和access日志格式不一样,所以使用了两个不同的normalize interceptor,配置了不同的processor,需要添加name来区分。
最重要的是,这里使用了belongTo指定关联的source,让stdout日志和access日志分别采用不同的处理逻辑。

logconfig

配置source如下所示:

Example

  1. apiVersion: loggie.io/v1beta1
  2. kind: LogConfig
  3. metadata:
  4. name: tomcat
  5. namespace: default
  6. spec:
  7. selector:
  8. labelSelector:
  9. app: tomcat
  10. type: pod
  11. pipeline:
  12. interceptorRef: tomcat
  13. sinkRef: dev
  14. sources: |
  15. - type: file
  16. name: stdout
  17. paths:
  18. - stdout
  19. - type: file
  20. name: access
  21. paths:
  22. - /usr/local/tomcat/logs/localhost_access_log.*.txt

注意这里的source.name和上面interceptor配置的belongTo需要关联上。

创建完以上的cr后,便可以采集指定的Pod日志,并进行切分处理。