cvm_tracing/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Implements a tracing filter to restrict logging of events that are marked
5//! as [`CVM_CONFIDENTIAL`].
6
7// How it works:
8// The magic value [`tracing::field::Empty`] will cause that field to be omitted
9// from the tracing output. This allows us to use a field with that value as a
10// metadata tag on individual events without polluting the output.
11
12#![forbid(unsafe_code)]
13
14use tracing::Subscriber;
15use tracing::field::Empty;
16use tracing_subscriber::filter::FilterFn;
17use tracing_subscriber::layer::Filter;
18
19/// A marker that can be used to tag events that are safe to log out of a
20/// confidential environment.
21pub const CVM_ALLOWED: Empty = Empty;
22
23/// A marker that can be used to tag events that are confidential and should
24/// not be logged out of a confidential environment.
25pub const CVM_CONFIDENTIAL: Empty = Empty;
26
27/// A tracing filter that will block events that are marked as [`CVM_CONFIDENTIAL`].
28pub fn confidential_event_filter<S: Subscriber>() -> impl Filter<S> {
29    FilterFn::new(move |m| m.fields().field("CVM_CONFIDENTIAL").is_none())
30}
31
32#[cfg(test)]
33mod test {
34    use crate::CVM_ALLOWED;
35    use crate::CVM_CONFIDENTIAL;
36    use std::sync::Arc;
37    use std::sync::atomic::AtomicU32;
38    use tracing::Subscriber;
39    use tracing_subscriber::Layer;
40    use tracing_subscriber::layer::SubscriberExt;
41
42    struct TestLayer {
43        count: Arc<AtomicU32>,
44    }
45
46    impl<S: Subscriber> Layer<S> for TestLayer {
47        fn on_event(
48            &self,
49            _event: &tracing::Event<'_>,
50            _ctx: tracing_subscriber::layer::Context<'_, S>,
51        ) {
52            self.count
53                .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
54        }
55    }
56
57    fn create_test_subscriber() -> (Arc<AtomicU32>, impl Subscriber + Send + Sync + 'static) {
58        let filter = crate::confidential_event_filter();
59        let count = Arc::new(AtomicU32::new(0));
60        let layer = TestLayer {
61            count: count.clone(),
62        };
63        (
64            count,
65            tracing_subscriber::registry().with(layer.with_filter(filter)),
66        )
67    }
68
69    fn log_test_events(subscriber: impl Subscriber + Send + Sync + 'static) {
70        tracing::subscriber::with_default(subscriber, || {
71            tracing::trace!(foo = 4, "unknown trace");
72            tracing::debug!(bar = 82, "unknown debug");
73            tracing::info!("unknown info");
74            tracing::warn!("unknown warn");
75            tracing::event!(tracing::Level::ERROR, "unknown error");
76
77            tracing::trace!(foo = 4, CVM_ALLOWED, "safe trace");
78            tracing::debug!(CVM_ALLOWED, bar = 82, "safe debug");
79            tracing::info!(?CVM_ALLOWED, "safe info");
80            tracing::warn!(CVM_ALLOWED, "safe warn");
81            tracing::event!(tracing::Level::ERROR, CVM_ALLOWED, "safe error");
82
83            tracing::trace!(foo = 4, CVM_CONFIDENTIAL, "confidential trace");
84            tracing::debug!(CVM_CONFIDENTIAL, bar = 82, "confidential debug");
85            tracing::info!(?CVM_CONFIDENTIAL, "confidential info");
86            tracing::warn!(CVM_CONFIDENTIAL, "confidential warn");
87            tracing::event!(
88                tracing::Level::ERROR,
89                CVM_CONFIDENTIAL,
90                "confidential error"
91            );
92        });
93    }
94
95    #[test]
96    fn it_works() {
97        let (count, subscriber) = create_test_subscriber();
98        log_test_events(subscriber);
99        assert_eq!(count.load(std::sync::atomic::Ordering::SeqCst), 10);
100    }
101}