diagnostics_log/
lib.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3
4#![deny(missing_docs)]
5
6//! Provides the `log::Log` implementation that allows to publish `log` events to
7//! Fuchsia Logging System.
8//!
9//! This library isn't Fuchsia-specific and provides a general `log::Log` that allows
10//! the library to also be used in the host.
11
12#[cfg(all(target_os = "fuchsia", fuchsia_api_level_at_least = "NEXT"))]
13mod fuchsia;
14#[cfg(all(target_os = "fuchsia", fuchsia_api_level_at_least = "NEXT"))]
15use self::fuchsia as implementation;
16
17// Version 28 of the SDK was the last version that used sockets for the Rust
18// client. The latest uses IOBuffers.
19#[cfg(all(target_os = "fuchsia", not(fuchsia_api_level_at_least = "NEXT")))]
20mod fuchsia_28;
21#[cfg(all(target_os = "fuchsia", not(fuchsia_api_level_at_least = "NEXT")))]
22use self::fuchsia_28 as implementation;
23
24#[cfg(not(target_os = "fuchsia"))]
25mod portable;
26#[cfg(not(target_os = "fuchsia"))]
27use self::portable as implementation;
28
29pub use diagnostics_log_types::Severity;
30pub use implementation::*;
31
32/// Adds a panic hook which will log an `ERROR` log with the panic information.
33pub(crate) fn install_panic_hook(prefix: Option<&'static str>) {
34    let previous_hook = std::panic::take_hook();
35    std::panic::set_hook(Box::new(move |info| {
36        let message = format!("{info}");
37        let prefix = prefix.unwrap_or("PANIC");
38        log::logger().log(
39            &log::RecordBuilder::new()
40                .level(log::Level::Error)
41                .line(Some(info.location().unwrap().line()))
42                .file(Some(info.location().unwrap().file()))
43                .key_values(&[("info", message.as_str())])
44                .args(format_args!("{prefix}"))
45                .build(),
46        );
47        previous_hook(info);
48    }));
49}
50
51/// A type which has a `Severity`.
52pub trait SeverityExt {
53    /// Return the severity of this value.
54    fn severity(&self) -> Severity;
55
56    /// Return the raw severity of this value.
57    fn raw_severity(&self) -> u8 {
58        self.severity() as u8
59    }
60}
61
62impl SeverityExt for log::Metadata<'_> {
63    fn severity(&self) -> Severity {
64        match self.level() {
65            log::Level::Error => Severity::Error,
66            log::Level::Warn => Severity::Warn,
67            log::Level::Info => Severity::Info,
68            log::Level::Debug => Severity::Debug,
69            log::Level::Trace => Severity::Trace,
70        }
71    }
72}
73
74/// Options to configure publishing. This is for initialization of logs, it's a superset of
75/// `PublisherOptions`.
76// NOTE: `Default` is implemented by the target specific implementations.
77pub struct PublishOptions<'t> {
78    pub(crate) publisher: PublisherOptions<'t>,
79    pub(crate) install_panic_hook: bool,
80    pub(crate) panic_prefix: Option<&'static str>,
81}
82
83impl PublishOptions<'_> {
84    /// Whether or not to install a panic hook which will log an ERROR whenever a panic happens.
85    ///
86    /// Default: true.
87    pub fn install_panic_hook(mut self, enable: bool) -> Self {
88        self.install_panic_hook = enable;
89        self
90    }
91
92    /// Enable to always log file/line information, otherwise only log
93    /// when severity is ERROR or above.
94    #[cfg(target_os = "fuchsia")]
95    pub fn always_log_file_line(mut self) -> Self {
96        self.publisher.always_log_file_line = true;
97        self
98    }
99
100    /// Override the default string prefix for a logged panic message.
101    pub fn panic_prefix(mut self, prefix: &'static str) -> Self {
102        self.panic_prefix = Some(prefix);
103        self
104    }
105}
106
107macro_rules! publisher_options {
108    ($(($name:ident, $self:ident, $($self_arg:ident),*)),*) => {
109        $(
110            impl<'t> $name<'t> {
111                /// Sets the tags applied to all published events.
112                ///
113                /// When set to an empty slice (the default), events are tagged with the moniker of
114                /// the component in which they are recorded.
115                ///
116                /// Default: empty.
117                pub fn tags(mut $self, tags: &'t [&'t str]) -> Self {
118                    let this = &mut $self$(.$self_arg)*;
119                    this.tags = tags;
120                    $self
121                }
122
123                /// Enable a metatag. It'll be applied to all published events.
124                ///
125                /// Default: no metatags are enabled.
126                pub fn enable_metatag(mut $self, metatag: Metatag) -> Self {
127                    let this = &mut $self$(.$self_arg)*;
128                    this.metatags.insert(metatag);
129                    $self
130                }
131
132                /// An interest filter to apply to messages published.
133                ///
134                /// Default: EMPTY, which implies INFO.
135                pub fn minimum_severity(mut $self, severity: impl Into<Severity>) -> Self {
136                    let this = &mut $self$(.$self_arg)*;
137                    this.interest.min_severity = Some(severity.into().into());
138                    $self
139                }
140            }
141        )*
142    };
143}
144
145publisher_options!((PublisherOptions, self,), (PublishOptions, self, publisher));