All built-in publisher support custom transformation of the events
before being processed by the publisher. μ/log's publishers
accept a custom transformation function via the :transform
key in
the publisher configuration options.
The transformation function is a function that takes a sequence of events and returns a potentially modified sequence of events.
transform -> event-seq -> event-seq
With this type of function you can filter the events you wish to be sent to the specified publisher, apply transformations, drop events which are not interesting to you etc.
Here is an example of the general usage with an identity function:
(μ/start-publisher!
{:type :console
:transform (fn [events] events)})
For example, let assume that I would like to send to the console
publisher only the events with the following names:
:myapp/payment-done
and :myapp/transaction-closed
, here is a
sample of the transform function
(u/start-publisher!
{:type :console
:pretty? true
:transform
(fn [events]
(filter #(or (= (:mulog/event-name %) :myapp/payment-done)
(= (:mulog/event-name %) :myapp/transaction-closed))
events))})
With the above transform we will only see on the console events of the
above type. There is an easier way to write the filter
predicate
function via a library called where
https://github.com/BrunoBonacci/where.
where
offers a small DSL to write powerful predicate functions which
are robust, nil-safe, and easier to read. With this library we can
rewrite the above predicate function as follow:
(u/start-publisher!
{:type :console
:pretty? true
:transform
(partial filter (where :mulog/event-name :in? [:myapp/payment-done :myapp/transaction-closed]))})
As another example we might want to see only large transactions:
(require '[where.core :refer [where]])
(u/start-publisher!
{:type :console
:pretty? true
:transform
(partial filter (where [:and [:mulog/event-name :is? :myapp/transaction-closed]
[:amount > 1000]]))})
Or maybe we are only interested into events with errors:
(u/start-publisher!
{:type :console
:pretty? true
:transform
(partial filter :exception)})
Another possibility is to change the events in way that are specific to the destination system or the particular way our project or team needs.
One common need is to send the :mulog/duration
in milliseconds
rather than nanoseconds. This is easily done with :transform
.
(μ/start-publisher!
{:type :console
:transform (fn [events]
(map (fn [{:keys [mulog/duration] :as e}]
(if duration
(update e :mulog/duration quot 1000000)
e)) events))})
Should the custom transformation raise an exception, the exception
will be recorded as event in μ/log with the following event name
:mulog/publisher-error
and the actual exception in the :exception
field.
Samplers are special publishers. Instead of sending events off to
another system, they generating new events by sampling system
variables. Although they use the publishers infrastructure they are
not publishers. Examples of samplers are the
:jvm-metrics
which samples
memory and garbage collector metrics at regular intervals, or
:filesystem-metrics
which samples total and free spaces for attached file-systems.
The samplers accept a similar custom transforming function called :transform-samples
with the following signature:
transform-samples -> sample-seq -> sample-seq
A key difference between the :transform-samples
and :transform
is that the :transform-samples
is only available in the built-in
samplers.
Samplers do not support the general :transform
function. The reason
is that the :transform
function works on events, while
:transform-samples
works on samples before they are recorded as
events, and they act on the sampled value. This means that the transformation
function received maps which don't have all the common event fields like
:mulog/event-name
and :mulog/timestamp
etc.
For example, the custom :transform-samples
for :filesystem-metrics
sampler
in this example access a field called :total-bytes
which is part of the sample
(μ/start-publisher!
{:type :filesystem-metrics
;; (e.g. filter only volumes over 1 GB)
:transform-samples (partial filter #(> (:total-bytes %) 1e9))})
The generated sample will look like:
;; This is a SAMPLE
{:name "/dev/disk1s1"
:type "apfs"
:path "/"
:readonly? false
:total-bytes 499963170816
:unallocated-bytes 40646381568
:usable-bytes 30255194112}
and the recorded events will look like:
;; This is an EVENT
{:mulog/event-name :mulog/filesystem-metrics-sampled,
:mulog/timestamp 1601629811722,
:mulog/trace-id #mulog/flake "4YcWozKEUcfE9JxfQMnuwb-NnO8ygEpE",
:filesystem-metrics
{:name "/dev/disk1s1"
:type "apfs"
:path "/"
:readonly? false
:total-bytes 499963170816
:unallocated-bytes 40646381568
:usable-bytes 30255194112}}
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close