本文档讨论了结构化日志记录的概念以及
向日志条目载荷字段添加结构。何时为日志载荷设置格式
作为 JSON 对象,并且该对象存储在 jsonPayload
字段中,则日志
条目称为“结构化日志”。对于这些日志,您可以构建用于搜索特定 JSON 路径的查询,还可以为日志载荷中的特定字段编制索引。相反,如果日志载荷的格式设置为字符串,
存储在 textPayload
字段中,则日志条目是非结构化的。
您可以搜索文本字段,但无法对其内容编入索引。
如需创建结构化日志条目,请执行以下任一操作:
- 调用
entries.write
API 方法并提供完全格式化的LogEntry
。 - 使用
gcloud logging write
命令。
- 使用可写入结构化日志的 Cloud Logging 客户端库。
- 使用 BindPlane 服务。
使用代理写入日志:
某些 Google Cloud 服务包含集成的日志记录代理,该代理会将写入
stdout
或stderr
的数据作为日志发送到 Cloud Logging。您可以将此方法用于 Google Cloud 服务,例如 Google Kubernetes Engine、 App Engine 柔性环境和 Cloud Run 函数对于 Compute Engine 虚拟机 (VM),您可以安装和配置 Ops Agent 或旧版 Logging 代理,然后使用 已安装的代理,以将日志发送到 Cloud Logging。
如需详细了解这些方法,请参阅以下部分。
使用客户端库或 API 写入日志
您可以使用调用 Cloud Logging API 的 Cloud Logging 客户端库或直接调用 Cloud Logging API 来写入日志数据。客户端库可简化特殊 JSON 字段的填充,
自动捕获一些信息,并提供接口
正确填充这些字段不过,为了全面控制
载荷结构,请直接调用 Cloud Logging API 并将
完整 LogEntry
结构添加到 Cloud Logging API。
如需了解详情,请参阅 entries.write
参考文档。
如需查看代码示例,请参阅写入结构化日志。
使用 gcloud CLI 写入日志
您可以使用 gcloud CLI 写入日志数据。该接口支持非结构化日志和结构化日志。如需写入结构化日志,请向该命令提供序列化 JSON 对象。
有关快速入门,请参阅 使用 Google Cloud CLI 写入和查询日志条目。
如需查看代码示例,请参阅 gcloud logging write
参考文档。
使用 BindPlane 写入日志
您可以使用 BindPlane 服务将日志发送到 Logging。 这些日志的载荷采用 JSON 格式 格式,并根据源系统进行结构化处理。如需了解如何查找和查看使用 BindPlane 提取的日志,请参阅 BindPlane 快速入门指南。
使用代理写入日志
如需从 Compute Engine 实例获取日志,请执行以下操作: 您可以使用 Ops Agent 或 旧版 Cloud Logging 代理。 这两种代理都可以从第三方应用收集指标,并且都支持结构化日志记录:
Ops Agent 是用于从 Compute Engine 实例收集遥测数据的推荐代理。此代理将日志记录和指标组合到单个代理中,提供了基于 YAML 的配置,并具有高吞吐量日志记录功能。
有关如何配置 Ops Agent 以支持 结构化日志记录或自定义结构化日志的形式,请参阅 配置 Ops Agent。
旧版 Cloud Logging 代理会收集日志。此代理不会收集其他形式的遥测数据。
本部分的其余内容专门介绍了 旧版 Logging 代理。
Logging 代理:特殊 JSON 字段
JSON 对象中的某些字段会被旧版 Logging 代理识别为特殊字段,并提取到 LogEntry
结构中。这些特殊的 JSON 字段可用于设置 LogEntry
中的以下字段:
severity
spanId
labels
由用户定义httpRequest
由于 JSON 比文本行更精确且更全能,因此您可以使用 JSON 对象编写多行消息并添加元数据。
如需使用简化格式为您的应用创建结构化日志条目,请参阅下表,其中列出了 JSON 格式的字段及其值:
JSON 日志字段 |
LogEntry 字段
|
Cloud Logging 代理函数 | 示例值 |
---|---|---|---|
severity
|
severity
|
Logging 代理尝试匹配各种常见严重性字符串,其中包括 Logging API 识别的 LogSeverity 字符串列表。 | "severity":"ERROR"
|
message
|
textPayload (或 jsonPayload 的一部分)
|
日志浏览器中的日志条目行显示的消息。 |
"message":"There was an error in the application." 注意:如果在 Logging 代理移动其他特殊用途字段之后只留下了一个 message 字段并且 detect_json 未启用,则该 message 将保存为 textPayload ,否则 message 仍保留在 jsonPayload 中。detect_json 不适用于 Google Kubernetes Engine 等代管式日志记录环境。如果您的日志条目包含异常堆栈轨迹,则应在此 message JSON 日志字段中设置异常堆栈轨迹,以便系统可以解析该异常堆栈跟踪并将其保存到 Error Reporting 之中。 |
log (仅限旧版 Google Kubernetes Engine) |
textPayload
|
仅适用于旧版 Google Kubernetes Engine:如果在移动特殊用途字段后,只留下一个 log 字段,则该字段将保存为 textPayload 。 |
|
httpRequest
|
httpRequest
|
采用 LogEntry HttpRequest 字段格式的结构化记录。 |
"httpRequest":{"requestMethod":"GET"}
|
与时间相关的字段 | timestamp
|
如需了解详情,请参阅与时间相关的字段。 | "time":"2020-10-12T07:20:50.52Z"
|
logging.googleapis.com/insertId
|
insertId
|
如需了解详情,请参阅 LogEntry 页面上的 insertId 。 |
"logging.googleapis.com/insertId":"42"
|
logging.googleapis.com/labels
|
labels
|
此字段的值必须为结构化记录。如需了解详情,请参阅 LogEntry 页面上的 labels 。 |
"logging.googleapis.com/labels":
{"user_label_1":"value_1","user_label_2":"value_2"}
|
logging.googleapis.com/operation
|
operation
|
此字段的值也可用于日志浏览器对相关日志条目进行分组。如需了解详情,请参阅 LogEntry 页面上的 operation 。 |
"logging.googleapis.com/operation":
{"id":"get_data","producer":"github.com/MyProject/MyApplication",
"first":"true"}
|
logging.googleapis.com/sourceLocation
|
sourceLocation
|
与日志条目关联的源代码位置信息(如果有)。如需了解详情,请参阅 LogEntry 页面上的 LogEntrySourceLocation 。 |
"logging.googleapis.com/sourceLocation":
{"file":"get_data.py","line":"142","function":"getData"}
|
logging.googleapis.com/spanId
|
spanId
|
与日志条目相关联的跟踪记录内的 Span ID。如需了解详情,请参阅 LogEntry 页面上的 spanId 。 |
"logging.googleapis.com/spanId":"000000000000004a"
|
logging.googleapis.com/trace
|
trace
|
与日志条目关联的跟踪记录的资源名称(如果有)。如需了解详情,请参阅 LogEntry 页面上的 trace 。
|
"logging.googleapis.com/trace":"projects/my-projectid/traces/0679686673a" 注意:如果未向 stdout 或 stderr 写入数据,则此字段的值应设置为 projects/[PROJECT-ID]/traces/[TRACE-ID] 格式,以便 Logs Explorer 和 Trace Viewer 可以使用此字段对日志条目进行分组,并且将日志条目与跟踪记录一起显示。
如果 autoformat_stackdriver_trace 为 true,并且 [V] 与 ResourceTrace traceId 的格式相匹配,则 LogEntry trace 字段的值将是 projects/[PROJECT-ID]/traces/[V] 。 |
logging.googleapis.com/trace_sampled
|
traceSampled
|
此字段的值必须是 true 或 false 。如需了解详情,请参阅 LogEntry 页面上的 traceSampled 。 |
"logging.googleapis.com/trace_sampled": false
|
如需创建简化格式的日志条目,请使用字段创建条目的 JSON 表示。所有字段均为可选字段。
以下是简化版 JSON 日志条目的示例:
{ "severity":"ERROR", "message":"There was an error in the application.", "httpRequest":{ "requestMethod":"GET" }, "times":"2020-10-12T07:20:50.52Z", "logging.googleapis.com/insertId":"42", "logging.googleapis.com/labels":{ "user_label_1":"value_1", "user_label_2":"value_2" }, "logging.googleapis.com/operation":{ "id":"get_data", "producer":"github.com/MyProject/MyApplication", "first":"true" }, "logging.googleapis.com/sourceLocation":{ "file":"get_data.py", "line":"142", "function":"getData" }, "logging.googleapis.com/spanId":"000000000000004a", "logging.googleapis.com/trace":"projects/my-projectid/traces/06796866738c859f2f19b7cfb3214824", "logging.googleapis.com/trace_sampled":false }
以下是生成的日志条目的示例:
{ "insertId": "42", "jsonPayload": { "message": "There was an error in the application", "times": "2020-10-12T07:20:50.52Z" }, "httpRequest": { "requestMethod": "GET" }, "resource": { "type": "k8s_container", "labels": { "container_name": "hello-app", "pod_name": "helloworld-gke-6cfd6f4599-9wff8", "project_id": "stackdriver-sandbox-92334288", "namespace_name": "default", "location": "us-west4", "cluster_name": "helloworld-gke" } }, "timestamp": "2020-11-07T15:57:35.945508391Z", "severity": "ERROR", "labels": { "user_label_2": "value_2", "user_label_1": "value_1" }, "logName": "projects/stackdriver-sandbox-92334288/logs/stdout", "operation": { "id": "get_data", "producer": "github.com/MyProject/MyApplication", "first": true }, "trace": "projects/my-projectid/traces/06796866738c859f2f19b7cfb3214824", "sourceLocation": { "file": "get_data.py", "line": "142", "function": "getData" }, "receiveTimestamp": "2020-11-07T15:57:42.411414059Z", "spanId": "000000000000004a" }
Logging 代理:配置
旧版 Logging 代理 google-fluentd
是 Cloud Logging 专属的 Fluentd 日志数据收集器的程序包。Logging 代理默认采用 Fluentd 配置,并使用 Fluentd 输入插件从外部源(例如磁盘上的文件)拉取事件日志,或者使用该插件解析传入的日志记录。
Fluentd 支持多种解析器,这些解析器可提取日志并将日志转换为结构化 (JSON) 负载。
通过使用 format [PARSER_NAME]
配置日志源,您可以在
内置解析器。有关如何配置
旧版 Logging 代理,请参阅
配置 Logging 代理。
以下代码示例展示了 Fluentd 配置、输入日志记录,以及属于 Cloud Logging 日志条目一部分的输出结构化载荷:
Fluentd 配置:
<source> @type tail format syslog # This uses a predefined log format regex named # `syslog`. See details at https://docs.fluentd.org/parser/syslog. path /var/log/syslog pos_file /var/lib/google-fluentd/pos/syslog.pos read_from_head true tag syslog </source>
日志记录(输入):
<6>Feb 28 12:00:00 192.168.0.1 fluentd[11111]: [error] Syslog test
结构化负载(输出):
jsonPayload: { "pri": "6", "host": "192.168.0.1", "ident": "fluentd", "pid": "11111", "message": "[error] Syslog test" }
如需详细了解 syslog
解析器的工作原理,请参阅详细的 Fluentd 文档。
Logging 代理:默认启用标准解析器
下表列出了启用结构化日志记录后代理中包含的标准解析器:
解析器名称 | 配置文件 |
---|---|
syslog |
/etc/google-fluentd/config.d/syslog.conf |
nginx |
/etc/google-fluentd/config.d/nginx.conf |
apache2 |
/etc/google-fluentd/config.d/apache.conf |
apache_error |
/etc/google-fluentd/config.d/apache.conf |
如需了解如何在安装旧版 Logging 代理时启用结构化日志记录,请参阅安装部分。
Logging 代理:安装
如需启用结构化日志记录,您必须在安装或重新安装旧版 Logging 代理时更改其默认配置。如果启用结构化日志记录,则系统会替换之前列出的配置文件,但不会更改代理本身的操作。
启用结构化日志记录后,列出的日志将转换为与启用结构化日志之前的格式不同的日志条目。如果正在将日志路由到 Logging 之外的目标位置,发生的更改可能会影响所有后处理应用。例如,如果将日志路由到 BigQuery,则 BigQuery 会因架构错误拒绝当天剩余时间内的新日志条目。
如需了解如何安装旧版 Logging 代理和启用结构化日志记录,请参阅安装 Logging 代理。
您可以在以下位置找到旧版 Logging 代理配置文件:
/etc/google-fluentd/config.d/
,其中现在应包含
默认启用的标准解析器。
Logging 代理:配置 Apache 访问日志格式
默认情况下,旧版 Logging 代理将 Apache 访问日志数据存储在 jsonPayload
字段中。例如:
{
"logName": ...,
"resource": ...,
"httpRequest": ...,
"jsonPayload": {
"user" : "some-user",
"method" : "GET",
"code" : 200,
"size" : 777,
"host" : "192.168.0.1",
"path" : "/some-path",
"referer": "some-referer",
"agent" : "Opera/12.0"
},
...
}
或者,您可以配置旧版 Logging 代理以将某些字段提取到 httpRequest
字段。例如:
{
"logName": ...,
"resource": ...,
"httpRequest": {
"requestMethod": "GET",
"requestUrl": "/some-path",
"requestSize": "777",
"status": "200",
"userAgent": "Opera/12.0",
"serverIp": "192.168.0.1",
"referrer":"some-referrer",
},
"jsonPayload": {
"user":"some-user"
},
...
}
如前面的示例所示,配置 httpRequest
字段有助于跟踪:Google Cloud 控制台中会以父子层次结构显示给定 HTTP 请求的所有日志。
要配置此提取,请将以下内容添加到 /etc/google-fluentd/config.d/apache.conf
的末尾:
<filter apache-access>
@type record_transformer
enable_ruby true
<record>
httpRequest ${ {"requestMethod" => record['method'], "requestUrl" => record['path'], "requestSize" => record['size'], "status" => record['code'], "userAgent" => record['agent'], "serverIp" => record['host'],
"referer" => record['referer']} }
</record>
remove_keys method, path, size, code, agent, host, referer
</filter>
如需详细了解如何配置日志条目,请参阅修改日志记录。
Logging 代理:配置 nginx 访问日志格式
默认情况下,旧版 Logging 代理会存储 nginx 访问权限
日志数据。jsonPayload
例如:
{
"logName": ...,
"resource": ...,
"httpRequest": ...,
"jsonPayload": {
"remote":"127.0.0.1",
"host":"192.168.0.1",
"user":"some-user",
"method":"GET",
"path":"/some-path",
"code":"200",
"size":"777",
"referrer":"some-referrer",
"agent":"Opera/12.0",
"http_x_forwarded_for":"192.168.3.3"
},
...
}
或者,您可以配置旧版 Logging 代理以将某些字段提取到 httpRequest
字段。例如:
{
"logName": ...,
"resource": ...,
"httpRequest": {
"requestMethod": "GET",
"requestUrl": "/some-path",
"requestSize": "777",
"status": "200",
"userAgent": "Opera/12.0",
"remoteIp": "127.0.0.1",
"serverIp": "192.168.0.1",
"referrer":"some-referrer",
},
"jsonPayload": {
"user":"some-user",
"http_x_forwarded_for":"192.168.3.3"
},
...
}
配置 httpRequest
字段(如前面的示例所示)有助于
跟踪:Google Cloud 控制台显示给定 HTTP 请求的所有日志
处于父级-子级层次结构中
要配置此提取,请将以下内容添加到 /etc/google-fluentd/config.d/nginx.conf
的末尾:
<filter nginx-access>
@type record_transformer
enable_ruby true
<record>
httpRequest ${ {"requestMethod" => record['method'], "requestUrl" => record['path'], "requestSize" => record['size'], "status" => record['code'], "userAgent" => record['agent'], "remoteIp" => record['remote'], "serverIp" => record['host'], "referer" => record['referer']} }
</record>
remove_keys method, path, size, code, agent, remote, host, referer
</filter>
如需详细了解如何配置日志条目,请参阅修改日志记录。
编写您自己的解析器
如果标准解析器不支持您的日志,您可以编写自己的解析器。解析器包含一个用于匹配日志记录并将标签应用于各部分的正则表达式。
以下代码示例分别显示了日志记录中的日志行、包含指示日志行格式的正则表达式的配置,以及存储的日志条目:
日志记录中的日志行:
REPAIR CAR $500
包含指示日志行格式的正则表达式的配置:
$ sudo vim /etc/google-fluentd/config.d/test-structured-log.conf $ cat /etc/google-fluentd/config.d/test-structured-log.conf <source> @type tail # Format indicates the log should be translated from text to # structured (JSON) with three fields, "action", "thing" and "cost", # using the following regex: format /(?<action>\w+) (?<thing>\w+) \$(?<cost>\d+)/ # The path of the log file. path /tmp/test-structured-log.log # The path of the position file that records where in the log file # we have processed already. This is useful when the agent # restarts. pos_file /var/lib/google-fluentd/pos/test-structured-log.pos read_from_head true # The log tag for this log input. tag structured-log </source>
生成的日志条目:
{ insertId: "eps2n7g1hq99qp" jsonPayload: { "action": "REPAIR" "thing": "CAR" "cost": "500" } labels: { compute.googleapis.com/resource_name: "add-structured-log-resource" } logName: "projects/my-sample-project-12345/logs/structured-log" receiveTimestamp: "2023-03-21T01:47:11.475065313Z" resource: { labels: { instance_id: "3914079432219560274" project_id: "my-sample-project-12345" zone: "us-central1-c" } type: "gce_instance" } timestamp: "2023-03-21T01:47:05.051902169Z" }
问题排查
排查在安装或与 旧版 Logging 代理,请参阅 排查代理问题。
后续步骤
如需查询和查看日志条目,请参阅 使用日志浏览器查看日志。
如需使用 Google Cloud CLI 读取日志条目,请参阅 读取日志条目。
要使用 Logging API 读取日志条目,请参阅
entries.list
方法。