subscriber: impl Layer for Option<T:Layer> (#910)

## Motivation

Fixes #894

## Solution

This PR implements Layer for Option, allowing users to wrap a Layer with
an Option, allowing it to be passed internally wherever Layer is used
there by allowing by allowing layers to be enabled or disabled.

Using this with `reload` further allows a Layer to be dynamically
toggled based by using `handle.modify`

This PR also consists of a basic example.

Signed-off-by: Tarun Pothulapati <tarunpothulapati@outlook.com>
This commit is contained in:
Tarun Pothulapati 2020-08-14 22:59:16 +05:30 committed by GitHub
parent 2a5da8d75b
commit e9b6645f0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 145 additions and 0 deletions

View File

@ -31,6 +31,8 @@ This directory contains a collection of examples that demonstrate the use of the
debug a server under load in production.
+ `journald`: Demonstrates how to use `fmt` and `journald` layers to output to
both the terminal and the system journal.
+ `toggle-layers` : Demonstrates how Layers can be wrapped with an `Option` allowing
them to be dynamically toggled.
- **tracing-futures**:
+ `spawny-thing`: Demonstrates the use of the `#[instrument]` attribute macro
asynchronous functions.

View File

@ -0,0 +1,47 @@
#![deny(rust_2018_idioms)]
/// This is a example showing how `Layer` can be enabled or disabled by
/// by wrapping them with an `Option`. This example shows `fmt` and `json`
/// being toggled based on the `json` command line flag.
///
/// You can run this example by running the following command in a terminal
///
/// ```
/// cargo run --example toggle-layers -- json
/// ```
///
use clap::{App, Arg};
use tracing::info;
use tracing_subscriber::{prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt};
#[path = "fmt/yak_shave.rs"]
mod yak_shave;
fn main() {
let matches = App::new("fmt optional Example")
.version("1.0")
.arg(
Arg::with_name("json")
.help("Enabling json formatting of logs")
.required(false)
.takes_value(false),
)
.get_matches();
let (json, plain) = if matches.is_present("json") {
(Some(tracing_subscriber::fmt::layer().json()), None)
} else {
(None, Some(tracing_subscriber::fmt::layer()))
};
tracing_subscriber::registry().with(json).with(plain).init();
let number_of_yaks = 3;
// this creates a new event, outside of any spans.
info!(number_of_yaks, "preparing to shave yaks");
let number_shaved = yak_shave::shave_all(number_of_yaks);
info!(
all_yaks_shaved = number_shaved == number_of_yaks,
"yak shaving completed."
);
}

View File

@ -808,6 +808,102 @@ where
}
}
impl<L, S> Layer<S> for Option<L>
where
L: Layer<S>,
S: Subscriber,
{
#[inline]
fn new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
if let Some(ref inner) = self {
inner.new_span(attrs, id, ctx)
}
}
#[inline]
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
match self {
Some(ref inner) => inner.register_callsite(metadata),
None => Interest::always(),
}
}
#[inline]
fn enabled(&self, metadata: &Metadata<'_>, ctx: Context<'_, S>) -> bool {
match self {
Some(ref inner) => inner.enabled(metadata, ctx),
None => true,
}
}
#[inline]
fn max_level_hint(&self) -> Option<LevelFilter> {
match self {
Some(ref inner) => inner.max_level_hint(),
None => None,
}
}
#[inline]
fn on_record(&self, span: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) {
if let Some(ref inner) = self {
inner.on_record(span, values, ctx);
}
}
#[inline]
fn on_follows_from(&self, span: &span::Id, follows: &span::Id, ctx: Context<'_, S>) {
if let Some(ref inner) = self {
inner.on_follows_from(span, follows, ctx);
}
}
#[inline]
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
if let Some(ref inner) = self {
inner.on_event(event, ctx);
}
}
#[inline]
fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
if let Some(ref inner) = self {
inner.on_enter(id, ctx);
}
}
#[inline]
fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
if let Some(ref inner) = self {
inner.on_exit(id, ctx);
}
}
#[inline]
fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
if let Some(ref inner) = self {
inner.on_close(id, ctx);
}
}
#[inline]
fn on_id_change(&self, old: &span::Id, new: &span::Id, ctx: Context<'_, S>) {
if let Some(ref inner) = self {
inner.on_id_change(old, new, ctx)
}
}
#[doc(hidden)]
#[inline]
unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
if id == TypeId::of::<Self>() {
Some(self as *const _ as *const ())
} else {
self.as_ref().and_then(|inner| inner.downcast_raw(id))
}
}
}
#[cfg(feature = "registry")]
#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
impl<'a, L, S> LookupSpan<'a> for Layered<L, S>