1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker //! Facilities for sending log message to syslog.
6*bb4ee6a4SAndroid Build Coastguard Worker //!
7*bb4ee6a4SAndroid Build Coastguard Worker //! Every function exported by this module is thread-safe. Each function will silently fail until
8*bb4ee6a4SAndroid Build Coastguard Worker //! `syslog::init()` is called and returns `Ok`.
9*bb4ee6a4SAndroid Build Coastguard Worker //!
10*bb4ee6a4SAndroid Build Coastguard Worker //! This implements and sets logger up for logging facade exposed by the [`log`
11*bb4ee6a4SAndroid Build Coastguard Worker //! crate][log-crate-url].
12*bb4ee6a4SAndroid Build Coastguard Worker //!
13*bb4ee6a4SAndroid Build Coastguard Worker //! # Examples
14*bb4ee6a4SAndroid Build Coastguard Worker //!
15*bb4ee6a4SAndroid Build Coastguard Worker //! ```
16*bb4ee6a4SAndroid Build Coastguard Worker //! use log::{error, warn};
17*bb4ee6a4SAndroid Build Coastguard Worker //! use base::syslog;
18*bb4ee6a4SAndroid Build Coastguard Worker //!
19*bb4ee6a4SAndroid Build Coastguard Worker //! if let Err(e) = syslog::init() {
20*bb4ee6a4SAndroid Build Coastguard Worker //! println!("failed to initiailize syslog: {}", e);
21*bb4ee6a4SAndroid Build Coastguard Worker //! return;
22*bb4ee6a4SAndroid Build Coastguard Worker //! }
23*bb4ee6a4SAndroid Build Coastguard Worker //! warn!("this is your {} warning", "final");
24*bb4ee6a4SAndroid Build Coastguard Worker //! error!("something went horribly wrong: {}", "out of RAMs");
25*bb4ee6a4SAndroid Build Coastguard Worker //! ```
26*bb4ee6a4SAndroid Build Coastguard Worker //!
27*bb4ee6a4SAndroid Build Coastguard Worker //! ```
28*bb4ee6a4SAndroid Build Coastguard Worker //! use log::{error, warn};
29*bb4ee6a4SAndroid Build Coastguard Worker //! use base::syslog::{init_with, LogConfig, fmt};
30*bb4ee6a4SAndroid Build Coastguard Worker //! use std::io::Write;
31*bb4ee6a4SAndroid Build Coastguard Worker //!
32*bb4ee6a4SAndroid Build Coastguard Worker //! let mut cfg = LogConfig::default();
33*bb4ee6a4SAndroid Build Coastguard Worker //! cfg.log_args.stderr = true;
34*bb4ee6a4SAndroid Build Coastguard Worker //! cfg.log_args.filter = String::from("info,base=debug,base::syslog=error,serial_console=false");
35*bb4ee6a4SAndroid Build Coastguard Worker //!
36*bb4ee6a4SAndroid Build Coastguard Worker //! init_with(cfg).unwrap();
37*bb4ee6a4SAndroid Build Coastguard Worker //! error!("something went horribly wrong: {}", "out of RAMs");
38*bb4ee6a4SAndroid Build Coastguard Worker //! ```
39*bb4ee6a4SAndroid Build Coastguard Worker //!
40*bb4ee6a4SAndroid Build Coastguard Worker //!
41*bb4ee6a4SAndroid Build Coastguard Worker //! [log-crate-url]: https://docs.rs/log/
42*bb4ee6a4SAndroid Build Coastguard Worker
43*bb4ee6a4SAndroid Build Coastguard Worker use std::fmt::Display;
44*bb4ee6a4SAndroid Build Coastguard Worker use std::io;
45*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Write;
46*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::MutexGuard;
47*bb4ee6a4SAndroid Build Coastguard Worker
48*bb4ee6a4SAndroid Build Coastguard Worker use chrono::Utc;
49*bb4ee6a4SAndroid Build Coastguard Worker pub use env_logger::fmt;
50*bb4ee6a4SAndroid Build Coastguard Worker pub use env_logger::{self};
51*bb4ee6a4SAndroid Build Coastguard Worker pub use log::*;
52*bb4ee6a4SAndroid Build Coastguard Worker use once_cell::sync::Lazy;
53*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
54*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
55*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
56*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
57*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
58*bb4ee6a4SAndroid Build Coastguard Worker
59*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor::AsRawDescriptor;
60*bb4ee6a4SAndroid Build Coastguard Worker use crate::platform::syslog::PlatformSyslog;
61*bb4ee6a4SAndroid Build Coastguard Worker use crate::platform::RawDescriptor;
62*bb4ee6a4SAndroid Build Coastguard Worker
63*bb4ee6a4SAndroid Build Coastguard Worker /// The priority (i.e. severity) of a syslog message.
64*bb4ee6a4SAndroid Build Coastguard Worker ///
65*bb4ee6a4SAndroid Build Coastguard Worker /// See syslog man pages for information on their semantics.
66*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
67*bb4ee6a4SAndroid Build Coastguard Worker pub enum Priority {
68*bb4ee6a4SAndroid Build Coastguard Worker Emergency = 0,
69*bb4ee6a4SAndroid Build Coastguard Worker Alert = 1,
70*bb4ee6a4SAndroid Build Coastguard Worker Critical = 2,
71*bb4ee6a4SAndroid Build Coastguard Worker Error = 3,
72*bb4ee6a4SAndroid Build Coastguard Worker Warning = 4,
73*bb4ee6a4SAndroid Build Coastguard Worker Notice = 5,
74*bb4ee6a4SAndroid Build Coastguard Worker Info = 6,
75*bb4ee6a4SAndroid Build Coastguard Worker Debug = 7,
76*bb4ee6a4SAndroid Build Coastguard Worker }
77*bb4ee6a4SAndroid Build Coastguard Worker
78*bb4ee6a4SAndroid Build Coastguard Worker impl Display for Priority {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result79*bb4ee6a4SAndroid Build Coastguard Worker fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
80*bb4ee6a4SAndroid Build Coastguard Worker use self::Priority::*;
81*bb4ee6a4SAndroid Build Coastguard Worker
82*bb4ee6a4SAndroid Build Coastguard Worker let string = match self {
83*bb4ee6a4SAndroid Build Coastguard Worker Emergency => "EMERGENCY",
84*bb4ee6a4SAndroid Build Coastguard Worker Alert => "ALERT",
85*bb4ee6a4SAndroid Build Coastguard Worker Critical => "CRITICAL",
86*bb4ee6a4SAndroid Build Coastguard Worker Error => "ERROR",
87*bb4ee6a4SAndroid Build Coastguard Worker Warning => "WARNING",
88*bb4ee6a4SAndroid Build Coastguard Worker Notice => "NOTICE",
89*bb4ee6a4SAndroid Build Coastguard Worker Info => "INFO",
90*bb4ee6a4SAndroid Build Coastguard Worker Debug => "DEBUG",
91*bb4ee6a4SAndroid Build Coastguard Worker };
92*bb4ee6a4SAndroid Build Coastguard Worker
93*bb4ee6a4SAndroid Build Coastguard Worker write!(f, "{}", string)
94*bb4ee6a4SAndroid Build Coastguard Worker }
95*bb4ee6a4SAndroid Build Coastguard Worker }
96*bb4ee6a4SAndroid Build Coastguard Worker
97*bb4ee6a4SAndroid Build Coastguard Worker impl From<log::Level> for Priority {
from(level: log::Level) -> Self98*bb4ee6a4SAndroid Build Coastguard Worker fn from(level: log::Level) -> Self {
99*bb4ee6a4SAndroid Build Coastguard Worker match level {
100*bb4ee6a4SAndroid Build Coastguard Worker log::Level::Error => Priority::Error,
101*bb4ee6a4SAndroid Build Coastguard Worker log::Level::Warn => Priority::Warning,
102*bb4ee6a4SAndroid Build Coastguard Worker log::Level::Info => Priority::Info,
103*bb4ee6a4SAndroid Build Coastguard Worker log::Level::Debug => Priority::Debug,
104*bb4ee6a4SAndroid Build Coastguard Worker log::Level::Trace => Priority::Debug,
105*bb4ee6a4SAndroid Build Coastguard Worker }
106*bb4ee6a4SAndroid Build Coastguard Worker }
107*bb4ee6a4SAndroid Build Coastguard Worker }
108*bb4ee6a4SAndroid Build Coastguard Worker
109*bb4ee6a4SAndroid Build Coastguard Worker impl TryFrom<&str> for Priority {
110*bb4ee6a4SAndroid Build Coastguard Worker type Error = &'static str;
111*bb4ee6a4SAndroid Build Coastguard Worker
try_from(value: &str) -> Result<Self, <Self as TryFrom<&str>>::Error>112*bb4ee6a4SAndroid Build Coastguard Worker fn try_from(value: &str) -> Result<Self, <Self as TryFrom<&str>>::Error> {
113*bb4ee6a4SAndroid Build Coastguard Worker match value {
114*bb4ee6a4SAndroid Build Coastguard Worker "0" | "EMERGENCY" => Ok(Priority::Emergency),
115*bb4ee6a4SAndroid Build Coastguard Worker "1" | "ALERT" => Ok(Priority::Alert),
116*bb4ee6a4SAndroid Build Coastguard Worker "2" | "CRITICAL" => Ok(Priority::Critical),
117*bb4ee6a4SAndroid Build Coastguard Worker "3" | "ERROR" => Ok(Priority::Error),
118*bb4ee6a4SAndroid Build Coastguard Worker "4" | "WARNING" => Ok(Priority::Warning),
119*bb4ee6a4SAndroid Build Coastguard Worker "5" | "NOTICE" => Ok(Priority::Notice),
120*bb4ee6a4SAndroid Build Coastguard Worker "6" | "INFO" => Ok(Priority::Info),
121*bb4ee6a4SAndroid Build Coastguard Worker "7" | "DEBUG" => Ok(Priority::Debug),
122*bb4ee6a4SAndroid Build Coastguard Worker _ => Err("Priority can only be parsed from 0-7 and given variant names"),
123*bb4ee6a4SAndroid Build Coastguard Worker }
124*bb4ee6a4SAndroid Build Coastguard Worker }
125*bb4ee6a4SAndroid Build Coastguard Worker }
126*bb4ee6a4SAndroid Build Coastguard Worker /// The facility of a syslog message.
127*bb4ee6a4SAndroid Build Coastguard Worker ///
128*bb4ee6a4SAndroid Build Coastguard Worker /// See syslog man pages for information on their semantics.
129*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, serde::Deserialize, serde::Serialize)]
130*bb4ee6a4SAndroid Build Coastguard Worker pub enum Facility {
131*bb4ee6a4SAndroid Build Coastguard Worker Kernel = 0,
132*bb4ee6a4SAndroid Build Coastguard Worker User = 1 << 3,
133*bb4ee6a4SAndroid Build Coastguard Worker Mail = 2 << 3,
134*bb4ee6a4SAndroid Build Coastguard Worker Daemon = 3 << 3,
135*bb4ee6a4SAndroid Build Coastguard Worker Auth = 4 << 3,
136*bb4ee6a4SAndroid Build Coastguard Worker Syslog = 5 << 3,
137*bb4ee6a4SAndroid Build Coastguard Worker Lpr = 6 << 3,
138*bb4ee6a4SAndroid Build Coastguard Worker News = 7 << 3,
139*bb4ee6a4SAndroid Build Coastguard Worker Uucp = 8 << 3,
140*bb4ee6a4SAndroid Build Coastguard Worker Local0 = 16 << 3,
141*bb4ee6a4SAndroid Build Coastguard Worker Local1 = 17 << 3,
142*bb4ee6a4SAndroid Build Coastguard Worker Local2 = 18 << 3,
143*bb4ee6a4SAndroid Build Coastguard Worker Local3 = 19 << 3,
144*bb4ee6a4SAndroid Build Coastguard Worker Local4 = 20 << 3,
145*bb4ee6a4SAndroid Build Coastguard Worker Local5 = 21 << 3,
146*bb4ee6a4SAndroid Build Coastguard Worker Local6 = 22 << 3,
147*bb4ee6a4SAndroid Build Coastguard Worker Local7 = 23 << 3,
148*bb4ee6a4SAndroid Build Coastguard Worker }
149*bb4ee6a4SAndroid Build Coastguard Worker
150*bb4ee6a4SAndroid Build Coastguard Worker /// Errors returned by `syslog::init()`.
151*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
152*bb4ee6a4SAndroid Build Coastguard Worker #[derive(ThisError, Debug)]
153*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error {
154*bb4ee6a4SAndroid Build Coastguard Worker /// Error while attempting to connect socket.
155*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to connect socket: {0}")]
156*bb4ee6a4SAndroid Build Coastguard Worker Connect(io::Error),
157*bb4ee6a4SAndroid Build Coastguard Worker /// There was an error using `open` to get the lowest file descriptor.
158*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to get lowest file descriptor: {0}")]
159*bb4ee6a4SAndroid Build Coastguard Worker GetLowestFd(io::Error),
160*bb4ee6a4SAndroid Build Coastguard Worker /// The guess of libc's file descriptor for the syslog connection was invalid.
161*bb4ee6a4SAndroid Build Coastguard Worker #[error("guess of fd for syslog connection was invalid")]
162*bb4ee6a4SAndroid Build Coastguard Worker InvalidFd,
163*bb4ee6a4SAndroid Build Coastguard Worker /// Initialization was never attempted.
164*bb4ee6a4SAndroid Build Coastguard Worker #[error("initialization was never attempted")]
165*bb4ee6a4SAndroid Build Coastguard Worker NeverInitialized,
166*bb4ee6a4SAndroid Build Coastguard Worker /// Initialization has previously failed and can not be retried.
167*bb4ee6a4SAndroid Build Coastguard Worker #[error("initialization previously failed and cannot be retried")]
168*bb4ee6a4SAndroid Build Coastguard Worker Poisoned,
169*bb4ee6a4SAndroid Build Coastguard Worker /// Error while creating socket.
170*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to create socket: {0}")]
171*bb4ee6a4SAndroid Build Coastguard Worker Socket(io::Error),
172*bb4ee6a4SAndroid Build Coastguard Worker }
173*bb4ee6a4SAndroid Build Coastguard Worker
174*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) trait Syslog {
new( proc_name: String, facility: Facility, ) -> Result<(Option<Box<dyn Log + Send>>, Option<RawDescriptor>), Error>175*bb4ee6a4SAndroid Build Coastguard Worker fn new(
176*bb4ee6a4SAndroid Build Coastguard Worker proc_name: String,
177*bb4ee6a4SAndroid Build Coastguard Worker facility: Facility,
178*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<(Option<Box<dyn Log + Send>>, Option<RawDescriptor>), Error>;
179*bb4ee6a4SAndroid Build Coastguard Worker }
180*bb4ee6a4SAndroid Build Coastguard Worker
181*bb4ee6a4SAndroid Build Coastguard Worker pub struct State {
182*bb4ee6a4SAndroid Build Coastguard Worker /// Record filter
183*bb4ee6a4SAndroid Build Coastguard Worker filter: env_logger::filter::Filter,
184*bb4ee6a4SAndroid Build Coastguard Worker /// All the loggers we have
185*bb4ee6a4SAndroid Build Coastguard Worker loggers: Vec<Box<dyn Log + Send>>,
186*bb4ee6a4SAndroid Build Coastguard Worker /// Raw Descriptors to preserve
187*bb4ee6a4SAndroid Build Coastguard Worker descriptors: Vec<RawDescriptor>,
188*bb4ee6a4SAndroid Build Coastguard Worker /// True if we have just been initialized with safe startup defaults (stderr logging), false
189*bb4ee6a4SAndroid Build Coastguard Worker /// after detailed initialization has occurred.
190*bb4ee6a4SAndroid Build Coastguard Worker early_init: bool,
191*bb4ee6a4SAndroid Build Coastguard Worker }
192*bb4ee6a4SAndroid Build Coastguard Worker
193*bb4ee6a4SAndroid Build Coastguard Worker /// The logger that is provided to the `log` crate. Wraps our State struct so that we can
194*bb4ee6a4SAndroid Build Coastguard Worker /// reconfigure logging sinks on the fly.
195*bb4ee6a4SAndroid Build Coastguard Worker struct LoggingFacade {}
196*bb4ee6a4SAndroid Build Coastguard Worker
197*bb4ee6a4SAndroid Build Coastguard Worker impl Log for LoggingFacade {
enabled(&self, metadata: &log::Metadata) -> bool198*bb4ee6a4SAndroid Build Coastguard Worker fn enabled(&self, metadata: &log::Metadata) -> bool {
199*bb4ee6a4SAndroid Build Coastguard Worker STATE.lock().enabled(metadata)
200*bb4ee6a4SAndroid Build Coastguard Worker }
201*bb4ee6a4SAndroid Build Coastguard Worker
log(&self, record: &log::Record)202*bb4ee6a4SAndroid Build Coastguard Worker fn log(&self, record: &log::Record) {
203*bb4ee6a4SAndroid Build Coastguard Worker STATE.lock().log(record)
204*bb4ee6a4SAndroid Build Coastguard Worker }
205*bb4ee6a4SAndroid Build Coastguard Worker
flush(&self)206*bb4ee6a4SAndroid Build Coastguard Worker fn flush(&self) {
207*bb4ee6a4SAndroid Build Coastguard Worker STATE.lock().flush()
208*bb4ee6a4SAndroid Build Coastguard Worker }
209*bb4ee6a4SAndroid Build Coastguard Worker }
210*bb4ee6a4SAndroid Build Coastguard Worker
211*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, serde::Deserialize, serde::Serialize)]
212*bb4ee6a4SAndroid Build Coastguard Worker pub struct LogArgs {
213*bb4ee6a4SAndroid Build Coastguard Worker /// A filter for log messages. Please see
214*bb4ee6a4SAndroid Build Coastguard Worker /// module level documentation and [`env_logger` crate](https://docs.rs/env_logger)
215*bb4ee6a4SAndroid Build Coastguard Worker ///
216*bb4ee6a4SAndroid Build Coastguard Worker /// Example: `off`, `trace`, `trace,crosvm=error,base::syslog=debug`
217*bb4ee6a4SAndroid Build Coastguard Worker pub filter: String,
218*bb4ee6a4SAndroid Build Coastguard Worker /// If set to true will duplicate output to stderr
219*bb4ee6a4SAndroid Build Coastguard Worker pub stderr: bool,
220*bb4ee6a4SAndroid Build Coastguard Worker /// TAG to use for syslog output
221*bb4ee6a4SAndroid Build Coastguard Worker pub proc_name: String,
222*bb4ee6a4SAndroid Build Coastguard Worker /// Enable/disable platform's "syslog"
223*bb4ee6a4SAndroid Build Coastguard Worker pub syslog: bool,
224*bb4ee6a4SAndroid Build Coastguard Worker /// Facility to use for syslog output
225*bb4ee6a4SAndroid Build Coastguard Worker pub syslog_facility: Facility,
226*bb4ee6a4SAndroid Build Coastguard Worker }
227*bb4ee6a4SAndroid Build Coastguard Worker
228*bb4ee6a4SAndroid Build Coastguard Worker impl Default for LogArgs {
default() -> Self229*bb4ee6a4SAndroid Build Coastguard Worker fn default() -> Self {
230*bb4ee6a4SAndroid Build Coastguard Worker Self {
231*bb4ee6a4SAndroid Build Coastguard Worker filter: String::from("info"),
232*bb4ee6a4SAndroid Build Coastguard Worker stderr: true,
233*bb4ee6a4SAndroid Build Coastguard Worker proc_name: String::from("crosvm"),
234*bb4ee6a4SAndroid Build Coastguard Worker syslog: true,
235*bb4ee6a4SAndroid Build Coastguard Worker syslog_facility: Facility::User,
236*bb4ee6a4SAndroid Build Coastguard Worker }
237*bb4ee6a4SAndroid Build Coastguard Worker }
238*bb4ee6a4SAndroid Build Coastguard Worker }
239*bb4ee6a4SAndroid Build Coastguard Worker
240*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Default)]
241*bb4ee6a4SAndroid Build Coastguard Worker pub struct LogConfig {
242*bb4ee6a4SAndroid Build Coastguard Worker /// Logging configuration arguments.
243*bb4ee6a4SAndroid Build Coastguard Worker pub log_args: LogArgs,
244*bb4ee6a4SAndroid Build Coastguard Worker /// If specified will output to given Sink
245*bb4ee6a4SAndroid Build Coastguard Worker pub pipe: Option<Box<dyn io::Write + Send>>,
246*bb4ee6a4SAndroid Build Coastguard Worker /// descriptor to preserve on forks (intended to be used with pipe)
247*bb4ee6a4SAndroid Build Coastguard Worker pub pipe_fd: Option<RawDescriptor>,
248*bb4ee6a4SAndroid Build Coastguard Worker /// A formatter to use with the pipe. (Syslog has hardcoded format)
249*bb4ee6a4SAndroid Build Coastguard Worker /// see module level documentation and [`env_logger` crate](https://docs.rs/env_logger)
250*bb4ee6a4SAndroid Build Coastguard Worker pub pipe_formatter: Option<
251*bb4ee6a4SAndroid Build Coastguard Worker Box<dyn Fn(&mut fmt::Formatter, &log::Record<'_>) -> std::io::Result<()> + Sync + Send>,
252*bb4ee6a4SAndroid Build Coastguard Worker >,
253*bb4ee6a4SAndroid Build Coastguard Worker }
254*bb4ee6a4SAndroid Build Coastguard Worker
255*bb4ee6a4SAndroid Build Coastguard Worker impl State {
new(cfg: LogConfig) -> Result<Self, Error>256*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(cfg: LogConfig) -> Result<Self, Error> {
257*bb4ee6a4SAndroid Build Coastguard Worker let mut loggers: Vec<Box<dyn Log + Send>> = vec![];
258*bb4ee6a4SAndroid Build Coastguard Worker let mut descriptors = vec![];
259*bb4ee6a4SAndroid Build Coastguard Worker let mut builder = env_logger::filter::Builder::new();
260*bb4ee6a4SAndroid Build Coastguard Worker builder.parse(&cfg.log_args.filter);
261*bb4ee6a4SAndroid Build Coastguard Worker let filter = builder.build();
262*bb4ee6a4SAndroid Build Coastguard Worker
263*bb4ee6a4SAndroid Build Coastguard Worker let create_formatted_builder = || {
264*bb4ee6a4SAndroid Build Coastguard Worker let mut builder = env_logger::Builder::new();
265*bb4ee6a4SAndroid Build Coastguard Worker
266*bb4ee6a4SAndroid Build Coastguard Worker // Output log lines w/ local ISO 8601 timestamps.
267*bb4ee6a4SAndroid Build Coastguard Worker builder.format(|buf, record| {
268*bb4ee6a4SAndroid Build Coastguard Worker writeln!(
269*bb4ee6a4SAndroid Build Coastguard Worker buf,
270*bb4ee6a4SAndroid Build Coastguard Worker "[{} {:5} {}] {}",
271*bb4ee6a4SAndroid Build Coastguard Worker Utc::now().format("%Y-%m-%dT%H:%M:%S%.9f%:z"),
272*bb4ee6a4SAndroid Build Coastguard Worker record.level(),
273*bb4ee6a4SAndroid Build Coastguard Worker record.module_path().unwrap_or("<missing module path>"),
274*bb4ee6a4SAndroid Build Coastguard Worker record.args()
275*bb4ee6a4SAndroid Build Coastguard Worker )
276*bb4ee6a4SAndroid Build Coastguard Worker });
277*bb4ee6a4SAndroid Build Coastguard Worker builder
278*bb4ee6a4SAndroid Build Coastguard Worker };
279*bb4ee6a4SAndroid Build Coastguard Worker
280*bb4ee6a4SAndroid Build Coastguard Worker if cfg.log_args.stderr {
281*bb4ee6a4SAndroid Build Coastguard Worker let mut builder = create_formatted_builder();
282*bb4ee6a4SAndroid Build Coastguard Worker builder.filter_level(log::LevelFilter::Trace);
283*bb4ee6a4SAndroid Build Coastguard Worker builder.target(env_logger::Target::Stderr);
284*bb4ee6a4SAndroid Build Coastguard Worker loggers.push(Box::new(builder.build()));
285*bb4ee6a4SAndroid Build Coastguard Worker descriptors.push(std::io::stderr().as_raw_descriptor());
286*bb4ee6a4SAndroid Build Coastguard Worker }
287*bb4ee6a4SAndroid Build Coastguard Worker
288*bb4ee6a4SAndroid Build Coastguard Worker if let Some(fd) = cfg.pipe_fd {
289*bb4ee6a4SAndroid Build Coastguard Worker descriptors.push(fd);
290*bb4ee6a4SAndroid Build Coastguard Worker }
291*bb4ee6a4SAndroid Build Coastguard Worker
292*bb4ee6a4SAndroid Build Coastguard Worker if let Some(file) = cfg.pipe {
293*bb4ee6a4SAndroid Build Coastguard Worker let mut builder = create_formatted_builder();
294*bb4ee6a4SAndroid Build Coastguard Worker builder.filter_level(log::LevelFilter::Trace);
295*bb4ee6a4SAndroid Build Coastguard Worker builder.target(env_logger::Target::Pipe(Box::new(file)));
296*bb4ee6a4SAndroid Build Coastguard Worker // https://github.com/env-logger-rs/env_logger/issues/208
297*bb4ee6a4SAndroid Build Coastguard Worker builder.is_test(true);
298*bb4ee6a4SAndroid Build Coastguard Worker
299*bb4ee6a4SAndroid Build Coastguard Worker if let Some(format) = cfg.pipe_formatter {
300*bb4ee6a4SAndroid Build Coastguard Worker builder.format(format);
301*bb4ee6a4SAndroid Build Coastguard Worker }
302*bb4ee6a4SAndroid Build Coastguard Worker loggers.push(Box::new(builder.build()));
303*bb4ee6a4SAndroid Build Coastguard Worker }
304*bb4ee6a4SAndroid Build Coastguard Worker
305*bb4ee6a4SAndroid Build Coastguard Worker if cfg.log_args.syslog {
306*bb4ee6a4SAndroid Build Coastguard Worker match PlatformSyslog::new(cfg.log_args.proc_name, cfg.log_args.syslog_facility) {
307*bb4ee6a4SAndroid Build Coastguard Worker Ok((mut logger, fd)) => {
308*bb4ee6a4SAndroid Build Coastguard Worker if let Some(fd) = fd {
309*bb4ee6a4SAndroid Build Coastguard Worker descriptors.push(fd);
310*bb4ee6a4SAndroid Build Coastguard Worker }
311*bb4ee6a4SAndroid Build Coastguard Worker if let Some(logger) = logger.take() {
312*bb4ee6a4SAndroid Build Coastguard Worker loggers.push(logger);
313*bb4ee6a4SAndroid Build Coastguard Worker }
314*bb4ee6a4SAndroid Build Coastguard Worker }
315*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
316*bb4ee6a4SAndroid Build Coastguard Worker // The default log configuration used in early_init() enables syslog, so we
317*bb4ee6a4SAndroid Build Coastguard Worker // don't want to terminate the program if syslog can't be initialized. Warn the
318*bb4ee6a4SAndroid Build Coastguard Worker // user but continue running.
319*bb4ee6a4SAndroid Build Coastguard Worker eprintln!("syslog init failed: {}", e);
320*bb4ee6a4SAndroid Build Coastguard Worker }
321*bb4ee6a4SAndroid Build Coastguard Worker }
322*bb4ee6a4SAndroid Build Coastguard Worker }
323*bb4ee6a4SAndroid Build Coastguard Worker
324*bb4ee6a4SAndroid Build Coastguard Worker Ok(State {
325*bb4ee6a4SAndroid Build Coastguard Worker filter,
326*bb4ee6a4SAndroid Build Coastguard Worker loggers,
327*bb4ee6a4SAndroid Build Coastguard Worker descriptors,
328*bb4ee6a4SAndroid Build Coastguard Worker early_init: false,
329*bb4ee6a4SAndroid Build Coastguard Worker })
330*bb4ee6a4SAndroid Build Coastguard Worker }
331*bb4ee6a4SAndroid Build Coastguard Worker }
332*bb4ee6a4SAndroid Build Coastguard Worker
333*bb4ee6a4SAndroid Build Coastguard Worker impl Default for State {
default() -> Self334*bb4ee6a4SAndroid Build Coastguard Worker fn default() -> Self {
335*bb4ee6a4SAndroid Build Coastguard Worker Self::new(Default::default()).unwrap()
336*bb4ee6a4SAndroid Build Coastguard Worker }
337*bb4ee6a4SAndroid Build Coastguard Worker }
338*bb4ee6a4SAndroid Build Coastguard Worker
339*bb4ee6a4SAndroid Build Coastguard Worker static STATE: Lazy<Mutex<State>> = Lazy::new(|| {
340*bb4ee6a4SAndroid Build Coastguard Worker let mut state = State::new(LogConfig::default()).expect("failed to configure minimal logging");
341*bb4ee6a4SAndroid Build Coastguard Worker state.early_init = true;
342*bb4ee6a4SAndroid Build Coastguard Worker Mutex::new(state)
343*bb4ee6a4SAndroid Build Coastguard Worker });
344*bb4ee6a4SAndroid Build Coastguard Worker static LOGGING_FACADE: LoggingFacade = LoggingFacade {};
345*bb4ee6a4SAndroid Build Coastguard Worker static EARLY_INIT_CALLED: Mutex<bool> = Mutex::new(false);
346*bb4ee6a4SAndroid Build Coastguard Worker
347*bb4ee6a4SAndroid Build Coastguard Worker /// Initialize the syslog connection and internal variables.
348*bb4ee6a4SAndroid Build Coastguard Worker ///
349*bb4ee6a4SAndroid Build Coastguard Worker /// This should only be called once per process before any other threads have been spawned or any
350*bb4ee6a4SAndroid Build Coastguard Worker /// signal handlers have been registered. Every call made after the first will panic.
351*bb4ee6a4SAndroid Build Coastguard Worker ///
352*bb4ee6a4SAndroid Build Coastguard Worker /// Use `init_with_filter` to initialize with filtering
init() -> Result<(), Error>353*bb4ee6a4SAndroid Build Coastguard Worker pub fn init() -> Result<(), Error> {
354*bb4ee6a4SAndroid Build Coastguard Worker init_with(Default::default())
355*bb4ee6a4SAndroid Build Coastguard Worker }
356*bb4ee6a4SAndroid Build Coastguard Worker
357*bb4ee6a4SAndroid Build Coastguard Worker /// Initialize the syslog connection and internal variables.
358*bb4ee6a4SAndroid Build Coastguard Worker ///
359*bb4ee6a4SAndroid Build Coastguard Worker /// This should only be called once per process before any other threads have been spawned or any
360*bb4ee6a4SAndroid Build Coastguard Worker /// signal handlers have been registered. Every call made after the first will
361*bb4ee6a4SAndroid Build Coastguard Worker /// panic.
362*bb4ee6a4SAndroid Build Coastguard Worker ///
363*bb4ee6a4SAndroid Build Coastguard Worker /// Arguments:
364*bb4ee6a4SAndroid Build Coastguard Worker /// * filter: See <https://docs.rs/env_logger/0.9/env_logger/index.html> for example filter
365*bb4ee6a4SAndroid Build Coastguard Worker /// specifications
366*bb4ee6a4SAndroid Build Coastguard Worker /// * stderr: If set will output to stderr (in addition)
367*bb4ee6a4SAndroid Build Coastguard Worker /// * file: If set will output to this file (in addition)
368*bb4ee6a4SAndroid Build Coastguard Worker /// * proc_name: proc name for Syslog implementation
369*bb4ee6a4SAndroid Build Coastguard Worker /// * syslog_facility: syslog facility
370*bb4ee6a4SAndroid Build Coastguard Worker /// * file_formatter: custom formatter for file output. See env_logger docs
init_with(cfg: LogConfig) -> Result<(), Error>371*bb4ee6a4SAndroid Build Coastguard Worker pub fn init_with(cfg: LogConfig) -> Result<(), Error> {
372*bb4ee6a4SAndroid Build Coastguard Worker let mut state = STATE.lock();
373*bb4ee6a4SAndroid Build Coastguard Worker if !state.early_init {
374*bb4ee6a4SAndroid Build Coastguard Worker panic!("double-init of the logging system is not permitted.");
375*bb4ee6a4SAndroid Build Coastguard Worker }
376*bb4ee6a4SAndroid Build Coastguard Worker *state = State::new(cfg)?;
377*bb4ee6a4SAndroid Build Coastguard Worker
378*bb4ee6a4SAndroid Build Coastguard Worker // This has no effect if the logging facade was already set.
379*bb4ee6a4SAndroid Build Coastguard Worker apply_logging_state(&LOGGING_FACADE);
380*bb4ee6a4SAndroid Build Coastguard Worker
381*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
382*bb4ee6a4SAndroid Build Coastguard Worker }
383*bb4ee6a4SAndroid Build Coastguard Worker
384*bb4ee6a4SAndroid Build Coastguard Worker /// Performs early (as in, moment of process start) logging initialization. Any logging prior to
385*bb4ee6a4SAndroid Build Coastguard Worker /// this call will be SILENTLY discarded. Calling more than once per process will panic.
early_init()386*bb4ee6a4SAndroid Build Coastguard Worker pub fn early_init() {
387*bb4ee6a4SAndroid Build Coastguard Worker let mut early_init_called = EARLY_INIT_CALLED.lock();
388*bb4ee6a4SAndroid Build Coastguard Worker if !*early_init_called {
389*bb4ee6a4SAndroid Build Coastguard Worker apply_logging_state(&LOGGING_FACADE);
390*bb4ee6a4SAndroid Build Coastguard Worker *early_init_called = true;
391*bb4ee6a4SAndroid Build Coastguard Worker } else {
392*bb4ee6a4SAndroid Build Coastguard Worker panic!("double early init of the logging system is not permitted.");
393*bb4ee6a4SAndroid Build Coastguard Worker }
394*bb4ee6a4SAndroid Build Coastguard Worker }
395*bb4ee6a4SAndroid Build Coastguard Worker
396*bb4ee6a4SAndroid Build Coastguard Worker /// Test only function that ensures logging has been configured. Since tests
397*bb4ee6a4SAndroid Build Coastguard Worker /// share module state, we need a way to make sure it has been initialized
398*bb4ee6a4SAndroid Build Coastguard Worker /// with *some* configuration.
test_only_ensure_inited() -> Result<(), Error>399*bb4ee6a4SAndroid Build Coastguard Worker pub fn test_only_ensure_inited() -> Result<(), Error> {
400*bb4ee6a4SAndroid Build Coastguard Worker let mut early_init_called = EARLY_INIT_CALLED.lock();
401*bb4ee6a4SAndroid Build Coastguard Worker if !*early_init_called {
402*bb4ee6a4SAndroid Build Coastguard Worker apply_logging_state(&LOGGING_FACADE);
403*bb4ee6a4SAndroid Build Coastguard Worker *early_init_called = true;
404*bb4ee6a4SAndroid Build Coastguard Worker }
405*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
406*bb4ee6a4SAndroid Build Coastguard Worker }
407*bb4ee6a4SAndroid Build Coastguard Worker
apply_logging_state(facade: &'static LoggingFacade)408*bb4ee6a4SAndroid Build Coastguard Worker fn apply_logging_state(facade: &'static LoggingFacade) {
409*bb4ee6a4SAndroid Build Coastguard Worker let _ = log::set_logger(facade);
410*bb4ee6a4SAndroid Build Coastguard Worker log::set_max_level(log::LevelFilter::Trace);
411*bb4ee6a4SAndroid Build Coastguard Worker }
412*bb4ee6a4SAndroid Build Coastguard Worker
413*bb4ee6a4SAndroid Build Coastguard Worker /// Retrieves the file descriptors owned by the global syslogger.
414*bb4ee6a4SAndroid Build Coastguard Worker ///
415*bb4ee6a4SAndroid Build Coastguard Worker /// Does nothing if syslog was never initialized. If their are any file descriptors, they will be
416*bb4ee6a4SAndroid Build Coastguard Worker /// pushed into `fds`.
417*bb4ee6a4SAndroid Build Coastguard Worker ///
418*bb4ee6a4SAndroid Build Coastguard Worker /// Note that the `stderr` file descriptor is never added, as it is not owned by syslog.
push_descriptors(fds: &mut Vec<RawDescriptor>)419*bb4ee6a4SAndroid Build Coastguard Worker pub fn push_descriptors(fds: &mut Vec<RawDescriptor>) {
420*bb4ee6a4SAndroid Build Coastguard Worker let state = STATE.lock();
421*bb4ee6a4SAndroid Build Coastguard Worker fds.extend(state.descriptors.iter());
422*bb4ee6a4SAndroid Build Coastguard Worker }
423*bb4ee6a4SAndroid Build Coastguard Worker
424*bb4ee6a4SAndroid Build Coastguard Worker impl Log for State {
enabled(&self, metadata: &log::Metadata) -> bool425*bb4ee6a4SAndroid Build Coastguard Worker fn enabled(&self, metadata: &log::Metadata) -> bool {
426*bb4ee6a4SAndroid Build Coastguard Worker self.filter.enabled(metadata)
427*bb4ee6a4SAndroid Build Coastguard Worker }
428*bb4ee6a4SAndroid Build Coastguard Worker
log(&self, record: &log::Record)429*bb4ee6a4SAndroid Build Coastguard Worker fn log(&self, record: &log::Record) {
430*bb4ee6a4SAndroid Build Coastguard Worker if self.filter.matches(record) {
431*bb4ee6a4SAndroid Build Coastguard Worker for logger in self.loggers.iter() {
432*bb4ee6a4SAndroid Build Coastguard Worker logger.log(record)
433*bb4ee6a4SAndroid Build Coastguard Worker }
434*bb4ee6a4SAndroid Build Coastguard Worker }
435*bb4ee6a4SAndroid Build Coastguard Worker }
436*bb4ee6a4SAndroid Build Coastguard Worker
flush(&self)437*bb4ee6a4SAndroid Build Coastguard Worker fn flush(&self) {
438*bb4ee6a4SAndroid Build Coastguard Worker for logger in self.loggers.iter() {
439*bb4ee6a4SAndroid Build Coastguard Worker logger.flush()
440*bb4ee6a4SAndroid Build Coastguard Worker }
441*bb4ee6a4SAndroid Build Coastguard Worker }
442*bb4ee6a4SAndroid Build Coastguard Worker }
443*bb4ee6a4SAndroid Build Coastguard Worker
444*bb4ee6a4SAndroid Build Coastguard Worker // Struct that implements io::Write to be used for writing directly to the syslog
445*bb4ee6a4SAndroid Build Coastguard Worker pub struct Syslogger<'a> {
446*bb4ee6a4SAndroid Build Coastguard Worker buf: Vec<u8>,
447*bb4ee6a4SAndroid Build Coastguard Worker level: log::Level,
448*bb4ee6a4SAndroid Build Coastguard Worker get_state_fn: Box<dyn Fn() -> MutexGuard<'a, State> + Send + 'a>,
449*bb4ee6a4SAndroid Build Coastguard Worker }
450*bb4ee6a4SAndroid Build Coastguard Worker
451*bb4ee6a4SAndroid Build Coastguard Worker impl<'a> Syslogger<'a> {
new(level: log::Level) -> Syslogger<'a>452*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(level: log::Level) -> Syslogger<'a> {
453*bb4ee6a4SAndroid Build Coastguard Worker Syslogger {
454*bb4ee6a4SAndroid Build Coastguard Worker buf: Vec::new(),
455*bb4ee6a4SAndroid Build Coastguard Worker level,
456*bb4ee6a4SAndroid Build Coastguard Worker get_state_fn: Box::new(|| STATE.lock()),
457*bb4ee6a4SAndroid Build Coastguard Worker }
458*bb4ee6a4SAndroid Build Coastguard Worker }
test_only_from_state<F: 'a + Fn() -> MutexGuard<'a, State> + Send>( level: log::Level, get_state_fn: F, ) -> Syslogger<'a>459*bb4ee6a4SAndroid Build Coastguard Worker pub fn test_only_from_state<F: 'a + Fn() -> MutexGuard<'a, State> + Send>(
460*bb4ee6a4SAndroid Build Coastguard Worker level: log::Level,
461*bb4ee6a4SAndroid Build Coastguard Worker get_state_fn: F,
462*bb4ee6a4SAndroid Build Coastguard Worker ) -> Syslogger<'a> {
463*bb4ee6a4SAndroid Build Coastguard Worker Syslogger {
464*bb4ee6a4SAndroid Build Coastguard Worker buf: Vec::new(),
465*bb4ee6a4SAndroid Build Coastguard Worker level,
466*bb4ee6a4SAndroid Build Coastguard Worker get_state_fn: Box::new(get_state_fn),
467*bb4ee6a4SAndroid Build Coastguard Worker }
468*bb4ee6a4SAndroid Build Coastguard Worker }
469*bb4ee6a4SAndroid Build Coastguard Worker }
470*bb4ee6a4SAndroid Build Coastguard Worker
471*bb4ee6a4SAndroid Build Coastguard Worker impl<'a> io::Write for Syslogger<'a> {
write(&mut self, buf: &[u8]) -> io::Result<usize>472*bb4ee6a4SAndroid Build Coastguard Worker fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
473*bb4ee6a4SAndroid Build Coastguard Worker let state = (self.get_state_fn)();
474*bb4ee6a4SAndroid Build Coastguard Worker self.buf.extend_from_slice(buf);
475*bb4ee6a4SAndroid Build Coastguard Worker
476*bb4ee6a4SAndroid Build Coastguard Worker if let Some(last_newline_idx) = self.buf.iter().rposition(|&x| x == b'\n') {
477*bb4ee6a4SAndroid Build Coastguard Worker for line in (self.buf[..last_newline_idx]).split(|&x| x == b'\n') {
478*bb4ee6a4SAndroid Build Coastguard Worker // Also drop CR+LF line endings.
479*bb4ee6a4SAndroid Build Coastguard Worker let send_line = match line.split_last() {
480*bb4ee6a4SAndroid Build Coastguard Worker Some((b'\r', trimmed)) => trimmed,
481*bb4ee6a4SAndroid Build Coastguard Worker _ => line,
482*bb4ee6a4SAndroid Build Coastguard Worker };
483*bb4ee6a4SAndroid Build Coastguard Worker // Match is to explicitly limit lifetime of args
484*bb4ee6a4SAndroid Build Coastguard Worker // https://github.com/rust-lang/rust/issues/92698
485*bb4ee6a4SAndroid Build Coastguard Worker // https://github.com/rust-lang/rust/issues/15023
486*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::match_single_binding)]
487*bb4ee6a4SAndroid Build Coastguard Worker match format_args!("{}", String::from_utf8_lossy(send_line)) {
488*bb4ee6a4SAndroid Build Coastguard Worker args => {
489*bb4ee6a4SAndroid Build Coastguard Worker let mut record_builder = log::Record::builder();
490*bb4ee6a4SAndroid Build Coastguard Worker record_builder.level(self.level);
491*bb4ee6a4SAndroid Build Coastguard Worker record_builder.target("syslogger");
492*bb4ee6a4SAndroid Build Coastguard Worker record_builder.args(args);
493*bb4ee6a4SAndroid Build Coastguard Worker let record = record_builder.build();
494*bb4ee6a4SAndroid Build Coastguard Worker state.log(&record);
495*bb4ee6a4SAndroid Build Coastguard Worker }
496*bb4ee6a4SAndroid Build Coastguard Worker }
497*bb4ee6a4SAndroid Build Coastguard Worker }
498*bb4ee6a4SAndroid Build Coastguard Worker
499*bb4ee6a4SAndroid Build Coastguard Worker self.buf.drain(..=last_newline_idx);
500*bb4ee6a4SAndroid Build Coastguard Worker }
501*bb4ee6a4SAndroid Build Coastguard Worker Ok(buf.len())
502*bb4ee6a4SAndroid Build Coastguard Worker }
503*bb4ee6a4SAndroid Build Coastguard Worker
flush(&mut self) -> io::Result<()>504*bb4ee6a4SAndroid Build Coastguard Worker fn flush(&mut self) -> io::Result<()> {
505*bb4ee6a4SAndroid Build Coastguard Worker STATE.lock().flush();
506*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
507*bb4ee6a4SAndroid Build Coastguard Worker }
508*bb4ee6a4SAndroid Build Coastguard Worker }
509