-
Notifications
You must be signed in to change notification settings - Fork 375
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add sidekiq integration #79
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,3 +47,6 @@ Metrics/CyclomaticComplexity: | |
|
||
Metrics/PerceivedComplexity: | ||
Max: 15 | ||
|
||
Lint/UnusedMethodArgument: | ||
Enabled: false |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,4 +66,5 @@ appraise "contrib" do | |
gem "hiredis" | ||
gem "rack-test" | ||
gem "sinatra" | ||
gem "sidekiq" | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -175,6 +175,47 @@ Net::HTTP module. | |
|
||
content = Net::HTTP.get(URI('http://127.0.0.1/index.html')) | ||
|
||
### Sidekiq | ||
|
||
The Sidekiq integration is a server-side middleware which will trace job | ||
executions. It can be added as any other Sidekiq middleware: | ||
|
||
require 'sidekiq' | ||
require 'ddtrace' | ||
require 'ddtrace/contrib/sidekiq/tracer' | ||
|
||
Sidekiq.configure_server do |config| | ||
config.server_middleware do |chain| | ||
chain.add(Datadog::Contrib::Sidekiq::Tracer, debug: true) | ||
end | ||
end | ||
|
||
#### Configure the tracer | ||
|
||
To modify the default configuration, simply pass arguments to the middleware. | ||
For example, to change the default service name and activate the debug mode: | ||
|
||
Sidekiq.configure_server do |config| | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually I'm wondering what happen when we use Sidekiq with Rails. The current status is that if we install both Sidekiq and Rails, when Sidekiq is executed via Also I was thinking about providing a good pattern (I think docs are enough) to instrument Sidekiq inside the Rails initializer so that our tracing configurations are all together. In this way Sidekiq is still separated from Rails instrumentation but users can easily follow our docs to share the Rails configuration with Sidekiq. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sidekiq uses the redis library, so its calls will be traced by the redis contrib. The sidekiq contrib traces job executions, so I think we're good. |
||
config.server_middleware do |chain| | ||
chain.add(Datadog::Contrib::Sidekiq::Tracer, | ||
default_service: 'my_app', debug: true) | ||
end | ||
end | ||
|
||
Available settings are: | ||
|
||
* ``enabled``: define if the ``tracer`` is enabled or not. If set to | ||
``false``, the code is still instrumented but no spans are sent to the local | ||
trace agent. | ||
* ``default_service``: set the service name used when tracing application | ||
requests. Defaults to ``sidekiq``. | ||
* ``tracer``: set the tracer to use. Usually you don't need to change that | ||
value unless you're already using a different initialized tracer somewhere | ||
else. | ||
* ``debug``: set to ``true`` to enable debug logging. | ||
* ``trace_agent_hostname``: set the hostname of the trace agent. | ||
* ``trace_agent_port``: set the port the trace agent is listening on. | ||
|
||
## Advanced usage | ||
|
||
### Manual Instrumentation | ||
|
@@ -360,6 +401,10 @@ The currently supported web server are: | |
|
||
Currently we are supporting Sinatra >= 1.4.0. | ||
|
||
#### Sidekiq versions | ||
|
||
Currently we are supporting Sidekiq >= 4.0.0. | ||
|
||
### Glossary | ||
|
||
* ``Service``: The name of a set of processes that do the same job. Some examples are ``datadog-web-app`` or ``datadog-metrics-db``. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
|
||
require 'sidekiq/api' | ||
|
||
require 'ddtrace/ext/app_types' | ||
|
||
sidekiq_vs = Gem::Version.new(Sidekiq::VERSION) | ||
sidekiq_min_vs = Gem::Version.new('4.0.0') | ||
if sidekiq_vs < sidekiq_min_vs | ||
raise "sidekiq version #{sidekiq_vs} is not supported yet " \ | ||
+ "(supporting versions >=#{sidekiq_min_vs})" | ||
end | ||
|
||
Datadog::Tracer.log.info("activating instrumentation for sidekiq #{sidekiq_vs}") | ||
|
||
module Datadog | ||
module Contrib | ||
module Sidekiq | ||
# Middleware is a Sidekiq server-side middleware which traces executed | ||
# jobs. | ||
class Tracer | ||
def initialize(options) | ||
@enabled = options.fetch(:enabled, true) | ||
@default_service = options.fetch(:default_service, 'sidekiq') | ||
@tracer = options.fetch(:tracer, Datadog.tracer) | ||
@debug = options.fetch(:debug, false) | ||
@trace_agent_hostname = options.fetch(:trace_agent_hostname, | ||
Datadog::Writer::HOSTNAME) | ||
@trace_agent_port = options.fetch(:trace_agent_port, | ||
Datadog::Writer::PORT) | ||
|
||
Datadog::Tracer.debug_logging = @debug | ||
|
||
@tracer.enabled = @enabled | ||
@tracer.set_service_info(@default_service, 'sidekiq', | ||
Datadog::Ext::AppTypes::WORKER) | ||
end | ||
|
||
def call(worker, job, queue) | ||
return yield unless @enabled | ||
|
||
@tracer.trace('sidekiq.job', | ||
service: @default_service, span_type: 'job') do |span| | ||
span.resource = job['class'] | ||
span.set_tag('sidekiq.job.id', job['jid']) | ||
span.set_tag('sidekiq.job.retry', job['retry']) | ||
span.set_tag('sidekiq.job.queue', job['queue']) | ||
|
||
yield | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ module AppTypes | |
WEB = 'web'.freeze | ||
DB = 'db'.freeze | ||
CACHE = 'cache'.freeze | ||
WORKER = 'worker'.freeze | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
|
||
require 'contrib/sidekiq/tracer_test_base' | ||
|
||
class DisabledTracerTest < TracerTestBase | ||
class EmptyWorker | ||
include Sidekiq::Worker | ||
|
||
def perform; end | ||
end | ||
|
||
def setup | ||
super | ||
|
||
Sidekiq::Testing.server_middleware do |chain| | ||
chain.add(Datadog::Contrib::Sidekiq::Tracer, | ||
tracer: @tracer, enabled: false) | ||
end | ||
end | ||
|
||
def test_empty | ||
EmptyWorker.perform_async() | ||
|
||
spans = @writer.spans() | ||
assert_equal(0, spans.length) | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
|
||
require 'contrib/sidekiq/tracer_test_base' | ||
|
||
class TracerTest < TracerTestBase | ||
class TestError < StandardError; end | ||
|
||
class EmptyWorker | ||
include Sidekiq::Worker | ||
|
||
def perform(); end | ||
end | ||
|
||
class ErrorWorker | ||
include Sidekiq::Worker | ||
|
||
def perform | ||
raise TestError, 'job error' | ||
end | ||
end | ||
|
||
def setup | ||
super | ||
|
||
Sidekiq::Testing.server_middleware do |chain| | ||
chain.add(Datadog::Contrib::Sidekiq::Tracer, | ||
tracer: @tracer, enabled: true) | ||
end | ||
end | ||
|
||
def test_empty | ||
EmptyWorker.perform_async() | ||
|
||
spans = @writer.spans() | ||
assert_equal(1, spans.length) | ||
|
||
span = spans[0] | ||
assert_equal('sidekiq', span.service) | ||
assert_equal('TracerTest::EmptyWorker', span.resource) | ||
assert_equal('default', span.get_tag('sidekiq.job.queue')) | ||
assert_equal(0, span.status) | ||
assert_nil(span.parent) | ||
end | ||
|
||
# rubocop:disable Lint/HandleExceptions | ||
def test_error | ||
begin | ||
ErrorWorker.perform_async() | ||
rescue TestError | ||
end | ||
|
||
spans = @writer.spans() | ||
assert_equal(1, spans.length) | ||
|
||
span = spans[0] | ||
assert_equal('sidekiq', span.service) | ||
assert_equal('TracerTest::ErrorWorker', span.resource) | ||
assert_equal('default', span.get_tag('sidekiq.job.queue')) | ||
assert_equal(1, span.status) | ||
assert_equal('job error', span.get_tag(Datadog::Ext::Errors::MSG)) | ||
assert_equal('TracerTest::TestError', span.get_tag(Datadog::Ext::Errors::TYPE)) | ||
assert_nil(span.parent) | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
|
||
require 'sidekiq/testing' | ||
require 'ddtrace' | ||
require 'ddtrace/contrib/sidekiq/tracer' | ||
require 'helper' | ||
|
||
class TracerTestBase < Minitest::Test | ||
REDIS_HOST = '127.0.0.1'.freeze() | ||
REDIS_PORT = 46379 | ||
|
||
def setup | ||
@writer = FauxWriter.new() | ||
@tracer = Datadog::Tracer.new(writer: @writer) | ||
|
||
redis_url = "redis://#{REDIS_HOST}:#{REDIS_PORT}" | ||
|
||
Sidekiq.configure_client do |config| | ||
config.redis = { url: redis_url } | ||
end | ||
|
||
Sidekiq.configure_server do |config| | ||
config.redis = { url: redis_url } | ||
end | ||
|
||
Sidekiq::Testing.inline! | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume that the
add
method appends the middleware at the bottom of the chain right? don't we have a way to keep it as the first one? in this way we can trace other middlewares execution time. If we can't, a suggestion in the docs is enough.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently the last added middlewares are executed first, and
add()
append at the end.