Module: Familia::Logging

Included in:
Familia
Defined in:
lib/familia/logging.rb

Overview

The Logging module provides logging capabilities for Familia.

Familia uses a custom FamiliaLogger that extends the standard Ruby Logger with a TRACE level for detailed debugging output.

== Log Levels (from most to least verbose):

  • TRACE: Extremely detailed debugging (controlled by FAMILIA_TRACE env var)
  • DEBUG: Detailed debugging information
  • INFO: General informational messages
  • WARN: Warning messages
  • ERROR: Error messages
  • FATAL: Fatal errors that cause termination

== Usage: # Use default logger Familia.info "Connection established" Familia.warn "Cache miss"

# Set custom logger Familia.logger = Logger.new('familia.log')

# Trace-level debugging (requires FAMILIA_TRACE=true) Familia.trace :LOAD, redis_client, "user:123", "from cache"

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(base) ⇒ Object

Thread-safe mutex initialization when module is extended



179
180
181
# File 'lib/familia/logging.rb', line 179

def self.extended(base)
  base.instance_variable_set(:@logger_mutex, Mutex.new)
end

Instance Method Details

#debug(message = nil, **context) ⇒ true?

Log a debug message with optional structured context.

Only outputs when FAMILIA_DEBUG environment variable is enabled. Supports both simple string messages and structured logging with keyword context for operational observability.

Examples:

Simple message

Familia.debug "Cache lookup for user:123"

Structured context

Familia.debug "Horreum saved", class: "User", identifier: "user_123", duration: 1234
# => "Horreum saved class=User identifier=user_123 duration=1234"

Parameters:

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

    The message to log

  • context (Hash)

    Structured context (key-value pairs)

Returns:

  • (true, nil)

    Returns true if logged, nil if debug disabled



269
270
271
272
# File 'lib/familia/logging.rb', line 269

def debug(message = nil, **context)
  return unless Familia.debug?
  logger.debug(format_log(message, context))
end

#error(message = nil, **context) ⇒ true

Log an error message with optional structured context.

Examples:

Simple message

Familia.error "Failed to deserialize value"

Structured context

Familia.error "Serialization failed", field: :email, error: e.message, class: "User"

Parameters:

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

    The message to log

  • context (Hash)

    Structured context (key-value pairs)

Returns:

  • (true)


302
303
304
# File 'lib/familia/logging.rb', line 302

def error(message = nil, **context)
  logger.error(format_log(message, context))
end

#info(message = nil, **context) ⇒ true

Log an informational message with optional structured context.

Examples:

Simple message

Familia.info "Connection pool initialized"

Structured context

Familia.info "Pipeline executed", commands: 5, duration: 2340

Parameters:

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

    The message to log

  • context (Hash)

    Structured context (key-value pairs)

Returns:

  • (true)


286
287
288
# File 'lib/familia/logging.rb', line 286

def info(message = nil, **context)
  logger.info(format_log(message, context))
end

#loggerFamiliaLogger

Get the logger instance, initializing with defaults if not yet set

Thread-safe lazy initialization using double-checked locking to ensure only a single logger instance is created even under concurrent logging calls.

Examples:

Set a custom logger

Familia.logger = Logger.new('familia.log')

Use the default logger

Familia.logger.info "Connection established"

Returns:



196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/familia/logging.rb', line 196

def logger
  # Fast path: return existing logger if already initialized
  return @logger if @logger

  # Slow path: thread-safe initialization
  @logger_mutex.synchronize do
    @logger ||= FamiliaLogger.new($stderr).tap do |log|
      log.progname = name
      log.formatter = LogFormatter.new
    end
  end

  @logger
end

#logger=(new_logger) ⇒ Logger

Set a custom logger instance.

Allows replacing the default FamiliaLogger with any Logger-compatible object. Useful for integrating with application logging frameworks.

Automatically synchronizes the logger to DatabaseLogger if it's loaded, ensuring consistent logging across Familia's middleware stack.

Examples:

Use Rails logger

Familia.logger = Rails.logger

Custom file logger

Familia.logger = Logger.new('familia.log').tap do |log|
  log.level = Logger::INFO
end

Parameters:

  • new_logger (Logger)

    The logger to use

Returns:

  • (Logger)

    The logger that was set



230
231
232
233
234
235
236
237
# File 'lib/familia/logging.rb', line 230

def logger=(new_logger)
  @logger_mutex.synchronize do
    @logger = new_logger
    # Auto-sync to DatabaseLogger if loaded (inside mutex for atomicity)
    DatabaseLogger.logger = new_logger if defined?(DatabaseLogger)
  end
  @logger
end

#trace(label, instance_id = nil, ident = nil, extra_context = nil) ⇒ nil

Note:

Controlled by FAMILIA_TRACE environment variable (set to '1', 'true', or 'yes')

Note:

The instance_id can be a Redis client, Redis::Future, or nil

Logs a structured trace message for debugging Familia operations.

This method only executes when both FAMILIA_TRACE and FAMILIA_DEBUG environment variables are enabled.

Examples:

Familia.trace :LOAD, redis_client, "user:123", "from cache"
# Output: T, 10-05 20:43:09.843 pid:123 [456/789]: [LOAD] #<Redis> -> user:123 <-from cache

Parameters:

  • label (Symbol)

    A label for the trace message (e.g., :EXPAND, :FROMREDIS, :LOAD, :EXISTS).

  • instance_id (Object) (defaults to: nil)

    The object instance being traced (e.g., Redis client)

  • ident (String) (defaults to: nil)

    An identifier or key related to the operation being traced

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

    Any extra details to include

Returns:

  • (nil)


326
327
328
329
330
331
# File 'lib/familia/logging.rb', line 326

def trace(label, instance_id = nil, ident = nil, extra_context = nil)
  return unless trace_enabled? && Familia.debug?

  ident_str = ident.nil? ? '<nil>' : ident.to_s
  logger.trace format('[%s] %s -> %s <-%s', label, instance_id, ident_str, extra_context)
end

#warn(msg) ⇒ true

Log a warning message.

Examples:

Familia.warn "Cache miss for key: user:123"

Parameters:

  • msg (String)

    The message to log

Returns:

  • (true)


248
249
250
# File 'lib/familia/logging.rb', line 248

def warn(msg)
  logger.warn(msg)
end