cargo/util/log_message.rs
1//! Messages for logging.
2
3use std::borrow::Cow;
4use std::io::Write;
5use std::path::PathBuf;
6
7use cargo_util_schemas::core::PackageIdSpec;
8use jiff::Timestamp;
9use serde::Deserialize;
10use serde::Serialize;
11
12use crate::core::compiler::CompileMode;
13use crate::core::compiler::fingerprint::DirtyReason;
14
15/// A log message.
16///
17/// Each variant represents a different type of event.
18#[derive(Serialize, Deserialize)]
19#[serde(tag = "reason", rename_all = "kebab-case")]
20pub enum LogMessage {
21 /// Emitted when a build starts.
22 BuildStarted {
23 /// Current working directory.
24 cwd: PathBuf,
25 /// Host triple.
26 host: String,
27 /// Number of parallel jobs.
28 jobs: u32,
29 /// Available parallelism of the compilation environment.
30 num_cpus: Option<u64>,
31 /// Build profile name (e.g., "dev", "release").
32 profile: String,
33 /// The rustc version (`1.23.4-beta.2`).
34 rustc_version: String,
35 /// The rustc verbose version information (the output of `rustc -vV`).
36 rustc_version_verbose: String,
37 /// Target directory for build artifacts.
38 target_dir: PathBuf,
39 /// Workspace root directory.
40 workspace_root: PathBuf,
41 },
42 /// Emitted when resolving dependencies starts.
43 ResolutionStarted {
44 /// Seconds elapsed from build start.
45 elapsed: f64,
46 },
47 /// Emitted when resolving dependencies finishes.
48 ResolutionFinished {
49 /// Seconds elapsed from build start.
50 elapsed: f64,
51 },
52 /// Emitted when unit graph generation starts.
53 UnitGraphStarted {
54 /// Seconds elapsed from build start.
55 elapsed: f64,
56 },
57 /// Emitted when unit graph generation finishes.
58 UnitGraphFinished {
59 /// Seconds elapsed from build start.
60 elapsed: f64,
61 },
62 /// Emitted when a compilation unit is registered in the unit graph,
63 /// right before [`LogMessage::UnitGraphFinished`] that Cargo finalizes
64 /// the unit graph.
65 UnitRegistered {
66 /// Package ID specification.
67 package_id: PackageIdSpec,
68 /// Cargo target (lib, bin, example, etc.).
69 target: Target,
70 /// The compilation action this unit is for (check, build, test, etc.).
71 mode: CompileMode,
72 /// The target platform this unit builds for.
73 ///
74 /// It is either a [target triple] the compiler accepts,
75 /// or a file name with the `json` extension for a [custom target].
76 ///
77 /// [target triple]: https://doc.rust-lang.org/nightly/rustc/platform-support.html
78 /// [custom target]: https://doc.rust-lang.org/nightly/rustc/targets/custom.html
79 platform: String,
80 /// Unit index for compact reference in subsequent events.
81 index: u64,
82 /// Enabled features.
83 #[serde(default, skip_serializing_if = "Vec::is_empty")]
84 features: Vec<String>,
85 /// Whether this is requested to build by user directly,
86 /// like via the `-p` flag or the default workspace members.
87 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
88 requested: bool,
89 },
90 /// Emitted when a compilation unit starts.
91 UnitStarted {
92 /// Unit index from the associated unit-registered event.
93 index: u64,
94 /// Seconds elapsed from build start.
95 elapsed: f64,
96 },
97 /// Emitted when a section (e.g., rmeta, link) of the compilation unit finishes.
98 UnitRmetaFinished {
99 /// Unit index from the associated unit-registered event.
100 index: u64,
101 /// Seconds elapsed from build start.
102 elapsed: f64,
103 /// Unit indices that were unblocked by this rmeta completion.
104 #[serde(default, skip_serializing_if = "Vec::is_empty")]
105 unblocked: Vec<u64>,
106 },
107 /// Emitted when a section (e.g., rmeta, link) of the compilation unit starts.
108 ///
109 /// Requires `-Zsection-timings` to be enabled.
110 UnitSectionStarted {
111 /// Unit index from the associated unit-registered event.
112 index: u64,
113 /// Seconds elapsed from build start.
114 elapsed: f64,
115 /// Section name from rustc's `-Zjson=timings` (e.g., "codegen", "link").
116 section: String,
117 },
118 /// Emitted when a section (e.g., rmeta, link) of the compilation unit finishes.
119 ///
120 /// Requires `-Zsection-timings` to be enabled.
121 UnitSectionFinished {
122 /// Unit index from the associated unit-registered event.
123 index: u64,
124 /// Seconds elapsed from build start.
125 elapsed: f64,
126 /// Section name from rustc's `-Zjson=timings` (e.g., "codegen", "link").
127 section: String,
128 },
129 /// Emitted when a compilation unit finishes.
130 UnitFinished {
131 /// Unit index from the associated unit-registered event.
132 index: u64,
133 /// Seconds elapsed from build start.
134 elapsed: f64,
135 /// Unit indices that were unblocked by this completion.
136 #[serde(default, skip_serializing_if = "Vec::is_empty")]
137 unblocked: Vec<u64>,
138 },
139 /// Emitted when rebuild fingerprint information is determined for a unit.
140 UnitFingerprint {
141 /// Unit index from the associated unit-registered event.
142 index: u64,
143 /// Status of the rebuild detection fingerprint of this unit
144 status: FingerprintStatus,
145 /// Reason why the unit is dirty and needs rebuilding.
146 #[serde(default, skip_deserializing, skip_serializing_if = "Option::is_none")]
147 cause: Option<DirtyReason>,
148 },
149}
150
151/// Cargo target information.
152#[derive(Serialize, Deserialize)]
153pub struct Target {
154 /// Target name.
155 pub name: String,
156 /// Target kind (lib, bin, test, bench, example, build-script).
157 pub kind: Cow<'static, str>,
158}
159
160/// Status of the rebuild detection fingerprint.
161#[derive(Serialize, Deserialize)]
162#[serde(rename_all = "kebab-case")]
163pub enum FingerprintStatus {
164 /// There is no previous fingerprints for this unit.
165 /// Might be a brand-new build.
166 New,
167 /// The current fingerprint doesn't match the previous fingerprints.
168 /// Rebuild needed.
169 Dirty,
170 /// The current fingerprint matches the previous fingerprints.
171 /// No rebuild needed.
172 Fresh,
173}
174
175impl From<&crate::core::Target> for Target {
176 fn from(target: &crate::core::Target) -> Self {
177 use crate::core::TargetKind;
178 Self {
179 name: target.name().to_string(),
180 kind: match target.kind() {
181 TargetKind::Lib(..) => "lib",
182 TargetKind::Bin => "bin",
183 TargetKind::Test => "test",
184 TargetKind::Bench => "bench",
185 TargetKind::ExampleLib(..) | TargetKind::ExampleBin => "example",
186 TargetKind::CustomBuild => "build-script",
187 }
188 .into(),
189 }
190 }
191}
192
193impl LogMessage {
194 /// Serializes this message as a JSON log line directly to the writer.
195 pub fn write_json_log<W: Write>(&self, writer: &mut W, run_id: &str) -> std::io::Result<()> {
196 #[derive(Serialize)]
197 struct LogEntry<'a> {
198 run_id: &'a str,
199 timestamp: Timestamp,
200 #[serde(flatten)]
201 msg: &'a LogMessage,
202 }
203
204 let entry = LogEntry {
205 run_id,
206 timestamp: Timestamp::now(),
207 msg: self,
208 };
209
210 serde_json::to_writer(&mut *writer, &entry)?;
211 writer.write_all(b"\n")?;
212 Ok(())
213 }
214}