Golang 语言快速开始
快速开始
本文将描述您如何在 Golang 中开始使用 OpenTelemetry即OTel。您将学习如何对一个简单的Golang应用程序进行观测,并向控制台上报trace、log、metrics数据
注意:
日志信号仍处于实验阶段。未来版本中可能会引入重大更改。
前置条件
确保您已在本地安装以下软件:
go 1.22 或更高版本
Demo示例
以下示例使用基本的 net/http 应用程序。如果您不使用 net/http,那也没关系——您也可以将 OpenTelemetry Go 与其他 Web 框架一起使用,例如 Gin 和 Echo。有关受支持框架的库的完整列表,请参阅注册表。
有关更详细的示例,请参阅示例
设置
开始时候在你的新的目录中设置go mod
go mod init dice
创建并启动 HTTP 服务器
在同一文件夹中,创建一个名为 main.go 的文件并将以下代码添加到该文件中:
package main
import ( "log" "net/http")
func main() { http.HandleFunc("/rolldice", rolldice)
log.Fatal(http.ListenAndServe(":8080", nil))}
创建另一个名为 rolldice.go 的文件,并将以下代码添加到该文件中:
package main
import ( "io" "log" "math/rand" "net/http" "strconv")
func rolldice(w http.ResponseWriter, r *http.Request) { roll := 1 + rand.Intn(6)
resp := strconv.Itoa(roll) + "\n" if _, err := io.WriteString(w, resp); err != nil { log.Printf("Write failed: %v\n", err) }}
使用以下命令构建并运行应用程序:
go run .
在 Web 浏览器中打开 http://localhost:8080/rolldice 以确保其正常工作。
增加OpenTelemetry 注入
现在我们将展示如何将OpenTelemetry注入添加到示例应用程序中。如果您正在使用自己的应用程序,可以跟随操作,只需注意您的代码可能会略有不同。
添加依赖项
go get "go.opentelemetry.io/otel" \ "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" \ "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" \ "go.opentelemetry.io/otel/exporters/stdout/stdoutlog" \ "go.opentelemetry.io/otel/sdk/log" \ "go.opentelemetry.io/otel/log/global" \ "go.opentelemetry.io/otel/propagation" \ "go.opentelemetry.io/otel/sdk/metric" \ "go.opentelemetry.io/otel/sdk/resource" \ "go.opentelemetry.io/otel/sdk/trace" \ "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"\ "go.opentelemetry.io/contrib/bridges/otelslog"
这将安装OpenTelemetry SDK组件和针对net/http的自动监测功能。如果你需要对其他用于网络请求的库进行监测,你可能需要安装相应的库监测工具。更多关于库的信息,请参见相关文档。
初始化OpenTelemetry SDK
首先,我们将初始化OpenTelemetry SDK。这对于任何导出遥测数据的应用程序都是必需的。
创建一个名为<font style="color:rgb(51, 51, 51);background-color:rgb(247, 249, 253);">otel.go</font>
的文件,并在里面添加OpenTelemetry SDK的引导代码:
package main
import ( "context" "errors" "time"
"go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/stdout/stdoutlog" "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/log/global" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/log" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/trace")
// setupOTelSDK bootstraps the OpenTelemetry pipeline.// If it does not return an error, make sure to call shutdown for proper cleanup.func setupOTelSDK(ctx context.Context) (shutdown func(context.Context) error, err error) { var shutdownFuncs []func(context.Context) error
// shutdown calls cleanup functions registered via shutdownFuncs. // The errors from the calls are joined. // Each registered cleanup will be invoked once. shutdown = func(ctx context.Context) error { var err error for _, fn := range shutdownFuncs { err = errors.Join(err, fn(ctx)) } shutdownFuncs = nil return err }
// handleErr calls shutdown for cleanup and makes sure that all errors are returned. handleErr := func(inErr error) { err = errors.Join(inErr, shutdown(ctx)) }
// Set up propagator. prop := newPropagator() otel.SetTextMapPropagator(prop)
// Set up trace provider. tracerProvider, err := newTraceProvider() if err != nil { handleErr(err) return } shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown) otel.SetTracerProvider(tracerProvider)
// Set up meter provider. meterProvider, err := newMeterProvider() if err != nil { handleErr(err) return } shutdownFuncs = append(shutdownFuncs, meterProvider.Shutdown) otel.SetMeterProvider(meterProvider)
// Set up logger provider. loggerProvider, err := newLoggerProvider() if err != nil { handleErr(err) return } shutdownFuncs = append(shutdownFuncs, loggerProvider.Shutdown) global.SetLoggerProvider(loggerProvider)
return}
func newPropagator() propagation.TextMapPropagator { return propagation.NewCompositeTextMapPropagator( propagation.TraceContext{}, propagation.Baggage{}, )}
func newTraceProvider() (*trace.TracerProvider, error) { traceExporter, err := stdouttrace.New( stdouttrace.WithPrettyPrint()) if err != nil { return nil, err }
traceProvider := trace.NewTracerProvider( trace.WithBatcher(traceExporter, // Default is 5s. Set to 1s for demonstrative purposes. trace.WithBatchTimeout(time.Second)), ) return traceProvider, nil}
func newMeterProvider() (*metric.MeterProvider, error) { metricExporter, err := stdoutmetric.New() if err != nil { return nil, err }
meterProvider := metric.NewMeterProvider( metric.WithReader(metric.NewPeriodicReader(metricExporter, // Default is 1m. Set to 3s for demonstrative purposes. metric.WithInterval(3*time.Second))), ) return meterProvider, nil}
func newLoggerProvider() (*log.LoggerProvider, error) { logExporter, err := stdoutlog.New() if err != nil { return nil, err }
loggerProvider := log.NewLoggerProvider( log.WithProcessor(log.NewBatchProcessor(logExporter)), ) return loggerProvider, nil}
如果你只使用追踪(Tracing)或度量(Metrics),你可以省略对应的TracerProvider
或MeterProvider
初始化代码。
对HTTP Server进行注入
现在我们已经初始化了OpenTelemetry SDK,接下来可以对HTTP服务器进行监控(instrument)了。
请修改main.go文件,以包含以下代码:这将设置OpenTelemetry SDK,并使用otelhttp库来对HTTP服务器进行监控。
package main
import ( "context" "errors" "log" "net" "net/http" "os" "os/signal" "time"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp")
func main() { if err := run(); err != nil { log.Fatalln(err) }}
func run() (err error) { // Handle SIGINT (CTRL+C) gracefully. ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) defer stop()
// Set up OpenTelemetry. otelShutdown, err := setupOTelSDK(ctx) if err != nil { return } // Handle shutdown properly so nothing leaks. defer func() { err = errors.Join(err, otelShutdown(context.Background())) }()
// Start HTTP server. srv := &http.Server{ Addr: ":8080", BaseContext: func(_ net.Listener) context.Context { return ctx }, ReadTimeout: time.Second, WriteTimeout: 10 * time.Second, Handler: newHTTPHandler(), } srvErr := make(chan error, 1) go func() { srvErr <- srv.ListenAndServe() }()
// Wait for interruption. select { case err = <-srvErr: // Error when starting HTTP server. return case <-ctx.Done(): // Wait for first CTRL+C. // Stop receiving signal notifications as soon as possible. stop() }
// When Shutdown is called, ListenAndServe immediately returns ErrServerClosed. err = srv.Shutdown(context.Background()) return}
func newHTTPHandler() http.Handler { mux := http.NewServeMux()
// handleFunc is a replacement for mux.HandleFunc // which enriches the handler's HTTP instrumentation with the pattern as the http.route. handleFunc := func(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) { // Configure the "http.route" for the HTTP instrumentation. handler := otelhttp.WithRouteTag(pattern, http.HandlerFunc(handlerFunc)) mux.Handle(pattern, handler) }
// Register handlers. handleFunc("/rolldice/", rolldice) handleFunc("/rolldice/{player}", rolldice)
// Add HTTP instrumentation for the whole server. handler := otelhttp.NewHandler(mux, "/") return handler}
增加第三方注入
注入库在系统的边缘处捕获遥测数据,例如入站和出站HTTP请求,但它们不会捕获应用程序内部的情况。为此,您需要编写一些自定义的手动注入代码。
使用OpenTelemetry API修改rolldice.go以包含自定义注入:
package main
import ( "fmt" "io" "log" "math/rand" "net/http" "strconv"
"go.opentelemetry.io/contrib/bridges/otelslog" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric")
const name = "go.opentelemetry.io/otel/example/dice"
var ( tracer = otel.Tracer(name) meter = otel.Meter(name) logger = otelslog.NewLogger(name) rollCnt metric.Int64Counter)
func init() { var err error rollCnt, err = meter.Int64Counter("dice.rolls", metric.WithDescription("The number of rolls by roll value"), metric.WithUnit("{roll}")) if err != nil { panic(err) }}
func rolldice(w http.ResponseWriter, r *http.Request) { ctx, span := tracer.Start(r.Context(), "roll") defer span.End()
roll := 1 + rand.Intn(6)
var msg string if player := r.PathValue("player"); player != "" { msg = fmt.Sprintf("%s is rolling the dice", player) } else { msg = "Anonymous player is rolling the dice" } logger.InfoContext(ctx, msg, "result", roll)
rollValueAttr := attribute.Int("roll.value", roll) span.SetAttributes(rollValueAttr) rollCnt.Add(ctx, 1, metric.WithAttributes(rollValueAttr))
resp := strconv.Itoa(roll) + "\n" if _, err := io.WriteString(w, resp); err != nil { log.Printf("Write failed: %v\n", err) }}
请注意,如果您仅使用跟踪或度量,可以省略用于注入另一种遥测类型对应的代码。
运行应用
通过以下命令编译并运行这个应用:
go mod tidyexport OTEL_RESOURCE_ATTRIBUTES="service.name=dice,service.version=0.1.0"go run .
在您的网络浏览器中打开 http://localhost:8080/rolldice/Alice。当您向服务器发送请求时,您将在控制台看到两个跨度(span)记录。由监控库生成的跨度跟踪了对/rolldice/{player} 路由的请求生命周期。另一个称为“roll”的跨度是手动创建的,并且它是前一个提到的跨度的子级。
查看demo输出
{ "Name": "roll", "SpanContext": { "TraceID": "829fb7ceb787403c96eac3caf285c965", "SpanID": "8b6b408b6c1a35e5", "TraceFlags": "01", "TraceState": "", "Remote": false }, "Parent": { "TraceID": "829fb7ceb787403c96eac3caf285c965", "SpanID": "612be4bbdf450de6", "TraceFlags": "01", "TraceState": "", "Remote": false }, "SpanKind": 1, "StartTime": "2023-09-25T12:42:06.177119576+02:00", "EndTime": "2023-09-25T12:42:06.177136776+02:00", "Attributes": [ { "Key": "roll.value", "Value": { "Type": "INT64", "Value": 6 } } ], "Events": null, "Links": null, "Status": { "Code": "Unset", "Description": "" }, "DroppedAttributes": 0, "DroppedEvents": 0, "DroppedLinks": 0, "ChildSpanCount": 0, "Resource": [ { "Key": "service.name", "Value": { "Type": "STRING", "Value": "dice" } }, { "Key": "service.version", "Value": { "Type": "STRING", "Value": "0.1.0" } }, { "Key": "telemetry.sdk.language", "Value": { "Type": "STRING", "Value": "go" } }, { "Key": "telemetry.sdk.name", "Value": { "Type": "STRING", "Value": "opentelemetry" } }, { "Key": "telemetry.sdk.version", "Value": { "Type": "STRING", "Value": "1.19.0-rc.1" } } ], "InstrumentationLibrary": { "Name": "rolldice", "Version": "", "SchemaURL": "" }}{ "Name": "/", "SpanContext": { "TraceID": "829fb7ceb787403c96eac3caf285c965", "SpanID": "612be4bbdf450de6", "TraceFlags": "01", "TraceState": "", "Remote": false }, "Parent": { "TraceID": "00000000000000000000000000000000", "SpanID": "0000000000000000", "TraceFlags": "00", "TraceState": "", "Remote": false }, "SpanKind": 2, "StartTime": "2023-09-25T12:42:06.177071077+02:00", "EndTime": "2023-09-25T12:42:06.177158076+02:00", "Attributes": [ { "Key": "http.method", "Value": { "Type": "STRING", "Value": "GET" } }, { "Key": "http.scheme", "Value": { "Type": "STRING", "Value": "http" } }, { "Key": "http.flavor", "Value": { "Type": "STRING", "Value": "1.1" } }, { "Key": "net.host.name", "Value": { "Type": "STRING", "Value": "localhost" } }, { "Key": "net.host.port", "Value": { "Type": "INT64", "Value": 8080 } }, { "Key": "net.sock.peer.addr", "Value": { "Type": "STRING", "Value": "::1" } }, { "Key": "net.sock.peer.port", "Value": { "Type": "INT64", "Value": 49046 } }, { "Key": "http.user_agent", "Value": { "Type": "STRING", "Value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36" } }, { "Key": "http.route", "Value": { "Type": "STRING", "Value": "/rolldice/Alice" } }, { "Key": "http.wrote_bytes", "Value": { "Type": "INT64", "Value": 2 } }, { "Key": "http.status_code", "Value": { "Type": "INT64", "Value": 200 } } ], "Events": null, "Links": null, "Status": { "Code": "Unset", "Description": "" }, "DroppedAttributes": 0, "DroppedEvents": 0, "DroppedLinks": 0, "ChildSpanCount": 1, "Resource": [ { "Key": "service.name", "Value": { "Type": "STRING", "Value": "dice" } }, { "Key": "service.version", "Value": { "Type": "STRING", "Value": "0.1.0" } }, { "Key": "telemetry.sdk.language", "Value": { "Type": "STRING", "Value": "go" } }, { "Key": "telemetry.sdk.name", "Value": { "Type": "STRING", "Value": "opentelemetry" } }, { "Key": "telemetry.sdk.version", "Value": { "Type": "STRING", "Value": "1.19.0-rc.1" } } ], "InstrumentationLibrary": { "Name": "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp", "Version": "0.44.0", "SchemaURL": "" }}
除了跟踪信息,日志消息也会被输出到控制台。
查看输出
{ "Timestamp": "2023-09-25T12:42:05.177136776+02:00", "ObservedTimestamp": "2023-09-25T12:42:06.809396011+02:00", "Severity": 9, "SeverityText": "", "Body": { "Type": "String", "Value": "Alice is rolling the dice" }, "Attributes": [ { "Key": "result", "Value": { "Type": "Int64", "Value": 6 } } ], "TraceID": "829fb7ceb787403c96eac3caf285c965", "SpanID": "8b6b408b6c1a35e5", "TraceFlags": "01", "Resource": [ { "Key": "service.name", "Value": { "Type": "STRING", "Value": "dice" } }, { "Key": "service.version", "Value": { "Type": "STRING", "Value": "0.1.0" } }, { "Key": "telemetry.sdk.language", "Value": { "Type": "STRING", "Value": "go" } }, { "Key": "telemetry.sdk.name", "Value": { "Type": "STRING", "Value": "opentelemetry" } }, { "Key": "telemetry.sdk.version", "Value": { "Type": "STRING", "Value": "1.19.0-rc.1" } } ], "Scope": { "Name": "rolldice", "Version": "", "SchemaURL": "" }, "DroppedAttributes": 0}
刷新几次http://localhost:8080/rolldice/Alice这个页面,然后稍等片刻或者终止应用程序,你将会在控制台输出中看到指标信息。你会观察到dice.rolls这个指标被输出到控制台,针对每个掷骰子的结果值都有独立的计数,同时还能看到由监控库生成的HTTP相关指标。
查看输出:
{ "Resource": [ { "Key": "service.name", "Value": { "Type": "STRING", "Value": "dice" } }, { "Key": "service.version", "Value": { "Type": "STRING", "Value": "0.1.0" } }, { "Key": "telemetry.sdk.language", "Value": { "Type": "STRING", "Value": "go" } }, { "Key": "telemetry.sdk.name", "Value": { "Type": "STRING", "Value": "opentelemetry" } }, { "Key": "telemetry.sdk.version", "Value": { "Type": "STRING", "Value": "1.19.0-rc.1" } } ], "ScopeMetrics": [ { "Scope": { "Name": "rolldice", "Version": "", "SchemaURL": "" }, "Metrics": [ { "Name": "dice.rolls", "Description": "The number of rolls by roll value", "Unit": "{roll}", "Data": { "DataPoints": [ { "Attributes": [ { "Key": "roll.value", "Value": { "Type": "INT64", "Value": 1 } } ], "StartTime": "2023-09-25T12:42:04.279204638+02:00", "Time": "2023-09-25T12:42:15.482694258+02:00", "Value": 4 }, { "Attributes": [ { "Key": "roll.value", "Value": { "Type": "INT64", "Value": 5 } } ], "StartTime": "2023-09-25T12:42:04.279204638+02:00", "Time": "2023-09-25T12:42:15.482694258+02:00", "Value": 3 }, { "Attributes": [ { "Key": "roll.value", "Value": { "Type": "INT64", "Value": 3 } } ], "StartTime": "2023-09-25T12:42:04.279204638+02:00", "Time": "2023-09-25T12:42:15.482694258+02:00", "Value": 4 }, { "Attributes": [ { "Key": "roll.value", "Value": { "Type": "INT64", "Value": 2 } } ], "StartTime": "2023-09-25T12:42:04.279204638+02:00", "Time": "2023-09-25T12:42:15.482694258+02:00", "Value": 2 }, { "Attributes": [ { "Key": "roll.value", "Value": { "Type": "INT64", "Value": 6 } } ], "StartTime": "2023-09-25T12:42:04.279204638+02:00", "Time": "2023-09-25T12:42:15.482694258+02:00", "Value": 5 }, { "Attributes": [ { "Key": "roll.value", "Value": { "Type": "INT64", "Value": 4 } } ], "StartTime": "2023-09-25T12:42:04.279204638+02:00", "Time": "2023-09-25T12:42:15.482694258+02:00", "Value": 9 } ], "Temporality": "CumulativeTemporality", "IsMonotonic": true } } ] }, { "Scope": { "Name": "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp", "Version": "0.44.0", "SchemaURL": "" }, "Metrics": [ { "Name": "http.server.request_content_length", "Description": "", "Unit": "", "Data": { "DataPoints": [ { "Attributes": [ { "Key": "http.flavor", "Value": { "Type": "STRING", "Value": "1.1" } }, { "Key": "http.method", "Value": { "Type": "STRING", "Value": "GET" } }, { "Key": "http.route", "Value": { "Type": "STRING", "Value": "/rolldice/Alice" } }, { "Key": "http.scheme", "Value": { "Type": "STRING", "Value": "http" } }, { "Key": "http.status_code", "Value": { "Type": "INT64", "Value": 200 } }, { "Key": "net.host.name", "Value": { "Type": "STRING", "Value": "localhost" } }, { "Key": "net.host.port", "Value": { "Type": "INT64", "Value": 8080 } } ], "StartTime": "2023-09-25T12:42:04.279212238+02:00", "Time": "2023-09-25T12:42:15.482695758+02:00", "Value": 0 } ], "Temporality": "CumulativeTemporality", "IsMonotonic": true } }, { "Name": "http.server.response_content_length", "Description": "", "Unit": "", "Data": { "DataPoints": [ { "Attributes": [ { "Key": "http.flavor", "Value": { "Type": "STRING", "Value": "1.1" } }, { "Key": "http.method", "Value": { "Type": "STRING", "Value": "GET" } }, { "Key": "http.route", "Value": { "Type": "STRING", "Value": "/rolldice/Alice" } }, { "Key": "http.scheme", "Value": { "Type": "STRING", "Value": "http" } }, { "Key": "http.status_code", "Value": { "Type": "INT64", "Value": 200 } }, { "Key": "net.host.name", "Value": { "Type": "STRING", "Value": "localhost" } }, { "Key": "net.host.port", "Value": { "Type": "INT64", "Value": 8080 } } ], "StartTime": "2023-09-25T12:42:04.279214438+02:00", "Time": "2023-09-25T12:42:15.482696158+02:00", "Value": 54 } ], "Temporality": "CumulativeTemporality", "IsMonotonic": true } }, { "Name": "http.server.duration", "Description": "", "Unit": "", "Data": { "DataPoints": [ { "Attributes": [ { "Key": "http.flavor", "Value": { "Type": "STRING", "Value": "1.1" } }, { "Key": "http.method", "Value": { "Type": "STRING", "Value": "GET" } }, { "Key": "http.route", "Value": { "Type": "STRING", "Value": "/rolldice/Alice" } }, { "Key": "http.scheme", "Value": { "Type": "STRING", "Value": "http" } }, { "Key": "http.status_code", "Value": { "Type": "INT64", "Value": 200 } }, { "Key": "net.host.name", "Value": { "Type": "STRING", "Value": "localhost" } }, { "Key": "net.host.port", "Value": { "Type": "INT64", "Value": 8080 } } ], "StartTime": "2023-09-25T12:42:04.279219438+02:00", "Time": "2023-09-25T12:42:15.482697158+02:00", "Count": 27, "Bounds": [ 0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000 ], "BucketCounts": [ 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "Min": {}, "Max": {}, "Sum": 2.1752759999999993 } ], "Temporality": "CumulativeTemporality" } } ] } ]}
将观测数据发往 OTel Collector
OTel Collector 是大多数生产部署中一个关键的组件。以下是一些使用OTel Collector的优势:
● 一个由多个服务共享的单一可观测数据收集器,以减少切换Exporter的开销
- 在发往服务端之前可以集中处理trace,避免重复处理操作
● 可以聚合多个服务、多个主机上的Trace
除非您只有一个服务或正在进行测试,否则在生产部署中,推荐您使用收集器
配置并启动一个本地的OTel Collector
首先,将以下OTel Collector配置代码保存到 /tmp/ 目录中的文件中:
receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4319 http: endpoint: 0.0.0.0:4320exporters: # NOTE: Prior to v0.86.0 use `logging` instead of `debug`. debug: verbosity: detailedprocessors: batch:service: pipelines: traces: receivers: [otlp] exporters: [debug] processors: [batch] metrics: receivers: [otlp] exporters: [debug] processors: [batch] logs: receivers: [otlp] exporters: [debug] processors: [batch]
以上配置将使用otlp 协议来接收用户的输入,即OTel Go SDK与OTel Collector之间使用otlp 协议进行通信。并将数据最终打印在OTel Collector控制台。您也可以将数据上报至于Prometheus 或者Jaeger中,详细的配置信息见:OTel Collector配置
然后运行 Docker 命令,根据此配置获取并运行OTel Collector:
docker run -p 4320:4320 \ -v /tmp/otel-collector-config.yaml:/etc/otel-collector-config.yaml \ otel/opentelemetry-collector:latest \ --config=/etc/otel-collector-config.yaml
您现在将在本地运行一个OTel Collector实例,该实例监听4320端口。
运行Demo
export OTEL_EXPORTER_OTLP_ENDPOINT="0.0.0.0:4320"
https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/examples/demo
启动Jaeger
通过4317端口接收OTel Collector发送的数据
docker run -d --name jaeger \ -e COLLECTOR_OTLP_ENABLED=true \ -p 16686:16686 \ -p 4317:4317 \ -p 4318:4318 \ jaegertracing/all-in-one:latest
查看数据
通过http://0.0.0.0:16686 查看Trace数据