如何使用stdout Go 1.11记录与跟踪ID相关的Stackdriver日志消息

And*_*iak 5 google-app-engine go stackdriver google-cloud-stackdriver

我在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输出到stdout的日志记录到Stackdriver。

当我打印纯文本消息时,它们将按预期显示在日志查看器面板中的textPayload。当我传递JSON字符串时,它们会显示在下方jsonPayload。到目前为止,一切都很好。

因此,我severity在输出字符串中添加了一个字段,然后Stackdriver Log Viewer根据已分级的日志记录NOTICE,WARNING等成功地对消息进行了分类 。https://cloud.google.com/logging/docs/reference/v2/rest/v2/登录项

文档说要设置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从正在运行的进程中解析stdout流的确切方式是什么?(在GCE上的VM设置指南中,有一些关于安装代理程序以充当Stackdriver Logging的渠道的信息-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))
}
Run Code Online (Sandbox Code Playgroud)

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

...,
jsonPayload: {
  age:  45   
  name:  "Andy"   
  spanId:  "13076979521824861986"   
  trace:  "projects/glowing-market-234808/traces/e880a38fb5f726216f94548a76a6e474"   
},
severity:  "WARNING",
...
Run Code Online (Sandbox Code Playgroud)

And*_*iak 4

我通过调整程序来代替 和 代替 解决logging.googleapis.com/tracetrace这个logging.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)
Run Code Online (Sandbox Code Playgroud)

看来GAE正在使用日志记录代理google-fluentd(日志数据收集器的修改版本fluentd。)

请参阅此链接以获取完整说明。 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 插件似乎也可以在该平台上正常工作。