module OpenTelemetry::Instrumentation::Trilogy::Patches::Client

Module to prepend to Trilogy for instrumentation

Constants

COMPONENTS_REGEX_MAP
FULL_SQL_REGEXP
MYSQL_COMPONENTS
QUERY_NAMES
QUERY_NAME_RE

Public Class Methods

new(args) click to toggle source
Calls superclass method
# File lib/opentelemetry/instrumentation/trilogy/patches/client.rb, line 51
def initialize(args)
  @_otel_net_peer_name = args[:host]
  super
end

Public Instance Methods

query(sql) click to toggle source
Calls superclass method
# File lib/opentelemetry/instrumentation/trilogy/patches/client.rb, line 56
def query(sql)
  tracer.in_span(
    database_span_name(sql),
    attributes: client_attributes(sql),
    kind: :client
  ) do
    super(sql)
  end
end

Private Instance Methods

client_attributes(sql) click to toggle source
# File lib/opentelemetry/instrumentation/trilogy/patches/client.rb, line 68
def client_attributes(sql)
  attributes = {
    ::OpenTelemetry::SemanticConventions::Trace::DB_SYSTEM => 'mysql',
    ::OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => net_peer_name
  }

  attributes[::OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = config[:peer_service] unless config[:peer_service].nil?

  case config[:db_statement]
  when :obfuscate
    attributes[::OpenTelemetry::SemanticConventions::Trace::DB_STATEMENT] = obfuscate_sql(sql)
  when :include
    attributes[::OpenTelemetry::SemanticConventions::Trace::DB_STATEMENT] = sql
  end

  attributes
end
config() click to toggle source
# File lib/opentelemetry/instrumentation/trilogy/patches/client.rb, line 135
def config
  Trilogy::Instrumentation.instance.config
end
database_span_name(sql) click to toggle source
# File lib/opentelemetry/instrumentation/trilogy/patches/client.rb, line 105
def database_span_name(sql)
  # Setting span name to the SQL query without obfuscation would
  # result in PII + cardinality issues.
  # First attempt to infer the statement type then fallback to
  # current Otel approach {database.component_name}.{database_instance_name}
  # https://github.com/open-telemetry/opentelemetry-python/blob/39fa078312e6f41c403aa8cad1868264011f7546/ext/opentelemetry-ext-dbapi/tests/test_dbapi_integration.py#L53
  # This creates span names like mysql.default, mysql.replica, postgresql.staging etc.

  statement_type = extract_statement_type(sql)

  return statement_type unless statement_type.nil?

  # fallback
  'mysql'
end
detect_unmatched_pairs(obfuscated) click to toggle source
# File lib/opentelemetry/instrumentation/trilogy/patches/client.rb, line 96
def detect_unmatched_pairs(obfuscated)
  # We use this to check whether the query contains any quote characters
  # after obfuscation. If so, that's a good indication that the original
  # query was malformed, and so our obfuscation can't reliably find
  # literals. In such a case, we'll replace the entire query with a
  # placeholder.
  %r{'|"|\/\*|\*\/}.match(obfuscated)
end
extract_statement_type(sql) click to toggle source
# File lib/opentelemetry/instrumentation/trilogy/patches/client.rb, line 139
def extract_statement_type(sql)
  QUERY_NAME_RE.match(sql) { |match| match[1].downcase } unless sql.nil?
rescue StandardError => e
  OpenTelemetry.logger.error("Error extracting sql statement type: #{e.message}")
end
net_peer_name() click to toggle source
# File lib/opentelemetry/instrumentation/trilogy/patches/client.rb, line 121
def net_peer_name
  if defined?(@connected_host)
    @connected_host
  elsif @_otel_net_peer_name
    @_otel_net_peer_name
  else
    'unknown sock'
  end
end
obfuscate_sql(sql) click to toggle source
# File lib/opentelemetry/instrumentation/trilogy/patches/client.rb, line 86
def obfuscate_sql(sql)
  if sql.size > 2000
    'SQL query too large to remove sensitive data ...'
  else
    obfuscated = sql.gsub(FULL_SQL_REGEXP, '?')
    obfuscated = 'Failed to obfuscate SQL query - quote characters remained after obfuscation' if detect_unmatched_pairs(obfuscated)
    obfuscated
  end
end
tracer() click to toggle source
# File lib/opentelemetry/instrumentation/trilogy/patches/client.rb, line 131
def tracer
  Trilogy::Instrumentation.instance.tracer
end