aws_smithy_http_server/instrumentation/sensitivity/
sensitive.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! A general wrapper to allow for feature flagged redactions.
7
8use std::fmt::{Debug, Display, Error, Formatter};
9
10use crate::instrumentation::MakeFmt;
11
12use super::REDACTED;
13
14/// A wrapper used to modify the [`Display`] and [`Debug`] implementation of the inner structure
15/// based on the feature flag `unredacted-logging`. When the `unredacted-logging` feature is enabled, the
16/// implementations will defer to those on `T`, when disabled they will defer to [`REDACTED`].
17///
18/// Note that there are [`Display`] and [`Debug`] implementations for `&T` where `T: Display`
19/// and `T: Debug` respectively - wrapping references is allowed for the cases when consuming the
20/// inner struct is not desired.
21///
22/// # Example
23///
24/// ```
25/// # use aws_smithy_http_server::instrumentation::sensitivity::Sensitive;
26/// # let address = "";
27/// tracing::debug!(
28///     name = %Sensitive("Alice"),
29///     friends = ?Sensitive(["Bob"]),
30///     address = ?Sensitive(&address)
31/// );
32/// ```
33pub struct Sensitive<T>(pub T);
34
35impl<T> Debug for Sensitive<T>
36where
37    T: Debug,
38{
39    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
40        if cfg!(feature = "unredacted-logging") {
41            self.0.fmt(f)
42        } else {
43            Debug::fmt(&REDACTED, f)
44        }
45    }
46}
47
48impl<T> Display for Sensitive<T>
49where
50    T: Display,
51{
52    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
53        if cfg!(feature = "unredacted-logging") {
54            self.0.fmt(f)
55        } else {
56            Display::fmt(&REDACTED, f)
57        }
58    }
59}
60
61/// A [`MakeFmt`] producing [`Sensitive`].
62#[derive(Debug, Clone)]
63pub struct MakeSensitive;
64
65impl<T> MakeFmt<T> for MakeSensitive {
66    type Target = Sensitive<T>;
67
68    fn make(&self, source: T) -> Self::Target {
69        Sensitive(source)
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn debug() {
79        let inner = "hello world";
80        let sensitive = Sensitive(inner);
81        let actual = format!("{:?}", sensitive);
82        let expected = if cfg!(feature = "unredacted-logging") {
83            format!("{:?}", inner)
84        } else {
85            format!("{:?}", REDACTED)
86        };
87        assert_eq!(actual, expected)
88    }
89
90    #[test]
91    fn display() {
92        let inner = "hello world";
93        let sensitive = Sensitive(inner);
94        let actual = format!("{}", sensitive);
95        let expected = if cfg!(feature = "unredacted-logging") {
96            inner.to_string()
97        } else {
98            REDACTED.to_string()
99        };
100        assert_eq!(actual, expected)
101    }
102}