Class: Datadog::Core::Telemetry::Component Private

Inherits:
Object
  • Object
show all
Includes:
Logging, Utils::Forking
Defined in:
lib/datadog/core/telemetry/component.rb

Overview

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

Telemetry entry point, coordinates sending telemetry events at various points in application lifecycle.

API:

  • private

Constant Summary collapse

ENDPOINT_COLLECTION_MESSAGE_LIMIT =

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

300
ONLY_ONCE =

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

Utils::OnlyOnce.new

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Logging

#error, #report

Methods included from Utils::Forking

#after_fork!, extended, #fork_pid, #forked?, included, #update_fork_pid!

Constructor Details

#initialize(settings:, agent_settings:, logger:, enabled:) ⇒ Component

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 a new instance of Component.

Parameters:

  • Determines whether telemetry events should be sent to the API

API:

  • private



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/datadog/core/telemetry/component.rb', line 59

def initialize( # standard:disable Metrics/MethodLength
  settings:,
  agent_settings:,
  logger:,
  enabled:
)
  ONLY_ONCE.run do
    Utils::AtForkMonkeyPatch.apply!

    # All of the other at fork monkey patch callbacks reference
    # globals, follow that pattern here to avoid having the component
    # referenced via the at fork callbacks.
    Datadog::Core::Utils::AtForkMonkeyPatch.at_fork(:child) do
      Datadog.send(:components, allow_initialization: false)&.telemetry&.after_fork
    end
  end

  @enabled = enabled
  @log_collection_enabled = settings.telemetry.log_collection_enabled
  @logger = logger

  @metrics_manager = MetricsManager.new(
    enabled: @enabled && settings.telemetry.metrics_enabled,
    aggregation_interval: settings.telemetry.metrics_aggregation_interval_seconds,
  )

  @stopped = false

  return unless @enabled

  @transport = if settings.telemetry.agentless_enabled
    # We don't touch the `agent_settings` since we still want the telemetry payloads to refer to the original
    # settings, even though the telemetry itself may be using a different path.
    telemetry_specific_agent_settings = Core::Configuration::AgentlessSettingsResolver.call(
      settings,
      host_prefix: 'instrumentation-telemetry-intake',
      url_override: settings.telemetry.agentless_url_override,
      url_override_source: 'c.telemetry.agentless_url_override',
      logger: logger,
    )
    Telemetry::Transport::HTTP.agentless_telemetry(
      agent_settings: telemetry_specific_agent_settings,
      logger: logger,
      # api_key should have already validated to be
      # not nil by +build+ method above.
      api_key: settings.api_key,
    )
  else
    Telemetry::Transport::HTTP.agent_telemetry(
      agent_settings: agent_settings, logger: logger,
    )
  end

  @worker = Telemetry::Worker.new(
    enabled: @enabled,
    heartbeat_interval_seconds: settings.telemetry.heartbeat_interval_seconds,
    metrics_aggregation_interval_seconds: settings.telemetry.metrics_aggregation_interval_seconds,
    emitter: Emitter.new(
      @transport,
      logger: @logger,
      debug: settings.telemetry.debug,
    ),
    metrics_manager: @metrics_manager,
    dependency_collection: settings.telemetry.dependency_collection,
    logger: logger,
    shutdown_timeout: settings.telemetry.shutdown_timeout_seconds,
  )

  @agent_settings = agent_settings
end

Instance Attribute Details

#agent_settingsObject (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



31
32
33
# File 'lib/datadog/core/telemetry/component.rb', line 31

def agent_settings
  @agent_settings
end

#enabledObject (readonly) Also known as: enabled?

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



26
27
28
# File 'lib/datadog/core/telemetry/component.rb', line 26

def enabled
  @enabled
end

#loggerObject (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



27
28
29
# File 'lib/datadog/core/telemetry/component.rb', line 27

def logger
  @logger
end

#metrics_managerObject (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



32
33
34
# File 'lib/datadog/core/telemetry/component.rb', line 32

def metrics_manager
  @metrics_manager
end

#settingsObject (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



30
31
32
# File 'lib/datadog/core/telemetry/component.rb', line 30

def settings
  @settings
end

#transportObject (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



28
29
30
# File 'lib/datadog/core/telemetry/component.rb', line 28

def transport
  @transport
end

#workerObject (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



29
30
31
# File 'lib/datadog/core/telemetry/component.rb', line 29

def worker
  @worker
end

Class Method Details

.build(settings, agent_settings, logger) ⇒ 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



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/datadog/core/telemetry/component.rb', line 41

def self.build(settings, agent_settings, logger)
  enabled = settings.telemetry.enabled
  agentless_enabled = settings.telemetry.agentless_enabled

  if agentless_enabled && settings.api_key.nil?
    enabled = false
    logger.debug { 'Telemetry disabled. Agentless telemetry requires a DD_API_KEY variable to be set.' }
  end

  Telemetry::Component.new(
    settings: settings,
    agent_settings: agent_settings,
    enabled: enabled,
    logger: logger,
  )
end

Instance Method Details

#after_forkObject

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.

When a fork happens, we generally need to do two things inside the child proess:

  1. Restart the worker.

  2. Discard any events and metrics that were submitted in the parent process (because they will be sent out in the parent process, sending them in the child would cause duplicate submission).

API:

  • private



238
239
240
241
242
243
244
245
# File 'lib/datadog/core/telemetry/component.rb', line 238

def after_fork
  # We cannot simply create a new instance of metrics manager because
  # it is referenced from other objects (e.g. the worker).
  # We must reset the existing instance.
  @metrics_manager.clear

  worker&.send(:after_fork_monkey_patched)
end

#app_endpoints_loaded(endpoints, page_size: ENDPOINT_COLLECTION_MESSAGE_LIMIT) ⇒ 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.

Report application endpoints

API:

  • private



198
199
200
201
202
203
204
# File 'lib/datadog/core/telemetry/component.rb', line 198

def app_endpoints_loaded(endpoints, page_size: ENDPOINT_COLLECTION_MESSAGE_LIMIT)
  return unless enabled?

  endpoints.each_slice(page_size).with_index do |endpoints_slice, i|
    @worker.enqueue(Event::AppEndpointsLoaded.new(endpoints_slice, is_first: i.zero?))
  end
end

#client_configuration_change!(changes) ⇒ 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.

Report configuration changes caused by Remote Configuration.

API:

  • private



191
192
193
194
195
# File 'lib/datadog/core/telemetry/component.rb', line 191

def client_configuration_change!(changes)
  return unless enabled?

  @worker.enqueue(Event::AppClientConfigurationChange.new(changes, 'remote_config'))
end

#dec(namespace, metric_name, value, tags: {}, common: true) ⇒ 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.

Decremenets a count metric.

API:

  • private



212
213
214
# File 'lib/datadog/core/telemetry/component.rb', line 212

def dec(namespace, metric_name, value, tags: {}, common: true)
  @metrics_manager.dec(namespace, metric_name, value, tags: tags, common: common)
end

#disable!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



130
131
132
133
# File 'lib/datadog/core/telemetry/component.rb', line 130

def disable!
  @enabled = false
  @worker&.enabled = false
end

#distribution(namespace, metric_name, value, tags: {}, common: true) ⇒ 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.

Tracks distribution metric.

API:

  • private



227
228
229
# File 'lib/datadog/core/telemetry/component.rb', line 227

def distribution(namespace, metric_name, value, tags: {}, common: true)
  @metrics_manager.distribution(namespace, metric_name, value, tags: tags, common: common)
end

#emit_closing!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



161
162
163
164
165
# File 'lib/datadog/core/telemetry/component.rb', line 161

def emit_closing!
  return unless enabled?

  @worker.enqueue(Event::AppClosing.new)
end

#flush(timeout: 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.

Wait for the worker to send out all events that have already been queued, up to 15 seconds. Returns whether all events have been flushed, or nil if telemetry is disabled.

API:

  • private



184
185
186
187
188
# File 'lib/datadog/core/telemetry/component.rb', line 184

def flush(timeout: nil)
  return unless enabled?

  @worker.flush(timeout: timeout)
end

#gauge(namespace, metric_name, value, tags: {}, common: true) ⇒ 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.

Tracks gauge metric.

API:

  • private



217
218
219
# File 'lib/datadog/core/telemetry/component.rb', line 217

def gauge(namespace, metric_name, value, tags: {}, common: true)
  @metrics_manager.gauge(namespace, metric_name, value, tags: tags, common: common)
end

#inc(namespace, metric_name, value, tags: {}, common: true) ⇒ 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.

Increments a count metric.

API:

  • private



207
208
209
# File 'lib/datadog/core/telemetry/component.rb', line 207

def inc(namespace, metric_name, value, tags: {}, common: true)
  @metrics_manager.inc(namespace, metric_name, value, tags: tags, common: common)
end

#integrations_change!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



167
168
169
170
171
# File 'lib/datadog/core/telemetry/component.rb', line 167

def integrations_change!
  return unless enabled?

  @worker.enqueue(Event::AppIntegrationsChange.new)
end

#log!(event) ⇒ 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



173
174
175
176
177
# File 'lib/datadog/core/telemetry/component.rb', line 173

def log!(event)
  return unless enabled? && @log_collection_enabled

  @worker.enqueue(event)
end

#rate(namespace, metric_name, value, tags: {}, common: true) ⇒ 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.

Tracks rate metric.

API:

  • private



222
223
224
# File 'lib/datadog/core/telemetry/component.rb', line 222

def rate(namespace, metric_name, value, tags: {}, common: true)
  @metrics_manager.rate(namespace, metric_name, value, tags: tags, common: common)
end

#shutdown!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



151
152
153
154
155
156
157
158
159
# File 'lib/datadog/core/telemetry/component.rb', line 151

def shutdown!
  return if @stopped

  if defined?(@worker)
    @worker&.stop(true)
  end

  @stopped = true
end

#start(initial_event_is_change = false, components:) ⇒ 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



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/datadog/core/telemetry/component.rb', line 135

def start(initial_event_is_change = false, components:)
  return unless enabled?

  initial_event = if initial_event_is_change
    Event::SynthAppClientConfigurationChange.new(
      components: components,
    )
  else
    Event::AppStarted.new(
      components: components,
    )
  end

  @worker.start(initial_event)
end