|
| 1 | +--- |
| 2 | +title: 日志 |
| 3 | +description: 对事件的记录。 |
| 4 | +weight: 3 |
| 5 | +default_lang_commit: e1bf6c870fbf82791a3826baaf276bc0ca79c88b |
| 6 | +cSpell:ignore: filelogreceiver semistructured transformprocessor |
| 7 | +--- |
| 8 | + |
| 9 | +**日志**是带有时间戳的文本记录,可以是结构化的(推荐)或非结构化的,且可附带元数据。 |
| 10 | +在所有遥测信号中,日志具有最悠久的历史。大多数编程语言都内置了日志记录功能,或有知名且广泛使用的日志库。 |
| 11 | + |
| 12 | +## OpenTelemetry 日志 {#opentelemetry-logs} |
| 13 | + |
| 14 | +OpenTelemetry 并未定义专用的 API 或 SDK 来创建日志。相反,OpenTelemetry 日志指的是你已有的日志, |
| 15 | +这些日志来自现有的日志框架或基础设施组件。OpenTelemetry SDK 和自动注入功能利用多个组件, |
| 16 | +自动将日志与[链路](../traces)关联。 |
| 17 | + |
| 18 | +OpenTelemetry 的日志支持旨在与你已有的日志完全兼容,提供了能力来为这些日志添加上下文, |
| 19 | +并提供统一的工具包,将来自不同来源的日志解析并转换为统一格式。 |
| 20 | + |
| 21 | +### OpenTelemetry Collector 中的 OpenTelemetry 日志 {#opentelemetry-logs-in-the-opentelemetry-collector} |
| 22 | + |
| 23 | +[OpenTelemetry Collector](/docs/collector/) 提供了多个处理日志的工具: |
| 24 | + |
| 25 | +- 多种接收器,可从特定的、已知的数据源解析日志。 |
| 26 | +- `filelogreceiver`,可从任意文件读取日志,并支持多种日志格式解析或使用正则表达式。 |
| 27 | +- 类似 `transformprocessor` 的处理器,可解析嵌套数据、扁平化结构、添加/移除/更新值等。 |
| 28 | +- 多种导出器(exporters),可将日志数据导出为非 OpenTelemetry 格式。 |
| 29 | + |
| 30 | +采纳 OpenTelemetry 的第一步通常是部署 Collector 作为通用日志代理。 |
| 31 | + |
| 32 | +### 应用中的 OpenTelemetry 日志 {#opentelemetry-logs-for-applications} |
| 33 | + |
| 34 | +在应用中,可以通过任意日志库或语言内置日志功能创建 OpenTelemetry 日志。 |
| 35 | +当你启用自动注入或激活 SDK 后,OpenTelemetry 会自动将现有日志与活动的链路与 Span 关联起来, |
| 36 | +并将这些 ID 包裹到日志正文中。换句话说,OpenTelemetry 会自动关联你的日志与链路信息。 |
| 37 | + |
| 38 | +### 语言支持情况 {#language-support} |
| 39 | + |
| 40 | +日志信号在 OpenTelemetry 规范中是[稳定的](/docs/specs/otel/versioning-and-stability/#stable)。 |
| 41 | +各语言对 Logs API 和 SDK 的支持情况如下: |
| 42 | + |
| 43 | +{{% signal-support-table "logs" %}} |
| 44 | + |
| 45 | +## 结构化、非结构化与半结构化日志 {#structured-unstructured-and-semistructured-logs} |
| 46 | + |
| 47 | +OpenTelemetry 在技术上并不区分结构化与非结构化日志。你可以使用任何已有的日志配合 OpenTelemetry。不过, |
| 48 | +并非所有日志格式都同样有用!尤其是在生产环境中,推荐使用结构化日志,因为它们易于解析和大规模分析。 |
| 49 | +以下部分将解释三种类型日志的差异。 |
| 50 | + |
| 51 | +### 结构化日志 {#structured-logs} |
| 52 | + |
| 53 | +结构化日志是指其文本格式具有一致性、可被机器读取的日志。在应用中,最常见的结构化格式是 JSON: |
| 54 | + |
| 55 | +```json |
| 56 | +{ |
| 57 | + "timestamp": "2024-08-04T12:34:56.789Z", |
| 58 | + "level": "INFO", |
| 59 | + "service": "user-authentication", |
| 60 | + "environment": "production", |
| 61 | + "message": "User login successful", |
| 62 | + "context": { |
| 63 | + "userId": "12345", |
| 64 | + "username": "johndoe", |
| 65 | + "ipAddress": "192.168.1.1", |
| 66 | + "userAgent": "Mozilla/5.0 ..." |
| 67 | + }, |
| 68 | + "transactionId": "abcd-efgh-ijkl-mnop", |
| 69 | + "duration": 200, |
| 70 | + "request": { |
| 71 | + "method": "POST", |
| 72 | + "url": "/api/v1/login", |
| 73 | + "headers": { |
| 74 | + "Content-Type": "application/json", |
| 75 | + "Accept": "application/json" |
| 76 | + }, |
| 77 | + "body": { |
| 78 | + "username": "johndoe", |
| 79 | + "password": "******" |
| 80 | + } |
| 81 | + }, |
| 82 | + "response": { |
| 83 | + "statusCode": 200, |
| 84 | + "body": { |
| 85 | + "success": true, |
| 86 | + "token": "jwt-token-here" |
| 87 | + } |
| 88 | + } |
| 89 | +} |
| 90 | +``` |
| 91 | + |
| 92 | +对于基础设施组件,通常使用通用日志格式(CLF): |
| 93 | + |
| 94 | +```text |
| 95 | +127.0.0.1 - johndoe [04/Aug/2024:12:34:56 -0400] "POST /api/v1/login HTTP/1.1" 200 1234 |
| 96 | +``` |
| 97 | + |
| 98 | +也可以混用不同结构化格式。例如扩展日志格式(ELF)可以将 JSON 与空格分隔的 CLF 数据混合: |
| 99 | + |
| 100 | +```text |
| 101 | +192.168.1.1 - johndoe [04/Aug/2024:12:34:56 -0400] "POST /api/v1/login HTTP/1.1" 200 1234 "http://example.com" "Mozilla/5.0 ..." {"transactionId": "abcd-efgh...", ...} |
| 102 | +``` |
| 103 | + |
| 104 | +为了充分利用这类日志,需要将 JSON 和 ELF 部分都解析为统一格式,便于在可观测性后端分析。 |
| 105 | +OpenTelemetry Collector 中的 `filelogreceiver` 提供了解析这类日志的标准方法。 |
| 106 | + |
| 107 | +结构化日志是最推荐的日志使用方式。由于格式一致,它们更易于解析,从而便于在 Collector |
| 108 | +中预处理、与其他数据关联,并在后端平台分析。 |
| 109 | + |
| 110 | +### 非结构化日志 {#unstructured-logs} |
| 111 | + |
| 112 | +非结构化日志指没有一致结构的日志。它们可能更易读,因此在开发中常用。 |
| 113 | +但在生产可观测性中不推荐使用,因为很难大规模解析和分析。 |
| 114 | + |
| 115 | +非结构化日志示例: |
| 116 | + |
| 117 | +```text |
| 118 | +[ERROR] 2024-08-04 12:45:23 - Failed to connect to database. Exception: java.sql.SQLException: Timeout expired. ... |
| 119 | +
|
| 120 | +System reboot initiated at 2024-08-04 03:00:00 by user: admin. Reason: Scheduled maintenance. ... |
| 121 | +
|
| 122 | +DEBUG - 2024-08-04 09:30:15 - User johndoe performed action: file_upload. Filename: report_Q3_2024.pdf, Size: 2.3 MB ... |
| 123 | +``` |
| 124 | + |
| 125 | +在生产环境中也可以存储和分析非结构化日志,尽管你可能需要进行大量解析或预处理工作,使其具备机器可读性。 |
| 126 | +例如,前面提到的三条日志就需要使用正则表达式解析时间戳,并编写自定义解析器来稳定地提取日志消息的正文。 |
| 127 | +这通常是日志后端根据时间戳对日志进行排序和组织所必需的。虽然解析非结构化日志以便分析是可行的, |
| 128 | +但所需工作量往往比直接采用结构化日志要大,比如通过在应用中使用标准的日志记录框架来实现结构化日志。 |
| 129 | + |
| 130 | +### 半结构化日志 {#semistructured-logs} |
| 131 | + |
| 132 | +半结构化日志具有某种自一致的模式以便被机器读取,但不同系统之间的数据格式和分隔符可能不一致。 |
| 133 | + |
| 134 | +半结构化日志示例: |
| 135 | + |
| 136 | +```text |
| 137 | +2024-08-04T12:45:23Z level=ERROR service=user-authentication userId=12345 action=login message="Failed login attempt" error="Invalid password" ... |
| 138 | +``` |
| 139 | + |
| 140 | +尽管机器可读,但为了实现大规模分析,仍可能需要多个解析器。 |
| 141 | + |
| 142 | +## OpenTelemetry 日志组件 {#opentelemetry-logging-components} |
| 143 | + |
| 144 | +以下是构成 OpenTelemetry 日志支持的核心概念和组件。 |
| 145 | + |
| 146 | +### 日志附加器/桥接器 {#log-appender--bridge} |
| 147 | + |
| 148 | +作为应用开发者,你无需直接调用 **Logs Bridge API**,该 API 是为日志库作者构建日志附加器或桥接器而设。 |
| 149 | +你只需使用喜欢的日志库,并配置其使用能将日志传递给 OpenTelemetry LogRecordExporter 的附加器。 |
| 150 | + |
| 151 | +OpenTelemetry 各语言 SDK 提供了此功能。 |
| 152 | + |
| 153 | +### Logger Provider |
| 154 | + |
| 155 | +> 属于 **Logs Bridge API**,仅供日志库作者使用。 |
| 156 | +
|
| 157 | +Logger Provider(有时叫 `LoggerProvider`)是 `Logger` 的工厂。 |
| 158 | +一般在应用启动时初始化一次,其生命周期与应用相同。初始化时也包括 Resource 和 Exporter 的初始化。 |
| 159 | + |
| 160 | +### Logger |
| 161 | + |
| 162 | +> 属于 **Logs Bridge API**,仅供日志库作者使用。 |
| 163 | +
|
| 164 | +Logger 用于创建日志记录,Logger 实例由 Logger Provider 生成。 |
| 165 | + |
| 166 | +### 日志记录导出器 {#log-record-exporter} |
| 167 | + |
| 168 | +Log Record Exporter 将日志记录发送到某个消费者。 |
| 169 | +消费者可以是标准输出(用于调试或开发),也可以是 OpenTelemetry Collector,或你选择的任何开源或商业后端。 |
| 170 | + |
| 171 | +### 日志记录 {#log-record} |
| 172 | + |
| 173 | +日志记录代表对事件的记录。在 OpenTelemetry 中,日志记录包含两类字段: |
| 174 | + |
| 175 | +- 具备特定含义的命名顶级字段; |
| 176 | +- 可任意定义的 Resource 和 Attributes 字段。 |
| 177 | + |
| 178 | +顶级字段如下: |
| 179 | + |
| 180 | +| 字段名 | 描述 | |
| 181 | +| -------------------- | -------------------------- | |
| 182 | +| Timestamp | 事件发生的时间 | |
| 183 | +| ObservedTimestamp | 观察到事件的时间 | |
| 184 | +| TraceId | 请求的链路 ID | |
| 185 | +| SpanId | 请求的 Span ID | |
| 186 | +| TraceFlags | W3C 链路标志 | |
| 187 | +| SeverityText | 严重性文本(也称日志级别) | |
| 188 | +| SeverityNumber | 严重性的数值表示 | |
| 189 | +| Body | 日志正文 | |
| 190 | +| Resource | 日志来源 | |
| 191 | +| InstrumentationScope | 产生该日志的范围 | |
| 192 | +| Attributes | 事件的附加信息 | |
| 193 | + |
| 194 | +更多有关日志记录与字段的细节,请参阅[日志数据模型](/docs/specs/otel/logs/data-model/)。 |
| 195 | + |
| 196 | +### 规范 {#specification} |
| 197 | + |
| 198 | +如需进一步了解 OpenTelemetry 中的日志,请参阅[日志规范][logs specification]。 |
| 199 | + |
| 200 | +[logs specification]: /docs/specs/otel/overview/#log-signal |
0 commit comments