zipkin

Description

Zipkin is an open source distributed tracing system. The zipkin Plugin supports collecting and reporting traces to Zipkin collector based on the Zipkin API specification.

It also works with Apache SkyWalking and Jaeger, both of which support Zipkin v1 and v2 APIs. It can also work with other tracing systems adapted to Zipkin v1/v2 API format.

Attributes

NameTypeRequiredDefaultValid valuesDescription
endpointstringTrueZipkin HTTP endpoint. For example, http://127.0.0.1:9411/api/v2/spans.
sample_rationumberTrue[0.00001, 1]How often to sample the requests. Setting to 1 will sample all requests.
service_namestringFalse“APISIX”Service name for the Zipkin reporter to be displayed in Zipkin.
server_addrstringFalse$server_addrIPv4 address for the Zipkin reporter. You can specify your external IP address.
span_versionintegerFalse2[1, 2]Version of the span type.

Each traced request will create the spans shown below:

  1. request
  2. ├── proxy: from the beginning of the request to the beginning of header filter
  3. └── response: from the beginning of header filter to the beginning of log

For older versions (set span_version attribute to 1), these spans are created:

  1. request
  2. ├── rewrite
  3. ├── access
  4. └── proxy
  5. └── body_filter
zipkin - 图1note

The span name doesn’t represent the corresponding Nginx phase.

Sample code for upstream configuration

Go with Gin

  1. func GetTracer(serviceName string, port int, enpoitUrl string, rate float64) *zipkin.Tracer {
  2. // create a reporter to be used by the tracer
  3. reporter := httpreporter.NewReporter(enpoitUrl)
  4. // set-up the local endpoint for our service host is ip:host
  5. thisip, _ := GetLocalIP()
  6. host := fmt.Sprintf("%s:%d", thisip, port)
  7. endpoint, _ := zipkin.NewEndpoint(serviceName, host)
  8. // set-up our sampling strategy
  9. sampler, _ := zipkin.NewCountingSampler(rate)
  10. // initialize the tracer
  11. tracer, _ := zipkin.NewTracer(
  12. reporter,
  13. zipkin.WithLocalEndpoint(endpoint),
  14. zipkin.WithSampler(sampler),
  15. )
  16. return tracer
  17. }
  18. func main(){
  19. r := gin.Default()
  20. tracer := GetTracer(...)
  21. // use middleware to extract parentID from http header that injected by APISIX
  22. r.Use(func(c *gin.Context) {
  23. span := this.Tracer.Extract(b3.ExtractHTTP(c.Request))
  24. childSpan := this.Tracer.StartSpan(spanName, zipkin.Parent(span))
  25. defer childSpan.Finish()
  26. c.Next()
  27. })
  28. }

Enable Plugin

The example below enables the Plugin on a specific Route:

zipkin - 图2note

You can fetch the admin_key from config.yaml and save to an environment variable with the following command:

  1. admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
  1. curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
  2. {
  3. "methods": ["GET"],
  4. "uri": "/index.html",
  5. "plugins": {
  6. "zipkin": {
  7. "endpoint": "http://127.0.0.1:9411/api/v2/spans",
  8. "sample_ratio": 1,
  9. "service_name": "APISIX-IN-SG",
  10. "server_addr": "192.168.3.50"
  11. }
  12. },
  13. "upstream": {
  14. "type": "roundrobin",
  15. "nodes": {
  16. "127.0.0.1:1980": 1
  17. }
  18. }
  19. }'

Example usage

You need to have your Zipkin instance running. You can run Zipkin on Docker by running:

  1. docker run -d -p 9411:9411 openzipkin/zipkin

Now, when you make requests, it will be updated in Zipkin:

  1. curl http://127.0.0.1:9080/index.html
  1. HTTP/1.1 200 OK
  2. ...

You can then open up the Zipkin UI on your browser at http://127.0.0.1:9411/zipkin:

zipkin web-ui

zipkin web-ui list view

Reporting traces to Jaeger

The Plugin also supports reporting traces to Jaeger. First, you have to have Jaeger running.

To run it on Docker:

  1. docker run -d --name jaeger \
  2. -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
  3. -p 16686:16686 \
  4. -p 9411:9411 \
  5. jaegertracing/all-in-one:1.31

Similar to configuring for Zipkin, create a Route and enable the Plugin:

  1. curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
  2. {
  3. "methods": ["GET"],
  4. "uri": "/index.html",
  5. "plugins": {
  6. "zipkin": {
  7. "endpoint": "http://127.0.0.1:9411/api/v2/spans",
  8. "sample_ratio": 1,
  9. "service_name": "APISIX-IN-SG",
  10. "server_addr": "192.168.3.50"
  11. }
  12. },
  13. "upstream": {
  14. "type": "roundrobin",
  15. "nodes": {
  16. "127.0.0.1:1980": 1
  17. }
  18. }
  19. }'

Now, when you make requests, it will be updated on Jaeger:

  1. curl http://127.0.0.1:9080/index.html
  1. HTTP/1.1 200 OK
  2. ...

You can access the Jaeger UI to view the traces in endpoint http://127.0.0.1:16686:

jaeger web-ui

jaeger web-ui trace

Delete Plugin

To remove the zipkin Plugin, you can delete the corresponding JSON configuration from the Plugin configuration. APISIX will automatically reload and you do not have to restart for this to take effect.

  1. curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
  2. {
  3. "methods": ["GET"],
  4. "uri": "/index.html",
  5. "plugins": {
  6. },
  7. "upstream": {
  8. "type": "roundrobin",
  9. "nodes": {
  10. "127.0.0.1:1980": 1
  11. }
  12. }
  13. }'

Variables

The following nginx variables are set by zipkin:

  • zipkin_context_traceparent - W3C trace context, e.g.: 00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01
  • zipkin_trace_id - Trace Id of the current span
  • zipkin_span_id - Span Id of the current span

How to use variables? you have to add it to your configuration file (conf/config.yaml):

./conf/config.yaml

  1. http:
  2. enable_access_log: true
  3. access_log: "/dev/stdout"
  4. access_log_format: '{"time": "$time_iso8601","zipkin_context_traceparent": "$zipkin_context_traceparent","zipkin_trace_id": "$zipkin_trace_id","zipkin_span_id": "$zipkin_span_id","remote_addr": "$remote_addr","uri": "$uri"}'
  5. access_log_format_escape: json
  6. plugins:
  7. - zipkin
  8. plugin_attr:
  9. zipkin:
  10. set_ngx_var: true

You can also include a trace_id when printing logs

  1. log.error(ngx.ERR,ngx_var.zipkin_trace_id,"error message")