cargo/util/
log_message.rs

1//! Messages for logging.
2
3use std::io::Write;
4use std::path::PathBuf;
5
6use cargo_util_schemas::core::PackageIdSpec;
7use jiff::Timestamp;
8use serde::Serialize;
9
10use crate::core::compiler::CompileMode;
11use crate::core::compiler::fingerprint::DirtyReason;
12
13/// A log message.
14///
15/// Each variant represents a different type of event.
16#[derive(Serialize)]
17#[serde(tag = "reason", rename_all = "kebab-case")]
18pub enum LogMessage {
19    /// Emitted when a build starts.
20    BuildStarted {
21        /// Current working directory.
22        cwd: PathBuf,
23        /// Host triple.
24        host: String,
25        /// Number of parallel jobs.
26        jobs: u32,
27        /// Build profile name (e.g., "dev", "release").
28        profile: String,
29        /// The rustc version (`1.23.4-beta.2`).
30        rustc_version: String,
31        /// The rustc verbose version information (the output of `rustc -vV`).
32        rustc_version_verbose: String,
33        /// Target directory for build artifacts.
34        target_dir: PathBuf,
35        /// Workspace root directory.
36        workspace_root: PathBuf,
37    },
38    /// Emitted when a compilation unit starts.
39    UnitStarted {
40        /// Package ID specification.
41        package_id: PackageIdSpec,
42        /// Cargo target (lib, bin, example, etc.).
43        target: Target,
44        /// The compilation action this unit is for (check, build, test, etc.).
45        mode: CompileMode,
46        /// Unit index for compact reference in subsequent events.
47        index: u64,
48        /// Seconds elapsed from build start.
49        elapsed: f64,
50    },
51    /// Emitted when a section (e.g., rmeta, link) of the compilation unit finishes.
52    UnitRmetaFinished {
53        /// Unit index from the associated unit-started event.
54        index: u64,
55        /// Seconds elapsed from build start.
56        elapsed: f64,
57        /// Unit indices that were unblocked by this rmeta completion.
58        #[serde(skip_serializing_if = "Vec::is_empty")]
59        unblocked: Vec<u64>,
60    },
61    /// Emitted when a section (e.g., rmeta, link) of the compilation unit starts.
62    ///
63    /// Requires `-Zsection-timings` to be enabled.
64    UnitSectionStarted {
65        /// Unit index from the associated unit-started event.
66        index: u64,
67        /// Seconds elapsed from build start.
68        elapsed: f64,
69        /// Section name from rustc's `-Zjson=timings` (e.g., "codegen", "link").
70        section: String,
71    },
72    /// Emitted when a section (e.g., rmeta, link) of the compilation unit finishes.
73    ///
74    /// Requires `-Zsection-timings` to be enabled.
75    UnitSectionFinished {
76        /// Unit index from the associated unit-started event.
77        index: u64,
78        /// Seconds elapsed from build start.
79        elapsed: f64,
80        /// Section name from rustc's `-Zjson=timings` (e.g., "codegen", "link").
81        section: String,
82    },
83    /// Emitted when a compilation unit finishes.
84    UnitFinished {
85        /// Unit index from the associated unit-started event.
86        index: u64,
87        /// Seconds elapsed from build start.
88        elapsed: f64,
89        /// Unit indices that were unblocked by this completion.
90        #[serde(skip_serializing_if = "Vec::is_empty")]
91        unblocked: Vec<u64>,
92    },
93    /// Emitted when a unit needs to be rebuilt.
94    Rebuild {
95        /// Package ID specification.
96        package_id: PackageIdSpec,
97        /// Cargo target (lib, bin, example, etc.).
98        target: Target,
99        /// The compilation action this unit is for (check, build, test, etc.).
100        mode: CompileMode,
101        /// Reason why the unit is dirty and needs rebuilding.
102        cause: DirtyReason,
103    },
104}
105
106/// Cargo target information.
107#[derive(Serialize)]
108pub struct Target {
109    /// Target name.
110    name: String,
111    /// Target kind (lib, bin, test, bench, example, build-script).
112    kind: &'static str,
113}
114
115impl From<&crate::core::Target> for Target {
116    fn from(target: &crate::core::Target) -> Self {
117        use crate::core::TargetKind;
118        Self {
119            name: target.name().to_string(),
120            kind: match target.kind() {
121                TargetKind::Lib(..) => "lib",
122                TargetKind::Bin => "bin",
123                TargetKind::Test => "test",
124                TargetKind::Bench => "bench",
125                TargetKind::ExampleLib(..) | TargetKind::ExampleBin => "example",
126                TargetKind::CustomBuild => "build-script",
127            },
128        }
129    }
130}
131
132impl LogMessage {
133    /// Serializes this message as a JSON log line directly to the writer.
134    pub fn write_json_log<W: Write>(&self, writer: &mut W, run_id: &str) -> std::io::Result<()> {
135        #[derive(Serialize)]
136        struct LogEntry<'a> {
137            run_id: &'a str,
138            timestamp: Timestamp,
139            #[serde(flatten)]
140            msg: &'a LogMessage,
141        }
142
143        let entry = LogEntry {
144            run_id,
145            timestamp: Timestamp::now(),
146            msg: self,
147        };
148
149        serde_json::to_writer(&mut *writer, &entry)?;
150        writer.write_all(b"\n")?;
151        Ok(())
152    }
153}