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.

1_000_000_000
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, logger, telemetry: nil) ⇒ 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.



14
15
16
17
18
19
20
21
22
# File 'lib/datadog/di/probe_notification_builder.rb', line 14

def initialize(settings, serializer, logger, telemetry: nil)
  @settings = settings
  @serializer = serializer
  @logger = logger
  @telemetry = telemetry
  @capture_expression_evaluator = CaptureExpressionEvaluator.new(
    settings: settings, serializer: serializer, logger: logger, telemetry: telemetry,
  )
end

Instance Attribute Details

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



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

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



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

def logger
  @logger
end

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



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

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.



24
25
26
# File 'lib/datadog/di/probe_notification_builder.rb', line 24

def settings
  @settings
end

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



30
31
32
# File 'lib/datadog/di/probe_notification_builder.rb', line 30

def telemetry
  @telemetry
end

Instance Method Details

#build_condition_evaluation_failed(context, expression, exception) ⇒ 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.



150
151
152
153
154
155
156
# File 'lib/datadog/di/probe_notification_builder.rb', line 150

def build_condition_evaluation_failed(context, expression, exception)
  error = {
    message: "#{exception.class}: #{exception}",
    expr: expression.dsl_expr,
  }
  build_snapshot_base(context, evaluation_errors: [error])
end

#build_disabled(probe, duration) ⇒ 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.



59
60
61
62
63
# File 'lib/datadog/di/probe_notification_builder.rb', line 59

def build_disabled(probe, duration)
  build_status(probe,
    message: "Probe #{probe.id} was disabled because it consumed #{duration} seconds of CPU time in DI processing",
    status: "ERROR",)
end

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



46
47
48
49
50
# File 'lib/datadog/di/probe_notification_builder.rb', line 46

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.



52
53
54
55
56
57
# File 'lib/datadog/di/probe_notification_builder.rb', line 52

def build_errored(probe, exc)
  build_status(probe,
    message: "Instrumentation for probe #{probe.id} failed: #{exc}",
    status: "ERROR",
    exception: exc)
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.



67
68
69
# File 'lib/datadog/di/probe_notification_builder.rb', line 67

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.



40
41
42
43
44
# File 'lib/datadog/di/probe_notification_builder.rb', line 40

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.



34
35
36
37
38
# File 'lib/datadog/di/probe_notification_builder.rb', line 34

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.



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
# File 'lib/datadog/di/probe_notification_builder.rb', line 74

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
  capture_expression_evaluation_errors = []
  captures = if probe.capture_snapshot?
    snapshot_limits = probe.snapshot_serializer_limits(settings)
    if probe.method?
      return_arguments = {
        "@return": serializer.serialize_value(context.return_value, **snapshot_limits),
        self: serializer.serialize_value(context.target_self, **snapshot_limits),
      }
      {
        entry: {
          arguments: context.serialized_entry_args,
        },
        return: {
          arguments: return_arguments,
          throwable: context.exception ? serialize_throwable(context.exception) : nil,
        },
      }
    elsif probe.line?
      {
        lines: (locals = context.serialized_locals) && {
          probe.line_no => {
            locals: locals,
            arguments: {self: serializer.serialize_value(context.target_self, **snapshot_limits)},
          },
        },
      }
    end
  elsif probe.capture_expressions?
    if probe.method?
      if probe.evaluate_at_entry?
        captured_block = context.entry_capture_expressions || {}
        capture_expression_evaluation_errors = context.entry_capture_evaluation_errors || []
        {
          entry: {captureExpressions: captured_block},
        }
      else
        captured_block, capture_expression_evaluation_errors =
          capture_expression_evaluator.evaluate(probe, context)
        {
          return: {
            captureExpressions: captured_block,
            throwable: context.exception ? serialize_throwable(context.exception) : nil,
          },
        }
      end
    elsif probe.line?
      captured_block, capture_expression_evaluation_errors =
        capture_expression_evaluator.evaluate(probe, context)
      {
        lines: {
          probe.line_no => {captureExpressions: captured_block},
        },
      }
    end
  end

  message = nil
  evaluation_errors = []
  if segments = probe.template_segments
    message, evaluation_errors = evaluate_template(segments, context)
  end
  evaluation_errors.concat(capture_expression_evaluation_errors)
  build_snapshot_base(context,
    evaluation_errors: evaluation_errors, message: message,
    captures: captures)
end

#build_status(probe, message:, status:, exception: nil) ⇒ Hash

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.

Builds a probe status notification payload.

Parameters:

  • probe (Probe)

    the probe to build status for

  • message (String)

    human-readable status message

  • status (String)

    status value (RECEIVED, INSTALLED, EMITTING, ERROR)

  • exception (Exception, nil) (defaults to: nil)

    exception to include for ERROR status

Returns:

  • (Hash)

    the status payload



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/datadog/di/probe_notification_builder.rb', line 165

def build_status(probe, message:, status:, exception: nil)
  diagnostics = {
    probeId: probe.id,
    probeVersion: 0,
    runtimeId: Core::Environment::Identity.id,
    parentId: nil,
    status: status,
  }

  # Exception field is required by the backend for ERROR status.
  # If the ERROR status is sent without the exception field, the status
  # appears to be completely ignored by the backend.
  # Note: The Go DI implementation does not send the top-level message
  # field at all when sending error statuses.
  if status == "ERROR"
    diagnostics[:exception] = { # steep:ignore
      type: exception ? exception.class.name : "Error",
      message: exception ? exception.message : message,
    }
  end

  {
    service: settings.service,
    timestamp: timestamp_now,
    message: message,
    ddsource: "dd_debugger",
    debugger: {
      diagnostics: diagnostics,
    },
  }
end