module PostgresExtension
Constants
- COMPONENTS_REGEX_MAP
- EXEC_ISH_METHODS
These are all alike in that they will have a SQL statement as the first parameter. That statement may possibly be parameterized, but we can still use it - the obfuscation code will just transform $1 -> $? in that case (which is fine enough).
- EXEC_PREPARED_ISH_METHODS
The following methods take a prepared statement name as their first parameter - everything after that is either potentially quite sensitive (an array of bind params) or not useful to us. We trace them all alike.
- POSTGRES_COMPONENTS
- PREPARE_ISH_METHODS
The following methods all take a statement name as the first parameter, and a SQL statement as the second - and possibly further parameters after that. We can trace them all alike.
- SQL_COMMANDS
A list of SQL commands, from: www.postgresql.org/docs/current/sql-commands.html Commands are truncated to their first word, and all duplicates are removed, This favors brevity and low-cardinality over descriptiveness.
- UNMATCHED_PAIRS_REGEX
Public Instance Methods
# File lib/instrumentation/postgres.rb, line 221 def client_attributes attributes = { 'db.system' => 'postgresql', 'db.user' => conninfo_hash[:user]&.to_s, 'db.name' => database_name, 'net.peer.name' => conninfo_hash[:host]&.to_s } # attributes['peer.service'] = config[:peer_service] # if config[:peer_service] attributes.merge(transport_attrs).reject { |_, v| v.nil? } end
# File lib/instrumentation/postgres.rb, line 142 def config EpsagonPostgresInstrumentation.instance.config end
# File lib/instrumentation/postgres.rb, line 217 def database_name conninfo_hash[:dbname]&.to_s end
# File lib/instrumentation/postgres.rb, line 208 def extract_operation(sql) # From: https://github.com/open-telemetry/opentelemetry-js-contrib/blob/9244a08a8d014afe26b82b91cf86e407c2599d73/plugins/node/opentelemetry-instrumentation-pg/src/utils.ts#L35 sql.to_s.split[0].to_s.upcase end
# File lib/instrumentation/postgres.rb, line 213 def generated_postgres_regex @generated_postgres_regex ||= Regexp.union(PostgresExtension::POSTGRES_COMPONENTS.map { |component| PostgresExtension::COMPONENTS_REGEX_MAP[component] }) end
# File lib/instrumentation/postgres.rb, line 150 def lru_cache # When SQL is being sanitized, we know that this cache will # never be more than 50 entries * 2000 characters (so, presumably # 100k bytes - or 97k). When not sanitizing SQL, then this cache # could grow much larger - but the small cache size should otherwise # help contain memory growth. The intended use here is to cache # prepared SQL statements, so that we can attach a reasonable # `db.sql.statement` value to spans when those prepared statements # are executed later on. @lru_cache ||= LruCache.new(50) end
Rubocop is complaining about 19.31/18 for Metrics/AbcSize. But, getting that metric in line would force us over the module size limit! We can't win here unless we want to start abstracting things into a million pieces.
# File lib/instrumentation/postgres.rb, line 166 def span_attrs(kind, *args) # rubocop:disable Metrics/AbcSize if kind == :query operation = extract_operation(args[0]) sql = args[0] else statement_name = args[0] if kind == :prepare sql = args[1] lru_cache[statement_name] = sql operation = 'PREPARE' else sql = lru_cache[statement_name] operation = 'EXECUTE' end end attrs = { 'db.operation' => validated_operation(operation), 'db.postgresql.prepared_statement_name' => statement_name } attrs['db.statement'] = sql if config[:epsagon][:metadata_only] == false attrs['db.sql.table'] = table_name(sql) attrs.reject! { |_, v| v.nil? } [database_name, client_attributes.merge(attrs)] end
# File lib/instrumentation/postgres.rb, line 191 def table_name(sql) return '' if sql.nil? parsed_query = PgQuery.parse(sql) if parsed_query.tables.length == 0 '' else parsed_query.tables[0] end rescue PgQuery::ParseError '' end
# File lib/instrumentation/postgres.rb, line 146 def tracer EpsagonPostgresInstrumentation.instance.tracer end
# File lib/instrumentation/postgres.rb, line 233 def transport_attrs if conninfo_hash[:host]&.start_with?('/') { 'net.transport' => 'Unix' } else { 'net.transport' => 'IP.TCP', 'net.peer.ip' => conninfo_hash[:hostaddr]&.to_s, 'net.peer.port' => conninfo_hash[:port]&.to_s } end end
# File lib/instrumentation/postgres.rb, line 204 def validated_operation(operation) operation if PostgresExtension::SQL_COMMANDS.include?(operation) end