Module: Datadog::Tracing::Contrib::Sequel::Utils

Defined in:
lib/datadog/tracing/contrib/sequel/utils.rb

Overview

General purpose functions for Sequel

Class Method Summary collapse

Class Method Details

.adapter_name(database) ⇒ Object

Ruby database connector library

e.g. adapter:mysql2 (database:mysql), adapter:jdbc (database:postgres)



26
27
28
29
30
31
32
33
34
35
36
# File 'lib/datadog/tracing/contrib/sequel/utils.rb', line 26

def adapter_name(database)
  scheme = database.adapter_scheme.to_s

  if scheme == "jdbc"
    # The subtype is more important in this case,
    # otherwise all database adapters will be 'jdbc'.
    database_type(database)
  else
    Contrib::Utils::Database.normalize_vendor(scheme)
  end
end

.connection_metadata(db) ⇒ Object

Resolves the connection host/port/database for a Sequel::Database. When the connection string is a JDBC URL (Sequel's JDBC adapter, used on JRuby), the host/port/database are parsed from it regardless of whether opts is set.



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/datadog/tracing/contrib/sequel/utils.rb', line 127

def (db)
  opts = db.opts || {}
  host = opts[:host]
  port = opts[:port]
  database = opts[:database]

  # A JDBC URL (in :uri, :url, or :database) can carry credentials, so always parse
  # it and emit only the parsed database name -- never the raw connection string.
  conn = opts[:uri] || opts[:url] || opts[:database]
  is_jdbc = conn.is_a?(String) && conn.byteslice(0, 5)&.casecmp("jdbc:") == 0
  if is_jdbc
    parsed = parse_jdbc_uri(conn)

    # Sequel's JDBC adapter connects with the URL and ignores separate
    # :host/:port options, unlike native adapters where those options take precedence.
    if !parsed[:host].nil? || !parsed[:port].nil? || !parsed[:database].nil?
      host = parsed[:host]
      port = parsed[:port]
    end
    database = parsed[:database]
  end

  {host: host, port: port&.to_s, database: database}
end

.database_type(database) ⇒ Object

Database engine

e.g. database:mysql (adapter:mysql2), database:postgres (adapter:jdbc)



41
42
43
# File 'lib/datadog/tracing/contrib/sequel/utils.rb', line 41

def database_type(database)
  Contrib::Utils::Database.normalize_vendor(database.database_type.to_s)
end

.parse_jdbc_uri(uri) ⇒ Object

Parses URI-style JDBC connection strings, extracting host, port, and (best-effort) database name. Unsupported or ambiguous forms return empty metadata rather than potentially incorrect tags.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/datadog/tracing/contrib/sequel/utils.rb', line 48

def parse_jdbc_uri(uri)
  result = {host: nil, port: nil, database: nil}
  return result unless uri.is_a?(String) && uri.valid_encoding?

  match = JDBC_URI_PATTERN.match(uri)
  return result unless match

  vendor = match[:vendor].downcase
  location, properties = match[:location].split(";", 2)

  # Several JDBC vendors append properties with semicolons, outside the URI
  # grammar. Parse the URI-compatible location separately from those properties.
  parsed = URI.parse("#{vendor}:#{location}")

  host = parsed.hostname
  port = parsed.port

  database = database_from_path(parsed.path) ||
    database_from_properties(properties) || database_from_properties(parsed.query)

  {host: host, port: port&.to_s, database: database}
rescue URI::InvalidURIError, Encoding::CompatibilityError, ArgumentError
  result
end

.parse_opts(sql, opts, db_opts, dataset = nil) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/datadog/tracing/contrib/sequel/utils.rb', line 73

def parse_opts(sql, opts, db_opts, dataset = nil)
  # Prepared statements don't provide their sql query in the +sql+ parameter.
  if !sql.is_a?(String) && dataset&.respond_to?(:prepared_sql) &&
      (resolved_sql = dataset.prepared_sql)
    # The dataset contains the resolved SQL query and prepared statement name.
    prepared_name = dataset.prepared_statement_name
    sql = resolved_sql
  end

  {
    name: opts[:type],
    query: sql,
    prepared_name: prepared_name,
    database: db_opts[:database],
    host: db_opts[:host],
  }
end

.set_common_tags(span, db) ⇒ Object



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
# File 'lib/datadog/tracing/contrib/sequel/utils.rb', line 91

def set_common_tags(span, db)
  span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
  span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_QUERY)
  span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_CLIENT)
  span.set_tag(Contrib::Ext::DB::TAG_SYSTEM, database_type(db))

   = (db)

   = false

  # Embedded/hostless databases (e.g. SQLite) have no network peer; skip peer-identifying tags.
  if [:host] && ![:host].empty?
    span.set_tag(Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME, [:host])
    span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, [:host])
    span.set_tag(Tracing::Metadata::Ext::TAG_PEER_HOSTNAME, [:host])
    span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, [:port]) if [:port]
     = true
  end

  if [:database] && ![:database].empty?
    span.set_tag(Contrib::Ext::DB::TAG_INSTANCE, [:database])
    span.set_tag(Ext::TAG_DB_NAME, [:database])
     = true
  end

  if 
    Contrib::SpanAttributeSchema.set_peer_service!(span, Ext::PEER_SERVICE_SOURCES)
  end

  # Set analytics sample rate
  Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled?
end