【问题标题】:How to log Stackdriver log messages correlated by trace id using stdout Go 1.11如何使用 stdout Go 1.11 记录与跟踪 id 相关的 Stackdriver 日志消息
【发布时间】:2019-08-08 00:54:01
【问题描述】:

我正在使用带有 Go 1.11 运行时的 Google App Engine 标准环境。 Go 1.11 的文档说“使用 stdout 编写应用程序日志作为输出,使用 stderr 编写错误”。 Go 1.9 指南的迁移还建议不要直接调用 Google Cloud Logging 库,而是通过 stdout 进行日志记录。 https://cloud.google.com/appengine/docs/standard/go111/writing-application-logs

考虑到这一点,我编写了一个小型 HTTP 服务(下面的代码)来试验使用 JSON 输出到标准输出来记录到 Stackdriver。

当我打印纯文本消息时,它们会按预期显示在 textPayload 下的“日志查看器”面板中。当我传递一个 JSON 字符串时,它们出现在jsonPayload 下。到目前为止,一切顺利。

所以,我在输出字符串中添加了一个severity 字段,Stackdriver Log Viewer 成功地根据分级日志通知、警告等对消息进行分类。 https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry

文档说设置trace 标识符以将日志条目与原始请求日志相关联。跟踪 ID 是从容器设置的 X-Cloud-Trace-Context 标头中提取的。

使用curl -v -H 'X-Cloud-Trace-Context: 1ad1e4f50427b51eadc9b36064d40cc2/8196282844182683029;o=1' http://localhost:8080/在本地模拟它

但是,这不会导致消息按请求线程化,而是trace 属性出现在日志的jsonPayload 对象中。 (见下文)。

请注意,severity 已按预期解释,并且未出现在 jsonPayload 中。我原以为trace 也会发生同样的情况,但它似乎未处理。

如何在原始请求日志消息中实现嵌套消息? (这必须在 Go 1.11 上使用 stdout 完成,因为我不希望直接使用 Google Cloud 日志记录包进行记录)。

GAE 究竟在做什么来解析我正在运行的进程中的标准输出流? (在 GCE 上的虚拟机设置指南中,有一些关于安装代理程序以充当 Stackdriver 日志记录的管道——这是 GAE 安装的吗?)

app.yaml 文件如下所示:

runtime: go111

handlers:
- url: /.*
  script: auto



package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
    "strings"
)

var projectID = "glowing-market-234808"

func parseXCloudTraceContext(t string) (traceID, spanID, traceTrue string) {
    slash := strings.Index(t, "/")
    semi := strings.Index(t, ";")
    equal := strings.Index(t, "=")
    return t[0:slash], t[slash+1 : semi], t[equal+1:]
}

func sayHello(w http.ResponseWriter, r *http.Request) {
    xTrace := r.Header.Get("X-Cloud-Trace-Context")
    traceID, spanID, _ := parseXCloudTraceContext(xTrace)
    trace := fmt.Sprintf("projects/%s/traces/%s", projectID, traceID)

    warning := fmt.Sprintf(`{"trace":"%s","spanId":"%s", "severity":"WARNING","name":"Andy","age":45}`, trace, spanID)
    fmt.Fprintf(os.Stdout, "%s\n", warning)

    message := "Hello"
    w.Write([]byte(message))
}

func main() {
    http.HandleFunc("/", sayHello)
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }
    log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
}

日志查看器中显示的输出:

...,
jsonPayload: {
  age:  45   
  name:  "Andy"   
  spanId:  "13076979521824861986"   
  trace:  "projects/glowing-market-234808/traces/e880a38fb5f726216f94548a76a6e474"   
},
severity:  "WARNING",
...

【问题讨论】:

  • 除了这个单线程测试示例之外,不要使用上面的 parseXCloudTraceContext() 函数。在生产中,x-cloud-trace-context 的 ;o=1 部分并不总是存在,导致它出现恐慌。

标签: google-app-engine go stackdriver google-cloud-stackdriver


【解决方案1】:

我通过调整程序以使用logging.googleapis.com/trace 代替tracelogging.googleapis.com/spanId 代替spanId 解决了这个问题。

    warning := fmt.Sprintf(`{"logging.googleapis.com/trace":"%s","logging.googleapis.com/spanId":"%s", "severity":"WARNING","name":"Andy","age":45}`, trace, spanID)
    fmt.Fprintf(os.Stdout, "%s\n", warning)

GAE 似乎正在使用日志代理 google-fluentdfluentd 日志数据收集器的修改版本。)

查看此链接以获取完整说明。 https://cloud.google.com/logging/docs/agent/configuration#special-fields

[更新] 2019 年 6 月 25 日:我编写了一个 Logrus 插件,该插件将帮助通过 HTTP 请求线程化日志条目。它可以在 GitHub https://github.com/andyfusniak/stackdriver-gae-logrus-plugin 下找到。

[更新]] 2020 年 4 月 3 日:我已经改用 Cloud Run,Logrus 插件似乎也可以在这个平台上正常工作。

【讨论】:

    猜你喜欢
    • 2020-04-09
    • 2020-02-13
    • 1970-01-01
    • 2013-04-08
    • 2018-12-24
    • 1970-01-01
    • 2015-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多