天天看点

OpenTelemetry Log规范解读前言初衷&宗旨日志架构演进特性字段类型LogModel定义LogModel示例总结参考

前言

OpenTelemetry作为目前可观察性的标准方案,近年来的发展速度非常快,目前OpenTelemetry Trace规范v1.0版本已经发布,Metrics v1.0也将在几个月后发布。相对最慢的当属Log规范,但在众多公司的参与下,Log规范的第一个版本已经在半年前发布,且经过了几次更新,也在朝着v1.0的方向快速前进。

本文主要介绍OpenTelemetry Log规范,这一规范来自于Google、Microsoft、AWS、Splunk、DataDog、ES、Fluntd等众多优秀的公司和项目成员,其中有很多点是我们在平时开发、运维需要关注的知识和经验,值得大家一观。

初衷&宗旨

官方定义的宗旨如下:

  • 日志模型能够表达各种来源的日志:应用程序、机器事件、系统日志、容器日志等。
  • 能够将现有的大部分日志格式映射到日志模型,并且日志模型也可以很容易的转换成各种日志格式。
  • 通过日志数据模型和语义的定义,能够指导日志系统如何记录、传输、存储和理解日志。

从OpenTelemetry的顶层宗旨来看,日志模型的定义最主要还是规范化,能够将Metrics、Tracing、Logging的common schema统一,这样可以做到3者的无缝打通。当然,为了尽可能的通用,模型的定义会参考众多的日志格式,表达信息的方式需要尽肯能灵活。

日志架构演进

OpenTelemetry Log规范解读前言初衷&宗旨日志架构演进特性字段类型LogModel定义LogModel示例总结参考

传统架构下Logs、Traces、Metrics都是单独产生并收集的,在OpenTelemetry的规划中,所有的数据都会通过OpenTelemetry的Collector进行采集并传输到统一的后端进行关联。好处非常明显:

  1. 应用只需要一个SDK就可以做所有可观测性上的事情,依赖更少、资源消耗也更小
  2. 采集端只需要一个,部署和运维代价更低
  3. 数据格式统一,数据关联更容易

上面的图展示的是终极目标,但目前OpenTelemetry Collector对于Log的支持还比较弱,估计未来1-2年还是要用其他的日志采集去支撑。

特性

  1. LogModel(日志模型)应该支持任意类型的日志能够明确的转换成该类型,对于两种相同含义不同格式的日志,转换到LogModel后应该是完全等价的。
  2. 从其他日志类型映射到LogModel是有一定意义的,LogModel必须能够表示出其他日志类型的语义。
  3. 将类型A的日志换成到LogModel,然后再由LogModel转换到类型B。这种场景应该和从类型A直接转换到类型B是一致的,即转换过程中不应该丢失/增加数据。
  4. LogModel在传输和存储的效率上需尽可能的高,主要是对于CPU和内存的使用尽可能低,即序列化/反序列化尽可能高效以及存储空间尽可能低。

从表达能力上看,LogModel需要能够表达至少以下3种的日志/Event:

  1. 系统日志:即操作系统/硬件产生的日志,一个最典型的代表是Syslog。
  2. 三方应用日志:一些流行的三方软件的日志格式,例如Apache日志、MySQL慢日志等。
  3. 应用日志:业务应用产生的日志,这些日志一般由程序员打印,在需要的时候可以适当修改源码来适应新的LogModel。

字段类型

LogModel只定义日志(Record)的逻辑表现形式,与具体的物理格式和编码形式无关,每个Record包含两种字段类型:

  1. 具有特定类型和含义的顶级字段(Top-Level)
  2. 具体的字段,通常以KeyValue对的形式,根据不同的Top-Level名称,对应的字段会有不同的类型

LogModel定义

字段名 描述 必选
Timestamp 日志时间戳
TraceId 关联请求的TraceId
SpanId 关联请求的SpanId
TraceFlags W3C trace flag.
SeverityText 日志等级的可读描述.
SeverityNumber 日志等级.
ShortName 用于标识日志类型的短语.
Body 具体的日志内容.
Resource Log关联的Resource.
Attributes 额外关联属性.

字段详细解释

uint64,纳秒

字节数组,具体可以参考:

W3C Trace Context

字节数组,如果SpanId出现,则TraceId必须出现。

单字节,具体可参考:

日志等级的可读描述,如果不设置,则按照

SeverityNumber

的默认Mapping规则映射。

SeverityNumber

和Syslog中的日志等级比较像,OpenTelemetry定义了6大类、24种日志等级,基本上可以包含所有类型日志的等级定义。

SeverityNumber range 通用等级 含义
1-4 TRACE A fine-grained debugging event. Typically disabled in default configurations.
5-8 DEBUG A debugging event.
9-12 INFO An informational event. Indicates that an event happened.
13-16 WARN A warning event. Not an error but is likely more important than an informational event.
17-20 ERROR An error event. Something went wrong.
21-24 FATAL A fatal error such as application or system crash.

SeverityNumber

SeverityText

可通过Mapping的方式自动映射,所以在日志产生的时候,可以不填写

SeverityText

字段,以介绍序列化/反序列化和传输代价。映射关系如下:

Short Name
1
2 TRACE2
3 TRACE3
4 TRACE4
5
6 DEBUG2
7 DEBUG3
8 DEBUG4
9
10 INFO2
11 INFO3
12 INFO4
13
14 WARN2
15 WARN3
16 WARN4
17
18 ERROR2
19 ERROR3
20 ERROR4
21
22 FATAL2
23 FATAL3
24 FATAL4

一般用一个特定的词来标识日志类型,通常不要超过50个字节,例如:

ProcessStarted

日志内容为Any类型,Any类型,可以是 int、string、bool、float,也可以是一个数组或是Map。

Key/Value对列表,参考OpenTelemetry的

通用Resource定义

这里包括主机名、进程号、服务名等信息,可以用于关联Metrics、Tracing。

Key/Value对列表,Key始终是 string,Value是Any类型。具体可以参考Tracing中

Attributes的定义

LogModel示例

Example 1

{
  "Timestamp": 1586960586000, // JSON needs to make a decision about
                              // how to represent nanoseconds.
  "Attributes": {
    "http.status_code": 500,
    "http.url": "http://example.com",
    "my.custom.application.tag": "hello",
  },
  "Resource": {
    "service.name": "donut_shop",
    "service.version": "semver:2.0.0",
    "k8s.pod.uid": "1138528c-c36e-11e9-a1a7-42010a800198",
  },
  "TraceId": "f4dbb3edd765f620", // this is a byte sequence
                                 // (hex-encoded in JSON)
  "SpanId": "43222c2d51a7abe3",
  "SeverityText": "INFO",
  "SeverityNumber": 9,
  "Body": "20200415T072306-0700 INFO I like donuts"
}      

Example 2

{
  "Timestamp": 1586960586000,
  ...
  "Body": {
    "i": "am",
    "an": "event",
    "of": {
      "some": "complexity"
    }
  }
}      

Example 3

{
   "Timestamp": 1586960586000,
   "Attributes":{
      "http.scheme":"https",
      "http.host":"donut.mycie.com",
      "http.target":"/order",
      "http.method":"post",
      "http.status_code":500,
      "http.flavor":"1.1",
      "http.user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36",
   }
}      

总结

从上述的规范可以看出,OpenTelemetry的Log模型主要追求以下几点:

  1. 作为Metrics、Traces、Logs三大可观测性数据的终极细节性数据,Log需要能够表达足够详细的信息
  2. 如果Log在Trace场景中,需要包裹TraceID、SpanID,以便和Traces关联,同时借助Resource信息可以更好的和Traces、Metrics关联
  3. Log的性能需要尽可能的高,因为日志是数据量最大的可观测性数据,而且不会做采样,一定要确保对应用的性能影响尽可能的小
  4. 兼容性要好,因为目前有太多的日志系统,且都存在了很久也有很明确的存在意义,所以需要能够保证这些不同类型的Log可以和OpenTelemetry Log进行无缝转换

整体上这个模型还是非常适合现代的IT系统,但想要把这套标准成功实施下来还有很多工作要做,包括日志采集、解析、传输工具,兼容其他很多已有系统、环境等。不过好在Fluentd也在CNCF项目下,未来可能会成为OpenTelemetry的日志采集内核,配合Collector一起工作。

参考

  1. https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/overview.md
  2. https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md
  3. https://www.w3.org/TR/trace-context/#trace-id
  4. https://docs.datadoghq.com/tracing/connect_logs_and_traces/java/?tab=log4j2
  5. https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/overview.md#resources
  6. https://github.com/open-telemetry/opentelemetry-specification/tree/master/specification/trace/semantic_conventions

继续阅读