This allows to define default values for certain fields which can be
inserted just before a Buffer is flushed. They won;t overwrite prior
user-provided fields.
Through the use of a block, expensive calculations for a field could be
avoided if the field is not going to be inserted, e.g. because it exists
already or is forbidden from being set.
That way, we can ensure that the BufferStack and the Buffers themselves
including their nested fields can not be accessed by different threads,
providing some thread safety for non malicious users.
Using a block here is unnecessary and doesn't help us with any
thread-safty guarantees on deeply nested fields or tags. Thus, we can
just remove this and replace it with a simpler method returning the
top-most buffer.
When using this buffer, we still have to ensure that only a single
Thread can access it.
Generally, we try hard to avoid additional dependencies to external gems
to keep us from having to maintain all these dependencies in the variety
of environments where Rackstash is going to be used.
We still decided to depend on two concurrent-ruby gems since they are
1. are of exceptional code quality
2. are well-maintained and with devs eager to maintain a stable and
well-understood interface
3. provide very useful buolding-blocks for safe interoperations across
thread-boundaries.
The chosen versions are selected to be compatible with a wide range of
external frameworks.
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 fields follow the basic structure of basic Hashes and Arrays but
provide an interface better suitable for us. Specifically:
* They check and enforce the datatypes for keys and values to be
strictly JSON-conforming. Only the basic data-types are accepted
respectively converted to.
* Hashes only accept String keys.
* Basic values are always frozen.