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