Class: Hanami::UniversalLogger

Inherits:
Object
  • Object
show all
Defined in:
lib/hanami/universal_logger.rb

Overview

An adapter that optionally wraps the logger configured for a Hanami app. Ensures that both structured and tagged logging can be used across the Hanami framework.

Provides ‘.call` as its main entrypoint, expecting a logger object. If a compatible logger is given (such as the Dry Logger instance provided by default in Hanami apps), then that logger is returned directly and not wrapped.

If a non-compatible logger is given, then it will be wrapped by an instance of UniversalLogger, which adapts a structured and tagged logging API to the given logger.

This leads to two levels of logger enhancement:

  1. Structured-capable loggers (accepts keyword arguments, but no ‘#tagged` method): tags are are provided as a `:tags` keyword argument when logging.

  2. Legacy loggers (such as the Ruby standard ‘Logger`, no keyword arguments, no `#tagged` method): messages are logged as JSON, with tags under a `“tags”` key.

This adapter is used for all loggers configured in Hanami apps.

Since:

  • x.x.x

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(logger) ⇒ UniversalLogger

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of UniversalLogger.

Since:

  • x.x.x



66
67
68
69
70
# File 'lib/hanami/universal_logger.rb', line 66

def initialize(logger)
  @logger = logger
  @structured_logger = self.class.structured_logger?(logger)
  @tags_thread_key = :"hanami_universal_logger_tags_#{object_id}"
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method) ⇒ Object (private)

Delegates any other methods to the wrapped logger.

Since:

  • x.x.x



178
179
180
181
182
183
184
# File 'lib/hanami/universal_logger.rb', line 178

def method_missing(method, ...)
  if logger.respond_to?(method)
    logger.public_send(method, ...)
  else
    super
  end
end

Instance Attribute Details

#loggerObject (readonly)

Since:

  • x.x.x



63
64
65
# File 'lib/hanami/universal_logger.rb', line 63

def logger
  @logger
end

Class Method Details

.call(logger) ⇒ Object, UniversalLogger Also known as: []

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Wrap a logger if needed, or return it as-is if fully compatible.

Parameters:

  • logger (Object)

    the logger to wrap

Returns:

Since:

  • x.x.x



35
36
37
38
39
# File 'lib/hanami/universal_logger.rb', line 35

def call(logger)
  return logger if compatible_logger?(logger)

  new(logger)
end

.compatible_logger?(logger) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)

Since:

  • x.x.x



45
46
47
# File 'lib/hanami/universal_logger.rb', line 45

def compatible_logger?(logger)
  structured_logger?(logger) && tagged_logger?(logger)
end

.structured_logger?(logger) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)

Since:

  • x.x.x



55
56
57
58
# File 'lib/hanami/universal_logger.rb', line 55

def structured_logger?(logger)
  logger.respond_to?(:info) &&
    logger.method(:info).parameters.any? { |(type, _)| type == :keyrest }
end

.tagged_logger?(logger) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)

Since:

  • x.x.x



50
51
52
# File 'lib/hanami/universal_logger.rb', line 50

def tagged_logger?(logger)
  logger.respond_to?(:tagged)
end

Instance Method Details

#add(severity, message = nil, progname = nil, &blk) ⇒ Object Also known as: log

Since:

  • x.x.x



149
150
151
152
153
154
155
156
157
# File 'lib/hanami/universal_logger.rb', line 149

def add(severity, message = nil, progname = nil, &blk)
  # Convert severity to a level symbol if it's an integer (the standard Logger uses integers).
  level = _severity_to_level(severity)

  payload = {}
  payload[:progname] = progname if progname

  _log(level, message, payload, &blk)
end

#debug(message = nil, **payload, &blk) ⇒ void

This method returns an undefined value.

Logs a debug message.

Parameters:

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

    the log message

  • payload (Hash)

    structured data to include in the log entry

Yield Returns:

  • (Hash)

    additional payload data to merge

Since:

  • x.x.x



# File 'lib/hanami/universal_logger.rb', line 76

#error(message = nil, **payload, &blk) ⇒ void

This method returns an undefined value.

Logs an error message.

Parameters:

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

    the log message

  • payload (Hash)

    structured data to include in the log entry

Yield Returns:

  • (Hash)

    additional payload data to merge

Since:

  • x.x.x



# File 'lib/hanami/universal_logger.rb', line 108

#fatal(message = nil, **payload, &blk) ⇒ void

This method returns an undefined value.

Logs a fatal message.

Parameters:

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

    the log message

  • payload (Hash)

    structured data to include in the log entry

Yield Returns:

  • (Hash)

    additional payload data to merge

Since:

  • x.x.x



# File 'lib/hanami/universal_logger.rb', line 119

#info(message = nil, **payload, &blk) ⇒ void

This method returns an undefined value.

Logs an info message.

Parameters:

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

    the log message

  • payload (Hash)

    structured data to include in the log entry

Yield Returns:

  • (Hash)

    additional payload data to merge

Since:

  • x.x.x



# File 'lib/hanami/universal_logger.rb', line 87

#tagged(*tags) ⇒ Object

Since:

  • x.x.x



165
166
167
168
169
170
171
172
173
# File 'lib/hanami/universal_logger.rb', line 165

def tagged(*tags)
  previous_tags = _current_tags
  self._current_tags = tags
  begin
    yield
  ensure
    self._current_tags = previous_tags
  end
end

#unknown(message = nil, **payload, &blk) ⇒ void

This method returns an undefined value.

Logs a message with unknown severity.

Parameters:

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

    the log message

  • payload (Hash)

    structured data to include in the log entry

Yield Returns:

  • (Hash)

    additional payload data to merge

Since:

  • x.x.x



141
142
143
144
145
# File 'lib/hanami/universal_logger.rb', line 141

LOG_LEVEL_METHODS.each do |level|
  define_method(level) do |message = nil, **payload, &blk|
    _log(level, message, payload, &blk)
  end
end

#warn(message = nil, **payload, &blk) ⇒ void

This method returns an undefined value.

Logs a warning message.

Parameters:

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

    the log message

  • payload (Hash)

    structured data to include in the log entry

Yield Returns:

  • (Hash)

    additional payload data to merge

Since:

  • x.x.x



# File 'lib/hanami/universal_logger.rb', line 97