Class: Datadog::Tracing::SpanEvent

Inherits:
Object
  • Object
show all
Defined in:
lib/datadog/tracing/span_event.rb,
sig/datadog/tracing/span_event.rbs

Overview

Represents a timestamped annotation on a span. It is analogous to structured log message.

Constant Summary collapse

MIN_INT64_SIGNED =

Returns:

  • (Integer)
-2 << 62
MAX_INT64_SIGNED =

Returns:

  • (Integer)
(2 << 62) - 1
STRING_TYPE =

Returns:

  • (Integer)
0
BOOLEAN_TYPE =

Returns:

  • (Integer)
1
INTEGER_TYPE =

Returns:

  • (Integer)
2
DOUBLE_TYPE =

Returns:

  • (Integer)
3
ARRAY_TYPE =

Returns:

  • (Integer)
4

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, attributes: nil, time_unix_nano: nil) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/datadog/tracing/span_event.rb', line 23

def initialize(
  name,
  attributes: nil,
  time_unix_nano: nil
)
  @name = name

  @attributes = attributes.dup || {}
  validate_attributes!(@attributes)
  @attributes.transform_keys!(&:to_s)

  # OpenTelemetry SDK stores span event timestamps in nanoseconds (not seconds).
  # We will do the same here to avoid unnecessary conversions and inconsistencies.
  @time_unix_nano = time_unix_nano || (Core::Utils::Time.now.to_r * 1_000_000_000).to_i
end

Instance Attribute Details

#attributesObject (readonly)

Returns the value of attribute attributes.



16
17
18
# File 'lib/datadog/tracing/span_event.rb', line 16

def attributes
  @attributes
end

#nameObject (readonly)

Returns the value of attribute name.



12
13
14
# File 'lib/datadog/tracing/span_event.rb', line 12

def name
  @name
end

#time_unix_nanoObject (readonly)

Returns the value of attribute time_unix_nano.



20
21
22
# File 'lib/datadog/tracing/span_event.rb', line 20

def time_unix_nano
  @time_unix_nano
end

Instance Method Details

#serialize_native_attribute(value) ⇒ Object

Serializes individual scalar attributes into the native format.



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/datadog/tracing/span_event.rb', line 144

def serialize_native_attribute(value)
  case value
  when String
    {type: STRING_TYPE, string_value: value}
  when TrueClass, FalseClass
    {type: BOOLEAN_TYPE, bool_value: value}
  when Integer
    {type: INTEGER_TYPE, int_value: value}
  when Float
    {type: DOUBLE_TYPE, double_value: value}
  else
    # This is technically unreachable due to the validation in #initialize.
    raise ArgumentError, "Attribute must be a string, number, or boolean: #{value}."
  end
end

#to_hashObject

Converts the span event into a hash to be used by with the span tag serialization (span.set_tag('events) = [event.to_hash]). This serialization format has the drawback of being limiting span events to the size limit of a span tag. All Datadog agents support this format.



43
44
45
46
47
# File 'lib/datadog/tracing/span_event.rb', line 43

def to_hash
  h = {'name' => @name, 'time_unix_nano' => @time_unix_nano}
  h['attributes'] = @attributes unless @attributes.empty?
  h
end

#to_native_formatObject

Converts the span event into a hash to be used by the MessagePack serialization as a top-level span field (span.span_events = [event.to_native_format]). This serialization format removes the serialization limitations of the span.set_tag('events) approach, but is only supported by newer version of the Datadog agent.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/datadog/tracing/span_event.rb', line 53

def to_native_format
  h = {'name' => @name, 'time_unix_nano' => @time_unix_nano}

  attr = {}
  @attributes.each do |key, value|
    attr[key] = if value.is_a?(Array)
      {type: ARRAY_TYPE, array_value: {values: value.map { |v| serialize_native_attribute(v) }}}
    else
      serialize_native_attribute(value)
    end
  end

  h['attributes'] = attr unless @attributes.empty?

  h
end

#validate_attributes!(attributes) ⇒ Object

Checks the attributes hash to ensure it only contains serializable values. Invalid values are removed from the hash.



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
# File 'lib/datadog/tracing/span_event.rb', line 77

def validate_attributes!(attributes)
  attributes.select! do |key, value|
    case value
    when Array
      next true if value.empty?

      first = value.first
      case first
      when String, Integer, Float
        first_type = first.class
        if value.all? { |v| v.is_a?(first_type) }
          value.all? { |v| validate_scalar_attribute!(key, v) }
        else
          Datadog.logger.warn("Attribute #{key} array must be homogenous: #{value}.")
          false
        end
      when TrueClass, FalseClass
        if value.all? { |v| v.is_a?(TrueClass) || v.is_a?(FalseClass) }
          value.all? { |v| validate_scalar_attribute!(key, v) }
        else
          Datadog.logger.warn("Attribute #{key} array must be homogenous: #{value}.")
          false
        end
      else
        Datadog.logger.warn("Attribute #{key} must be a string, number, or boolean: #{value}.")
        false
      end
    when String, Numeric, TrueClass, FalseClass
      validate_scalar_attribute!(key, value)
    else
      Datadog.logger.warn("Attribute #{key} must be a string, number, boolean, or array: #{value}.")
      false
    end
  end
end

#validate_scalar_attribute!(key, value) ⇒ Boolean

Parameters:

  • key (String)
  • value (attributeValue)

Returns:

  • (Boolean)


113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/datadog/tracing/span_event.rb', line 113

def validate_scalar_attribute!(key, value)
  case value
  when String, TrueClass, FalseClass
    true
  when Integer
    # Cannot be larger than signed 64-bit integer
    if value < MIN_INT64_SIGNED || value > MAX_INT64_SIGNED
      Datadog.logger.warn("Attribute #{key} must be within the range of a signed 64-bit integer: #{value}.")
      false
    else
      true
    end
  when Float
    # Has to be finite
    return true if value.finite?

    Datadog.logger.warn("Attribute #{key} must be a finite number: #{value}.")
    false
  else
    Datadog.logger.warn("Attribute #{key} must be a string, number, or boolean: #{value}.")
    false
  end
end