Mackerel ã§ã¯ OpenTelemetry ã®ä¸»è¦ãªã·ã°ãã«ã®ãã¡ã®ãã¬ã¼ã¹ã«å¯¾å¿ããåæ£ãã¬ã¼ã·ã³ã°æ©è½ã§ãã Vaxila ã使ããããã«ãªãã¾ãããWeb ã¢ããªã±ã¼ã·ã§ã³ã®ãã³ãã©ãã©ãããããã¨ã§ç°¡åã«è¨è£
ããã©ã¤ãã©ãªãªã©ã¯ä½¿ã£ããã¨ãããã®ã§ãããä»åã¯èªåã§ã¹ãã³ãä½ããã¬ã¼ã¹ãè¨è£
ãããã¨ã§ããç解ãæ·±ãã¦ã¿ããã¨æãã¾ãã
ä»å㯠HTTP ãªã¯ã¨ã¹ããéä¿¡ããã¦ããã¬ã¹ãã³ã¹ãè¿ã£ã¦ããã¾ã§ã®æéããã¬ã¼ã¹ãã¦ã¿ããã¨æãã¾ããMackerel ã®å¤å½¢ç£è¦ã§ã¯ã¹ãã¼ã¿ã¹ã³ã¼ãã証ææ¸ã®æå¹æéãã¬ã¹ãã³ã¹ããã£ã®ãã§ãã¯ãã¬ã¹ãã³ã¹ã¿ã¤ã ã®å¯è¦åãªã©ã¯ã§ãã¾ãããDNS ã®åå解決ãã³ãã¯ã·ã§ã³ã®ç¢ºç«ãTLS ãã³ãã·ã§ã¤ã¯ã®æéãªã©ãè¦ããã¨ãã§ããªãããããããã¹ãã³ã¨ãã¦éä¿¡ãã¦ã¿ã¾ãã
æ¦å¿µã®ãããã
ãã¬ã¼ã¹ã®æ¦å¿µã«é¢ãã¦ã¯ OpenTelemetry ã®ããã¥ã¡ã³ããç°¡æ½ã«ã¾ã¨ã¾ã£ã¦ãã¦ããããããã§ãã
- ãã¬ã¼ã¹ | OpenTelemetry
- Overview | OpenTelemetry
HTTP ãªã¯ã¨ã¹ãå
é¨ã®è¨è£
åç´ã« HTTP ãªã¯ã¨ã¹ããè¨è£
ããã ããªã otelhttp package ã使ç¨ããæ¢åã® handler ã middleware ãã©ããããã ãã§å®çµãã¾ãããä»å㯠DNS ã®åå解決ãªã©ãè¨è£
ãããã®ã§ otelhttp.NewTransport
ãç¨ã㦠Transport
ãå·®ãæ¿ãã¾ããGo 㧠DNS ã®åå解決ãªã©ã® HTTP ãªã¯ã¨ã¹ãå
é¨ã®ã¤ãã³ãããã¬ã¼ã¹ããã«ã¯ httptrace package ã使ç¨ã§ãã¾ãï¼ç¨èªãæ··ãã£ã¦ãããããã§ãããã¡ã㯠OTel ã®ãã¬ã¼ã¹ã¨ã¯å¥ç©ï¼ãClientTrace ã®å®ç¾©ãè¦ãã¨ãããããã«ãåå解決ã®éå§ã¨çµäºãTLS ãã³ãã·ã§ã¤ã¯ã®éå§ã¨çµäºãªã©æ§ã
ãªã¿ã¤ãã³ã°ã«ããã¯ãä»è¾¼ããã¨ãã§ãã¾ãã
trace package ã¨ä¸è¨ã®ããã¯ãçµã¿åãã㦠HTTP ã®å
é¨å¦çã®ã¹ãã³ãä½æãã¾ããtracer.Start
/ tracer.End
ã«ãªãã·ã§ã³ã渡ããã¨ã§ã¿ã¤ã ã¹ã¿ã³ããå±æ§ãªã©æ§ã
ãªè¨å®ãã§ãã¾ããå®éã«ãã£ã¦ã¿ãã®ã以ä¸ã®ã³ã¼ãã
package main
import (
"context"
"crypto/tls"
"log"
"net/http"
"net/http/httptrace"
"time"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
)
func initTracer() func() {
exporter, err := otlptracegrpc.New(context.Background())
if err != nil {
log.Fatalf("failed to initialize exporter: %v", err)
}
tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter))
otel.SetTracerProvider(tp)
return func() {
if err := tp.Shutdown(context.Background()); err != nil {
log.Fatalf("failed to shut down tracer provider: %v", err)
}
}
}
func main() {
shutdown := initTracer()
defer shutdown()
url := "https://example.com"
client := http.Client{
Transport: otelhttp.NewTransport(
http.DefaultTransport,
otelhttp.WithClientTrace(func(ctx context.Context) *httptrace.ClientTrace {
tracer := otel.Tracer("example/client")
var dnsStart, handShakeStart, connStart time.Time
var host string
return &httptrace.ClientTrace{
DNSStart: func(info httptrace.DNSStartInfo) {
dnsStart = time.Now()
host = info.Host
},
DNSDone: func(info httptrace.DNSDoneInfo) {
dnsEnd := time.Now()
_, span := tracer.Start(ctx, "DNS Lookup",
trace.WithTimestamp(dnsStart),
trace.WithAttributes(attribute.String("host", host)),
trace.WithSpanKind(trace.SpanKindClient),
)
span.End(trace.WithTimestamp(dnsEnd))
},
TLSHandshakeStart: func() {
handShakeStart = time.Now()
},
TLSHandshakeDone: func(state tls.ConnectionState, err error) {
handShakeEnd := time.Now()
_, span := tracer.Start(ctx, "TLS Handshake",
trace.WithTimestamp(handShakeStart),
trace.WithAttributes(attribute.Int("CipherSuite", int(state.CipherSuite))),
trace.WithSpanKind(trace.SpanKindClient),
)
if err != nil {
span.RecordError(err)
}
span.End(trace.WithTimestamp(handShakeEnd))
},
ConnectStart: func(network, addr string) {
connStart = time.Now()
},
ConnectDone: func(network, addr string, err error) {
connEnd := time.Now()
_, span := tracer.Start(ctx, "Connection Establishment",
trace.WithTimestamp(connStart),
trace.WithAttributes(
attribute.String("network", network),
attribute.String("address", addr),
),
trace.WithSpanKind(trace.SpanKindClient),
)
if err != nil {
span.RecordError(err)
}
span.End(trace.WithTimestamp(connEnd))
},
}
}),
),
}
ctx := context.Background()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
log.Fatalf("failed to create request: %v", err)
}
resp, err := client.Do(req)
if err != nil {
log.Fatalf("failed to perform request: %v", err)
}
defer resp.Body.Close()
log.Printf("Response status: %s", resp.Status)
}
åããã¯ãã¤ã³ãã§ã¿ã¤ã ã¹ã¿ã³ãããã¹ãåãIP ã¢ãã¬ã¹ãªã©ãå±æ§ã¨ãã¦è¨å®ãã¦ãã¾ããã¾ããã¨ã©ã¼ãèµ·ããå ´åã¯ã¹ãã³ã®ã¨ã©ã¼ãè¨å®ãã¦ãã¾ãã以ä¸ã®éã HTTP ãªã¯ã¨ã¹ãã親ã¨ãã¦åå
é¨å¦çãã¹ãã³ã¨ãã¦æ§é åããã¦ãããã¨ããããã¾ãã
otelhttp.WithClientTrace
ã使ã
ããç¨åº¦ã³ã¼ããæ¸ãã¦ããããã¥ã¡ã³ãã®è£ã©ããä¸ã®ä¸ã§åããã¨ããã¦ãã人ãããªãããæ¹ãã¦èª¿ã¹ã¦ã¿ãã¨ãã otelhttptrace ã¨ããããã±ã¼ã¸ãç¨æããã¦ãããã¨ãç¥ãã¾ããã1
ãã®ããã±ã¼ã¸ã使ã㨠http.Client
ãä½ãé¨åã¯ããã ãã§æ¸ã¿ã¾ãã
client := http.Client{
Transport: otelhttp.NewTransport(
http.DefaultTransport,
otelhttp.WithClientTrace(func(ctx context.Context) *httptrace.ClientTrace {
return otelhttptrace.NewClientTrace(ctx)
}),
),
}
åå¾ããæ
å ±ãå¢ãã¦ãã¦ãããé©åã«æ§é åããã¦ãã¾ããã
åãããããã使ãã°ããã£ãããâ¦ã¨ããæ°æã¡ã«ãªãã¾ããããä»åã¯æã§ã¹ãã³ãä½ã£ã¦ã¿ãã¨ãããã¨ãç®çã ã£ãã®ã§ã°ãã¨ãã®æ°æã¡ã飲ã¿è¾¼ã¿ã¾ãããã£ããã©ã¤ãã©ãªããããã¨ãè¦ã¤ããã®ã§ãã¡ãã§ã¯ã©ããã£ããã¨ããã¦ããã®ããå°ãè¦ã¦ã¿ã¾ããã
åå®ç¾©ãè¦ã¦ããã¨ããã¬ã¼ãµã¼ãããã¤ãã¼ãæå®ããããåéããæ
å ±ã®ã«ã¹ã¿ãã¤ãºãã§ããããã§ããããã©ã«ãã§ã¯èªè¨¼ç¨ã®ãããã¼ãè½ã¨ãããã®ã§ãããåå¾ããããã«ããããè¦ã¤ãã£ãæ
å ±å
¨ã¦ãã¹ãã³ã«ãªããã¨ãæå¶ã§ããããããã
clienttrace.go ãã®ããã¦ã¿ãã¨ãããã¯ã®éå§ã»çµäºå¦çãå
±éåãã¦åã¿ã¤ãã³ã°ã§è¨å®ãããå±æ§ã¨ä¸ç·ã«ãããå¼ã°ãã¦ãã¾ããèªåã§æ¸ããå®è£
ã§ã¯ WithTimestamp
ã使ã£ã¦æã«ã¿ã¤ã ã¹ã¿ã³ããè¨å®ãã¦ãã¾ããããcontext ããã¹ãã³ãåå¾ãã¦éå§ã»çµäºã®ã¿ã¤ãã³ã°ã§åãã¹ãã³ã® Start
/End
ãå¼ãã§ããããã§ããåå®ç¾©ã®ã¨ããã§è¦ãuseSpans
ãã©ã°ã«ãã£ã¦ã¤ãã³ãã¨å±æ§ã®ã¿è¨å®ããã¨ããå¦çãããã¾ããã
Vaxila ã«éä¿¡ãã¦ã¿ã
æå¾ã« Vaxila ã«ãã¬ã¼ã¹ãéä¿¡ãã¦ã¿ã¾ããã¨ã¯ã¹ãã¼ã¿ã¼ã®è¨å®ã以ä¸ã®ããã«å¤ããã ãã§ããæ¨æºåããããããã³ã«ã®ä¾¿å©ããæ¹ãã¦æãã¾ããã
exporter, err := otlptracehttp.New(context.Background(),
otlptracehttp.WithEndpointURL("https://otlp-vaxila.mackerelio.com"),
otlptracehttp.WithHeaders(map[string]string{
"Mackerel-Api-Key": os.Getenv("MACKEREL_APIKEY"),
}),
)
ããæãã«è¡¨ç¤ºããã¾ããã
å®éã«æãåããã¦ãã¬ã¼ã¹ãè¨è£
ãããã¨ã«ãããã¹ãã³ã®è¦ªåé¢ä¿ã®è¨å®ãå±æ§ãã¤ãã³ãã®æ¦å¿µã®ãããããã§ããã®ã¨ãã¹ãã³ã®ç¨®é¡ãï¼ä»åã®å®è£
ã«ã¯åºã¦ãã¾ããã§ãããï¼ãªã³ã¯ãªã©è§¦ãããã¨ã®ãªãæ¦å¿µãããã¨ãããã¨ãç¥ããã¨ãã§ãã¾ããã
ãã®è¨äºã¯ Mackerel Advent Calendar 2024 7æ¥ç®ã®è¨äºã§ããã
qiita.com