Instead, let the encoders (and if necessary the adapters) add newlines
if necessary.
This makes it more straight-forward to filter messages and eventually
allows the encoders to format messages with fewer checks. Finally, we
might avoid the creation a lot of intermediary strings.
A absolute Windows path such as `C:/path.to/file.log` is a valid URL
with schema `C`. If a user specifies such a path, they likely want to
create a File adapter in this case. As such, we fallback from
`Adapter.adapter_by_uri_scheme` and create File adapter instance via
`Adapter.adapter_by_type`.
Newer Windows versions (i.e. >= 10.0.14393) apparently follow POSIX more
strictly. With current Windows and Linux versions, we can thus get away
with just writing to the file and depending on the OS to properly
serialize those writes.
On older versions or with some network filesystems, the user might still
have to enable file locking if they are writing to the same log file
from multiple processes.
Since Ruby 2.7 differences explicit keyword arguments from implicit hash
arguments, we should also avoid mixing them. By using explicit keyword
arguments, we avoid warning in Ruby 2.7 and errors in Ruby 3.0.
This reduces the change of a Hash argument being interpreted as keyword
argument inadvertently and clarifies the interface. If a resolver scope
is required, you can also call
delayed_tag = ->{ |request| request.host }
logger.tags.merge!(delayed_tag, scope: request)
This is required on Windows (where we enable this feature by default)
since they don't support concurrent atomic writes above the drive's
sector size (usually between 512 Bytes and 4 KiBytes). Without an
explicit lock, concurrent writes can be interleaved or be partially
lost.
Each flow now has an associated executor which performs all actions
(writing events, closing, reopening) asynchronously by default using a
Concurrent::SingleThreadExecutor.
This improves the responsiveness of the application by performing the
(usually) IO-bound task of writing the logs to a background thread.
By creating a flow with `synchronous: true`, all actions are run in the
calling thread as before, making the flow blocking.
With this, we also drop the ability to define conditions in the filter
itself. When adding a filter, users can still setup a condition using
the common functionality of all filters.
This takes care of edge-cases and ensures that multiple loads of
`lib/rackstash.rb` do not fail on an attempted second initialization of
the UndefinedClass.
We now support two different modes of file rotation at the same time:
* auto_reopen can be used to automatically reopen a logfile at the
original location if the file was moved or deleted from the filesystem
* rotate can be used to write to a rotate file which can be reopened /
created based on Date pattern.
The user can now decide whether they want to use an external logrotate
command or use internal rotation with Rackstash instead.