Class: Lumberjack::Device::Writer

Inherits:
Device
  • Object
show all
Defined in:
lib/lumberjack/device/writer.rb

Overview

A versatile logging device that writes formatted log entries to IO streams. This device serves as the foundation for most output-based logging, converting LogEntry objects into formatted strings using configurable templates and writing them to any IO-compatible stream.

The Writer device supports extensive customization through templates, encoding options, stream management, and error handling. It can write to files, console output, network streams, or any object that implements the IO interface.

Templates can be either string-based (compiled into Template objects) or callable objects (Procs, lambdas) for maximum flexibility. The device handles character encoding, whitespace normalization, and provides robust error recovery when stream operations fail.

See Also:

Constant Summary collapse

EDGE_WHITESPACE_PATTERN =
/\A\s|[ \t\f\v][\r\n]*\z/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(stream, options = {}) ⇒ Writer

Initialize a new Writer device with configurable formatting and stream options. The device supports multiple template types, encoding control, and stream behavior configuration for flexible output handling.

Parameters:

  • stream (IO, #write)

    The target stream for log output. Can be any object that responds to write(), including File objects, STDOUT/STDERR, StringIO, network streams, or custom IO-like objects

  • options (Hash) (defaults to: {})

    Configuration options for the writer device

Options Hash (options):

  • :template (String, Proc, nil)

    The formatting template for log entries.

    • String: Compiled into a Template object (default: "[:time :severity :progname(:pid)] :message")
    • Proc: Called with LogEntry, should return formatted string
    • nil: Uses default template
  • :standard_logger_formatter (Logger::Formatter)

    Use a Ruby Logger formatter for compatibility with existing logging code

  • :additional_lines (String, nil)

    Template for formatting additional lines in multi-line messages (default: "\n :message")

  • :time_format (String, Symbol)

    Format for timestamps in templates. Accepts strftime patterns or :milliseconds/:microseconds shortcuts

  • :attribute_format (String)

    Printf-style format for attributes with exactly two %s placeholders for name and value (default: "[%s:%s]")

  • :autoflush (Boolean) — default: true

    Whether to automatically flush the stream after each write for immediate output

  • :binmode (Boolean) — default: false

    Whether to treat the stream as binary, skipping UTF-8 encoding conversion

  • :colorize (Boolean) — default: false

    Whether to colorize log output



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
# File 'lib/lumberjack/device/writer.rb', line 55

def initialize(stream, options = {})
  @stream = stream
  @autoflush = options[:autoflush] != false
  # Only turn sync on; the stream may be shared with other code (i.e. $stdout), so
  # disabling autoflush must not change how anything else writing to it behaves.
  @stream.sync = true if @autoflush && @stream.respond_to?(:sync=)
  @lock = Mutex.new

  @binmode = options[:binmode]

  if options[:standard_logger_formatter]
    @template = Template::StandardFormatterTemplate.new(options[:standard_logger_formatter])
  else
    template = options[:template]

    template = TemplateRegistry.template(template, options) if template.is_a?(Symbol)

    @template = if template.respond_to?(:call)
      template
    else
      Template.new(
        template,
        additional_lines: options[:additional_lines],
        time_format: options[:time_format],
        attribute_format: options[:attribute_format],
        colorize: options[:colorize]
      )
    end
  end
end

Instance Attribute Details

#streamIO

The underlying stream object that is being written to.

Returns:

  • (IO)

    The current stream object



175
176
177
# File 'lib/lumberjack/device/writer.rb', line 175

def stream
  @stream
end

Instance Method Details

#closevoid

This method returns an undefined value.

Close the underlying stream and release any associated resources. This method ensures all buffered data is flushed before closing the stream, providing clean shutdown behavior for file handles and network connections.



113
114
115
116
117
118
# File 'lib/lumberjack/device/writer.rb', line 113

def close
  # Call the public flush so that subclasses that override it still get a chance to
  # drain whatever they buffer. It must be called outside the lock since it takes it.
  flush
  @lock.synchronize { stream.close }
end

#datetime_formatString?

Get the current datetime format from the template if supported. Returns the format string used for timestamp formatting in log entries.

Returns:

  • (String, nil)

    The datetime format string if the template supports it, or nil if the template doesn't provide datetime formatting



136
137
138
# File 'lib/lumberjack/device/writer.rb', line 136

def datetime_format
  @template.datetime_format if @template.respond_to?(:datetime_format)
end

#datetime_format=(format) ⇒ void

This method returns an undefined value.

Set the datetime format on the template if supported. This allows dynamic reconfiguration of timestamp formatting without recreating the device.

Parameters:

  • format (String)

    The datetime format string (strftime pattern) to apply to the template for timestamp formatting



146
147
148
149
150
# File 'lib/lumberjack/device/writer.rb', line 146

def datetime_format=(format)
  if @template.respond_to?(:datetime_format=)
    @template.datetime_format = format
  end
end

#devIO

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.

Access the underlying IO stream for direct manipulation or compatibility with code expecting Logger device interface. This method provides the raw stream object for advanced use cases.

Returns:

  • (IO)

    The underlying stream object used for output



158
159
160
# File 'lib/lumberjack/device/writer.rb', line 158

def dev
  stream
end

#flushvoid

This method returns an undefined value.

Flush the underlying stream to ensure all buffered data is written to the destination. This method is safe to call on streams that don't support flushing, making it suitable for various IO types.



125
126
127
128
129
# File 'lib/lumberjack/device/writer.rb', line 125

def flush
  @lock.synchronize do
    stream.flush if stream.respond_to?(:flush)
  end
end

#pathString?

Get the file system path of the underlying stream if available. This method is useful for monitoring, log rotation, or any operations that need to work with the actual file path.

Returns:

  • (String, nil)

    The file system path if the stream is file-based, or nil for non-file streams (STDOUT, StringIO, network streams, etc.)



168
169
170
# File 'lib/lumberjack/device/writer.rb', line 168

def path
  stream.path if stream.respond_to?(:path)
end

#write(entry) ⇒ void

This method returns an undefined value.

Write a log entry to the stream with automatic formatting and error handling. The entry is converted to a string using the configured template, processed for encoding and whitespace, and written to the stream with robust error recovery.

Parameters:

  • entry (LogEntry, String)

    The log entry to write. LogEntry objects are formatted using the template, while strings are written directly after encoding and whitespace processing



94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/lumberjack/device/writer.rb', line 94

def write(entry)
  string = (entry.is_a?(LogEntry) ? @template.call(entry) : entry)
  return if string.nil?

  if !@binmode && string.encoding != Encoding::UTF_8
    string = string.encode("UTF-8", invalid: :replace, undef: :replace)
  end

  string = string.strip if string.match?(EDGE_WHITESPACE_PATTERN)
  return if string.length == 0 || string == Lumberjack::LINE_SEPARATOR

  write_to_stream(string)
end