Skip to content

Commit

Permalink
Merge pull request #996 from DataDog/refactor/extract_components_from…
Browse files Browse the repository at this point in the history
…_config

Extract components from configuration
  • Loading branch information
delner authored Apr 9, 2020
2 parents 6598d46 + d4b6bf6 commit a019dc9
Show file tree
Hide file tree
Showing 25 changed files with 1,272 additions and 318 deletions.
2 changes: 1 addition & 1 deletion docs/DevelopmentGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ Then pass an adapter instance to the tracer configuration:

```ruby
Datadog.configure do |c|
c.tracer transport_options: proc { |t|
c.tracer.transport_options = proc { |t|
# By name
t.adapter :custom

Expand Down
41 changes: 23 additions & 18 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -1555,20 +1555,25 @@ To change the default behavior of the Datadog tracer, you can provide custom opt
# config/initializers/datadog-tracer.rb

Datadog.configure do |c|
c.tracer option_name: option_value, ...
c.tracer.enabled = true
c.tracer.hostname = 'my-agent'
c.tracer.port = 8126
c.tracer.partial_flush.enabled = false
c.tracer.sampler = Datadog::AllSampler.new

# OR for advanced use cases, you can specify your own tracer:
c.tracer.instance = Datadog::Tracer.new
end
```

Available options are:

- `enabled`: defines if the `tracer` is enabled or not. If set to `false` the code could be still instrumented because of other settings, but no spans are sent to the local trace agent.
- `debug`: set to true to enable debug logging.
- `enabled`: defines if the `tracer` is enabled or not. If set to `false` instrumentation will still run, but no spans are sent to the trace agent.
- `hostname`: set the hostname of the trace agent.
- `instance`: set to a custom `Datadog::Tracer` instance. If provided, other trace settings are ignored (you must configure it manually.)
- `partial_flush.enabled`: set to `true` to enable partial trace flushing (for long running traces.) Disabled by default. *Experimental.*
- `port`: set the port the trace agent is listening on.
- `env`: set the environment. Rails users may set it to `Rails.env` to use their application settings.
- `tags`: set global tags that should be applied to all spans. Defaults to an empty hash
- `log`: defines a custom logger.
- `partial_flush`: set to `true` to enable partial trace flushing (for long running traces.) Disabled by default. *Experimental.*
- `sampler`: set to a custom `Datadog::Sampler` instance. If provided, the tracer will use this sampler to determine sampling behavior.

#### Custom logging

Expand All @@ -1580,13 +1585,12 @@ Additionally, it is possible to override the default logger and replace it by a

```ruby
f = File.new("my-custom.log", "w+") # Log messages should go there
Datadog.configure do |c|
c.tracer log: Logger.new(f) # Overriding the default tracer
end

Datadog::Logger.log = Logger.new(f)
Datadog::Logger.log.info { "this is typically called by tracing code" }
```

Additionally, you may activate debug logging with `Datadog::Logger.debug_logging = true`.

### Environment and tags

By default, the trace agent (not this library, but the program running in the background collecting data from various clients) uses the tags set in the agent config file, see our [environments tutorial](https://app.datadoghq.com/apm/docs/tutorials/environments) for details.
Expand Down Expand Up @@ -1622,8 +1626,9 @@ Ultimately, tags can be set per span, but `env` should typically be the same for
```ruby
# Sample rate is between 0 (nothing sampled) to 1 (everything sampled).
sampler = Datadog::RateSampler.new(0.5) # sample 50% of the traces

Datadog.configure do |c|
c.tracer sampler: sampler
c.tracer.sampler = sampler
end
```

Expand Down Expand Up @@ -2010,7 +2015,7 @@ The `Net` adapter submits traces using `Net::HTTP` over TCP. It is the default t

```ruby
Datadog.configure do |c|
c.tracer transport_options: proc do |t|
c.tracer.transport_options = proc { |t|
# Hostname, port, and additional options. :timeout is in seconds.
t.adapter :net_http, '127.0.0.1', 8126, { timeout: 1 }
}
Expand All @@ -2025,7 +2030,7 @@ To use, first configure your trace agent to listen by Unix socket, then configur

```ruby
Datadog.configure do |c|
c.tracer transport_options: proc { |t|
c.tracer.transport_options = proc { |t|
# Provide filepath to trace agent Unix socket
t.adapter :unix, '/tmp/ddagent/trace.sock'
}
Expand All @@ -2038,7 +2043,7 @@ The `Test` adapter is a no-op transport that can optionally buffer requests. For

```ruby
Datadog.configure do |c|
c.tracer transport_options: proc { |t|
c.tracer.transport_options = proc { |t|
# Set transport to no-op mode. Does not retain traces.
t.adapter :test

Expand All @@ -2055,7 +2060,7 @@ Custom adapters can be configured with:

```ruby
Datadog.configure do |c|
c.tracer transport_options: proc { |t|
c.tracer.transport_options = proc { |t|
# Initialize and pass an instance of the adapter
custom_adapter = CustomAdapter.new
t.adapter custom_adapter
Expand Down Expand Up @@ -2086,12 +2091,12 @@ require 'ddtrace'
Datadog.configure do |c|
# To enable runtime metrics collection, set `true`. Defaults to `false`
# You can also set DD_RUNTIME_METRICS_ENABLED=true to configure this.
c.runtime_metrics_enabled = true
c.runtime_metrics.enabled = true

# Optionally, you can configure the Statsd instance used for sending runtime metrics.
# Statsd is automatically configured with default settings if `dogstatsd-ruby` is available.
# You can configure with host and port of Datadog agent; defaults to 'localhost:8125'.
c.runtime_metrics statsd: Datadog::Statsd.new
c.runtime_metrics.statsd = Datadog::Statsd.new
end
```

Expand Down
12 changes: 6 additions & 6 deletions lib/ddtrace/buffer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,16 @@ def measure_drop(trace)

def measure_pop(traces)
# Accepted
Diagnostics::Health.metrics.queue_accepted(@buffer_accepted)
Diagnostics::Health.metrics.queue_accepted_lengths(@buffer_accepted_lengths)
Datadog.health_metrics.queue_accepted(@buffer_accepted)
Datadog.health_metrics.queue_accepted_lengths(@buffer_accepted_lengths)

# Dropped
Diagnostics::Health.metrics.queue_dropped(@buffer_dropped)
Datadog.health_metrics.queue_dropped(@buffer_dropped)

# Queue gauges
Diagnostics::Health.metrics.queue_max_length(@max_size)
Diagnostics::Health.metrics.queue_spans(@buffer_spans)
Diagnostics::Health.metrics.queue_length(traces.length)
Datadog.health_metrics.queue_max_length(@max_size)
Datadog.health_metrics.queue_spans(@buffer_spans)
Datadog.health_metrics.queue_length(traces.length)

# Reset aggregated metrics
@buffer_accepted = 0
Expand Down
47 changes: 42 additions & 5 deletions lib/ddtrace/configuration.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
require 'forwardable'

require 'ddtrace/configuration/pin_setup'
require 'ddtrace/configuration/settings'
require 'ddtrace/configuration/components'

module Datadog
# Configuration provides a unique access point for configurations
module Configuration
extend Forwardable

attr_writer :configuration

def configuration
Expand All @@ -13,18 +18,50 @@ def configuration
def configure(target = configuration, opts = {})
if target.is_a?(Settings)
yield(target) if block_given?

# Rebuild immutable components from settings
rebuild_components!(target)

target
else
PinSetup.new(target, opts).call
end
end

# Helper methods
def tracer
configuration.tracer
def_delegators \
:components,
:health_metrics,
:runtime_metrics,
:tracer

protected

def components
@components ||= Components.new(configuration)
end

def runtime_metrics
tracer.writer.runtime_metrics
def rebuild_components!(configuration)
# Build new components
new_components = Components.new(configuration)

# Teardown old components if they exist
teardown_components!(@components, new_components) if instance_variable_defined?(:@components)

# Activate new components
@components = new_components
end

def teardown_components!(old, current)
# Shutdown the old tracer, unless it's still being used.
# (e.g. a custom tracer instance passed in.)
old.tracer.shutdown! unless old.tracer == current.tracer

# Shutdown the old metrics, unless they are still being used.
# (e.g. custom Statsd instances.)
old_statsd = [old.runtime_metrics.statsd, old.health_metrics.statsd].uniq
new_statsd = [current.runtime_metrics.statsd, current.health_metrics.statsd].uniq
unused_statsd = (old_statsd - (old_statsd & new_statsd))
unused_statsd.each(&:close)
end
end
end
94 changes: 94 additions & 0 deletions lib/ddtrace/configuration/components.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
require 'ddtrace/tracer'

module Datadog
module Configuration
# Global components for the trace library.
# rubocop:disable Metrics/LineLength
class Components
def initialize(settings)
# Tracer
@tracer = build_tracer(settings)

# Runtime metrics
build_runtime_metrics(settings)

# Health metrics
@health_metrics = build_health_metrics(settings)
end

attr_reader \
:health_metrics,
:tracer

def runtime_metrics
tracer.writer.runtime_metrics
end

private

def build_tracer(settings)
# If a custom tracer has been provided, use it instead.
# Ignore all other options (they should already be configured.)
return settings.tracer.instance unless settings.tracer.instance.nil?

tracer = Tracer.new(
default_service: settings.service,
enabled: settings.tracer.enabled,
partial_flush: settings.tracer.partial_flush,
tags: build_tracer_tags(settings)
)

# TODO: We reconfigure the tracer here because it has way too many
# options it allows to mutate, and it's overwhelming to rewrite
# tracer initialization for now. Just reconfigure using the
# existing mutable #configure function. Remove when these components
# are extracted.
tracer.configure(build_tracer_options(settings))

tracer
end

def build_tracer_tags(settings)
settings.tags.dup.tap do |tags|
tags['env'] = settings.env unless settings.env.nil?
tags['version'] = settings.version unless settings.version.nil?
end
end

def build_tracer_options(settings)
settings = settings.tracer

{}.tap do |opts|
opts[:hostname] = settings.hostname unless settings.hostname.nil?
opts[:min_spans_before_partial_flush] = settings.partial_flush.min_spans_threshold unless settings.partial_flush.min_spans_threshold.nil?
opts[:partial_flush] = settings.partial_flush.enabled unless settings.partial_flush.enabled.nil?
opts[:port] = settings.port unless settings.port.nil?
opts[:priority_sampling] = settings.priority_sampling unless settings.priority_sampling.nil?
opts[:sampler] = settings.sampler unless settings.sampler.nil?
opts[:transport_options] = settings.transport_options
opts[:writer] = settings.writer unless settings.writer.nil?
opts[:writer_options] = settings.writer_options if settings.writer.nil?
end
end

def build_runtime_metrics(settings)
settings = settings.runtime_metrics
options = { enabled: settings.enabled }
options[:statsd] = settings.statsd unless settings.statsd.nil?

# TODO: We reconfigure runtime metrics here because it is too deeply nested
# within the tracer/writer. Build a new runtime metrics instance when
# runtime metrics are extracted from tracer/writer.
runtime_metrics.configure(options)
end

def build_health_metrics(settings)
settings = settings.diagnostics.health_metrics
options = { enabled: settings.enabled }
options[:statsd] = settings.statsd unless settings.statsd.nil?

Datadog::Diagnostics::Health::Metrics.new(options)
end
end
end
end
Loading

0 comments on commit a019dc9

Please sign in to comment.