Module: SecApi::StructuredLogger

Extended by:
StructuredLogger
Included in:
StructuredLogger
Defined in:
lib/sec_api/structured_logger.rb

Overview

Provides structured JSON logging for SEC API operations.

This module can be used directly or via the default_logging config option. All log events follow the secapi.* naming convention for easy filtering in log aggregation tools like ELK, Datadog, Splunk, or CloudWatch.

Examples:

Manual usage with Rails logger

SecApi::StructuredLogger.log_request(Rails.logger, :info,
  request_id: "abc-123",
  method: :get,
  url: "https://api.sec-api.io/query"
)

Using with default_logging

config = SecApi::Config.new(
  api_key: "...",
  logger: Rails.logger,
  default_logging: true
)
# All requests/responses now logged automatically

ELK Stack integration

# Configure Logstash to parse JSON logs:
# filter {
#   json { source => "message" }
# }
# Query in Kibana: event:"secapi.request.complete" AND status:>=400

Datadog Logs integration

# Logs are automatically parsed as JSON by Datadog
# Create facets on: event, request_id, status, duration_ms
# Alert query: event:secapi.request.error count:>10

Splunk integration

# Search: sourcetype=ruby_json event="secapi.request.*"
# | stats avg(duration_ms) by method

CloudWatch Logs integration

# Filter pattern: { $.event = "secapi.request.error" }
# Metric filter: Count errors by request_id

Instance Method Summary collapse

Instance Method Details

#log_error(logger, level, request_id:, error:, url:, method:) ⇒ void

This method returns an undefined value.

Logs a request error event (final failure after all retries).

Examples:

Error logging

SecApi::StructuredLogger.log_error(logger, :error,
  request_id: "550e8400-e29b-41d4-a716-446655440000",
  error: SecApi::AuthenticationError.new("Invalid API key"),
  url: "https://api.sec-api.io/query",
  method: :get
)
# Output: {"event":"secapi.request.error","request_id":"550e8400-...","error_class":"SecApi::AuthenticationError",...}

Parameters:

  • logger (Logger)

    Logger instance

  • level (Symbol)

    Log level (typically :error)

  • request_id (String)

    Request correlation ID

  • error (Exception)

    The exception that caused failure

  • url (String)

    Request URL

  • method (Symbol)

    HTTP method



164
165
166
167
168
169
170
171
172
173
174
# File 'lib/sec_api/structured_logger.rb', line 164

def log_error(logger, level, request_id:, error:, url:, method:)
  log_event(logger, level, {
    event: "secapi.request.error",
    request_id: request_id,
    error_class: error.class.name,
    error_message: error.message,
    method: method.to_s.upcase,
    url: url,
    timestamp: timestamp
  })
end

#log_request(logger, level, request_id:, method:, url:) ⇒ void

This method returns an undefined value.

Logs a request start event.

Examples:

Basic request logging

SecApi::StructuredLogger.log_request(logger, :info,
  request_id: "550e8400-e29b-41d4-a716-446655440000",
  method: :get,
  url: "https://api.sec-api.io/query"
)
# Output: {"event":"secapi.request.start","request_id":"550e8400-...","method":"GET","url":"https://...","timestamp":"2024-01-15T10:30:00.123Z"}

Parameters:

  • logger (Logger)

    Logger instance (Ruby Logger or compatible interface)

  • level (Symbol)

    Log level (:debug, :info, :warn, :error)

  • request_id (String)

    Request correlation ID (UUID)

  • method (Symbol)

    HTTP method (:get, :post, etc.)

  • url (String)

    Request URL



65
66
67
68
69
70
71
72
73
# File 'lib/sec_api/structured_logger.rb', line 65

def log_request(logger, level, request_id:, method:, url:)
  log_event(logger, level, {
    event: "secapi.request.start",
    request_id: request_id,
    method: method.to_s.upcase,
    url: url,
    timestamp: timestamp
  })
end

#log_response(logger, level, request_id:, status:, duration_ms:, url:, method:) ⇒ void

This method returns an undefined value.

Logs a request completion event.

Examples:

Response logging with duration

SecApi::StructuredLogger.log_response(logger, :info,
  request_id: "550e8400-e29b-41d4-a716-446655440000",
  status: 200,
  duration_ms: 150,
  url: "https://api.sec-api.io/query",
  method: :get
)
# Output: {"event":"secapi.request.complete","request_id":"550e8400-...","status":200,"duration_ms":150,"success":true,...}

Parameters:

  • logger (Logger)

    Logger instance

  • level (Symbol)

    Log level (:debug, :info, :warn, :error)

  • request_id (String)

    Request correlation ID (matches on_request)

  • status (Integer)

    HTTP status code (200, 429, 500, etc.)

  • duration_ms (Integer, Float)

    Request duration in milliseconds

  • url (String)

    Request URL

  • method (Symbol)

    HTTP method



96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/sec_api/structured_logger.rb', line 96

def log_response(logger, level, request_id:, status:, duration_ms:, url:, method:)
  log_event(logger, level, {
    event: "secapi.request.complete",
    request_id: request_id,
    status: status,
    duration_ms: duration_ms,
    method: method.to_s.upcase,
    url: url,
    success: status < 400,
    timestamp: timestamp
  })
end

#log_retry(logger, level, request_id:, attempt:, max_attempts:, error_class:, error_message:, will_retry_in:) ⇒ void

This method returns an undefined value.

Logs a retry attempt event.

Examples:

Retry logging

SecApi::StructuredLogger.log_retry(logger, :warn,
  request_id: "550e8400-e29b-41d4-a716-446655440000",
  attempt: 2,
  max_attempts: 5,
  error_class: "SecApi::ServerError",
  error_message: "Internal Server Error",
  will_retry_in: 4.0
)
# Output: {"event":"secapi.request.retry","request_id":"550e8400-...","attempt":2,"max_attempts":5,...}

Parameters:

  • logger (Logger)

    Logger instance

  • level (Symbol)

    Log level (typically :warn)

  • request_id (String)

    Request correlation ID

  • attempt (Integer)

    Retry attempt number (1-indexed)

  • max_attempts (Integer)

    Maximum retry attempts configured

  • error_class (String)

    Exception class name that triggered retry

  • error_message (String)

    Exception message

  • will_retry_in (Float)

    Seconds until next retry attempt



132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/sec_api/structured_logger.rb', line 132

def log_retry(logger, level, request_id:, attempt:, max_attempts:, error_class:, error_message:, will_retry_in:)
  log_event(logger, level, {
    event: "secapi.request.retry",
    request_id: request_id,
    attempt: attempt,
    max_attempts: max_attempts,
    error_class: error_class,
    error_message: error_message,
    will_retry_in: will_retry_in,
    timestamp: timestamp
  })
end