diff --git a/cmd/layotto/main.go b/cmd/layotto/main.go index 4e433e27d9..1ef8f39a18 100644 --- a/cmd/layotto/main.go +++ b/cmd/layotto/main.go @@ -170,6 +170,7 @@ import ( _ "mosn.io/layotto/pkg/wasm" _ "mosn.io/layotto/diagnostics/exporter_iml" + "mosn.io/layotto/diagnostics/jaeger" lprotocol "mosn.io/layotto/diagnostics/protocol" lsky "mosn.io/layotto/diagnostics/skywalking" ) @@ -515,7 +516,7 @@ func ExtensionsRegister(_ *cli.Context) { trace.RegisterTracerBuilder("SOFATracer", protocol.HTTP1, tracehttp.NewTracer) trace.RegisterTracerBuilder("SOFATracer", lprotocol.Layotto, diagnostics.NewTracer) trace.RegisterTracerBuilder(skywalking.SkyDriverName, lprotocol.Layotto, lsky.NewGrpcSkyTracer) - + trace.RegisterTracerBuilder("Jaeger", lprotocol.Layotto, jaeger.NewGrpcJaegerTracer) } func main() { diff --git a/cmd/layotto_multiple_api/main.go b/cmd/layotto_multiple_api/main.go index aef59ed762..79f6cdbf99 100644 --- a/cmd/layotto_multiple_api/main.go +++ b/cmd/layotto_multiple_api/main.go @@ -175,6 +175,7 @@ import ( "mosn.io/layotto/pkg/runtime" _ "mosn.io/layotto/diagnostics/exporter_iml" + "mosn.io/layotto/diagnostics/jaeger" lprotocol "mosn.io/layotto/diagnostics/protocol" lsky "mosn.io/layotto/diagnostics/skywalking" ) @@ -528,6 +529,7 @@ func ExtensionsRegister(_ *cli.Context) { trace.RegisterTracerBuilder("SOFATracer", protocol.HTTP1, tracehttp.NewTracer) trace.RegisterTracerBuilder("SOFATracer", "layotto", diagnostics.NewTracer) trace.RegisterTracerBuilder(skywalking.SkyDriverName, lprotocol.Layotto, lsky.NewGrpcSkyTracer) + trace.RegisterTracerBuilder("Jaeger", lprotocol.Layotto, jaeger.NewGrpcJaegerTracer) } diff --git a/configs/config_trace_jaeger.json b/configs/config_trace_jaeger.json new file mode 100644 index 0000000000..0f2d8a0931 --- /dev/null +++ b/configs/config_trace_jaeger.json @@ -0,0 +1,86 @@ +{ + "servers": [ + { + "default_log_path": "stdout", + "default_log_level": "INFO", + "listeners": [ + { + "name": "grpc", + "address": "0.0.0.0:34904", + "bind_port": true, + "filter_chains": [ + { + "filters": [ + { + "type": "grpc", + "config": { + "server_name": "runtime", + "grpc_config": { + "hellos": { + "quick_start_demo": { + "type": "helloworld", + "hello": "greeting" + } + }, + "config_store": { + "config_demo": { + "type": "etcd", + "address": [ + "127.0.0.1:2379" + ], + "timeout": "10" + } + } + } + } + } + ] + } + ], + "stream_filters": [ + { + "type": "flowControlFilter", + "config": { + "global_switch": true, + "limit_key_type": "PATH", + "rules": [ + { + "resource": "/spec.proto.runtime.v1.Runtime/SayHello", + "grade": 1, + "threshold": 5 + } + ] + } + }, + { + "type": "grpc_metric" + } + ] + } + ] + } + ], + "tracing": { + "enable": true, + "driver": "jaeger", + "config": { + "config": { + "service_name": "layotto", + "strategy": "collector" + } + } + }, + "metrics": { + "sinks": [ + { + "type": "prometheus", + "config": { + "port": 34903 + } + } + ] + } +} + + + diff --git a/diagnostics/jaeger/grpc_tracer.go b/diagnostics/jaeger/grpc_tracer.go new file mode 100644 index 0000000000..22a4860551 --- /dev/null +++ b/diagnostics/jaeger/grpc_tracer.go @@ -0,0 +1,213 @@ +/* + * Copyright 2021 Layotto Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jaeger + +import ( + "context" + "os" + "time" + + "github.com/pkg/errors" + + "github.com/opentracing/opentracing-go" + jaegerc "github.com/uber/jaeger-client-go" + "github.com/uber/jaeger-client-go/config" + "mosn.io/api" + "mosn.io/mosn/pkg/log" + "mosn.io/mosn/pkg/trace" + "mosn.io/mosn/pkg/trace/jaeger" + "mosn.io/mosn/pkg/types" + + ltrace "mosn.io/layotto/components/trace" + "mosn.io/layotto/diagnostics/grpc" + "mosn.io/layotto/diagnostics/protocol" +) + +const ( + serviceName = "service_name" + strategy = "strategy" + agentHost = "agent_host" + collectorEndpoint = "collector_endpoint" + defaultServiceName = "layotto" + defaultJaegerAgentHost = "127.0.0.1:6831" + jaegerAgentHostKey = "TRACE" + appIDKey = "APP_ID" + defaultCollectorEndpoint = "http://127.0.0.1:14268/api/traces" + defaultStrategy = "collector" + configs = "config" +) + +type grpcJaegerTracer struct { + tracer opentracing.Tracer +} + +type grpcJaegerSpan struct { + *ltrace.Span + ctx context.Context + trace *grpcJaegerTracer + jaegerSpan opentracing.Span + spanCtx jaegerc.SpanContext +} + +func init() { + trace.RegisterTracerBuilder(jaeger.DriverName, protocol.Layotto, NewGrpcJaegerTracer) +} + +func NewGrpcJaegerTracer(traceCfg map[string]interface{}) (api.Tracer, error) { + // 1. construct the ReporterConfig, which is used to communicate with jaeger + var reporter *config.ReporterConfig + + // Determining whether to start the agent + strategy, err := getStrategy(traceCfg) + + if err != nil { + return nil, err + } + + if strategy == defaultStrategy { + reporter = &config.ReporterConfig{ + LogSpans: false, + BufferFlushInterval: 1 * time.Second, + CollectorEndpoint: getCollectorEndpoint(traceCfg), + } + } else { + reporter = &config.ReporterConfig{ + LogSpans: false, + BufferFlushInterval: 1 * time.Second, + LocalAgentHostPort: getAgentHost(traceCfg), + } + } + // 2. construct the Configuration + cfg := config.Configuration{ + Disabled: false, + Sampler: &config.SamplerConfig{ + Type: "const", + Param: 1, + }, + Reporter: reporter, + } + + cfg.ServiceName = getServiceName(traceCfg) + + // 3. use the Configuration to construct a new tracer + tracer, _, err := cfg.NewTracer() + + log.DefaultLogger.Infof("[layotto] [jaeger] [tracer] report service name:%s", getServiceName(traceCfg)) + + if err != nil { + log.DefaultLogger.Errorf("[layotto] [jaeger] [tracer] cannot initialize Jaeger Tracer") + return nil, err + } + + // 4. adapt to the `api.Tracer` + return &grpcJaegerTracer{ + tracer: tracer, + }, nil +} + +func getAgentHost(traceCfg map[string]interface{}) string { + if cfg, ok := traceCfg[configs]; ok { + host := cfg.(map[string]interface{}) + if agentHost, ok := host[agentHost]; ok { + return agentHost.(string) + } + } + + //if TRACE is not set, get it from the env variable + if host := os.Getenv(jaegerAgentHostKey); host != "" { + return host + } + + return defaultJaegerAgentHost +} + +func getStrategy(traceCfg map[string]interface{}) (string, error) { + if cfg, ok := traceCfg[configs]; ok { + str := cfg.(map[string]interface{}) + k, ok := str[strategy] + if ok && (k.(string) == defaultStrategy || k.(string) == "agent") { + return k.(string), nil + } else if ok { + return "", errors.New("Unknown Strategy") + } + } + + return defaultStrategy, nil +} + +func getCollectorEndpoint(traceCfg map[string]interface{}) string { + if cfg, ok := traceCfg[configs]; ok { + endpoint := cfg.(map[string]interface{}) + if collectorEndpoint, ok := endpoint[collectorEndpoint]; ok { + return collectorEndpoint.(string) + } + } + + return defaultCollectorEndpoint +} + +func getServiceName(traceCfg map[string]interface{}) string { + if cfg, ok := traceCfg[configs]; ok { + name := cfg.(map[string]interface{}) + if service, ok := name[serviceName]; ok { + return service.(string) + } + } + + //if service_name is not set, get it from the env variable + if appID := os.Getenv(appIDKey); appID != "" { + return appID + "_sidecar" + } + + return defaultServiceName +} + +func (t *grpcJaegerTracer) Start(ctx context.Context, request interface{}, startTime time.Time) api.Span { + header, ok := request.(*grpc.RequestInfo) + if !ok { + log.DefaultLogger.Debugf("[layotto] [jaeger] [tracer] unable to get request header, downstream trace ignored") + return &jaeger.Span{} + } + + //create entry span (downstream) + sp, _ := opentracing.StartSpanFromContextWithTracer(ctx, t.tracer, header.FullMethod) + + //renew span context + newSpanCtx, _ := sp.Context().(jaegerc.SpanContext) + + return &grpcJaegerSpan{ + trace: t, + ctx: ctx, + Span: <race.Span{}, + spanCtx: newSpanCtx, + jaegerSpan: sp, + } +} + +func (s *grpcJaegerSpan) TraceId() string { + return s.spanCtx.TraceID().String() +} + +func (s *grpcJaegerSpan) InjectContext(requestHeaders types.HeaderMap, requestInfo api.RequestInfo) { +} + +func (s *grpcJaegerSpan) SetRequestInfo(requestInfo api.RequestInfo) { +} + +func (s *grpcJaegerSpan) FinishSpan() { + s.jaegerSpan.Finish() +} diff --git a/diagnostics/jaeger/jaeger-docker-compose.yaml b/diagnostics/jaeger/jaeger-docker-compose.yaml new file mode 100644 index 0000000000..6a732715ac --- /dev/null +++ b/diagnostics/jaeger/jaeger-docker-compose.yaml @@ -0,0 +1,29 @@ +#Licensed to the Apache Software Foundation (ASF) under one or more +#contributor license agreements. See the NOTICE file distributed with +#this work for additional information regarding copyright ownership. +#The ASF licenses this file to You under the Apache License, Version 2.0 +#(the "License"); you may not use this file except in compliance with +#the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +#Unless required by applicable law or agreed to in writing, software +#distributed under the License is distributed on an "AS IS" BASIS, +#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#See the License for the specific language governing permissions and +#limitations under the License. + +version: '3.3' +services: + jaegertracing-all-in-one: + image: jaegertracing/all-in-one:latest + ports: + - "5775:5775/udp" + - "16686:16686" + - "14250:14250" + - "14268:14268" + - "6831:6831" + + + + diff --git a/docs/zh/_sidebar.md b/docs/zh/_sidebar.md index b02d46b5b8..ecaa8aa343 100644 --- a/docs/zh/_sidebar.md +++ b/docs/zh/_sidebar.md @@ -25,6 +25,7 @@ - [Trace, Metrics](zh/start/trace/trace.md) - [Metrics 接入 Prometheus](zh/start/trace/prometheus.md) - [Trace 接入 Skywalking](zh/start/trace/skywalking.md) + - [Trace 接入 Jaeger](zh/start/trace/jaeger.md) - [将业务逻辑通过 WASM 下沉进sidecar](zh/start/wasm/start.md) - [基于 WASM 跟 Runtime 实现的 Faas 模型](zh/start/faas/start.md) - [用户手册](zh/building_blocks/) diff --git a/docs/zh/start/trace/jaeger.md b/docs/zh/start/trace/jaeger.md new file mode 100644 index 0000000000..041d1081ce --- /dev/null +++ b/docs/zh/start/trace/jaeger.md @@ -0,0 +1,90 @@ +# Jaeger trace 接入 + +## 配置 + +示例:configs/config_trace_jaeger.json + +```json +{ + "tracing": { + "enable": true, + "driver": "jaeger", + "config": { + "config": { + "service_name": "layotto" + } + } + } +} +``` + +| 字段 | 必填 | 说明 | +|--------------|----|------------------------------------------------------| +| service_name | Y | 服务名称 | +| agent_host | N | agent组件端口 | +| strategy | N | 数据上报方式,默认使用 collector 方式. 可选的配置值有`collector`和`agent` | +|collector_endpoint | N | collector的端口号,默认http://127.0.0.1:14268/api/traces | + +## 运行Jaeger + +```shell +cd ${project_path}/diagnostics/jaeger + +docker-compose -f jaeger-docker-compose.yaml up -d +``` + +## 运行layotto + +可以按照如下方式启动一个layotto的server: + +切换目录: + +```shell +cd ${project_path}/cmd/layotto_multiple_api +``` + +构建: + +```shell @if.not.exist layotto +go build -o layotto +``` + +运行: + +```shell @background +./layotto start -c ../../configs/config_trace_jaeger.json +``` + +## 运行 Demo + +对应的调用端代码在[client.go](https://github.com/mosn/layotto/blob/main/demo/flowcontrol/client.go) 中,运行它会调用layotto的SayHello接口: + +切换目录: + +```shell + cd ${project_path}/demo/flowcontrol/ +``` + +构建: + +```shell @if.not.exist client + go build -o client +``` +运行: + +```shell +./client +``` + +访问 http://localhost:16686 + +![img.png](https://gw.alipayobjects.com/mdn/rms_5891a1/afts/img/A*-f2LSLAR9YMAAAAAAAAAAAAAARQnAQ) + + +## 清理资源 + +```shell +cd ${project_path}/diagnostics/jaeger + +docker-compose -f jaeger-docker-compose.yaml down +``` \ No newline at end of file diff --git a/etc/script/test-quickstart.sh b/etc/script/test-quickstart.sh index e0ce248860..0bfb3818f2 100755 --- a/etc/script/test-quickstart.sh +++ b/etc/script/test-quickstart.sh @@ -33,6 +33,7 @@ quickstarts_in_default="docs/en/start/configuration/start.md docs/zh/start/trace/skywalking.md docs/zh/start/trace/prometheus.md docs/en/start/trace/prometheus.md + docs/zh/start/trace/jaeger.md docs/en/start/wasm/start.md docs/zh/start/wasm/start.md docs/en/start/secret/start.md diff --git a/go.mod b/go.mod index e3d5fdce5e..449892055c 100644 --- a/go.mod +++ b/go.mod @@ -21,10 +21,12 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/json-iterator/go v1.1.12 + github.com/opentracing/opentracing-go v1.2.0 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 github.com/shirou/gopsutil v3.21.3+incompatible github.com/stretchr/testify v1.7.0 + github.com/uber/jaeger-client-go v2.25.0+incompatible github.com/urfave/cli v1.22.1 github.com/valyala/fasthttp v1.28.0 go.uber.org/automaxprocs v1.4.0 // indirect diff --git a/go.sum b/go.sum index a622e2eb1f..6d28b53338 100644 --- a/go.sum +++ b/go.sum @@ -123,6 +123,7 @@ github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3 github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/DataDog/zstd v1.4.6-0.20210211175136-c6db21d202f4 h1:++HGU87uq9UsSTlFeiOV9uZR3NpYkndUXeYyLv2DTc8= github.com/DataDog/zstd v1.4.6-0.20210211175136-c6db21d202f4/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/HdrHistogram/hdrhistogram-go v1.0.1 h1:GX8GAYDuhlFQnI2fRDHQhTlkHMz8bEn0jTI6LJU0mpw= github.com/HdrHistogram/hdrhistogram-go v1.0.1/go.mod h1:BWJ+nMSHY3L41Zj7CA3uXnloDp7xxV0YvstAE7nKTaM= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= @@ -1357,7 +1358,9 @@ github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3/go.mod h1:QDlp github.com/trainyao/go-maglev v0.0.0-20200611125015-4c1ae64d96a8 h1:o6jtI8/BV93ZCw681cNVMjyvLfnBboUP/lBOfmkb4Pg= github.com/trainyao/go-maglev v0.0.0-20200611125015-4c1ae64d96a8/go.mod h1:VBsRn0SDTltC3/SzN6SgXlQtmBk6U5sf0KW+eT+WMbc= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/uber/jaeger-client-go v2.25.0+incompatible h1:IxcNZ7WRY1Y3G4poYlx24szfsn/3LvK9QHCq9oQw8+U= github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v2.4.0+incompatible h1:fY7QsGQWiCt8pajv4r7JEvmATdCVaWxXbjwyYwsNaLQ= github.com/uber/jaeger-lib v2.4.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=