Crate slog_extlog_derive[][src]

Crate for autogenerating the ExtLoggable trait.

This massively simplifies the definition of extended logs - it is expected that most users will automatically derive ExtLoggable for their log objects. The derivation is done using the serde::Serialize crate, for maximum flexibility and minimal new code.

External Logs

To autoderive the ExtLoggable trait:

  • Import this crate and the slog_extlog crate with #[macro_use].
  • Define a constant string named CRATE_LOG_NAME which uniquely identifies this crate in log identifiers.
  • Implement (usually by auto-deriving) Clone and serde::Serialize for the object.
  • Add [#(derive(ExtLoggable)] above the object, and a LogDetails attribute.

The LogDetails must contain three key-value pairs, with all values quoted.

  • Level must be a valid slog::Level.
  • Text must be a string literal.
  • Id must be an unsigned integer, which should uniquely identify the log within your crate.

Your crate must also define a constant string named CRATE_LOG_NAME. This is prefixed to the log ID when the log is generated to


If you wish a structure type to be usable as a log parameter, but not to be a log itself, then this crate also allows derivation of the slog::Value trait - again, the type needs to also implement Clone and serde::Serialize, and again these can nearly always be auto-derived.


Because the logging infrastructure can run asynchronously, all logged types must have static lifetime and be Send. This means no non-static references, and no lifetime parameters.

Statistics triggers

An external log can automatically trigger changes in statistic values by adding the StatTrigger attribute to the log object. Like LogDetails, this attribute is a list of key=value pairs, with the following keys.

One StatTrigger attribute should be added to the log for each statistic it should update.

  • StatName (mandatory) - The name of the statistic to change, as defined on the corresponding StatDefinition.
  • Action (mandatory) - one of: Incr, Decr, and SetVal, depending on whether this change triggers an increment, decrement, or set to an explicit value.
  • Condition (optional) - A condition, based on the log fields, for this stat to be changed. if not set, the stat is changed on every log. The value of this parameter is an expression that returns a Boolean, and can use self for the current log object.
  • Value or ValueFrom - The value to increment/decrement/set. One and only one of these must be provided. Value for a fixed number, ValueFrom for an arbitrary expression to find the value that may return self.
  • FixedGroups (optional) - A comma-separated list of fixed tags to add to this statistic for this trigger - see below.

Grouped (tagged) statistics)

Some statistics may be grouped with tags. Tags can be defined in two ways.

  • To add one or more fixed groups on a given statistic update, add an attribute to the StatTrigger of the form: `FixedGroups = “=,=,…”. The names must be the names of the tags within the statistic definition.
  • To add a dynamic tag, you can take the value from a single field in the log. To specify which field within the triggering log should be used for the group value, add a #[StatGroup(StatName = "<name>")] attribute on the relevant field within the log, where ` is the relevant statistic name. The name of the group within the statistic definition must be the name of the field in the log structure.

WARNING - be careful with tagging where there can be large numbers of values - each seen value for the tag generates a new statistic, which is tracked forever once it is seen. Tags are most effective when used for fields that take a small number of values and where the set of values changes infrequently. Examples might be the type of remote client, or an error code.


Deriving Value and ExtLoggable for some simple objects.

use slog_extlog_derive::{ExtLoggable, SlogValue};
use serde::Serialize;

#[derive(Clone, Serialize, SlogValue)]
enum FooRspCode {

// The prefix to add to all log identifiers.
const CRATE_LOG_NAME: &'static str = "FOO";

#[derive(Clone, Serialize, ExtLoggable)]
#[LogDetails(Id="101", Text="Foo Request received", Level="Info")]
struct FooReqRcvd;

#[derive(Clone, Serialize, ExtLoggable)]
#[LogDetails(Id="103", Text="Foo response sent", Level="Info")]
struct FooRspSent(FooRspCode);

Defining some statistics from a single log.

use slog_extlog_derive::{ExtLoggable, SlogValue};
use serde::Serialize;

use slog_extlog::{define_stats, stats, xlog};
use slog_extlog::stats::{Buckets, StatDefinition};
use slog::o;

// The prefix to add to all log identifiers.
const CRATE_LOG_NAME: &'static str = "FOO";

define_stats! {
   FOO_STATS = {
       // Some simple counters
       FooNonEmptyCount(Counter, "FOO-1001", "Count of non-empty Foo requests", []),
       FooTotalBytesByUser(Counter, "FOO-1002",
                           "Total size of all Foo requests per user", ["user"])

#[derive(Clone, Serialize, ExtLoggable)]
#[LogDetails(Id="101", Text="Foo Request received", Level="Info")]
#[StatTrigger(StatName="FooNonEmptyCount", Action="Incr",
              Condition="self.bytes > 0", Value="1")]
#[StatTrigger(StatName="FooTotalBytesByUser", Action="Incr", ValueFrom="self.bytes")]
struct FooReqRcvd {
  // The number of bytes in the request
  bytes: usize,
  // The user for the request.
  #[StatGroup(StatName = "FooTotalBytesByUser")]
  user: String

async fn main() {
  // Create the logger using whatever log format required.
  let slog_logger = slog::Logger::root(slog::Discard, o!());
  let logger: slog_extlog::DefaultLogger = stats::StatsLoggerBuilder::default()

  // Now all logs of `FooReqRcvd` will increment the `FooNonEmptyCount` and
  // `FooTotalBytesByUser` stats...

  xlog!(logger, FooReqRcvd { bytes: 42, user: "ArthurDent".to_string()});

Derive Macros


Generate implementations of the ExtLoggable trait.


Generate implementations of the slog::Value trait.