Class: Datadog::Tracer
- Inherits:
-
Object
- Object
- Datadog::Tracer
- Defined in:
- lib/ddtrace/tracer.rb
Overview
A Tracer keeps track of the time spent by an application processing a single operation. For example, a trace can be used to track the entire time spent processing a complicated web request. Even though the request may require multiple resources and machines to handle the request, all of these function calls and sub-requests would be encapsulated within a single trace. rubocop:disable Metrics/ClassLength
Constant Summary collapse
- ALLOWED_SPAN_OPTIONS =
[:service, :resource, :span_type].freeze
- DEFAULT_ON_ERROR =
proc { |span, error| span.set_error(error) unless span.nil? }
Instance Attribute Summary collapse
-
#default_service ⇒ Object
A default value for service.
-
#enabled ⇒ Object
Returns the value of attribute enabled.
-
#provider ⇒ Object
readonly
Returns the value of attribute provider.
-
#sampler ⇒ Object
readonly
Returns the value of attribute sampler.
-
#tags ⇒ Object
readonly
Returns the value of attribute tags.
-
#writer ⇒ Object
Returns the value of attribute writer.
Class Method Summary collapse
-
.debug_logging ⇒ Object
Return if the debug mode is activated or not.
-
.debug_logging=(value) ⇒ Object
Activate the debug mode providing more information related to tracer usage Default to Warn level unless using custom logger.
-
.log ⇒ Object
Global, memoized, lazy initialized instance of a logger that is used within the the Datadog namespace.
-
.log=(logger) ⇒ Object
Override the default logger with a custom one.
Instance Method Summary collapse
-
#active_correlation ⇒ Object
Return a CorrelationIdentifier for active span.
-
#active_root_span ⇒ Object
Return the current active root span or
nil
. -
#active_span ⇒ Object
Return the current active span or
nil
. -
#call_context ⇒ Object
Return the current active Context for this traced execution.
-
#configure(options = {}) ⇒ Object
Updates the current Tracer instance, so that the tracer can be configured after the initialization.
-
#initialize(options = {}) ⇒ Tracer
constructor
Initialize a new Tracer used to create, sample and submit spans that measure the time of sections of code.
-
#record(context) ⇒ Object
Record the given
context
. - #services ⇒ Object
-
#set_service_info(service, app, app_type) ⇒ Object
Set the information about the given service.
-
#set_tags(tags) ⇒ Object
Set the given key / value tag pair at the tracer level.
-
#shutdown! ⇒ Object
Shorthand that calls the ‘shutdown!` method of a registered worker.
-
#start_span(name, options = {}) ⇒ Object
Return a span that will trace an operation called name.
-
#trace(name, options = {}) ⇒ Object
Return a
span
that will trace an operation calledname
.
Constructor Details
#initialize(options = {}) ⇒ Tracer
Initialize a new Tracer used to create, sample and submit spans that measure the time of sections of code. Available options
are:
-
enabled
: set if the tracer submits or not spans to the local agent. It’s enabled by default.
111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/ddtrace/tracer.rb', line 111 def initialize( = {}) @enabled = .fetch(:enabled, true) @writer = .fetch(:writer, Datadog::Writer.new) @sampler = .fetch(:sampler, Datadog::AllSampler.new) @provider = .fetch(:context_provider, Datadog::DefaultContextProvider.new) @provider ||= Datadog::DefaultContextProvider.new # @provider should never be nil @context_flush = [:partial_flush] ? Datadog::ContextFlush.new() : nil @mutex = Mutex.new @tags = {} end |
Instance Attribute Details
#default_service ⇒ Object
A default value for service. One should really override this one for non-root spans which have a parent. However, root spans without a service would be invalid and rejected.
173 174 175 176 177 178 179 180 181 182 |
# File 'lib/ddtrace/tracer.rb', line 173 def default_service return @default_service if instance_variable_defined?(:@default_service) && @default_service begin @default_service = File.basename($PROGRAM_NAME, '.*') rescue StandardError => e Datadog::Tracer.log.error("unable to guess default service: #{e}") @default_service = 'ruby'.freeze end @default_service end |
#enabled ⇒ Object
Returns the value of attribute enabled.
24 25 26 |
# File 'lib/ddtrace/tracer.rb', line 24 def enabled @enabled end |
#provider ⇒ Object (readonly)
Returns the value of attribute provider.
23 24 25 |
# File 'lib/ddtrace/tracer.rb', line 23 def provider @provider end |
#sampler ⇒ Object (readonly)
Returns the value of attribute sampler.
23 24 25 |
# File 'lib/ddtrace/tracer.rb', line 23 def sampler @sampler end |
#tags ⇒ Object (readonly)
Returns the value of attribute tags.
23 24 25 |
# File 'lib/ddtrace/tracer.rb', line 23 def @tags end |
#writer ⇒ Object
Returns the value of attribute writer.
24 25 26 |
# File 'lib/ddtrace/tracer.rb', line 24 def writer @writer end |
Class Method Details
.debug_logging ⇒ Object
Return if the debug mode is activated or not
66 67 68 |
# File 'lib/ddtrace/tracer.rb', line 66 def self.debug_logging log.level == Logger::DEBUG end |
.debug_logging=(value) ⇒ Object
Activate the debug mode providing more information related to tracer usage Default to Warn level unless using custom logger
57 58 59 60 61 62 63 |
# File 'lib/ddtrace/tracer.rb', line 57 def self.debug_logging=(value) if value log.level = Logger::DEBUG elsif log.is_a?(Datadog::Logger) log.level = Logger::WARN end end |
.log ⇒ Object
Global, memoized, lazy initialized instance of a logger that is used within the the Datadog namespace. This logger outputs to STDOUT
by default, and is considered thread-safe.
32 33 34 35 36 37 38 |
# File 'lib/ddtrace/tracer.rb', line 32 def self.log unless defined? @logger @logger = Datadog::Logger.new(STDOUT) @logger.level = Logger::WARN end @logger end |
.log=(logger) ⇒ Object
Override the default logger with a custom one.
41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/ddtrace/tracer.rb', line 41 def self.log=(logger) return unless logger return unless logger.respond_to? :methods return unless logger.respond_to? :error if logger.respond_to? :methods unimplemented = Logger.new(STDOUT).methods - logger.methods unless unimplemented.empty? logger.error("logger #{logger} does not implement #{unimplemented}") return end end @logger = logger end |
Instance Method Details
#active_correlation ⇒ Object
Return a CorrelationIdentifier for active span
362 363 364 |
# File 'lib/ddtrace/tracer.rb', line 362 def active_correlation Datadog::Correlation.identifier_from_context(call_context) end |
#active_root_span ⇒ Object
Return the current active root span or nil
.
357 358 359 |
# File 'lib/ddtrace/tracer.rb', line 357 def active_root_span call_context.current_root_span end |
#active_span ⇒ Object
Return the current active span or nil
.
352 353 354 |
# File 'lib/ddtrace/tracer.rb', line 352 def active_span call_context.current_span end |
#call_context ⇒ Object
Return the current active Context for this traced execution. This method is automatically called when calling Tracer.trace or Tracer.start_span, but it can be used in the application code during manual instrumentation.
This method makes use of a ContextProvider that is automatically set during the tracer initialization, or while using a library instrumentation.
102 103 104 |
# File 'lib/ddtrace/tracer.rb', line 102 def call_context @provider.context end |
#configure(options = {}) ⇒ Object
Updates the current Tracer instance, so that the tracer can be configured after the initialization. Available options
are:
-
enabled
: set if the tracer submits or not spans to the trace agent -
hostname
: change the location of the trace agent -
port
: change the port of the trace agent
For instance, if the trace agent runs in a different location, just:
tracer.configure(hostname: 'agent.service.consul', port: '8777')
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/ddtrace/tracer.rb', line 136 def configure( = {}) enabled = .fetch(:enabled, nil) # Those are rare "power-user" options. sampler = .fetch(:sampler, nil) max_spans_before_partial_flush = .fetch(:max_spans_before_partial_flush, nil) min_spans_before_partial_flush = .fetch(:min_spans_before_partial_flush, nil) partial_flush_timeout = .fetch(:partial_flush_timeout, nil) @enabled = enabled unless enabled.nil? @sampler = sampler unless sampler.nil? configure_writer() @context_flush = Datadog::ContextFlush.new() unless min_spans_before_partial_flush.nil? && max_spans_before_partial_flush.nil? && partial_flush_timeout.nil? end |
#record(context) ⇒ Object
Record the given context
. For compatibility with previous versions, context
can also be a span. It is similar to the child_of
argument, method will figure out what to do, submitting a span
for recording is like trying to record its context
.
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
# File 'lib/ddtrace/tracer.rb', line 328 def record(context) context = context.context if context.is_a?(Datadog::Span) return if context.nil? trace, sampled = context.get # If context flushing is configured... if @context_flush if sampled if trace.nil? || trace.empty? @context_flush.each_partial_trace(context) do |t| write(t) end else write(trace) end end # Default behavior else ready = !trace.nil? && !trace.empty? && sampled write(trace) if ready end end |
#services ⇒ Object
70 71 72 73 74 75 76 77 |
# File 'lib/ddtrace/tracer.rb', line 70 def services # Only log each deprecation warning once (safeguard against log spam) Datadog::Patcher.do_once('Tracer#set_service_info') do Datadog::Tracer.log.warn('services: Usage of Tracer.services has been deprecated') end {} end |
#set_service_info(service, app, app_type) ⇒ Object
Set the information about the given service. A valid example is:
tracer.set_service_info('web-application', 'rails', 'web')
set_service_info is deprecated, no service information needs to be tracked
160 161 162 163 164 165 166 167 168 |
# File 'lib/ddtrace/tracer.rb', line 160 def set_service_info(service, app, app_type) # Only log each deprecation warning once (safeguard against log spam) Datadog::Patcher.do_once('Tracer#set_service_info') do Datadog::Tracer.log.warn(%( set_service_info: Usage of set_service_info has been deprecated, service information no longer needs to be reported to the trace agent. )) end end |
#set_tags(tags) ⇒ Object
Set the given key / value tag pair at the tracer level. These tags will be appended to each span created by the tracer. Keys and values must be strings. A valid example is:
tracer.('env' => 'prod', 'component' => 'core')
189 190 191 |
# File 'lib/ddtrace/tracer.rb', line 189 def () @tags.update() end |
#shutdown! ⇒ Object
Shorthand that calls the ‘shutdown!` method of a registered worker. It’s useful to ensure that the Trace Buffer is properly flushed before shutting down the application.
For instance:
tracer.trace('operation_name', service='rake_tasks') do |span|
span.set_tag('task.name', 'script')
end
tracer.shutdown!
91 92 93 94 |
# File 'lib/ddtrace/tracer.rb', line 91 def shutdown! return if !@enabled || @writer.worker.nil? @writer.worker.stop end |
#start_span(name, options = {}) ⇒ Object
Return a span that will trace an operation called name. This method allows parenting passing child_of as an option. If it’s missing, the newly created span is a root span. Available options are:
-
service
: the service name for this span -
resource
: the resource this span refers, or name if it’s missing -
span_type
: the type of the span (such as http, db and so on) -
child_of
: a Span or a Context instance representing the parent for this span. -
start_time
: when the span actually starts (defaults to now) -
tags
: extra tags which should be added to the span.
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/ddtrace/tracer.rb', line 215 def start_span(name, = {}) start_time = .fetch(:start_time, Time.now.utc) = .fetch(:tags, {}) = .select do |k, _v| # Filter options, we want no side effects with unexpected args. ALLOWED_SPAN_OPTIONS.include?(k) end ctx, parent = guess_context_and_parent([:child_of]) [:context] = ctx unless ctx.nil? span = Span.new(self, name, ) if parent.nil? # root span @sampler.sample!(span) span.set_tag('system.pid', Process.pid) if ctx && ctx.trace_id span.trace_id = ctx.trace_id span.parent_id = ctx.span_id unless ctx.span_id.nil? end else # child span span.parent = parent # sets service, trace_id, parent_id, sampled end .each { |k, v| span.set_tag(k, v) } unless .empty? @tags.each { |k, v| span.set_tag(k, v) } unless @tags.empty? span.start_time = start_time # this could at some point be optional (start_active_span vs start_manual_span) ctx.add_span(span) unless ctx.nil? span end |
#trace(name, options = {}) ⇒ Object
Return a span
that will trace an operation called name
. You could trace your code using a do-block
like:
tracer.trace('web.request') do |span|
span.service = 'my-web-site'
span.resource = '/'
span.set_tag('http.method', request.request_method)
do_something()
end
The tracer.trace()
method can also be used without a block in this way:
span = tracer.trace('web.request', service: 'my-web-site')
do_something()
span.finish()
Remember that in this case, calling span.finish()
is mandatory.
When a Trace is started, trace()
will store the created span; subsequent spans will become it’s children and will inherit some properties:
parent = tracer.trace('parent') # has no parent span
child = tracer.trace('child') # is a child of 'parent'
child.finish()
parent.finish()
parent2 = tracer.trace('parent2') # has no parent span
parent2.finish()
Available options are:
-
service
: the service name for this span -
resource
: the resource this span refers, or name if it’s missing -
span_type
: the type of the span (such as http, db and so on) -
tags
: extra tags which should be added to the span.
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/ddtrace/tracer.rb', line 286 def trace(name, = {}) [:child_of] = call_context # call the finish only if a block is given; this ensures # that a call to tracer.trace() without a block, returns # a span that should be manually finished. if block_given? span = nil return_value = nil begin begin span = start_span(name, ) # rubocop:disable Lint/UselessAssignment rescue StandardError => e Datadog::Tracer.log.debug('Failed to start span: #{e}') ensure return_value = yield(span) end # rubocop:disable Lint/RescueException # Here we really want to catch *any* exception, not only StandardError, # as we really have no clue of what is in the block, # and it is user code which should be executed no matter what. # It's not a problem since we re-raise it afterwards so for example a # SignalException::Interrupt would still bubble up. rescue Exception => e ([:on_error] || DEFAULT_ON_ERROR).call(span, e) raise e ensure span.finish unless span.nil? end return_value else start_span(name, ) end end |