Module: Datadog::DI Private

Defined in:
lib/datadog/di.rb,
lib/datadog/di/base.rb,
lib/datadog/di/error.rb,
lib/datadog/di/probe.rb,
lib/datadog/di/utils.rb,
lib/datadog/di/logger.rb,
lib/datadog/di/remote.rb,
lib/datadog/di/context.rb,
lib/datadog/di/contrib.rb,
lib/datadog/di/redactor.rb,
lib/datadog/di/component.rb,
lib/datadog/di/extensions.rb,
lib/datadog/di/serializer.rb,
lib/datadog/di/el/compiler.rb,
lib/datadog/di/code_tracker.rb,
lib/datadog/di/el/evaluator.rb,
lib/datadog/di/instrumenter.rb,
lib/datadog/di/configuration.rb,
lib/datadog/di/el/expression.rb,
lib/datadog/di/probe_builder.rb,
lib/datadog/di/probe_manager.rb,
lib/datadog/di/proc_responder.rb,
lib/datadog/di/transport/http.rb,
lib/datadog/di/contrib/railtie.rb,
lib/datadog/di/transport/input.rb,
lib/datadog/di/probe_file_loader.rb,
lib/datadog/di/transport/http/input.rb,
lib/datadog/di/probe_notifier_worker.rb,
lib/datadog/di/transport/diagnostics.rb,
lib/datadog/di/configuration/settings.rb,
lib/datadog/di/probe_file_loader/railtie.rb,
lib/datadog/di/probe_notification_builder.rb,
lib/datadog/di/transport/http/diagnostics.rb

Overview

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Namespace for Datadog dynamic instrumentation.

API:

  • private

Defined Under Namespace

Modules: Configuration, Contrib, EL, Extensions, ProbeBuilder, ProbeFileLoader, Remote, Transport, Utils Classes: CodeTracker, Component, Context, Error, Instrumenter, Logger, Probe, ProbeManager, ProbeNotificationBuilder, ProbeNotifierWorker, ProcResponder, Redactor, Serializer

Constant Summary collapse

INSTRUMENTED_COUNTERS_LOCK =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

API:

  • private

Mutex.new
LOCK =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

API:

  • private

Mutex.new

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.code_trackerObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

API:

  • private



21
22
23
# File 'lib/datadog/di/base.rb', line 21

def code_tracker
  @code_tracker
end

Class Method Details

.activate_trackingObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Activates code tracking if possible.

This method does nothing if invoked in an environment that does not implement required trace points for code tracking (MRI Ruby < 2.6, JRuby) and rescues any exceptions that may be raised by downstream DI code.

API:

  • private



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/datadog/di/base.rb', line 41

def activate_tracking
  # :script_compiled trace point was added in Ruby 2.6.
  return unless RUBY_VERSION >= '2.6'

  begin
    # Activate code tracking by default because line trace points will not work
    # without it.
    Datadog::DI.activate_tracking!
  rescue => exc
    if defined?(Datadog.logger)
      Datadog.logger.warn { "di: Failed to activate code tracking for DI: #{exc.class}: #{exc}" }
    else
      # We do not have Datadog logger potentially because DI code tracker is
      # being loaded early in application boot process and the rest of datadog
      # wasn't loaded yet. Output to standard error.
      warn("datadog: di: Failed to activate code tracking for DI: #{exc.class}: #{exc}")
    end
  end
end

.activate_tracking!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Activates code tracking. Normally this method should be called when the application starts. If instrumenting third-party code, code tracking needs to be enabled before the third-party libraries are loaded. Any third-party code loaded before code tracking is activated will NOT be instrumentable using dynamic instrumentation.

TODO test that activating tracker multiple times preserves existing mappings in the registry

API:

  • private



31
32
33
# File 'lib/datadog/di/base.rb', line 31

def activate_tracking!
  (@code_tracker ||= CodeTracker.new).start
end

.add_current_component(component) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

To avoid potential races with DI::Component being added and removed, we maintain a list of the components. Normally the list should contain either zero or one component depending on whether DI is enabled in Datadog configuration. However, if a new instance of DI::Component is created while the previous instance is still running, we are guaranteed to not end up with no component when one is running.

API:

  • private



101
102
103
104
105
106
# File 'lib/datadog/di/base.rb', line 101

def add_current_component(component)
  LOCK.synchronize do
    @current_components ||= []
    @current_components << component
  end
end

.code_tracking_active?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns whether code tracking is available. This method should be used instead of querying #code_tracker because the latter one may be nil.

Returns:

API:

  • private



75
76
77
# File 'lib/datadog/di/base.rb', line 75

def code_tracking_active?
  code_tracker&.active? || false
end

.componentObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method is called from DI Remote handler to issue DI operations to the probe manager (add or remove probes).

When DI Remote is executing, Datadog.components should be initialized and we should be able to reference it to get to the DI component.

Given that we need the current_component anyway for code tracker, perhaps we should delete the component method and just use current_component in all cases.

API:

  • private



28
29
30
# File 'lib/datadog/di.rb', line 28

def component
  Datadog.send(:components).dynamic_instrumentation
end

.current_componentObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

DI code tracker is instantiated globally before the regular set of components is created, but the code tracker needs to call out to the “current” DI component to perform instrumentation when application code is loaded. Because this call may happen prior to Datadog components having been initialized, we maintain the “current component” which contains a reference to the most recently instantiated DI::Component. This way, if a DI component hasn’t been instantiated, we do not try to reference Datadog.components. In other words, this method exists so that we never attempt to call Datadog.components from the code tracker.

API:

  • private



89
90
91
92
93
# File 'lib/datadog/di/base.rb', line 89

def current_component
  LOCK.synchronize do
    @current_components&.last
  end
end

.deactivate_tracking!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Deactivates code tracking. In normal usage of DI this method should never be called, however it is used by DI’s test suite to reset state for individual tests.

Note that deactivating tracking clears out the registry, losing the ability to look up files that have been loaded into the process already.

API:

  • private



68
69
70
# File 'lib/datadog/di/base.rb', line 68

def deactivate_tracking!
  code_tracker&.stop
end

.enabled?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

API:

  • private



15
16
17
# File 'lib/datadog/di.rb', line 15

def enabled?
  Datadog.configuration.dynamic_instrumentation.enabled
end

.instrumented_count(kind = nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Track how many outstanding instrumentations are in DI.

It is hard to find the actual instrumentations - there is no method provided by Ruby to list all trace points, and we would need to manually track our instrumentation modules for method probes. Plus, tracking the modules could create active references to instrumentation, which is not desired.

A simpler solution is to maintain a counter which is increased whenever a probe is installed and decreased when a probe is removed.

This counter does not include pending probes - being not installed, those pose no concerns to customer applications.

API:

  • private



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/datadog/di.rb', line 45

def instrumented_count(kind = nil)
  INSTRUMENTED_COUNTERS_LOCK.synchronize do
    if defined?(@instrumented_count)
      if kind
        validate_kind!(kind)
        @instrumented_count[kind] || 0
      else
        @instrumented_count.inject(0) do |sum, (_kind, count)|
          sum + count
        end
      end
    else
      0
    end
  end
end

.instrumented_count_dec(kind) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

API:

  • private



70
71
72
73
74
75
76
77
78
79
80
# File 'lib/datadog/di.rb', line 70

def instrumented_count_dec(kind)
  validate_kind!(kind)
  INSTRUMENTED_COUNTERS_LOCK.synchronize do
    @instrumented_count = Hash.new(0) unless defined?(@instrumented_count)
    if @instrumented_count[kind] <= 0
      Datadog.logger.debug { "di: attempting to decrease instrumented count below zero for #{kind}" }
      return
    end
    @instrumented_count[kind] -= 1
  end
end

.instrumented_count_inc(kind) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

API:

  • private



62
63
64
65
66
67
68
# File 'lib/datadog/di.rb', line 62

def instrumented_count_inc(kind)
  validate_kind!(kind)
  INSTRUMENTED_COUNTERS_LOCK.synchronize do
    @instrumented_count = Hash.new(0) unless defined?(@instrumented_count)
    @instrumented_count[kind] += 1
  end
end

.remove_current_component(component) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

API:

  • private



108
109
110
111
112
# File 'lib/datadog/di/base.rb', line 108

def remove_current_component(component)
  LOCK.synchronize do
    @current_components&.delete(component)
  end
end