前言
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者的無縫打通。當然,為了盡可能的通用,模型的定義會參考衆多的日志格式,表達資訊的方式需要盡肯能靈活。
日志架構演進

傳統架構下Logs、Traces、Metrics都是單獨産生并收集的,在OpenTelemetry的規劃中,所有的資料都會通過OpenTelemetry的Collector進行采集并傳輸到統一的後端進行關聯。好處非常明顯:
- 應用隻需要一個SDK就可以做所有可觀測性上的事情,依賴更少、資源消耗也更小
- 采集端隻需要一個,部署和運維代價更低
- 資料格式統一,資料關聯更容易
上面的圖展示的是終極目标,但目前OpenTelemetry Collector對于Log的支援還比較弱,估計未來1-2年還是要用其他的日志采集去支撐。
特性
- LogModel(日志模型)應該支援任意類型的日志能夠明确的轉換成該類型,對于兩種相同含義不同格式的日志,轉換到LogModel後應該是完全等價的。
- 從其他日志類型映射到LogModel是有一定意義的,LogModel必須能夠表示出其他日志類型的語義。
- 将類型A的日志換成到LogModel,然後再由LogModel轉換到類型B。這種場景應該和從類型A直接轉換到類型B是一緻的,即轉換過程中不應該丢失/增加資料。
- LogModel在傳輸和存儲的效率上需盡可能的高,主要是對于CPU和記憶體的使用盡可能低,即序列化/反序列化盡可能高效以及存儲空間盡可能低。
從表達能力上看,LogModel需要能夠表達至少以下3種的日志/Event:
- 系統日志:即作業系統/硬體産生的日志,一個最典型的代表是Syslog。
- 三方應用日志:一些流行的三方軟體的日志格式,例如Apache日志、MySQL慢日志等。
- 應用日志:業務應用産生的日志,這些日志一般由程式員列印,在需要的時候可以适當修改源碼來适應新的LogModel。
字段類型
LogModel隻定義日志(Record)的邏輯表現形式,與具體的實體格式和編碼形式無關,每個Record包含兩種字段類型:
- 具有特定類型和含義的頂級字段(Top-Level)
- 具體的字段,通常以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模型主要追求以下幾點:
- 作為Metrics、Traces、Logs三大可觀測性資料的終極細節性資料,Log需要能夠表達足夠詳細的資訊
- 如果Log在Trace場景中,需要包裹TraceID、SpanID,以便和Traces關聯,同時借助Resource資訊可以更好的和Traces、Metrics關聯
- Log的性能需要盡可能的高,因為日志是資料量最大的可觀測性資料,而且不會做采樣,一定要確定對應用的性能影響盡可能的小
- 相容性要好,因為目前有太多的日志系統,且都存在了很久也有很明确的存在意義,是以需要能夠保證這些不同類型的Log可以和OpenTelemetry Log進行無縫轉換
整體上這個模型還是非常适合現代的IT系統,但想要把這套标準成功實施下來還有很多工作要做,包括日志采集、解析、傳輸工具,相容其他很多已有系統、環境等。不過好在Fluentd也在CNCF項目下,未來可能會成為OpenTelemetry的日志采集核心,配合Collector一起工作。
參考
- https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/overview.md
- https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md
- https://www.w3.org/TR/trace-context/#trace-id
- https://docs.datadoghq.com/tracing/connect_logs_and_traces/java/?tab=log4j2
- https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/overview.md#resources
- https://github.com/open-telemetry/opentelemetry-specification/tree/master/specification/trace/semantic_conventions