Module: DatabaseLogger

Defined in:
lib/middleware/database_middleware.rb

Overview

Note:

While there were concerns about the performance impact of logging in the redis-rb gem, this middleware is designed to be optional and can be easily enabled or disabled as needed. The performance impact is minimal when logging is disabled, and the benefits during development and debugging often outweigh the slight performance cost when enabled.

DatabaseLogger is Valkey/RedisClient middleware.

This middleware addresses the need for detailed Database command logging, which was removed from the redis-rb gem due to performance concerns. However, in many development and debugging scenarios, the ability to log Database commands can be invaluable.

Examples:

Enable Database command logging

DatabaseLogger.logger = Logger.new(STDOUT)
RedisClient.register(DatabaseLogger)

Capture commands for testing

commands = DatabaseLogger.capture_commands do
  redis.set('key', 'value')
  redis.get('key')
end
puts commands.first[:command]  # => ["SET", "key", "value"]

See Also:

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.commandsArray (readonly)

Gets the captured commands for testing purposes.

Returns:

  • (Array)

    Array of command hashes with :command, :duration, :timestamp



41
42
43
# File 'lib/middleware/database_middleware.rb', line 41

def commands
  @commands
end

.loggerLogger?

Gets/sets the logger instance used by DatabaseLogger.

Returns:

  • (Logger, nil)

    The current logger instance or nil if not set.



37
38
39
# File 'lib/middleware/database_middleware.rb', line 37

def logger
  @logger
end

Class Method Details

.capture_commands { ... } ⇒ Array

Captures commands in a block and returns them. This is useful for testing to see what commands were executed.

Examples:

Test what Redis commands your code executes

commands = DatabaseLogger.capture_commands do
  my_library_method()
end
assert_equal "SET", commands.first[:command][0]
assert commands.first[:duration] > 0

Yields:

  • [] The block of code to execute while capturing commands.

Returns:

  • (Array)

    Array of captured commands with timing information. Each command is a hash with :command, :duration, :timestamp keys.



62
63
64
65
66
# File 'lib/middleware/database_middleware.rb', line 62

def capture_commands
  clear_commands
  yield
  @commands.dup
end

.clear_commandsArray

Clears the captured commands array.

Returns:

  • (Array)

    Empty array



45
46
47
# File 'lib/middleware/database_middleware.rb', line 45

def clear_commands
  @commands = []
end

Instance Method Details

#call(command, _config) ⇒ Object

Note:

Commands are always captured with minimal overhead for testing purposes. Logging only occurs when DatabaseLogger.logger is set.

Logs the Database command and its execution time.

This method is called for each Database command when the middleware is active. It always captures commands for testing and logs them if a logger is set.

Parameters:

  • command (Array)

    The Database command and its arguments.

  • _config (Hash)

    The configuration options for the Valkey/Redis connection.

Returns:

  • (Object)

    The result of the Database command execution.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/middleware/database_middleware.rb', line 81

def call(command, _config)
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :microsecond)
  result = yield
  duration = Process.clock_gettime(Process::CLOCK_MONOTONIC, :microsecond) - start

  # Always capture commands for testing purposes
  DatabaseLogger.instance_variable_get(:@commands) << {
    command: command.dup,
    duration: duration,
    timestamp: Time.now,
  }

  # Log if logger is set
  DatabaseLogger.logger&.debug("Redis: #{command.inspect} (#{duration}µs)")

  result
end