With this, the Buffer knows three buffering modes:
* :full - This is the same as the previous buffering-enabled mode. With
this, we buffer everything and never auto-flush
* :none - the previous non-buffering mode. We autoflush everytime there
is a new messase or explicitly added fields. All stored data is
cleared afterwards.
* :data - the new mode. It behaves almost like :none with the notable
exception that we retain fields and tags after the auto flush.
The new mode is especially useful to emulate a regular Logger even when
using per-request buffers. With that, you can add fields once to a
buffer. Each time a message is added, it will be flushed directly
without waiting for the request to be finished. Yet, the flows can still
take advantage of all the previously added fields and tags to properly
format the emitted log event.
The Sink was a vehicle to transport some shared state between the logger
instance and the buffers, most notably the default fields and default
tags.
It turns out however, that error handling during merging of the
default_fields and default_tags is non trivial since there, the buffer
is in sime kind of limbo: users won't write to it anymore (and thus
don't expect exceptions there) while the error handling of the
individual flows is not yet reached. Since users can specify procs in
default_fields, they can still raise for whatever user-defined reason.
Luckily, the insertion of default fields and default tags can easily be
done by a filter later anyway, under the protection of the flow's error
handling in Flow#write. This allows us just remove the whole concept of
the sink and just pass the Flows object to the Buffer.
Not having to merge default_fields during event creation significantly
simplifies Buffer#to_event which was rather ugly to begin with but now
turned out quite beatifully.
With the change to allow ading fields to the Buffer with a Logger
interface in the previous commit, we should also flush those Buffers
with fields set that way by default.
With this interface, the user adds fields the same way they would add
messages. The implicit assumption here is that the buffer is handled the
same way. Thus, if the current buffer is non-buffering, we will
automatically flush it to the sink and clear it, just the same way as we
would have done it for a message.
This new name better reflects what this option actually does: it allows
to flush a Buffer even if there were just added fields or tags. A tryely
empty Buffer, i.e., one which has neither added messages, fields, or
tags is never flushed.
This field is only relevant when actually sending JSON to Logstash.
Other formats don't need it. It is thus more desireable to only include
this field in a specific logstash JSON encoder.
With this move, we can also optimize the sinplest case where there are
no fields or tags on the Buffer and no defines default_fields or
default_tags on the Sink. In that case, we don't need to merge them,
avoiding the creation of several unecessary objects on Buffer flush.
A single Sink is tied to a single Logger. It is responsible to:
* Create a log event from a Buffer on #write and send it to each of the
flows independently.
* Forward all actions to all of the defined Flows.
The Sink provides access to all configured data of the Logger which is
used for persisting the Buffers.
Generally, a non-buffering Buffer will eventually be flushed to the sink
after each logged message. This thus mostly resembles the way
traditional loggers work in Ruby. A buffering Buffer however holds log
messages, fields and tags for a longer time. Only at a specific time,
all log messages and stored fields will be flushed to the Sink as a
single log event. A common scope for such an event is a full request to
a Rack app.
Each buffer instance can hold messages, fields and tags. These together
form the log event which will eventually be written to the log target.
By adding fields and tags, you can add highly details structured
information to your logs which allow to filter and analyze the logs
without having to parse complex multi-line logs.
The Rackstash::Logger class will server as the public main entry point
for users. It will eventually implement the mostly complete interface of
Ruby's Logger.
The idea of Rackstash is the we will allow to buffer multiple log
messages allong with additional data until a combined log event is
eventually flushed to an underlying log target. This allows to keep
connected log messages and data as a single unit from the start without
having to painstakingly parse and connect these in later systems again.