Expand description
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_extlogcrate with#[macro_use]. - Define a constant string named
CRATE_LOG_NAMEwhich uniquely identifies this crate in log identifiers. - Implement (usually by auto-deriving)
Cloneandserde::Serializefor the object. - Add
[#(derive(ExtLoggable)]above the object, and aLogDetailsattribute.
The LogDetails must contain three key-value pairs, with all values quoted.
Levelmust be a validslog::Level.Textmust be a string literal.Idmust 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 useselffor the current log object.ValueorValueFrom- The value to increment/decrement/set. One and only one of these must be provided.Valuefor a fixed number,ValueFromfor 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
StatTriggerof 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", "request_type"])
}
}
#[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", FixedGroups="request_type=Foo")]
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 = 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
ExtLoggabletrait. - Slog
Value - Generate implementations of the
slog::Valuetrait.