بدون گلوبال به آثار otel بروید
بنابراین من در حال انجام برخی از کارهایی هستم که به یک سرویس GO اضافه می کنم و یادداشت هایی دارم. سرویس مورد نظر درخواست هایی را با عنوان های ردیابی دریافت می کند ، اما همچنین به خدمات دیگر تماس می گیرد و بنابراین باید عنوان ها را به درخواست های بعدی نیز تزریق کند.
در مرحله اول ، Otel SDK بسیار گسترده است و مدتی طول می کشد تا سرتان را دور خود بکشید. همچنین ، فکر نکنید که فقط می توانید یک افزونه را برای روتر HTTP خود اضافه کنید و انجام شود- متاسفانه چنین شانسی نیست. مثالهای SDK از متغیرهای جهانی در مکان های مختلف که من واقعاً دوست ندارم استفاده می کند. در واقع از چند سال پیش مانند کتابخانه پرومتئوس احساس می شود. به هر حال ، این راهنما با هدف جلوگیری از همه متغیرهای جهانی و انجام صحیح کارها است.
راه اندازی
اول چیزها اول- شما به یک دسته از مواردی که فوری می کنید نیاز دارید و سپس برنامه خود را منتقل می کنید. فهمیدم که 3 موردی که برای عبور از آن نیاز داشتم این بود trace.Tracer
با trace.TracerProvider
و propagation.TextMapPropagator
بشر
تنظیم واقعی هر یک از این موارد مانند این به نظر می رسد:
...
otel.SetTracerProvider(noop.NewTracerProvider())
exporter, err := otlptracehttp.New(ctx)
r := resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName("myService"),
semconv.ServiceVersionKey.String("myVersion"),
)
traceProvider := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(r),
)
tracer = traceProvider.Tracer(serviceName, trace.WithInstrumentationVersion(version))
textMapPropagator := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
...
کاری که من به پایان رساندم ، ایجاد ساختاری با این چیزها در آن است ، به علاوه برخی موارد مشاهده دیگر که همه در اطراف برنامه با هم منتقل می شوند و این باعث می شود چیز بسیار تمیزتر شود
...
type O11y struct {
Logger *zerolog.Logger
Metrics *PromMetrics
Tracer trace.Tracer
TraceProvider trace.TracerProvider
TextMapPropagator propagation.TextMapPropagator
}
...
در این تنظیم از برخی متغیرهای محیط استفاده می شود تا در واقع جزئیات نقطه انتهایی OTEL را بدست آورید. جزئیات بیشتر در مورد این موارد را می توان در مشخصات متغیر محیط یافت. من این الگوی را دوست دارم زیرا تغییر نقطه پایانی بدون تغییر کد واقعی می تواند رخ دهد.
اکنون ما آماده استفاده از این موارد در جایی هستیم.
سرور HTTP
بیایید فرض کنیم که از نوعی بسته روتر استفاده می کنید- من به شدت توصیه می کنم که از افزونه OTEL برای آن بسته استفاده کنید. می توانید این افزونه ها را در رجیستری OTEL پیدا کنید. در این حالت ما از Julien Schmidt Httprouter استفاده می کنیم و این افزونه از Splunk است (هیچ ارتباطی با ورود به سیستم Splunk شما نیست)- Splunkhttprouter.
مسیر واردات برای این کمی مسخره است ، اما من دوست دارم آن را نامعقول کنم تا بدانم که ما با نسخه ردیابی کار می کنیم:
import (
...
tracerouter "github.com/signalfx/splunk-otel-go/instrumentation/github.com/julienschmidt/httprouter/splunkhttprouter"
...
)
اکنون واقعاً باید روتر درست کنید و آن را به ساختار سرور اضافه کنید:
type Server struct {
router *tracerouter.Router
O11y
}
func New(o o11y.O11y) (*Server, error){
...
s := &Server{
router: tracerouter.New(
otelhttp.WithTracerProvider(o.TraceProvider),
otelhttp.WithPropagators(o.TextMapPropagator),
),
}
...
return s, nil
}
یک یادداشت کوچک در اینجا- ممکن است بخواهید برخی از مسیرها را از داشتن هرگونه ردیابی روی آنها محروم کنید. این به شرح زیر انجام می شود:
func OtelReqFilter(req *http.Request) bool {
return req.URL.Path != "/healthcheck" &&
req.URL.Path != "/metrics"
}
سپس این را به عنوان گزینه دیگری در tracerouter.New()
، یعنی
...
router: tracerouter.New(
otelhttp.WithFilter(tracer.OtelReqFilter),
...
اکنون سرانجام به جایی می رسیم و می توانیم برخی از دهانه ها را اضافه کنیم.
func (s *Server) myRouteHandler(w http.ResponseWriter, r *http.Request) {
span := trace.SpanFromContext(r.Context())
defer span.End()
....
}
یک چیز دیگر- رسیدگی به خطای یک عمل دو مرحله ای است:
span.RecordError(err)
span.SetStatus(codes.Error, "some error")
خلاف واقع در اولین عملیات در واقع وضعیت دهانه را تعیین نمی کند.
مشتری HTTP
اکنون مشتری بسیار ساده تر است ، با این حال ، زیرا ما از مقادیر جهانی در OTEL SDK استفاده نمی کنیم ، ما هنوز هم باید در بعضی موارد عبور کنیم تا هدرهای کمیاب در درخواست های خروجی تزریق شوند.
برای هر مشتری که آن را ایجاد می کنید باید چیزی شبیه به آن باشد:
client := &http.Client{Transport: otelhttp.NewTransport(
http.DefaultTransport,
otelhttp.WithTracerProvider(o.TraceProvider),
otelhttp.WithPropagators(o.TextMapPropagator),
)}
پایان
- از متغیرهای جهانی استفاده نکنید
- چیزهایی را که نیاز خود را به آن منتقل کنید- بیش از آنچه برای OTEL فکر می کنید وجود دارد.
- برای تنظیم پارامترهای OTEL مانند درصد نمونه برداری از متغیرهای محیط استفاده کنید. این بدان معنی است که برای به روزرسانی آنها به تغییر کد احتیاج ندارید.
- درخواست های خود را فیلتر کنید
/metrics
وت/healthchecks
بشر