GCPにおける効果的な囲碁


構造化ログ


構造化されたログは、クラウドランで実行されているアプリケーションにあなたの洞察をレベルアップする方法です.この中に
例では、ログの3種類のスタイルと、それぞれのために取得する増分の利点を行くだろう.
ソースコードはここにあります.

https://github.com/amammay/effectivecloudrun 標準ライブラリログ


私たちの基本的なログのアプローチは、それが取得するように簡単ですが、我々はログパッケージの下でgolang stdライブラリのログを使用します.If
あなたは行くために新しいです、これはあなたがこれまで使っていたものが最も可能です.と同じくらい簡単です
package main

import (
    "log"
)

func main() {
    log.Printf("hello %q", "alex")
}
このロガーを使用すると、出力はstderrに向けられ、クラウドランはログ文を取得し、
それのまわりの情報の小さいビット、ここでは、我々がログに記録するとき、GCPログによって生じるものの例です
このlog.Printf("hello %q! im an standard logger from the golang standard library", request.UserAgent())
{
  // text payload is our actual log message
  "textPayload": "2021/08/18 01:30:11 hello \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36\"! im an standard logger from the golang standard library",
  // insert id is automatically calculated
  "insertId": "611c62a30008cc0be6f91983",
  // resource is automatically inferred due to the log entry being written to STDERR
  "resource": {
    "type": "cloud_run_revision",
    "labels": {
      "service_name": "logging",
      "project_id": "mammay-labs",
      "revision_name": "logging-00003-wil",
      "location": "us-central1",
      "configuration_name": "logging"
    }
  },
  // timestamp is auto calculated
  "timestamp": "2021-08-18T01:30:11.576523Z",
  // instance id label is automatically added
  "labels": {
    "instanceId": "00bf4bf02dd076018e4f332daec97d8ebce3bb2a4da1d941bc9f30e3773efd19ff329eb7e3778f1461e05af587de3d79095acfe02468a6d875c5552845"
  },
  // gcp will monitor stdout and stderr
  "logName": "projects/mammay-labs/logs/run.googleapis.com%2Fstderr",
  // another timestamp that is auto calculated
  "receiveTimestamp": "2021-08-18T01:30:11.829264005Z"
}

それで、我々が標準ライブラリLoggerのために示したものはGCPの上で何かを記録する最も原始的な方法です、しかし、あなた
GCPでこれを実行している!あなたは同様にあなたの降圧のための最もバンを取得し、いくつかの構造化されたログとそれを牛肉て
文.

基本構造化ログ


私たちの基本的な構造化されたログの作成は、どのように実装したいかについて非常に柔軟です.あなたならば
チームは、あなたが他のチームメイトに配布されるロガーの上に多くの柔軟性/支配を必要とします
そのような目標を達成するためのビルディングブロックでしょう.
あなたがやりたいことの要点は、ログをstderrにJSONとして書くことです.次のスキーマがあります
エントリを書くと、要件を表示できます
こちらが
あなたが構造化されたログ記録スキーマに従う何かを実装することができる最も基本的な方法は、.
package logx

import (
    "fmt"
    "net/http"
)

func info(r *http.Request, message interface{}, projectID string) {
    get := r.Header.Get("X-Cloud-Trace-Context")
    traceID, spanID, traceSampled := deconstructXCloudTraceContext(get)
    traceID = fmt.Sprintf("projects/%s/traces/%s", projectID, traceID)
    entry := logEntry{
        Severity: "INFO",
        Message:  message,
        HttpRequest: &httpRequest{
            RequestMethod: r.Method,
            RequestUrl:    r.URL.String(),
            UserAgent:     r.UserAgent(),
            RemoteIp:      r.RemoteAddr,
            Referer:       r.Referer(),
        },
        Timestamp:    time.Now(),
        Labels:       map[string]string{"labels": "rock"},
        SpanID:       spanID,
        TraceID:      traceID,
        TraceSampled: traceSampled,
    }
    writelog(&entry)
}

func writelog(entry *logEntry) {
    if err := json.NewEncoder(os.Stderr).Encode(entry); err != nil {
        fmt.Printf("failure to write structured log entry: %v", err)
    }
}

// taken from https://github.com/googleapis/google-cloud-go/blob/master/logging/logging.go#L774
var reCloudTraceContext = regexp.MustCompile(
    // Matches on "TRACE_ID"
    `([a-f\d]+)?` +
        // Matches on "/SPAN_ID"
        `(?:/([a-f\d]+))?` +
        // Matches on ";0=TRACE_TRUE"
        `(?:;o=(\d))?`)

func deconstructXCloudTraceContext(s string) (traceID, spanID string, traceSampled bool) {
    // As per the format described at https://cloud.google.com/trace/docs/setup#force-trace
    //    "X-Cloud-Trace-Context: TRACE_ID/SPAN_ID;o=TRACE_TRUE"
    // for example:
    //    "X-Cloud-Trace-Context: 105445aa7843bc8bf206b120001000/1;o=1"
    //
    // We expect:
    //   * traceID (optional):          "105445aa7843bc8bf206b120001000"
    //   * spanID (optional):           "1"
    //   * traceSampled (optional):     true
    matches := reCloudTraceContext.FindStringSubmatch(s)

    traceID, spanID, traceSampled = matches[1], matches[2], matches[3] == "1"

    if spanID == "0" {
        spanID = ""
    }

    return
}

これは多くのことを達成する.最初にGCPのログ出力のように見えるものを見てみましょう
  • 重大度マッピングは、ログから報告された重大度に基づいて通知を送るために雲監視のために簡単に使われることができます
    文.
  • 高度なログ記録クエリのHTTPリクエストデータをログメッセージを出力します.
  • は、必要に応じて複雑でありえるログメッセージとして構造化されたJSONを提供します.これも機会を提供する
    高度なログ記録クエリ.
  • トレースID +スパンIDのサポート、これは私たちにより良い洞察のためにログエントリをログトレースに関連付けることができます
    細かい粒度のアプリケーションの動作.

  • {
      // auto generated insert ID
      "insertId": "611c679300037f00b8a3abce",
      // our log message gets wrapped in json payload if you send in a json friendly message
      "jsonPayload": {
        "timestamp": "2021-08-18T01:51:15.228952576Z",
        "message": "information message"
      },
      // fill in the http request to give extra context around what our application is handling
      "httpRequest": {
        "requestMethod": "GET",
        "requestUrl": "/structuredlogger",
        "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36",
        "remoteIp": "------"
      },
      // auto generated due to the nature that we are writing to STDERR
      "resource": {
        "type": "cloud_run_revision",
        "labels": {
          "project_id": "mammay-labs",
          "configuration_name": "logging",
          "revision_name": "logging-00003-wil",
          "location": "us-central1",
          "service_name": "logging"
        }
      },
      "timestamp": "2021-08-18T01:51:15.229120Z",
      // pure info severity message, can be anything from https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity
      "severity": "INFO",
      "labels": {
        // custom label we added
        "labels": "rock",
        "instanceId": "00bf4bf02d728741a6c4e41e7cabe309fe6857d005b0a31df24a74786e7f909f47e95c96545a213ea7789f7016f8e2ff0b47fc2732718fe030372f2792"
      },
      "logName": "projects/mammay-labs/logs/run.googleapis.com%2Fstderr",
      // add cloud trace id 
      "trace": "projects/mammay-labs/traces/c83f888de20ad443abe581370e2a3beb",
      "receiveTimestamp": "2021-08-18T01:51:15.474376268Z",
      // add our span id 
      "spanId": "3688206018754987042",
      // notify gcp that we should sample this trace and aggregate data into cloud trace
      "traceSampled": true
    }
    
    GCPの中で、様々な重大性を持つログエントリがどのように見えるかの例です.
    gcp structured-logging
    あなたが見ることができるように、構造化されたログはここで非常に素晴らしいです.さらに、クラウドトレースとスパンの追加
    IDのログステートメントにも、より洞察力のある方法で動作するように多くのGCP製品をパワーアップします.我々は雲をカバーする
    トレース+オープンテレメトリは、後者のポストではさらに生活の質の向上を得るために.

    サードパーティ製のロガー


    Ultra Zap + Zapdriverのようなサードパーティ製のロガーを使用すると、本当に良い開発者の経験を提供します.私たちは
    使いやすさ+構造化されたログ出力の容易さの周りの両方の世界のベスト.これは、同じ構造化されたログ出力を生成します
    前に、しかし、単にカスタムの全体の束を書くことなく、その動作を設定する簡単な方法を提供します
    それのためのコード.
    セットアップZAPはいくつかのコードを見てみましょう
    
    package main
    
    import (
        "fmt"
        "github.com/blendle/zapdriver"
        "go.uber.org/zap"
        "go.uber.org/zap/zapcore"
        "log"
        "net/http"
    )
    
    func uberzaplogger(projectID string, onGCE bool) http.HandlerFunc {
    
        var config zap.Config
        // if on the cloud we will use a production config
        if onGCE {
            // create our uber zap configuration
            config = zapdriver.NewProductionConfig()
            // set the min logging level to debug for this demo
            config.Level = zap.NewAtomicLevelAt(zap.DebugLevel)
        } else {
            // running locally we will use a human-readable output
            config = zapdriver.NewDevelopmentConfig()
            config.Encoding = "console"
            config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
        }
    
        // creates our logger instance
        clientLogger, err := config.Build()
        if err != nil {
            log.Fatalf("zap.config.Build(): %v", err)
        }
    
        wrapTraceContext := func(header string) *zap.SugaredLogger {
            traceID, spanID, sampled := deconstructXCloudTraceContext(header)
            fields := zapdriver.TraceContext(traceID, spanID, sampled, projectID)
            setFields := clientLogger.With(fields...)
            return setFields.Sugar()
        }
    
        return func(writer http.ResponseWriter, request *http.Request) {
            logger := wrapTraceContext(request.Header.Get("X-Cloud-Trace-Context"))
            logger.Debug("debug message")
            logger.Info("info message")
            logger.Warn("warn message")
            logger.Error("error message")
            // calling any below will cause application to quite from the behavior of uber zap
            // logger.DPanic("critical message")
            // logger.Panic("alert message")
            // logger.Fatal("EMERGENCY message")
    
            fmt.Fprintf(writer, "<h1> uber zap is saying hello %q", request.UserAgent())
    
        }
    }
    
    
    
    日の終わりに私の目標は、最も生産的かつ効率的にすることです、私は大いにオプション3に傾く
    すべての私のログの必要性のための設定ZAPを使用して設定とGCPに統合の容易さのため.