GCPにおける効果的な囲碁
35272 ワード
構造化ログ
構造化されたログは、クラウドランで実行されているアプリケーションにあなたの洞察をレベルアップする方法です.この中に
例では、ログの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のログ出力のように見えるものを見てみましょう文.
高度なログ記録クエリ.
細かい粒度のアプリケーションの動作.
{
// 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に統合の容易さのため.
Reference
この問題について(GCPにおける効果的な囲碁), 我々は、より多くの情報をここで見つけました https://dev.to/amammay/effective-go-on-cloud-run-structured-logging-56bdテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol