Class: Datadog::DI::ProbeNotificationBuilder Private

Inherits:
Object
  • Object
show all
Defined in:
lib/datadog/di/probe_notification_builder.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.

Builds probe status notification and snapshot payloads.

Constant Summary collapse

NANOSECONDS =

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.

10**9
MILLISECONDS =

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.

1000

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(settings, serializer) ⇒ ProbeNotificationBuilder

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 ProbeNotificationBuilder.



11
12
13
14
# File 'lib/datadog/di/probe_notification_builder.rb', line 11

def initialize(settings, serializer)
  @settings = settings
  @serializer = serializer
end

Instance Attribute Details

#serializerObject (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.



17
18
19
# File 'lib/datadog/di/probe_notification_builder.rb', line 17

def serializer
  @serializer
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.



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

def settings
  @settings
end

Instance Method Details

#build_emitting(probe) ⇒ 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.



31
32
33
34
35
# File 'lib/datadog/di/probe_notification_builder.rb', line 31

def build_emitting(probe)
  build_status(probe,
    message: "Probe #{probe.id} is emitting",
    status: 'EMITTING',)
end

#build_errored(probe, exc) ⇒ 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.



37
38
39
40
41
# File 'lib/datadog/di/probe_notification_builder.rb', line 37

def build_errored(probe, exc)
  build_status(probe,
    message: "Instrumentation for probe #{probe.id} failed: #{exc}",
    status: 'ERROR',)
end

#build_executed(context) ⇒ 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.

Duration is in seconds. path is the actual path of the instrumented file.



45
46
47
# File 'lib/datadog/di/probe_notification_builder.rb', line 45

def build_executed(context)
  build_snapshot(context)
end

#build_installed(probe) ⇒ 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.



25
26
27
28
29
# File 'lib/datadog/di/probe_notification_builder.rb', line 25

def build_installed(probe)
  build_status(probe,
    message: "Probe #{probe.id} has been instrumented correctly",
    status: 'INSTALLED',)
end

#build_received(probe) ⇒ 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.



19
20
21
22
23
# File 'lib/datadog/di/probe_notification_builder.rb', line 19

def build_received(probe)
  build_status(probe,
    message: "Probe #{probe.id} has been received correctly",
    status: 'RECEIVED',)
end

#build_snapshot(context) ⇒ 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.



52
53
54
55
56
57
58
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/datadog/di/probe_notification_builder.rb', line 52

def build_snapshot(context)
  probe = context.probe

  if probe.capture_snapshot? && !context.target_self
    raise ArgumentError, "Asked to build snapshot with snapshot capture but target_self is nil"
  end

  # TODO also verify that non-capturing probe does not pass
  # snapshot or vars/args into this method
  captures = if probe.capture_snapshot?
    if probe.method?
      return_arguments = {
        "@return": serializer.serialize_value(context.return_value,
          depth: probe.max_capture_depth || settings.dynamic_instrumentation.max_capture_depth,
          attribute_count: probe.max_capture_attribute_count || settings.dynamic_instrumentation.max_capture_attribute_count),
        self: serializer.serialize_value(context.target_self),
      }
      {
        entry: {
          arguments: context.serialized_entry_args,
        },
        return: {
          arguments: return_arguments,
          throwable: nil,
        },
      }
    elsif probe.line?
      {
        lines: (locals = context.serialized_locals) && {
          probe.line_no => {
            locals: locals,
            arguments: {self: serializer.serialize_value(context.target_self)},
          },
        },
      }
    end
  end

  location = if probe.line?
    {
      file: context.path,
      lines: [probe.line_no],
    }
  elsif probe.method?
    {
      method: probe.method_name,
      type: probe.type_name,
    }
  end

  stack = if caller_locations = context.caller_locations
    format_caller_locations(caller_locations)
  end

  timestamp = timestamp_now
  message = nil
  evaluation_errors = []
  if segments = probe.template_segments
    message, evaluation_errors = evaluate_template(segments, context)
  end
  duration = context.duration
  {
    service: settings.service,
    "debugger.snapshot": {
      id: SecureRandom.uuid,
      timestamp: timestamp,
      evaluationErrors: evaluation_errors,
      probe: {
        id: probe.id,
        version: 0,
        location: location,
      },
      language: 'ruby',
      # TODO add test coverage for callers being nil
      stack: stack,
      captures: captures,
    },
    # In python tracer duration is under debugger.snapshot,
    # but UI appears to expect it here at top level.
    duration: duration ? (duration * NANOSECONDS).to_i : 0,
    host: nil,
    logger: {
      name: probe.file,
      method: probe.method_name || 'no_method',
      thread_name: Thread.current.name,
      # Dynamic instrumentation currently does not need thread_id for
      # anything. It can be sent if a customer requests it at which point
      # we can also determine which thread identifier to send
      # (Thread#native_thread_id or something else).
      thread_id: nil,
      version: 2,
    },
    # TODO add tests that the trace/span id is correctly propagated
    "dd.trace_id": active_trace&.id&.to_s,
    "dd.span_id": active_span&.id&.to_s,
    ddsource: 'dd_debugger',
    message: message,
    timestamp: timestamp,
  }
end