Module: Datadog::DI::ProbeBuilder Private
- Defined in:
- lib/datadog/di/probe_builder.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.
Creates Probe instances from remote configuration payloads.
Due to the dynamic instrumentation product evolving over time, it is possible that the payload corresponds to a type of probe that the current version of the library does not handle. For now ArgumentError is raised in such cases (by ProbeBuilder or Probe constructor), since generally DI is meant to rescue all exceptions internally and not propagate any exceptions to applications. A dedicated exception could be added in the future if there is a use case for it.
Constant Summary collapse
- PROBE_TYPES =
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.
{ # steep:ignore IncompatibleAssignment "LOG_PROBE" => :log, }.freeze
- CAPTURE_EXPRESSION_NAME_PATTERN =
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.
/\A[a-zA-Z0-9_?]+\z/- EVALUATE_AT_STRINGS =
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.
{ "ENTRY" => :entry, "EXIT" => :exit, "DEFAULT" => :exit, }.freeze
Class Method Summary collapse
- .build_capture_expressions(raw) ⇒ Object private
- .build_capture_limits(raw) ⇒ Object private
- .build_from_remote_config(config, logger:) ⇒ Object private
- .build_template_segments(segments) ⇒ Object private
- .dedup_capture_expressions(capture_expressions, probe_id, logger) ⇒ Object private
- .parse_evaluate_at(raw, probe_id, logger) ⇒ Object private
Class Method Details
.build_capture_expressions(raw) ⇒ 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.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/datadog/di/probe_builder.rb', line 85 def build_capture_expressions(raw) return [] if raw.nil? unless Array === raw raise ArgumentError, "captureExpressions must be an array, got: #{raw.class}" end return [] if raw.empty? raw.map do |entry| unless Hash === entry raise ArgumentError, "captureExpressions entry must be a hash, got: #{entry.class}" end name = entry["name"] unless String === name && CAPTURE_EXPRESSION_NAME_PATTERN.match?(name) raise ArgumentError, "captureExpressions entry name missing or invalid (must match #{CAPTURE_EXPRESSION_NAME_PATTERN.inspect}): #{name.inspect}" end expr_spec = entry["expr"] unless Hash === expr_spec && expr_spec["dsl"] && expr_spec["json"] raise ArgumentError, "captureExpressions entry #{name}: missing or malformed expr" end compiled, regexps = EL::Compiler.new.compile(expr_spec["json"]) expr = EL::Expression.new(expr_spec["dsl"], compiled, regexps: regexps) limits = build_capture_limits(entry["capture"]) CaptureExpression.new(name: name, expr: expr, limits: limits) end end |
.build_capture_limits(raw) ⇒ 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.
123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/datadog/di/probe_builder.rb', line 123 def build_capture_limits(raw) return nil if raw.nil? unless Hash === raw raise ArgumentError, "capture-expression entry capture must be a hash, got: #{raw.class}" end CaptureLimits.new( max_reference_depth: raw["maxReferenceDepth"], max_collection_size: raw["maxCollectionSize"], max_length: raw["maxLength"], max_field_count: raw["maxFieldCount"], ) end |
.build_from_remote_config(config, 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.
40 41 42 43 44 45 46 47 48 49 50 51 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 |
# File 'lib/datadog/di/probe_builder.rb', line 40 def build_from_remote_config(config, logger:) # The validations here are not yet comprehensive. type = config.fetch("type") type_symbol = PROBE_TYPES[type] or raise ArgumentError, "Unrecognized probe type: #{type}" cond = if cond_spec = config["when"] unless cond_spec["dsl"] && cond_spec["json"] raise ArgumentError, "Malformed condition specification for probe: #{config}" end compiled, regexps = EL::Compiler.new.compile(cond_spec["json"]) EL::Expression.new(cond_spec["dsl"], compiled, regexps: regexps) end capture_expressions = build_capture_expressions(config["captureExpressions"]) capture_expressions = dedup_capture_expressions(capture_expressions, config["id"], logger) if !!config["captureSnapshot"] && !capture_expressions.empty? logger.debug do "di: probe #{config["id"]}: captureSnapshot=true wins over captureExpressions (n=#{capture_expressions.size})" end end Probe.new( id: config.fetch("id"), type: type_symbol, file: config["where"]&.[]("sourceFile"), # Sometimes lines are sometimes received as an array of nil # for some reason. line_no: config["where"]&.[]("lines")&.compact&.map(&:to_i)&.first, type_name: config["where"]&.[]("typeName"), method_name: config["where"]&.[]("methodName"), # We should not be using the template for anything - we instead # use +segments+ - but keep the template for debugging. template: config["template"], template_segments: build_template_segments(config["segments"]), capture_snapshot: !!config["captureSnapshot"], max_capture_depth: config["capture"]&.[]("maxReferenceDepth"), max_capture_attribute_count: config["capture"]&.[]("maxFieldCount"), max_capture_collection_size: config["capture"]&.[]("maxCollectionSize"), max_capture_string_length: config["capture"]&.[]("maxLength"), capture_expressions: capture_expressions, evaluate_at: parse_evaluate_at(config["evaluateAt"], config["id"], logger), rate_limit: config["sampling"]&.[]("snapshotsPerSecond"), condition: cond, ) rescue KeyError => exc raise ArgumentError, "Malformed remote configuration entry for probe: #{exc.class}: #{exc.}: #{config}" end |
.build_template_segments(segments) ⇒ 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.
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/datadog/di/probe_builder.rb', line 146 def build_template_segments(segments) segments&.map do |segment| if Hash === segment if str = segment["str"] str elsif ast = segment["json"] unless dsl = segment["dsl"] raise ArgumentError, "Missing dsl for json in segment: #{segment}" end compiler = EL::Compiler.new compiled, regexps = compiler.compile(ast) EL::Expression.new(dsl, compiled, regexps: regexps, redaction_identifier: compiler.redaction_identifier(ast)) else # TODO report to telemetry? end else # TODO report to telemetry? end end&.compact end |
.dedup_capture_expressions(capture_expressions, probe_id, 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.
110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/datadog/di/probe_builder.rb', line 110 def dedup_capture_expressions(capture_expressions, probe_id, logger) return capture_expressions if capture_expressions.size < 2 by_name = {} capture_expressions.each do |capture_expression| by_name[capture_expression.name] = capture_expression end return capture_expressions if by_name.size == capture_expressions.size logger.debug do "di: probe #{probe_id}: collapsed duplicate captureExpressions names, kept last per name (#{capture_expressions.size} -> #{by_name.size})" end by_name.values end |
.parse_evaluate_at(raw, probe_id, 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.
136 137 138 139 140 141 142 143 144 |
# File 'lib/datadog/di/probe_builder.rb', line 136 def parse_evaluate_at(raw, probe_id, logger) return :exit if raw.nil? EVALUATE_AT_STRINGS[raw] || begin logger.debug do "di: probe #{probe_id}: unrecognized evaluateAt value #{raw.inspect}, defaulting to :exit" end :exit end end |