This article illustrates how μ/log works internally. The objective of this article is to deepen the understanding of the technical choices and their consequences.
The design goals of μ/log are the following:
With the above goals in mind let's look at how it works!
Looking at the above picture let's see what happens step by step.
Logging starts with a call to the log
function. At this point
μ/log does the least amount of work possible. In fact, it only
appends the event and the context captured at that point to a
ring-buffer
. μ/log uses a ring-buffer to ensure that the use
of the memory is bound and it will not grow indiscriminately
potentially breaking the rule n.3
and causing the application to run
out of memory. The operation is cheap (typically less than 200
nanoseconds) and it is performed with a CAS atomic swap. In highly
concurrent systems there could be retries. The assumption is the the
number of retries is less than 6; after this point it would cost more
than the enqueueing the operation with a mutex.
At regular intervals an asynchronous thread will take the content of the buffer and send all the events to the registered publishers. The operation is not blocking in either side. It reads the content of the ring-buffer (atom) and sends the events to the publisher buffers (agent ring-buffer). The operation returns immediately and it is done asynchronously.
The publisher buffers are ring-buffers as well. This is to ensure that if one downstream system is not available for some time, the accumulating events won't crash the system. All the operations on this buffer are serialized and protected by an agent.
At regular intervals, the publish
function of the PPublisher
protocol is called with the content of the buffer. The publishing
function can take the all the events (or part of them) and send them
to the downstream system. If the operation is successful, the
publisher function returns the new state of the buffer minus the events
which have been successfully sent. In case of failure, the operation
will be re-attempted at the next round.
Any sort of formatting, transformation and manipulation of the events
is done at this time, right before sending to the target system.
Therefore, it is important that all the values passed to the log
function
are immutable.
Each system might require different pre-processing, and this processing
is done asynchronously for the logging itself.
For more information about how to implement custom publisher see: How to write custom publishers
Can you improve this documentation? These fine people already did:
Bruno Bonacci & Arnaud BosEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close