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
andserde::Serialize
for the object. - Add
[#(derive(ExtLoggable)]
above the object, and aLogDetails
attribute.
The LogDetails must contain three key-value pairs, with all values quoted.
Level
must be a validslog::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
Values
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.
Limitations
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 correspondingStatDefinition
.Action
(mandatory) - one of:Incr
,Decr
, andSetVal
, 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 useself
for the current log object.Value
orValueFrom
- 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.
Example
Deriving Value
and ExtLoggable
for some simple objects.
use slog_extlog_derive::{ExtLoggable, SlogValue}; use serde::Serialize; #[derive(Clone, Serialize, SlogValue)] enum FooRspCode { Success, InvalidUser, } // 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() .with_stats(vec![FOO_STATS]) .fuse(slog_logger); // Now all logs of `FooReqRcvd` will increment the `FooNonEmptyCount` and // `FooTotalBytesByUser` stats... xlog!(logger, FooReqRcvd { bytes: 42, user: "ArthurDent".to_string()}); }
Derive Macros
ExtLoggable | Generate implementations of the |
SlogValue | Generate implementations of the |