File: rust_logger.rs

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,122,156 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (112 lines) | stat: -rw-r--r-- 3,850 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

chromium::import! {
    "//base:logging_log_severity_bindgen" as log_severity;
}

use log::Level::{Debug, Error, Info, Trace, Warn};
use log::{LevelFilter, Metadata, Record};
use log_severity::logging::{LOGGING_ERROR, LOGGING_INFO, LOGGING_WARNING};
use std::ffi::CString;
use std::pin::Pin;

struct RustLogger;

impl log::Log for RustLogger {
    fn enabled(&self, _metadata: &Metadata) -> bool {
        // Always enabled, as it's controlled by command line flags managed by the C++
        // implementation.
        true
    }

    fn log(&self, record: &Record) {
        // TODO(thiruak1024@gmail.com): Rather than using heap allocation to pass |msg|
        // and |file|, we should return a pointer and size object to leverage the
        // string_view object in C++. https://crbug.com/371112531
        let file = CString::new(record.file().unwrap())
            .expect("CString::new failed to create the log file name!");
        let wrapped_args = RustFmtArguments(*record.args());
        unsafe {
            ffi::print_rust_log(
                &wrapped_args,
                file.as_ptr(),
                record.line().unwrap() as i32,
                match record.metadata().level() {
                    Error => LOGGING_ERROR,
                    Warn => LOGGING_WARNING,
                    Info => LOGGING_INFO,
                    // Note that Debug and Trace level logs are dropped at
                    // compile time at the macro call-site when DCHECK_IS_ON()
                    // is false. This is done through a Cargo feature.
                    Debug | Trace => LOGGING_INFO,
                },
                record.metadata().level() == Trace,
            )
        }
    }
    fn flush(&self) {}
}

static RUST_LOGGER: RustLogger = RustLogger;

/// Wrap a `std::fmt::Arguments` to pass to C++ code.
struct RustFmtArguments<'a>(std::fmt::Arguments<'a>);

impl<'a> RustFmtArguments<'a> {
    /// Format `msg` to the C++-provided stream in `wrapper`.
    fn format(&self, mut wrapper: Pin<&mut ffi::LogMessageRustWrapper>) {
        // No error expected because our `Write` impl below is infallible.
        std::fmt::write(&mut wrapper, self.0).unwrap();
    }
}

// Glue impl to use std::fmt tools with `ffi::LogMessageRustWrapper`.
impl std::fmt::Write for Pin<&mut ffi::LogMessageRustWrapper> {
    fn write_str(&mut self, s: &str) -> Result<(), std::fmt::Error> {
        self.as_mut().write_to_stream(s);
        Ok(())
    }
}

#[cxx::bridge(namespace = "logging::internal")]
mod ffi {
    extern "Rust" {
        type RustFmtArguments<'a>;

        fn format(&self, wrapper: Pin<&mut LogMessageRustWrapper>);

        fn init_rust_log_crate();
    }

    unsafe extern "C++" {
        include!("base/logging/rust_log_integration.h");

        /// Wraps a C++ LogMessage object so we can write to its ostream.
        type LogMessageRustWrapper;

        /// Write a block of characters to the stream.
        fn write_to_stream(self: Pin<&mut LogMessageRustWrapper>, s: &str);

        /// Emit a log message to the C++-managed logger. `msg` is passed back
        /// to `format_to_wrapped_message` to be stringified.
        unsafe fn print_rust_log(
            msg: &RustFmtArguments,
            file: *const c_char,
            line: i32,
            severity: i32,
            verbose: bool,
        );
    }
}

pub fn init_rust_log_crate() {
    // An error may occur if set_logger has already been called, which can happen
    // during unit tests. In that case, return from the method without executing the
    // subsequent code.
    if let Err(_) = log::set_logger(&RUST_LOGGER) {
        return;
    };
    log::set_max_level(LevelFilter::Trace);
}