Rack and Faraday integration middlewares for Zipkin tracing.
Options can be provided via Rails.config for a Rails 3+ app, or can be passed as a hash argument to the Rack plugin.
require 'zipkin-tracer'
use ZipkinTracer::RackHandler, config # config is optional
where Rails.config.zipkin_tracer or config is a hash that can contain the following keys:
:service_name
(REQUIRED) - the name of the service being traced:service_port
(REQUIRED) - the port of the service being traced (e.g. 80 or 443):scribe_server
(default from scribe gem) - the address of the scribe server where traces are delivered:scribe_max_buffer
(default: 10) - the number of annotations stored until automatic flush (note that annotations are also flushed when the request is complete):sample_rate
(default: 0.1) - the ratio of requests to sample, from 0 to 1:annotate_plugin
- plugin function which recieves Rack env, and response status, headers, and body; and can record annotations:filter_plugin
- plugin function which recieves Rack env and will skip tracing if it returns false:whitelist_plugin
- plugin function which recieves Rack env and will force sampling if it returns true:zookeeper
- plugin function which uses zookeeper and kafka instead of scribe as the transport
NOTE that access to the response body (available in the annotate plugin) may cause problems in the case that a response is being streamed; in general, this should be avoided (see the Rack specification for more detail and instructions for properly hijacking responses).
First, Faraday has to be part of your Gemfile:
gem 'faraday', '~> 0.8'
For the Faraday middleware to have the correct trace ID, the rack middleware should be used in your application as explained above.
Then include ZipkinTracer::FaradayHandler as a Faraday middleware:
require 'faraday'
require 'zipkin-tracer'
conn = Faraday.new(:url => 'http://localhost:9292/') do |faraday|
# 'service_name' is optional (but recommended)
faraday.use ZipkinTracer::FaradayHandler, 'service_name'
# default Faraday stack
faraday.request :url_encoded
faraday.adapter Faraday.default_adapter
end
Note that supplying the service name for the destination service is optional; the tracing will default to a service name derived from the first section of the destination URL (e.g. 'service.example.com' => 'service').
The annotate plugin expects a function of the form:
lambda {|env, status, response_headers, response_body| ...}
The annotate plugin is expected to perform annotation based on content of the Rack environment and the response components. The return value is ignored.
For example:
lambda do |env, status, response_headers, response_body|
# string annotation
::Trace.record(::Trace::BinaryAnnotation.new('http.referrer', env['HTTP_REFERRER'], 'STRING', ::Trace.default_endpoint))
# integer annotation
::Trace.record(::Trace::BinaryAnnotation.new('http.content_size', [env['CONTENT_SIZE']].pack('N'), 'I32', ::Trace.default_endpoint))
::Trace.record(::Trace::BinaryAnnotation.new('http.status', [status.to_i].pack('n'), 'I16', ::Trace.default_endpoint))
end
The filter plugin expects a function of the form:
lambda {|env| ...}
The filter plugin allows skipping tracing if the return value is false.
For example:
# don't trace /static/ URIs
lambda {|env| env['PATH_INFO'] ~! /^\/static\//}
The whitelist plugin expects a function of the form:
lambda {|env| ...}
The whitelist plugin allows forcing sampling if the return value is true.
For example:
# sample if request header specifies known device identifier
lambda {|env| KNOWN_DEVICES.include?(env['HTTP_X_DEVICE_ID'])}
Kafka tracer inherits from Tracer which is found in Finagle. It allows using Kafka as the transport instead of scribe. If a config[:zookeeper] parameter is pass into the initialization of the RackHandler, then the gem will use Kafka. Hermann is the kafka client library. Hermann and the Scribe gems are optionally installed because we would only use one of the other. In your application, you will need to explicitly install either Hermann or Scribe.
Caveat: Hermann is only usable from within Jruby, due to its implementation of zookeeper based broker discovery being JVM based.
# zipkin-kafka-tracer requires at minimim Hermann 0.25.0 or later
gem 'hermann', '~> 0.25'
# Install scribe
gem 'scribe', "~> 0.2.4"