mirror of
https://github.com/meineerde/rackstash.git
synced 2026-01-10 15:51:31 +00:00
This adapter allows to write newline-separated log lines to an existing IO object, e.g. STDOUT. It does not allow to reopen the IO device.
78 lines
2.7 KiB
Ruby
78 lines
2.7 KiB
Ruby
# Copyright 2017 Holger Just
|
|
#
|
|
# This software may be modified and distributed under the terms
|
|
# of the MIT license. See the LICENSE.txt file for details.
|
|
|
|
require 'thread'
|
|
|
|
require 'rackstash/adapters/adapter'
|
|
|
|
module Rackstash
|
|
module Adapters
|
|
# This adapter allows to write logs to an existing `IO` object, e.g.,
|
|
# `STDOUT`, an open file, a `StringIO` object, ...
|
|
#
|
|
# When writing a [12factor](https://12factor.net/logs) app, you can use this
|
|
# adapter to write formatted logs to `STDOUT` of the process to be captured
|
|
# by the environment and eventually sent to a log collector.
|
|
#
|
|
# Concurrent writes to this adapter will be serialized to ensure there are
|
|
# no overlapping writes. You still have to ensure that there are no other
|
|
# writes to the IO object from outside this adapter to ensure there that
|
|
# is no overlapping data visible on the IO object.
|
|
#
|
|
# Note that with some deployment models involving pre-forked application
|
|
# servers, e.g., Unicorn or Puma servers with multiple worker processes, the
|
|
# combined `STDOUT` stream of multiple processes can cause interleaved data
|
|
# when writing large log lines (typically > 4 KB). If you are using such a
|
|
# deployment model and expect large log lines, you should consider using a
|
|
# different adapter to ensure consistent logs.
|
|
#
|
|
# Suitable adapters include:
|
|
#
|
|
# * {Rackstash::Adapters::File} - When writing to a file, we ensure with
|
|
# explicit file locks that all data is written consistently.
|
|
# * {Rackstash::Adapters::TCP} - With a single TCP connection per adapter
|
|
# instance, the receiver can handle the log lines separately.
|
|
class IO < Adapter
|
|
register_for ->(o) { o.respond_to?(:write) && o.respond_to?(:close) }
|
|
|
|
# @param io [#write, #close] an IO object. It must at least respond to
|
|
# `write` and `close`.
|
|
def initialize(io)
|
|
unless io.respond_to?(:write) && io.respond_to?(:close)
|
|
raise TypeError, "#{io.inspect} does not look like an IO object"
|
|
end
|
|
|
|
@io = io
|
|
@mutex = Mutex.new
|
|
end
|
|
|
|
# Write a single log line with a trailing newline character to the IO
|
|
# object.
|
|
#
|
|
# @param log [#to_s] the encoded log event
|
|
# @return [nil]
|
|
def write_single(log)
|
|
@mutex.synchronize do
|
|
@io.write normalize_line(log)
|
|
end
|
|
nil
|
|
end
|
|
|
|
# Close the IO object.
|
|
#
|
|
# After closing, no further writes are possible. Further attempts to
|
|
# {#write} will result in an exception being thrown.
|
|
#
|
|
# @return [nil]
|
|
def close
|
|
@mutex.synchronize do
|
|
@io.close
|
|
end
|
|
nil
|
|
end
|
|
end
|
|
end
|
|
end
|