Files
dioxus/packages/cli/src/build/context.rs
T
Jonathan KelleyandEvan Almloff e43bf05b69 add basic crash analytics and very light telemetry to dioxus-cli (#4224)
* wip

* wip: basic telemetry

* fix merge

* keep errors for telemetry

* fix upload when queued events are empty

* add per session id and keep track of build timing

* keep track of what commands are run

* capture panics

* keep track of panics

* better path stripping

* better tracing error telemetry

* only sync every week and check settings before sending any telemetry

* keep track of the args passed to commands

* anonymize commands

* more error tolerant

* wip

* wip

* wip

* merge cnflict

* other merg conflict

* migrate everything from telemetry to logging

* update docs

* wip... about to merge trace controller

* lil bit more refactor to clean up tracer

* more performant log writer

* cleanup ci detecting

* wire up to posthog

* re-uploads work

* yoink out the anon from each file

* cleanup sig

* lil bit cleaner

* dont write empty files

* wip log handler

* fmt

* cleanup logging of backtraces

* add proper backtrace support

* use stable reporter

* adhere to posthog format

* fix stacktraces

* use anyhow for capturing backtraces

* I think we're done?

* cleanup logging

* properly collect!

* move out keycode handling

* she works

* typo

* add extra fields

* fix cargo doc

---------

Co-authored-by: Evan Almloff <evanalmloff@gmail.com>
2025-08-08 19:00:00 -07:00

188 lines
5.7 KiB
Rust

//! Report progress about the build to the user. We use channels to report progress back to the CLI.
use super::BuildMode;
use crate::{BuildArtifacts, BuildStage, Error, TraceSrc};
use cargo_metadata::diagnostic::Diagnostic;
use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
use serde::{Deserialize, Serialize};
use std::{path::PathBuf, process::ExitStatus};
/// The context of the build process. While the BuildRequest is a "plan" for the build, the BuildContext
/// provides some dynamic configuration that is only known at runtime. For example, the Progress channel
/// and the BuildMode can change while serving.
///
/// The structure of this is roughly taken from cargo itself which uses a similar pattern.
#[derive(Debug, Clone)]
pub struct BuildContext {
pub tx: ProgressTx,
pub mode: BuildMode,
}
pub type ProgressTx = UnboundedSender<BuilderUpdate>;
pub type ProgressRx = UnboundedReceiver<BuilderUpdate>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub struct BuildId(pub(crate) usize);
impl BuildId {
pub const CLIENT: Self = Self(0);
pub const SERVER: Self = Self(1);
}
#[allow(clippy::large_enum_variant)]
pub enum BuilderUpdate {
Progress {
stage: BuildStage,
},
CompilerMessage {
message: Diagnostic,
},
/// The build completed successfully and the artifacts are ready. The artifacts are dependent on
/// the build mode (fat vs thin vs base).
BuildReady {
bundle: BuildArtifacts,
},
/// The build failed. This might be because of a compilation error, or an error internal to DX.
BuildFailed {
err: Error,
},
/// A running process has received a stdout.
/// May or may not be a complete line - do not treat it as a line. It will include a line if it is a complete line.
///
/// We will poll lines and any content in a 50ms interval
StdoutReceived {
msg: String,
},
/// A running process has received a stderr.
/// May or may not be a complete line - do not treat it as a line. It will include a line if it is a complete line.
///
/// We will poll lines and any content in a 50ms interval
StderrReceived {
msg: String,
},
/// The running app (DUT) has exited and is no longer running.
ProcessExited {
status: ExitStatus,
},
/// Waiting for the process failed. This might be because it's hung or being debugged.
/// This is not the same as the process exiting, so it should just be logged but not treated as an error.
ProcessWaitFailed {
err: std::io::Error,
},
}
impl BuildContext {
pub(crate) fn status_wasm_bindgen_start(&self) {
_ = self.tx.unbounded_send(BuilderUpdate::Progress {
stage: BuildStage::RunningBindgen,
});
}
pub(crate) fn status_splitting_bundle(&self) {
_ = self.tx.unbounded_send(BuilderUpdate::Progress {
stage: BuildStage::SplittingBundle,
});
}
pub(crate) fn status_start_bundle(&self) {
_ = self.tx.unbounded_send(BuilderUpdate::Progress {
stage: BuildStage::Bundling,
});
}
pub(crate) fn status_running_gradle(&self) {
_ = self.tx.unbounded_send(BuilderUpdate::Progress {
stage: BuildStage::RunningGradle,
})
}
pub(crate) fn status_build_diagnostic(&self, message: Diagnostic) {
_ = self
.tx
.unbounded_send(BuilderUpdate::CompilerMessage { message });
}
pub(crate) fn status_build_error(&self, line: String) {
tracing::warn!(dx_src = ?TraceSrc::Cargo, "{line}");
}
pub(crate) fn status_build_message(&self, line: String) {
tracing::trace!(dx_src = ?TraceSrc::Cargo, "{line}");
}
pub(crate) fn status_build_progress(&self, count: usize, total: usize, name: String) {
_ = self.tx.unbounded_send(BuilderUpdate::Progress {
stage: BuildStage::Compiling {
current: count,
total,
krate: name,
},
});
}
pub(crate) fn status_starting_build(&self, crate_count: usize) {
_ = self.tx.unbounded_send(BuilderUpdate::Progress {
stage: BuildStage::Starting {
patch: matches!(self.mode, BuildMode::Thin { .. }),
crate_count,
},
});
}
pub(crate) fn status_starting_link(&self) {
_ = self.tx.unbounded_send(BuilderUpdate::Progress {
stage: BuildStage::Linking,
});
}
pub(crate) fn status_copied_asset(
progress: &UnboundedSender<BuilderUpdate>,
current: usize,
total: usize,
path: PathBuf,
) {
_ = progress.unbounded_send(BuilderUpdate::Progress {
stage: BuildStage::CopyingAssets {
current,
total,
path,
},
});
}
pub(crate) fn status_optimizing_wasm(&self) {
_ = self.tx.unbounded_send(BuilderUpdate::Progress {
stage: BuildStage::OptimizingWasm,
});
}
pub(crate) fn status_hotpatching(&self) {
_ = self.tx.unbounded_send(BuilderUpdate::Progress {
stage: BuildStage::Hotpatching,
});
}
pub(crate) fn status_installing_tooling(&self) {
_ = self.tx.unbounded_send(BuilderUpdate::Progress {
stage: BuildStage::InstallingTooling,
});
}
pub(crate) fn status_compressing_assets(&self) {
_ = self.tx.unbounded_send(BuilderUpdate::Progress {
stage: BuildStage::CompressingAssets,
});
}
pub(crate) fn status_extracting_assets(&self) {
_ = self.tx.unbounded_send(BuilderUpdate::Progress {
stage: BuildStage::ExtractingAssets,
});
}
}