File: logger_wrapper.rb

package info (click to toggle)
ruby-lumberjack 2.0.4-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 956 kB
  • sloc: ruby: 7,957; makefile: 2
file content (137 lines) | stat: -rw-r--r-- 5,453 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# frozen_string_literal: true

module Lumberjack
  # A logging device that forwards log entries to another logger instance.
  # This device enables hierarchical logging architectures and broadcasting scenarios
  # where log entries need to be distributed to multiple loggers or processed through
  # different logging pipelines.
  #
  # The device is particularly useful when combined with Device::Multi to create
  # master loggers that can simultaneously write to multiple destinations (files,
  # databases, external services) while maintaining consistent formatting and
  # attribute handling across all targets.
  #
  # Unlike other devices that write directly to output streams, this device delegates
  # to another logger's processing pipeline, allowing for complex logging topologies
  # and reuse of existing logger configurations.
  #
  # @example Basic logger forwarding
  #   file_logger = Lumberjack::Logger.new("/var/log/app.log")
  #   logger_device = Lumberjack::Device::LoggerWrapper.new(file_logger)
  #
  # @example Broadcasting with Multi device
  #   main_logger = Lumberjack::Logger.new("/var/log/main.log")
  #   error_logger = Lumberjack::Logger.new("/var/log/errors.log")
  #
  #   broadcast_device = Lumberjack::Device::Multi.new([
  #     Lumberjack::Device::LoggerWrapper.new(main_logger),
  #     Lumberjack::Device::LoggerWrapper.new(error_logger)
  #   ])
  #
  #   master_logger = Lumberjack::Logger.new(broadcast_device)
  #
  # @example Hierarchical logging with filtering
  #   # Main application logger
  #   app_logger = Lumberjack::Logger.new("/var/log/app.log")
  #
  #   # Focused error logs
  #   error_logger = Lumberjack::Logger.new("/var/log/error.log")
  #   error_logger.level = Logger::WARN
  #
  #   # Route all logs to app, error logs to error logger
  #   multi_device = Lumberjack::Device::Multi.new([
  #     Lumberjack::Device::LoggerWrapper.new(app_logger),
  #     Lumberjack::Device::LoggerWrapper.new(error_logger)
  #   ])
  #
  # @see Device::Multi
  # @see Lumberjack::Logger
  # @see Lumberjack::ContextLogger
  class Device::LoggerWrapper < Device
    # @!attribute [r] logger
    #   @return [Lumberjack::ContextLogger] The target logger that will receive forwarded log entries
    attr_reader :logger

    # Initialize a new Logger device that forwards entries to the specified logger.
    # The target logger must be a Lumberjack logger that supports the ContextLogger
    # interface to ensure proper entry handling and attribute processing.
    #
    # @param logger [Lumberjack::ContextLogger, ::Logger] The target logger to receive forwarded entries.
    #   Must be a Lumberjack logger instance (Logger, ForkedLogger, etc.) that includes
    #   the ContextLogger mixin for proper entry processing.
    #
    # @raise [ArgumentError] If the provided logger is not a Lumberjack::ContextLogger
    def initialize(logger)
      unless logger.is_a?(Lumberjack::ContextLogger) || logger.is_a?(::Logger)
        raise ArgumentError.new("Logger must be a Lumberjack logger")
      end

      @logger = logger
    end

    # Forward a log entry to the target logger for processing. This method extracts
    # the entry components and delegates to the target logger's add_entry method,
    # ensuring that all attributes, formatting, and processing logic of the target
    # logger are properly applied.
    #
    # The forwarded entry maintains all original metadata including severity,
    # timestamp, program name, and custom attributes, allowing the target logger
    # to process it as if it were generated directly.
    #
    # @param entry [Lumberjack::LogEntry] The log entry to forward to the target logger
    # @return [void]
    def write(entry)
      if @logger.is_a?(Lumberjack::ContextLogger)
        @logger.add_entry(entry.severity, entry.message, entry.progname, entry.attributes)
      else
        message = entry.message
        if entry.attributes && !entry.attributes.empty?
          message_attributes = []
          entry.attributes.each do |key, value|
            next if value.nil? || (value.respond_to?(:empty?) && value.empty?)

            value = value.join(",") if value.is_a?(Enumerable)
            message_attributes << "[#{key}=#{value}]"
          end
          message = "#{message} #{message_attributes.join(" ")}" unless message_attributes.empty?
        end
        @logger.add(entry.severity, message, entry.progname)
      end
    end

    # Closes the target logger to release any resources or finalize log output.
    # This method delegates to the target logger's +close+ method.
    #
    # @return [void]
    def close
      @logger.close
    end

    # Reopen the underlying logger device. This is typically used to reopen log files
    # after log rotation or to refresh the logger's output stream.
    #
    # Delegates to the target logger's +reopen+ method.
    #
    # @return [void]
    def reopen
      @logger.reopen
    end

    # Flushes the target logger, ensuring that any buffered log entries are written out.
    # This delegates to the target logger's flush method, which may flush buffers to disk,
    # external services, or other destinations depending on the logger's configuration.
    #
    # @return [void]
    def flush
      @logger.flush
    end

    # Expose the underlying stream if any.
    #
    # @return [IO, Lumberjack::Device, nil]
    # @api private
    def dev
      @logger.device&.dev
    end
  end
end