Semantic Logger Structured logs. Better decisions.

Log Event

Contents

Every call to a logger (logger.info, logger.measure_error, and so on) builds a single Log event object. That object is the unit of work that flows through the whole pipeline: it is handed to each filter, then to each appender’s formatter, and finally written out by the appender itself, usually on a background thread so the calling application is not blocked.

You meet the Log event whenever you customize Semantic Logger:

In every one of those places you are reading the same object documented here.

The event is mutable

The Log event is a plain mutable Ruby object: every attribute below has both a reader and a writer. All appenders share one event instance per log call, so change it only before it is handed to them: in an on_log subscriber, which runs for every entry, or in the filter of a logger instance, which runs for that logger’s entries. For example, to add context to every entry:

SemanticLogger.on_log do |log|
  log.set_context(:request_id, Thread.current[:request_id])
end

To redact sensitive data, see Redacting sensitive data.

Do not change the event in an appender’s filter or in a formatter: the appenders that ran before it have already written the event, and one that runs asynchronously may be reading it on its own thread at the same time.

Which fields are always present

A handful of attributes are populated for every event:

The rest are situational: they are set only when relevant to that particular call. For example duration is present only for measure_* calls, exception only when an exception was logged, metric/metric_amount/dimensions only for metrics, and backtrace only when backtrace capture is enabled (SemanticLogger.backtrace_level). Always guard against nil when reading a situational field.

Attributes

Attribute Type Description
level Symbol Log level of the call: :trace, :debug, :info, :warn, :error, :fatal.
level_index Integer Numeric form of the level for fast comparisons: :trace=>0, :debug=>1, :info=>2, :warn=>3, :error=>4, :fatal=>5.
name String Class or component name supplied to the logger, for example the "MyClass" in SemanticLogger["MyClass"].
message String The text message. May be nil (for example, a metric-only event).
payload Hash Structured data logged alongside the message. nil when none was supplied.
time Time The moment the event was created.
thread_name String Name (or id) of the thread that made the log call.
tags Array<String> Tags active on the thread when the call was made.
named_tags Hash<String, Object> Named tags active on the thread when the call was made.
context Hash Named contexts captured in-line at the point the event was created. nil when none.
duration Float Time in milliseconds taken by a measure_* call. nil for ordinary log calls.
exception Exception The Ruby exception that was logged. nil when none. Use each_exception to walk a cause chain.
backtrace Array<String> Backtrace captured at the call site, present only when the level is at or above SemanticLogger.backtrace_level.
metric String The metric name, present for metric and measure_* calls. See Metrics.
metric_amount Float Numeric amount for a counter or gauge metric, for example the quantity purchased.
dimensions Hash Dimensions (key/value labels) supplied for a metric.

Helper methods

These read-only helpers derive convenient values from the attributes above:

Method Returns Description
payload? true/false Whether the event carries a non-empty payload.
payload_to_s String or nil The payload rendered with inspect, or nil when absent.
metric_only? true/false true when the event has a metric but no message and no exception. Text appenders typically skip these; machine-readable (JSON) appenders usually keep them.
duration_to_s String or nil The duration in milliseconds as a short string, for example "12ms". nil when there is no duration.
duration_human String or nil The duration in human readable form, scaling up to seconds, minutes, hours, or days as needed.
level_to_s String The level as a single upper-case character, for example "I" for :info.
cleansed_message String The message with Rails/ANSI color escape codes stripped. Used to keep terminal codes out of structured output.
each_exception Enumerator Iterates the exception and its nested cause chain, yielding (exception, depth).
backtrace_to_s String The exception backtrace as a string, including every exception in the cause chain. With a block, each cause’s message and each backtrace line is replaced by the value the block returns, for example to escape it.
exception_details(exception, source: false) String or nil The detail Ruby’s Exception#detailed_message adds to the message of exception (this event’s exception or one of its causes), such as did_you_mean suggestions, without the class name. source: true also includes error_highlight’s source snippet. nil when there is none. Cached on the event.
file_name_and_line(short_name = false) [String, Integer] or nil The file name and line number from the event’s backtrace or exception. Pass true for just the base file name.
to_h Hash The event as a plain Hash (via the Raw formatter), including host, application, and environment. Handy for inspecting an event or building a custom formatter.
set_context(key, value) Hash Lazily initializes context and stores a key/value pair on it.

Inspecting an event

When writing a filter or formatter, the quickest way to see what a real event contains is to dump it with to_h:

SemanticLogger.add_appender(
  io:     $stdout,
  filter: ->(log) do
    pp log.to_h   # one-off: inspect the event during development
    true
  end
)