Skip to content

Lazy and cached log fields #360

@bobrik

Description

@bobrik

In our internal framework we have some relatively expensive log fields to compute (formatting is expensive):

"http.host" => format!("{:?}", extract_host(req))

We also have approximately zero logging in a course of normal request processing in the heaviest users, so all of this effort goes to waste. We can do this and switch to lazy evaluation:

"http.host" => PushFnValue(move |_, s| s.emit(format_args!("{host:?}")))

This is better, but it has an unfortunate downside for framework consumers that do log more than once during request processing.

We could get the best of both worlds by making evaluation both lazy (above) and cached (sketched by @TheJokr):

pub struct LazyValue<T, F>(LazyLock<T, F>);

impl<T: slog::Value, F: FnOnce() -> T> slog::Value for LazyValue<T, F> {
    fn serialize(&self, ...) -> ... {
        (*self.0).serialize(...)
    }
}

impl<T, F: FnOnce() -> T> LazyValue<T, F> {
    pub const fn new(init_fn: F) -> Self {
        Self(LazyLock::new(init_fn))
    }
}

It seems generally useful, so I think this should live in slog itself, as something like PushFnValueCached perhaps.

Metadata

Metadata

Assignees

Labels

C-feature-requestCategory: A feature request, i.e: not implemented / a PR.

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions