1use std::{
2    cell::RefCell,
3    cmp, env,
4    fmt::Arguments,
5    fs::{File, OpenOptions},
6    io::{Error as IoError, ErrorKind as IoErrorKind, Stdout, Write, stdout},
7    net::{SocketAddr, TcpStream, UdpSocket},
8    ops::{Deref, DerefMut},
9    path::Path,
10    str::FromStr,
11};
12
13use mio::net::UnixDatagram;
14use prost::{Message, encoding::encoded_len_varint};
15
16use crate::{
17    AsString,
18    config::{Config, DEFAULT_LOG_TARGET},
19    logging::{LogDuration, LogError, LogMessage, RequestRecord},
20    proto::command::ProtobufAccessLogFormat,
21    writer::MultiLineWriter,
22};
23
24thread_local! {
25  pub static LOGGER: RefCell<Logger> = RefCell::new(Logger::new());
26}
27
28pub static COMPAT_LOGGER: CompatLogger = CompatLogger;
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
34#[serde(deny_unknown_fields, rename_all = "lowercase")]
35pub enum AccessLogFormat {
36    Ascii,
37    Protobuf,
38}
39
40impl From<&ProtobufAccessLogFormat> for AccessLogFormat {
41    fn from(value: &ProtobufAccessLogFormat) -> Self {
42        match value {
43            ProtobufAccessLogFormat::Ascii => Self::Ascii,
44            ProtobufAccessLogFormat::Protobuf => Self::Protobuf,
45        }
46    }
47}
48
49impl From<&Option<AccessLogFormat>> for ProtobufAccessLogFormat {
50    fn from(value: &Option<AccessLogFormat>) -> Self {
51        match value {
52            Some(AccessLogFormat::Ascii) | None => Self::Ascii,
53            Some(AccessLogFormat::Protobuf) => Self::Protobuf,
54        }
55    }
56}
57
58pub struct InnerLogger {
59    directives: Vec<LogDirective>,
60    backend: LoggerBackend,
61    log_target: String,
63    pub colored: bool,
64    access_backend: Option<LoggerBackend>,
66    access_logs_target: Option<String>,
68    access_format: AccessLogFormat,
70    access_colored: bool,
71    buffer: LoggerBuffer,
72}
73
74pub struct Logger {
75    inner: InnerLogger,
76    tag: String,
78    pid: i32,
80    initialized: bool,
81}
82
83impl std::ops::Deref for Logger {
84    type Target = InnerLogger;
85    fn deref(&self) -> &Self::Target {
86        &self.inner
87    }
88}
89impl std::ops::DerefMut for Logger {
90    fn deref_mut(&mut self) -> &mut Self::Target {
91        &mut self.inner
92    }
93}
94
95impl Default for Logger {
96    fn default() -> Self {
97        Self {
98            inner: InnerLogger {
99                directives: vec![LogDirective {
100                    name: None,
101                    level: LogLevelFilter::Error,
102                }],
103                backend: LoggerBackend::Stdout(stdout()),
104                log_target: DEFAULT_LOG_TARGET.to_string(),
105                colored: false,
106                access_backend: None,
107                access_logs_target: None,
108                access_format: AccessLogFormat::Ascii,
109                access_colored: false,
110                buffer: LoggerBuffer(Vec::with_capacity(4096)),
111            },
112            tag: "UNINITIALIZED".to_string(),
113            pid: 0,
114            initialized: false,
115        }
116    }
117}
118
119impl Logger {
120    pub fn new() -> Self {
121        Self::default()
122    }
123
124    pub fn init(
125        tag: String,
126        spec: &str,
127        log_target: &str,
128        colored: bool,
129        access_logs_target: Option<&str>,
130        access_format: Option<AccessLogFormat>,
131        access_colored: Option<bool>,
132    ) -> Result<(), LogError> {
133        println!("Logs will be sent to {log_target}");
134        let backend = target_or_default(log_target);
135
136        println!("Access logs will be sent to {access_logs_target:?}");
137        let access_backend = access_logs_target.map(target_to_backend).transpose()?;
138
139        let (directives, _errors) = parse_logging_spec(spec);
140        LOGGER.with(|logger| {
141            let mut logger = logger.borrow_mut();
142            if !logger.initialized {
143                logger.set_directives(directives);
144                logger.colored = match backend {
145                    LoggerBackend::Stdout(_) => colored,
146                    _ => false,
147                };
148                logger.access_colored = match (&access_backend, &backend) {
149                    (Some(LoggerBackend::Stdout(_)), _) | (None, LoggerBackend::Stdout(_)) => {
150                        access_colored.unwrap_or(colored)
151                    }
152                    _ => false,
153                };
154                logger.backend = backend;
155                logger.log_target = log_target.to_owned();
156                logger.access_backend = access_backend;
157                logger.access_logs_target = access_logs_target.map(ToOwned::to_owned);
158                logger.access_format = access_format.unwrap_or(AccessLogFormat::Ascii);
159                logger.tag = tag;
160                logger.pid = unsafe { libc::getpid() };
161                logger.initialized = true;
162
163                let _ = log::set_logger(&COMPAT_LOGGER)
164                    .map_err(|e| println!("could not register compat logger: {e:?}"));
165
166                log::set_max_level(log::LevelFilter::Info);
167            }
168        });
169        Ok(())
170    }
171
172    pub fn set_directives(&mut self, directives: Vec<LogDirective>) {
173        self.directives = directives;
174    }
175
176    pub fn split(&mut self) -> (i32, &str, &mut InnerLogger) {
177        (self.pid, &self.tag, &mut self.inner)
178    }
179}
180
181struct LoggerBuffer(Vec<u8>);
182
183impl Deref for LoggerBuffer {
184    type Target = Vec<u8>;
185    fn deref(&self) -> &Self::Target {
186        &self.0
187    }
188}
189impl DerefMut for LoggerBuffer {
190    fn deref_mut(&mut self) -> &mut Self::Target {
191        &mut self.0
192    }
193}
194
195impl LoggerBuffer {
196    fn fmt<F: FnOnce(&[u8]) -> Result<usize, IoError>>(
197        &mut self,
198        args: Arguments,
199        flush: F,
200    ) -> Result<(), IoError> {
201        self.clear();
202        self.write_fmt(args)?;
203        flush(self.as_slice())?;
204        Ok(())
205    }
206}
207
208fn log_arguments(
209    args: Arguments,
210    backend: &mut LoggerBackend,
211    buffer: &mut LoggerBuffer,
212) -> Result<(), IoError> {
213    match backend {
214        LoggerBackend::Stdout(stdout) => {
215            let _ = stdout.write_fmt(args);
216            Ok(())
217        }
218        LoggerBackend::Tcp(socket) => socket.write_fmt(args),
219        LoggerBackend::File(file) => file.write_fmt(args),
220        LoggerBackend::Unix(socket) => buffer.fmt(args, |bytes| socket.send(bytes)),
221        LoggerBackend::Udp(sock, addr) => buffer.fmt(args, |b| sock.send_to(b, *addr)),
222    }
223}
224
225impl InnerLogger {
226    pub fn log(&mut self, args: Arguments) {
227        if let Err(e) = log_arguments(args, &mut self.backend, &mut self.buffer) {
228            println!("Could not write log to {}: {e:?}", self.backend.as_ref());
229        }
230    }
231
232    pub fn log_access(&mut self, log: RequestRecord) -> bool {
236        let backend = self.access_backend.as_mut().unwrap_or(&mut self.backend);
237
238        let io_result = match self.access_format {
239            AccessLogFormat::Protobuf => {
240                let binary_log = log.into_binary_access_log();
241                let log_length = binary_log.encoded_len();
242                let total_length = log_length + encoded_len_varint(log_length as u64);
243                self.buffer.clear();
244                let current_capacity = self.buffer.capacity();
245                if current_capacity < total_length {
246                    self.buffer.reserve(total_length - current_capacity);
247                }
248
249                if let Err(e) = binary_log.encode_length_delimited(&mut self.buffer.0) {
250                    Err(IoError::new(IoErrorKind::InvalidData, e))
251                } else {
252                    self.buffer.extend_from_slice(&[0, 0]); let bytes = &self.buffer;
254                    match backend {
255                        LoggerBackend::Stdout(stdout) => {
256                            let _ = stdout.write(bytes);
257                            return true;
258                        }
259                        LoggerBackend::Tcp(socket) => socket.write(bytes),
260                        LoggerBackend::File(file) => file.write(bytes),
261                        LoggerBackend::Unix(socket) => socket.send(bytes),
262                        LoggerBackend::Udp(socket, address) => socket.send_to(bytes, *address),
263                    }
264                    .map(|_| ())
265                }
266            }
267            AccessLogFormat::Ascii => crate::_prompt_log! {
268                logger: |args| log_arguments(args, backend, &mut self.buffer),
269                is_access: true,
270                condition: self.access_colored,
271                prompt: [
272                    log.now,
273                    log.precise_time,
274                    log.pid,
275                    log.level,
276                    log.tag,
277                ],
278                standard: {
279                    formats: ["{} {} {} {}/{}/{}/{}/{} {} {} [{}] {:?} {} {}{}\n"],
280                    args: [
281                        log.context,
282                        log.session_address.as_string_or("-"),
283                        log.backend_address.as_string_or("-"),
284                        LogDuration(Some(log.request_time)),
285                        LogDuration(Some(log.service_time)),
286                        LogDuration(log.response_time),
287                        LogDuration(log.client_rtt),
288                        LogDuration(log.server_rtt),
289                        log.bytes_in,
290                        log.bytes_out,
291                        log.full_tags(),
292                        log.otel,
293                        log.protocol,
294                        log.endpoint,
295                        LogMessage(log.message),
296                    ]
297                },
298                colored: {
299                    formats: ["\x1b[;1m{}\x1b[m {} {} {}/{}/{}/{}/{} {} {} \x1b[2m[{}] {:?} \x1b[;1m{} {:#}\x1b[m{}\n"],
300                    args: @,
301                }
302            },
303        };
304
305        if let Err(e) = io_result {
306            println!("Could not write access log to {}: {e:?}", backend.as_ref());
307            println!(
308                "Trying to revive the backend of access logs to {:?}, or defaulting to {}",
309                self.access_logs_target, self.log_target
310            );
311            let log_target = self.access_logs_target.as_ref().unwrap_or(&self.log_target);
312            if let Err(err) = backend.revive(log_target) {
313                eprintln!("could not revive logger backend: {err}");
314            }
315            false
316        } else {
317            true
318        }
319    }
320
321    pub fn enabled(&self, meta: Metadata) -> bool {
322        for directive in self.directives.iter().rev() {
324            match &directive.name {
325                Some(name) if !meta.target.starts_with(name) => {}
326                Some(_) | None => return meta.level <= directive.level,
327            }
328        }
329        false
330    }
331
332    fn compat_enabled(&self, meta: &log::Metadata) -> bool {
333        for directive in self.directives.iter().rev() {
335            match &directive.name {
336                Some(name) if !meta.target().starts_with(name) => {}
337                Some(_) | None => return LogLevel::from(meta.level()) <= directive.level,
338            }
339        }
340        false
341    }
342}
343
344pub enum LoggerBackend {
345    Stdout(Stdout),
346    Unix(UnixDatagram),
347    Udp(UdpSocket, SocketAddr),
348    Tcp(TcpStream),
349    File(crate::writer::MultiLineWriter<File>),
350}
351
352impl LoggerBackend {
353    fn revive(&mut self, log_target: &str) -> Result<(), LogError> {
354        *self = target_to_backend(log_target)?;
355        Ok(())
356    }
357}
358
359#[repr(usize)]
360#[derive(Clone, Copy, Eq, Debug)]
361pub enum LogLevel {
362    Error = 1, Warn,
370    Info,
374    Debug,
378    Trace,
382}
383
384static LOG_LEVEL_NAMES: [&str; 6] = ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"];
385
386impl PartialEq for LogLevel {
387    #[inline]
388    fn eq(&self, other: &LogLevel) -> bool {
389        *self as usize == *other as usize
390    }
391}
392
393impl PartialEq<LogLevelFilter> for LogLevel {
394    #[inline]
395    fn eq(&self, other: &LogLevelFilter) -> bool {
396        *self as usize == *other as usize
397    }
398}
399
400impl PartialOrd for LogLevel {
401    #[inline]
402    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
403        Some(self.cmp(other))
404    }
405}
406
407impl PartialOrd<LogLevelFilter> for LogLevel {
408    #[inline]
409    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
410        Some((*self as usize).cmp(&(*other as usize)))
411    }
412}
413
414impl Ord for LogLevel {
415    #[inline]
416    fn cmp(&self, other: &LogLevel) -> cmp::Ordering {
417        (*self as usize).cmp(&(*other as usize))
418    }
419}
420
421impl LogLevel {
422    fn from_usize(u: usize) -> Option<LogLevel> {
423        match u {
424            1 => Some(LogLevel::Error),
425            2 => Some(LogLevel::Warn),
426            3 => Some(LogLevel::Info),
427            4 => Some(LogLevel::Debug),
428            5 => Some(LogLevel::Trace),
429            _ => None,
430        }
431    }
432
433    #[inline]
435    pub fn max() -> LogLevel {
436        LogLevel::Trace
437    }
438
439    #[inline]
441    pub fn to_log_level_filter(self) -> LogLevelFilter {
442        LogLevelFilter::from_usize(self as usize).unwrap()
443    }
444}
445
446#[repr(usize)]
447#[derive(Clone, Copy, Eq, Debug)]
448pub enum LogLevelFilter {
449    Off,
450    Error,
451    Warn,
452    Info,
453    Debug,
454    Trace,
455}
456
457impl PartialEq for LogLevelFilter {
458    #[inline]
459    fn eq(&self, other: &LogLevelFilter) -> bool {
460        *self as usize == *other as usize
461    }
462}
463
464impl PartialEq<LogLevel> for LogLevelFilter {
465    #[inline]
466    fn eq(&self, other: &LogLevel) -> bool {
467        other.eq(self)
468    }
469}
470
471impl PartialOrd for LogLevelFilter {
472    #[inline]
473    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
474        Some(self.cmp(other))
475    }
476}
477
478impl PartialOrd<LogLevel> for LogLevelFilter {
479    #[inline]
480    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
481        other.partial_cmp(self).map(|x| x.reverse())
482    }
483}
484
485impl Ord for LogLevelFilter {
486    #[inline]
487    fn cmp(&self, other: &LogLevelFilter) -> cmp::Ordering {
488        (*self as usize).cmp(&(*other as usize))
489    }
490}
491
492impl FromStr for LogLevelFilter {
493    type Err = ();
494    fn from_str(level: &str) -> Result<LogLevelFilter, ()> {
495        LOG_LEVEL_NAMES
496            .iter()
497            .position(|&name| name.eq_ignore_ascii_case(level))
498            .map(|p| LogLevelFilter::from_usize(p).unwrap())
499            .ok_or(())
500    }
501}
502
503impl LogLevelFilter {
504    fn from_usize(u: usize) -> Option<LogLevelFilter> {
505        match u {
506            0 => Some(LogLevelFilter::Off),
507            1 => Some(LogLevelFilter::Error),
508            2 => Some(LogLevelFilter::Warn),
509            3 => Some(LogLevelFilter::Info),
510            4 => Some(LogLevelFilter::Debug),
511            5 => Some(LogLevelFilter::Trace),
512            _ => None,
513        }
514    }
515    #[inline]
517    pub fn max() -> LogLevelFilter {
518        LogLevelFilter::Trace
519    }
520
521    #[inline]
525    pub fn to_log_level(self) -> Option<LogLevel> {
526        LogLevel::from_usize(self as usize)
527    }
528}
529
530#[derive(Debug)]
532pub struct Metadata {
533    pub level: LogLevel,
534    pub target: &'static str,
535}
536
537#[derive(Debug)]
538pub struct LogDirective {
539    name: Option<String>,
540    level: LogLevelFilter,
541}
542
543#[derive(thiserror::Error, Debug)]
544pub enum LogSpecParseError {
545    #[error("Too many '/'s: {0}")]
546    TooManySlashes(String),
547    #[error("Too many '='s: {0}")]
548    TooManyEquals(String),
549    #[error("Invalid log level: {0}")]
550    InvalidLogLevel(String),
551}
552
553pub fn parse_logging_spec(spec: &str) -> (Vec<LogDirective>, Vec<LogSpecParseError>) {
554    let mut dirs = Vec::new();
555    let mut errors = Vec::new();
556
557    let mut parts = spec.split('/');
558    let mods = parts.next();
559    let _ = parts.next();
560    if parts.next().is_some() {
561        errors.push(LogSpecParseError::TooManySlashes(spec.to_string()));
562    }
563    if let Some(m) = mods {
564        for s in m.split(',') {
565            if s.is_empty() {
566                continue;
567            }
568            let mut parts = s.split('=');
569            let (log_level, name) =
570                match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
571                    (Some(part0), None, None) => {
572                        match part0.parse() {
575                            Ok(num) => (num, None),
576                            Err(_) => {
577                                errors.push(LogSpecParseError::InvalidLogLevel(s.to_string()));
578                                (LogLevelFilter::max(), None)
579                            }
580                        }
581                    }
582                    (Some(part0), Some(""), None) => (LogLevelFilter::max(), Some(part0)),
583                    (Some(part0), Some(part1), None) => match part1.parse() {
584                        Ok(num) => (num, Some(part0)),
585                        Err(_) => {
586                            errors.push(LogSpecParseError::InvalidLogLevel(s.to_string()));
587                            continue;
588                        }
589                    },
590                    _ => {
591                        errors.push(LogSpecParseError::TooManyEquals(s.to_string()));
592                        continue;
593                    }
594                };
595            dirs.push(LogDirective {
596                name: name.map(|s| s.to_string()),
597                level: log_level,
598            });
599        }
600    }
601
602    for error in &errors {
603        println!("{error:?}");
604    }
605    (dirs, errors)
606}
607
608pub fn setup_default_logging(
610    log_colored: bool,
611    log_level: &str,
612    tag: &str,
613) -> Result<(), LogError> {
614    setup_logging("stdout", log_colored, None, None, None, log_level, tag)
615}
616
617pub fn setup_logging_with_config(config: &Config, tag: &str) -> Result<(), LogError> {
619    setup_logging(
620        &config.log_target,
621        config.log_colored,
622        config.access_logs_target.as_deref(),
623        config.access_logs_format.clone(),
624        config.access_logs_colored,
625        &config.log_level,
626        tag,
627    )
628}
629
630pub fn setup_logging(
635    log_target: &str,
636    log_colored: bool,
637    access_logs_target: Option<&str>,
638    access_logs_format: Option<AccessLogFormat>,
639    access_logs_colored: Option<bool>,
640    log_level: &str,
641    tag: &str,
642) -> Result<(), LogError> {
643    Logger::init(
644        tag.to_string(),
645        env::var("RUST_LOG").as_deref().unwrap_or(log_level),
646        log_target,
647        log_colored,
648        access_logs_target,
649        access_logs_format,
650        access_logs_colored,
651    )
652}
653
654fn target_or_default(target: &str) -> LoggerBackend {
656    match target_to_backend(target) {
657        Ok(backend) => backend,
658        Err(target_error) => {
659            eprintln!("{target_error}, defaulting to stdout");
660            LoggerBackend::Stdout(stdout())
661        }
662    }
663}
664
665pub fn target_to_backend(target: &str) -> Result<LoggerBackend, LogError> {
666    if target == "stdout" {
667        return Ok(LoggerBackend::Stdout(stdout()));
668    }
669
670    if let Some(addr) = target.strip_prefix("udp://") {
671        let address = addr
672            .parse::<SocketAddr>()
673            .map_err(|e| LogError::InvalidSocketAddress(target.to_owned(), e))?;
674
675        let socket = UdpSocket::bind(("0.0.0.0", 0)).map_err(LogError::UdpBind)?;
676
677        return Ok(LoggerBackend::Udp(socket, address));
678    }
679
680    if let Some(addr) = target.strip_prefix("tcp://") {
681        let tcp_stream =
682            TcpStream::connect(addr).map_err(|e| LogError::TcpConnect(target.to_owned(), e))?;
683
684        return Ok(LoggerBackend::Tcp(tcp_stream));
685    }
686
687    if let Some(addr) = target.strip_prefix("unix://") {
688        let socket = UnixDatagram::unbound().map_err(LogError::CreateUnixSocket)?;
689
690        socket
691            .connect(addr)
692            .map_err(|e| LogError::ConnectToUnixSocket(target.to_owned(), e))?;
693
694        return Ok(LoggerBackend::Unix(socket));
695    }
696
697    if let Some(addr) = target.strip_prefix("file://") {
698        let path = Path::new(addr);
699        let file = OpenOptions::new()
700            .create(true)
701            .append(true)
702            .open(path)
703            .map_err(|e| LogError::OpenFile(target.to_owned(), e))?;
704
705        return Ok(LoggerBackend::File(MultiLineWriter::new(file)));
706    }
707
708    Err(LogError::InvalidLogTarget(
709        target.to_owned(),
710        "Log target is not parseable",
711    ))
712}
713
714#[macro_export]
715macro_rules! _prompt_log {
716    {
717        logger: $logger:expr,
718        is_access: $access:expr,
719        condition: $cond:expr,
720        prompt: [$($p:tt)*],
721        standard: {$($std:tt)*}$(,)?
722    } => {
723        $crate::_prompt_log!{
724            logger: $logger,
725            is_access: $access,
726            condition: $cond,
727            prompt: [$($p)*],
728            standard: {$($std)*},
729            colored: {$($std)*},
730        }
731    };
732    {
733        logger: $logger:expr,
734        is_access: $access:expr,
735        condition: $cond:expr,
736        prompt: [$($p:tt)*],
737        standard: {
738            formats: [$($std_fmt:tt)*],
739            args: [$($std_args:expr),*$(,)?]$(,)?
740        },
741        colored: {
742            formats: [$($col_fmt:tt)*],
743            args: @$(,)?
744        }$(,)?
745    } => {
746        $crate::_prompt_log!{
747            logger: $logger,
748            is_access: $access,
749            condition: $cond,
750            prompt: [$($p)*],
751            standard: {
752                formats: [$($std_fmt)*],
753                args: [$($std_args),*],
754            },
755            colored: {
756                formats: [$($col_fmt)*],
757                args: [$($std_args),*],
758            },
759        }
760    };
761    {
762        logger: $logger:expr,
763        is_access: $access:expr,
764        condition: $cond:expr,
765        prompt: [$now:expr, $precise_time:expr, $pid:expr, $lvl:expr, $tag:expr$(,)?],
766        standard: {
767            formats: [$($std_fmt:tt)*],
768            args: [$($std_args:expr),*$(,)?]$(,)?
769        },
770        colored: {
771            formats: [$($col_fmt:tt)*],
772            args: [$($col_args:expr),*$(,)?]$(,)?
773        }$(,)?
774    } => {
775        if $cond {
776            $crate::_prompt_log!(@bind [$logger, concat!("{} \x1b[2m{} \x1b[;2;1m{} {} \x1b[0;1m{}\x1b[m\t", $($col_fmt)*)] [$now, $precise_time, $pid, $lvl.as_str($access, true), $tag] $($col_args),*)
777        } else {
778            $crate::_prompt_log!(@bind [$logger, concat!("{} {} {} {} {}\t", $($std_fmt)*)] [$now, $precise_time, $pid, $lvl.as_str($access, false), $tag] $($std_args),*)
779        }
780    };
781    (@bind [$logger:expr, $fmt:expr] [$($bindings:expr),*] $arg:expr $(, $args:expr)*) => {{
782        let binding = &$arg;
783        $crate::_prompt_log!(@bind [$logger, $fmt] [$($bindings),* , binding] $($args),*)
784    }};
785    (@bind [$logger:expr, $fmt:expr] [$($bindings:expr),*]) => {
786        $logger(format_args!($fmt, $($bindings),*))
787    };
788}
789
790#[derive(Clone, Copy, Debug)]
791pub struct LogLineCachedState(u8);
792const LOG_LINE_ENABLED: u8 = 1 << 7;
793
794impl Default for LogLineCachedState {
795    fn default() -> Self {
796        Self::new()
797    }
798}
799
800impl LogLineCachedState {
801    pub const fn new() -> Self {
802        Self(0)
803    }
804    #[inline(always)]
805    pub fn version(&self) -> u8 {
806        self.0 & !LOG_LINE_ENABLED
807    }
808    #[inline(always)]
809    pub fn enabled(&self) -> bool {
810        self.0 & LOG_LINE_ENABLED != 0
811    }
812    #[inline(always)]
813    pub fn set(&mut self, version: u8, enabled: bool) {
814        self.0 = version;
815        if enabled {
816            self.0 |= LOG_LINE_ENABLED
817        }
818    }
819}
820
821#[macro_export]
822macro_rules! _log_enabled {
823    ($logger:expr, $lvl:expr) => {{
824        let logger = $logger.borrow_mut();
825        if !logger.enabled($crate::logging::Metadata {
826            level: $lvl,
827            target: module_path!(),
828        }) {
829            return;
830        }
831        logger
832    }};
833}
834
835#[macro_export]
836macro_rules! _log {
837    ($lvl:expr, $format:expr $(, $args:expr)*) => {{
838        $crate::logging::LOGGER.with(|logger| {
839            let mut logger = $crate::_log_enabled!(logger, $lvl);
840            let (pid, tag, inner) = logger.split();
841            let (now, precise_time) = $crate::logging::now();
842
843            $crate::_prompt_log!{
844                logger: |args| inner.log(args),
845                is_access: false,
846                condition: inner.colored,
847                prompt: [now, precise_time, pid, $lvl, tag],
848                standard: {
849                    formats: [$format, '\n'],
850                    args: [$($args),*]
851                }
852            };
853        })
854    }};
855}
856
857#[macro_export]
858macro_rules! _log_access {
859    ($lvl:expr, $on_failure:block, $($request_record_fields:tt)*) => {{
860         $crate::logging::LOGGER.with(|logger| {
861            let success = {
862                let mut logger = $crate::_log_enabled!(logger, $lvl);
863                let (pid, tag, inner) = logger.split();
864                let (now, precise_time) = $crate::logging::now();
865
866                inner.log_access(
867                    $crate::_structured_access_log!(
868                        [$crate::logging::RequestRecord]
869                        pid, tag, now, precise_time, level: $lvl, $($request_record_fields)*
870                    )
871                )
872            }; if !success {
875                $on_failure
878            }
879        });
880    }};
881}
882
883#[macro_export]
884macro_rules! _structured_access_log {
885    ([$($struct_name:tt)+] $($fields:tt)*) => {{
886        $($struct_name)+ {$(
887            $fields
888        )*}
889    }};
890}
891
892#[macro_export]
893macro_rules! log_access {
895    ($error:expr, on_failure: $on_failure:block, $($request_record_fields:tt)*) => {
896        let lvl = if $error {
897            $crate::logging::LogLevel::Error
898        } else {
899            $crate::logging::LogLevel::Info
900        };
901        _log_access!(lvl, $on_failure, $($request_record_fields)*);
902    };
903}
904
905#[macro_export]
907macro_rules! error_access {
908    (on_failure: $on_failure:block, $($request_record_fields:tt)*) => {
909        $crate::_log_access!($crate::logging::LogLevel::Error, $on_failure, $($request_record_fields)*);
910    };
911}
912
913#[macro_export]
915macro_rules! info_access {
916    (on_failure: $on_failure:block, $($request_record_fields:tt)*) => {
917        $crate::_log_access!($crate::logging::LogLevel::Info, $on_failure, $($request_record_fields)*);
918    };
919}
920
921#[macro_export]
923macro_rules! error {
924    ($format:expr $(, $args:expr)* $(,)?) => {
925        $crate::_log!($crate::logging::LogLevel::Error, $format $(, $args)*)
926    };
927}
928
929#[macro_export]
931macro_rules! warn {
932    ($format:expr $(, $args:expr)* $(,)?) => {
933        $crate::_log!($crate::logging::LogLevel::Warn, $format $(, $args)*)
934    };
935}
936
937#[macro_export]
939macro_rules! info {
940    ($format:expr $(, $args:expr)* $(,)?) => {
941        $crate::_log!($crate::logging::LogLevel::Info, $format $(, $args)*)
942    };
943}
944
945#[macro_export]
947macro_rules! debug {
948    ($format:expr $(, $args:expr)* $(,)?) => {{
949        #[cfg(any(debug_assertions, feature = "logs-debug", feature = "logs-trace"))]
950        $crate::_log!($crate::logging::LogLevel::Debug, concat!("{}\t", $format), module_path!() $(, $args)*);
951        #[cfg(not(any(debug_assertions, feature = "logs-trace")))]
952        if false {$( let _ = $args; )*}
953    }};
954}
955
956#[macro_export]
958macro_rules! trace {
959    ($format:expr $(, $args:expr)* $(,)?) => {{
960        #[cfg(any(debug_assertions, feature = "logs-trace"))]
961        $crate::_log!($crate::logging::LogLevel::Trace, concat!("{}\t", $format), module_path!() $(, $args)*);
962        #[cfg(not(any(debug_assertions, feature = "logs-trace")))]
963        if false {$( let _ = $args; )*}
964    }};
965}
966
967#[macro_export]
969macro_rules! fixme {
970    ($(, $args:expr)* $(,)?) => {
971        $crate::_log!($crate::logging::LogLevel::Info, "FIXME: {}:{} in {}: {}", file!(), line!(), module_path!() $(, $args)*)
972    };
973}
974
975pub struct CompatLogger;
976
977impl From<log::Level> for LogLevel {
978    fn from(lvl: log::Level) -> Self {
979        match lvl {
980            log::Level::Error => LogLevel::Error,
981            log::Level::Warn => LogLevel::Warn,
982            log::Level::Info => LogLevel::Info,
983            log::Level::Debug => LogLevel::Debug,
984            log::Level::Trace => LogLevel::Trace,
985        }
986    }
987}
988
989impl log::Log for CompatLogger {
990    fn enabled(&self, _: &log::Metadata) -> bool {
991        true
992    }
993
994    fn log(&self, record: &log::Record) {
995        LOGGER.with(|logger| {
996            let mut logger = logger.borrow_mut();
997            if !logger.compat_enabled(record.metadata()) {
998                return;
999            }
1000            let (pid, tag, inner) = logger.split();
1001            let (now, precise_time) = now();
1002            crate::_prompt_log! {
1003                logger: |args| inner.log(args),
1004                is_access: false,
1005                condition: inner.colored,
1006                prompt: [
1007                    now, precise_time, pid, LogLevel::from(record.level()), tag
1008                ],
1009                standard: {
1010                    formats: ["{}\n"],
1011                    args: [record.args()]
1012                }
1013            };
1014        })
1015    }
1016
1017    fn flush(&self) {}
1018}
1019
1020#[macro_export]
1022macro_rules! setup_test_logger {
1023    () => {
1024        let _ = $crate::logging::Logger::init(
1025            module_path!().to_string(),
1026            "error",
1027            sozu_command_lib::config::DEFAULT_LOG_TARGET,
1028            false,
1029            None,
1030            None,
1031            None,
1032        );
1033    };
1034}
1035
1036pub struct Rfc3339Time {
1037    pub inner: ::time::OffsetDateTime,
1038}
1039
1040pub fn now() -> (Rfc3339Time, i128) {
1042    let t = time::OffsetDateTime::now_utc();
1043    (
1044        Rfc3339Time { inner: t },
1045        (t - time::OffsetDateTime::UNIX_EPOCH).whole_nanoseconds(),
1046    )
1047}