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
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.
-
#services ⇒ Object
readonly
Returns the value of attribute services.
-
#tags ⇒ Object
readonly
Returns the value of attribute tags.
-
#writer ⇒ Object
readonly
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.
-
.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_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. -
#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.
-
#start_span(name, options = {}) ⇒ Object
Return a span that will trace an operation called name.
-
#trace(name, options = {}) ⇒ Object
Return a
spanthat 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.
75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/ddtrace/tracer.rb', line 75 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 @mutex = Mutex.new @services = {} = {} 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.
127 128 129 130 131 132 133 134 135 136 |
# File 'lib/ddtrace/tracer.rb', line 127 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.
22 23 24 |
# File 'lib/ddtrace/tracer.rb', line 22 def enabled @enabled end |
#provider ⇒ Object (readonly)
Returns the value of attribute provider.
21 22 23 |
# File 'lib/ddtrace/tracer.rb', line 21 def provider @provider end |
#sampler ⇒ Object (readonly)
Returns the value of attribute sampler.
21 22 23 |
# File 'lib/ddtrace/tracer.rb', line 21 def sampler @sampler end |
#services ⇒ Object (readonly)
Returns the value of attribute services.
21 22 23 |
# File 'lib/ddtrace/tracer.rb', line 21 def services @services end |
#tags ⇒ Object (readonly)
Returns the value of attribute tags.
21 22 23 |
# File 'lib/ddtrace/tracer.rb', line 21 def end |
#writer ⇒ Object (readonly)
Returns the value of attribute writer.
21 22 23 |
# File 'lib/ddtrace/tracer.rb', line 21 def writer @writer end |
Class Method Details
.debug_logging ⇒ Object
Return if the debug mode is activated or not
56 57 58 |
# File 'lib/ddtrace/tracer.rb', line 56 def self.debug_logging log.level == Logger::DEBUG end |
.debug_logging=(value) ⇒ Object
Activate the debug mode providing more information related to tracer usage
51 52 53 |
# File 'lib/ddtrace/tracer.rb', line 51 def self.debug_logging=(value) log.level = value ? Logger::DEBUG : Logger::WARN 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.
27 28 29 30 31 32 33 |
# File 'lib/ddtrace/tracer.rb', line 27 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.
36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/ddtrace/tracer.rb', line 36 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_span ⇒ Object
Return the current active span or nil.
289 290 291 |
# File 'lib/ddtrace/tracer.rb', line 289 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.
66 67 68 |
# File 'lib/ddtrace/tracer.rb', line 66 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')
99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/ddtrace/tracer.rb', line 99 def configure( = {}) enabled = .fetch(:enabled, nil) hostname = .fetch(:hostname, nil) port = .fetch(:port, nil) sampler = .fetch(:sampler, nil) @enabled = enabled unless enabled.nil? @writer.transport.hostname = hostname unless hostname.nil? @writer.transport.port = port unless port.nil? @sampler = sampler unless sampler.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.
280 281 282 283 284 285 286 |
# File 'lib/ddtrace/tracer.rb', line 280 def record(context) context = context.context if context.is_a?(Datadog::Span) return if context.nil? trace, sampled = context.get ready = !trace.nil? && !trace.empty? && sampled write(trace) if ready 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')
114 115 116 117 118 119 120 121 122 |
# File 'lib/ddtrace/tracer.rb', line 114 def set_service_info(service, app, app_type) @services[service] = { 'app' => app, 'app_type' => app_type } return unless Datadog::Tracer.debug_logging Datadog::Tracer.log.debug("set_service_info: service: #{service} app: #{app} type: #{app_type}") 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')
143 144 145 |
# File 'lib/ddtrace/tracer.rb', line 143 def () .update() 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.
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/ddtrace/tracer.rb', line 178 def start_span(name, = {}) start_time = .fetch(:start_time, Time.now.utc) = .fetch(:tags, {}) opts = .select do |k, _v| # Filter options, we want no side effects with unexpected args. # Plus, this documents the code (Ruby 2 named args would be better but we're Ruby 1.9 compatible) [:service, :resource, :span_type].include?(k) end ctx, parent = guess_context_and_parent() opts[:context] = ctx unless ctx.nil? span = Span.new(self, name, opts) if parent.nil? # root span @sampler.sample(span) span.set_tag('system.pid', Process.pid) else # child span span.parent = parent # sets service, trace_id, parent_id, sampled end .each { |k, v| span.set_tag(k, v) } unless .empty? .each { |k, v| span.set_tag(k, v) } unless .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.
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/ddtrace/tracer.rb', line 244 def trace(name, = {}) opts = .select do |k, _v| # Filter options, we want no side effects with unexpected args. # Plus, this documents the code (Ruby 2 named args would be better but we're Ruby 1.9 compatible) [:service, :resource, :span_type, :tags].include?(k) end opts[:child_of] = call_context span = start_span(name, opts) # 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? begin yield(span) # 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 span.set_error(e) raise e ensure span.finish() end else span end end |