Class: LogStruct::Log::SQL

Inherits:
T::Struct
  • Object
show all
Extended by:
T::Sig
Includes:
Interfaces::AdditionalDataField, Interfaces::CommonFields, MergeAdditionalDataFields, SerializeCommon
Defined in:
lib/log_struct/log/sql.rb

Overview

SQL Query Log Structure

Captures detailed information about SQL queries executed through ActiveRecord. This provides structured logging for database operations, including:

  • Query text and operation name
  • Execution timing and performance metrics
  • Row counts and connection information
  • Safely filtered bind parameters

Use Cases:

  • Development debugging of N+1 queries
  • Production performance monitoring
  • Database query analysis and optimization
  • Audit trails for data access patterns

Security:

  • SQL queries are safe (always parameterized with ?)
  • Bind parameters are filtered through LogStruct's param filters
  • Sensitive data like passwords, tokens are automatically scrubbed

Example Usage:

# Automatically captured when SQL query integration is enabled
LogStruct.config.integrations.enable_sql_logging = true

# Manual logging (rare)
sql_log = LogStruct::Log::SQL.new(
  message: "User lookup query",
  sql: "SELECT * FROM users WHERE id = ?",
  name: "User Load",
  duration: 2.3,
  row_count: 1,
  bind_params: [123]
)
LogStruct.info(sql_log)

Constant Summary collapse

SQLEvent =
T.type_alias {
  Event::Database
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from MergeAdditionalDataFields

#merge_additional_data_fields

Methods included from SerializeCommon

#as_json, #serialize_common

Constructor Details

#initialize(source: T.let(Source::App, Source), event: T.let(Event::Database, SQLEvent), level: T.let(Level::Info, Level), timestamp:, message:, sql:, name:, duration:, row_count: nil, connection_adapter: nil, bind_params: nil, database_name: nil, connection_pool_size: nil, active_connections: nil, operation_type: nil, table_names: nil, additional_data: {}) ⇒ void

Parameters:

  • source (Source) (defaults to: T.let(Source::App, Source))

    Common fields

  • event (SQLEvent) (defaults to: T.let(Event::Database, SQLEvent))
  • level (Level) (defaults to: T.let(Level::Info, Level))
  • timestamp (Time)
  • message (String)
  • sql (String)

    The SQL query that was executed (parameterized, safe to log)

  • name (String)

    The name of the database operation (e.g., "User Load", "Post Create")

  • duration (Float)

    Duration of the query execution in milliseconds

  • row_count (Integer, nil) (defaults to: nil)

    Number of rows affected or returned by the query

  • connection_adapter (String, nil) (defaults to: nil)

    Database connection information (adapter name)

  • bind_params (Array<T.untyped>, nil) (defaults to: nil)

    Filtered bind parameters (sensitive data removed)

  • database_name (String, nil) (defaults to: nil)

    Database name (if available)

  • connection_pool_size (Integer, nil) (defaults to: nil)

    Connection pool size information (for monitoring)

  • active_connections (Integer, nil) (defaults to: nil)

    Active connection count (for monitoring)

  • operation_type (String, nil) (defaults to: nil)

    SQL operation type (SELECT, INSERT, UPDATE, DELETE, etc.)

  • table_names (Array<String>, nil) (defaults to: nil)

    Table names involved in the query (extracted from SQL)

  • additional_data (Hash{Symbol => T.untyped}) (defaults to: {})

    Allow additional custom data



# File ''

const :source, Source, default: T.let(Source::App, Source)
const :event, SQLEvent, default: T.let(Event::Database, SQLEvent)
const :level, Level, default: T.let(Level::Info, Level)
const :timestamp, Time, factory: -> { Time.now }
const :message, String
const :sql, String
const :name, String
const :duration, Float
const :row_count, T.nilable(Integer)
const :connection_adapter, T.nilable(String)
const :bind_params, T.nilable(T::Array[T.untyped])
const :database_name, T.nilable(String)
const :connection_pool_size, T.nilable(Integer)
const :active_connections, T.nilable(Integer)
const :operation_type, T.nilable(String)
const :table_names, T.nilable(T::Array[String])
const :additional_data, T::Hash[Symbol, T.untyped], default: {}

Instance Attribute Details

#active_connectionsInteger? (readonly)

Active connection count (for monitoring)

Returns:

  • (Integer, nil)


# File ''

const :active_connections, T.nilable(Integer)

#additional_dataHash{Symbol => T.untyped} (readonly)

Allow additional custom data

Returns:

  • (Hash{Symbol => T.untyped})


# File ''

const :additional_data, T::Hash[Symbol, T.untyped], default: {}

#bind_paramsArray<T.untyped>? (readonly)

Filtered bind parameters (sensitive data removed)

Returns:

  • (Array<T.untyped>, nil)


# File ''

const :bind_params, T.nilable(T::Array[T.untyped])

#connection_adapterString? (readonly)

Database connection information (adapter name)

Returns:

  • (String, nil)


# File ''

const :connection_adapter, T.nilable(String)

#connection_pool_sizeInteger? (readonly)

Connection pool size information (for monitoring)

Returns:

  • (Integer, nil)


# File ''

const :connection_pool_size, T.nilable(Integer)

#database_nameString? (readonly)

Database name (if available)

Returns:

  • (String, nil)


# File ''

const :database_name, T.nilable(String)

#durationFloat (readonly)

Duration of the query execution in milliseconds

Returns:

  • (Float)


# File ''

const :duration, Float

#eventSQLEvent (readonly)

Returns the value of prop event.

Returns:



# File ''

const :event, SQLEvent, default: T.let(Event::Database, SQLEvent)

#levelLevel (readonly)

Returns the value of prop level.

Returns:



# File ''

const :level, Level, default: T.let(Level::Info, Level)

#messageString (readonly)

Returns the value of prop message.

Returns:

  • (String)


# File ''

const :message, String

#nameString (readonly)

The name of the database operation (e.g., "User Load", "Post Create")

Returns:

  • (String)


# File ''

const :name, String

#operation_typeString? (readonly)

SQL operation type (SELECT, INSERT, UPDATE, DELETE, etc.)

Returns:

  • (String, nil)


# File ''

const :operation_type, T.nilable(String)

#row_countInteger? (readonly)

Number of rows affected or returned by the query

Returns:

  • (Integer, nil)


# File ''

const :row_count, T.nilable(Integer)

#sourceSource (readonly)

Common fields

Returns:



# File ''

const :source, Source, default: T.let(Source::App, Source)

#sqlString (readonly)

The SQL query that was executed (parameterized, safe to log)

Returns:

  • (String)


# File ''

const :sql, String

#table_namesArray<String>? (readonly)

Table names involved in the query (extracted from SQL)

Returns:

  • (Array<String>, nil)


# File ''

const :table_names, T.nilable(T::Array[String])

#timestampTime (readonly)

Returns the value of prop timestamp.

Returns:

  • (Time)


# File ''

const :timestamp, Time, factory: -> { Time.now }

Instance Method Details

#serialize(strict = true) ⇒ Hash{Symbol => T.untyped}

Convert the log entry to a hash for serialization

Parameters:

  • strict (Boolean) (defaults to: true)

Returns:

  • (Hash{Symbol => T.untyped})


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/log_struct/log/sql.rb', line 104

def serialize(strict = true)
  hash = serialize_common(strict)
  merge_additional_data_fields(hash)

  # Add SQL-specific fields using LOG_KEYS mapping for consistency
  hash[LOG_KEYS.fetch(:message)] = message
  hash[LOG_KEYS.fetch(:sql)] = sql
  hash[LOG_KEYS.fetch(:name)] = name
  hash[LOG_KEYS.fetch(:duration)] = duration
  hash[LOG_KEYS.fetch(:row_count)] = row_count
  hash[LOG_KEYS.fetch(:connection_adapter)] = connection_adapter
  hash[LOG_KEYS.fetch(:bind_params)] = bind_params
  hash[LOG_KEYS.fetch(:database_name)] = database_name
  hash[LOG_KEYS.fetch(:connection_pool_size)] = connection_pool_size
  hash[LOG_KEYS.fetch(:active_connections)] = active_connections
  hash[LOG_KEYS.fetch(:operation_type)] = operation_type
  hash[LOG_KEYS.fetch(:table_names)] = table_names

  hash
end