blob: f10f17bbe451623c5e28c19f95fec70d73d8d7d1 [file] [edit]
//! Messages for logging.
use std::borrow::Cow;
use std::io::Write;
use std::path::PathBuf;
use cargo_util_schemas::core::PackageIdSpec;
use jiff::Timestamp;
use serde::Deserialize;
use serde::Serialize;
use crate::compiler::CompileMode;
use crate::compiler::UnitIndex;
use crate::compiler::fingerprint::DirtyReason;
/// A log message.
///
/// Each variant represents a different type of event.
#[derive(Serialize, Deserialize, Clone)]
#[serde(tag = "reason", rename_all = "kebab-case")]
pub enum LogMessage {
/// Emitted when a build starts.
BuildStarted {
/// The command-line arguments Cargo was invoked with.
command: Vec<String>,
/// Current working directory.
cwd: PathBuf,
/// Host triple.
host: String,
/// Number of parallel jobs.
jobs: u32,
/// Available parallelism of the compilation environment.
num_cpus: Option<u64>,
/// Build profile name (e.g., "dev", "release").
profile: String,
/// The rustc version (`1.23.4-beta.2`).
rustc_version: String,
/// The rustc verbose version information (the output of `rustc -vV`).
rustc_version_verbose: String,
/// Target directory for build artifacts.
target_dir: PathBuf,
/// Workspace root directory.
workspace_root: PathBuf,
},
/// Emitted when resolving dependencies starts.
ResolutionStarted {
/// Seconds elapsed from build start.
elapsed: f64,
},
/// Emitted when resolving dependencies finishes.
ResolutionFinished {
/// Seconds elapsed from build start.
elapsed: f64,
},
/// Emitted when unit graph generation starts.
UnitGraphStarted {
/// Seconds elapsed from build start.
elapsed: f64,
},
/// Emitted when unit graph generation finishes.
UnitGraphFinished {
/// Seconds elapsed from build start.
elapsed: f64,
},
/// Emitted when a compilation unit is registered in the unit graph,
/// right before [`LogMessage::UnitGraphFinished`] that Cargo finalizes
/// the unit graph.
UnitRegistered {
/// Package ID specification.
package_id: PackageIdSpec,
/// Cargo target (lib, bin, example, etc.).
target: Target,
/// The compilation action this unit is for (check, build, test, etc.).
mode: CompileMode,
/// The target platform this unit builds for.
///
/// It is either a [target triple] the compiler accepts,
/// or a file name with the `json` extension for a [custom target].
///
/// [target triple]: https://doc.rust-lang.org/nightly/rustc/platform-support.html
/// [custom target]: https://doc.rust-lang.org/nightly/rustc/targets/custom.html
platform: String,
/// Unit index for compact reference in subsequent events.
index: UnitIndex,
/// Enabled features.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
features: Vec<String>,
/// Whether this is requested to build by user directly,
/// like via the `-p` flag or the default workspace members.
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
requested: bool,
/// Unit indices that this unit depends on.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
dependencies: Vec<UnitIndex>,
},
/// Emitted when a compilation unit starts.
UnitStarted {
/// Unit index from the associated unit-registered event.
index: UnitIndex,
/// Seconds elapsed from build start.
elapsed: f64,
},
/// Emitted when a section (e.g., rmeta, link) of the compilation unit finishes.
UnitRmetaFinished {
/// Unit index from the associated unit-registered event.
index: UnitIndex,
/// Seconds elapsed from build start.
elapsed: f64,
/// Unit indices that were unblocked by this rmeta completion.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
unblocked: Vec<UnitIndex>,
},
/// Emitted when a section (e.g., rmeta, link) of the compilation unit starts.
///
/// Requires `-Zsection-timings` to be enabled.
UnitSectionStarted {
/// Unit index from the associated unit-registered event.
index: UnitIndex,
/// Seconds elapsed from build start.
elapsed: f64,
/// Section name from rustc's `-Zjson=timings` (e.g., "codegen", "link").
section: String,
},
/// Emitted when a section (e.g., rmeta, link) of the compilation unit finishes.
///
/// Requires `-Zsection-timings` to be enabled.
UnitSectionFinished {
/// Unit index from the associated unit-registered event.
index: UnitIndex,
/// Seconds elapsed from build start.
elapsed: f64,
/// Section name from rustc's `-Zjson=timings` (e.g., "codegen", "link").
section: String,
},
/// Emitted when a compilation unit finishes.
UnitFinished {
/// Unit index from the associated unit-registered event.
index: UnitIndex,
/// Seconds elapsed from build start.
elapsed: f64,
/// Unit indices that were unblocked by this completion.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
unblocked: Vec<UnitIndex>,
},
/// Emitted when rebuild fingerprint information is determined for a unit.
UnitFingerprint {
/// Unit index from the associated unit-registered event.
index: UnitIndex,
/// Status of the rebuild detection fingerprint of this unit
status: FingerprintStatus,
/// Reason why the unit is dirty and needs rebuilding.
#[serde(default, skip_serializing_if = "Option::is_none")]
cause: Option<DirtyReason>,
},
}
/// Cargo target information.
#[derive(Serialize, Deserialize, Clone)]
pub struct Target {
/// Target name.
pub name: String,
/// Target kind (lib, bin, test, bench, example, build-script).
pub kind: Cow<'static, str>,
}
/// Status of the rebuild detection fingerprint.
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "kebab-case")]
pub enum FingerprintStatus {
/// There is no previous fingerprints for this unit.
/// Might be a brand-new build.
New,
/// The current fingerprint doesn't match the previous fingerprints.
/// Rebuild needed.
Dirty,
/// The current fingerprint matches the previous fingerprints.
/// No rebuild needed.
Fresh,
}
impl From<&crate::workspace::Target> for Target {
fn from(target: &crate::workspace::Target) -> Self {
use crate::workspace::TargetKind;
Self {
name: target.name().to_string(),
kind: match target.kind() {
TargetKind::Lib(..) => "lib",
TargetKind::Bin => "bin",
TargetKind::Test => "test",
TargetKind::Bench => "bench",
TargetKind::ExampleLib(..) | TargetKind::ExampleBin => "example",
TargetKind::CustomBuild => "build-script",
}
.into(),
}
}
}
impl LogMessage {
/// Serializes this message as a JSON log line directly to the writer.
pub fn write_json_log<W: Write>(&self, writer: &mut W, run_id: &str) -> std::io::Result<()> {
#[derive(Serialize)]
struct LogEntry<'a> {
run_id: &'a str,
timestamp: Timestamp,
#[serde(flatten)]
msg: &'a LogMessage,
}
let entry = LogEntry {
run_id,
timestamp: Timestamp::now(),
msg: self,
};
serde_json::to_writer(&mut *writer, &entry)?;
writer.write_all(b"\n")?;
Ok(())
}
}