Skip to main content
Version: Next

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:

request
├── proxy: from the beginning of the request to the beginning of header filter
└── 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:

request
├── rewrite
├── access
└── proxy
└── body_filter
note

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

Sample code for upstream configuration#

Go with Gin
func GetTracer(serviceName string, port int, enpoitUrl string, rate float64) *zipkin.Tracer {
// create a reporter to be used by the tracer
reporter := httpreporter.NewReporter(enpoitUrl)
// set-up the local endpoint for our service host is ip:host

thisip, _ := GetLocalIP()

host := fmt.Sprintf("%s:%d", thisip, port)
endpoint, _ := zipkin.NewEndpoint(serviceName, host)
// set-up our sampling strategy
sampler, _ := zipkin.NewCountingSampler(rate)
// initialize the tracer
tracer, _ := zipkin.NewTracer(
reporter,
zipkin.WithLocalEndpoint(endpoint),
zipkin.WithSampler(sampler),
)
return tracer
}

func main(){
r := gin.Default()

tracer := GetTracer(...)

// use middleware to extract parentID from http header that injected by APISIX
r.Use(func(c *gin.Context) {
span := this.Tracer.Extract(b3.ExtractHTTP(c.Request))
childSpan := this.Tracer.StartSpan(spanName, zipkin.Parent(span))
defer childSpan.Finish()
c.Next()
})

}

Enable Plugin#

The example below enables the Plugin on a specific Route:

note

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

admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
curl http://127.0.0.1:9180/apisix/admin/routes/1  -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/index.html",
"plugins": {
"zipkin": {
"endpoint": "http://127.0.0.1:9411/api/v2/spans",
"sample_ratio": 1,
"service_name": "APISIX-IN-SG",
"server_addr": "192.168.3.50"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'

Example usage#

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

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

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

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

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

Reporting traces to Jaeger#

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

To run it on Docker:

docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
-p 16686:16686 \
-p 9411:9411 \
jaegertracing/all-in-one:1.31

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

curl http://127.0.0.1:9180/apisix/admin/routes/1  -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/index.html",
"plugins": {
"zipkin": {
"endpoint": "http://127.0.0.1:9411/api/v2/spans",
"sample_ratio": 1,
"service_name": "APISIX-IN-SG",
"server_addr": "192.168.3.50"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'

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

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

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

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.

curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/index.html",
"plugins": {
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'

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
http:
enable_access_log: true
access_log: "/dev/stdout"
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"}'
access_log_format_escape: json
plugins:
- zipkin
plugin_attr:
zipkin:
set_ngx_var: true

You can also include a trace_id when printing logs

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