Как регистрировать сообщения журнала Stackdriver, сопоставленные по идентификатору трассировки, с помощью stdout Go 1.11

# #google-app-engine #go #stackdriver #google-cloud-stackdriver

#google-app-engine #Вперед #stackdriver #google-cloud-stackdriver

Вопрос:

Я использую стандартную среду Google App Engine со средой выполнения Go 1.11. В документации для Go 1.11 сказано «Записывайте журналы вашего приложения, используя stdout для вывода и stderr для ошибок». В руководстве по переходу с Go 1.9 также предлагается не вызывать библиотеку ведения журнала Google Cloud напрямую, а вместо этого регистрироваться через стандартный вывод. https://cloud.google.com/appengine/docs/standard/go111/writing-application-logs

Имея это в виду, я написал небольшой HTTP-сервис (код ниже), чтобы поэкспериментировать с регистрацией в Stackdriver, используя вывод JSON в стандартный вывод.

Когда я печатаю обычные текстовые сообщения, они отображаются, как и ожидалось, на панели просмотра журналов под textPayload . Когда я передаю строку JSON, они отображаются под jsonPayload . Пока все хорошо.

Итак, я добавил severity поле в выходную строку, и Stackdriver Log Viewer успешно классифицирует сообщение в соответствии с УВЕДОМЛЕНИЕМ о регистрации на уровне, ПРЕДУПРЕЖДЕНИЕМ и т.д.https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry

В документах говорится, что нужно установить trace идентификатор для сопоставления записей журнала с исходным журналом запросов. Идентификатор трассировки извлекается из 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, поскольку я не хочу регистрироваться напрямую с помощью пакета ведения журнала Google Cloud).

Что именно GAE делает для анализа потока stdout из моего запущенного процесса? (В руководстве по установке для виртуальных машин на 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, "%sn", 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",
...
  

Комментарии:

1. Не используйте функцию parseXCloudTraceContext (), описанную выше, ни для чего другого, кроме этого однопоточного тестового примера. В рабочей среде не всегда присутствует часть x-cloud-trace-context ;o = 1, что приводит к панике.

Ответ №1:

Я решил это, настроив программу на использование logging.googleapis.com/trace вместо trace и 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, "%sn", warning)
  

Похоже, GAE использует агент ведения журнала google-fluentd (модифицированную версию fluentd сборщика данных журнала).)

Смотрите эту ссылку для полного объяснения. https://cloud.google.com/logging/docs/agent/configuration#special-fields

[обновление] 25 июня 2019 года: Я написал плагин Logrus, который поможет обрабатывать записи журнала с помощью HTTP-запроса. Он доступен на GitHubhttps://github.com/andyfusniak/stackdriver-gae-logrus-plugin.

[обновление]] 3 апреля 2020 года: с тех пор я перешел на использование Cloud Run, и плагин Logrus, похоже, также отлично работает с этой платформой.