Skip to content

Commit 7819a9a

Browse files
branchseerclaude
andcommitted
feat: add Chrome tracing support and performance instrumentation
- Add Chrome DevTools timeline tracing output via `VITE_LOG_OUTPUT=chrome-json` - Update `init_tracing()` to support three output modes: chrome-json, readable, stdout - Add `VITE_LOG_OUTPUT` env var constant - Add `tracing` and `tracing-chrome` dependencies to vite_shared - Keep tracing guard alive in main() for Chrome trace file flushing - Update vite-task dependency to include tracing instrumentation - Enable tracing in e2e-test workflow and upload trace artifacts - Run e2e commands twice to measure caching performance Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 4592307 commit 7819a9a

6 files changed

Lines changed: 113 additions & 32 deletions

File tree

.github/workflows/e2e-test.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,38 @@ jobs:
287287
288288
- name: Run vite-plus commands in ${{ matrix.project.name }}
289289
working-directory: ${{ runner.temp }}/vite-plus-ecosystem-ci/${{ matrix.project.name }}${{ matrix.project.directory && format('/{0}', matrix.project.directory) || '' }}
290+
env:
291+
VITE_LOG: debug
292+
VITE_LOG_OUTPUT: chrome-json
293+
run: ${{ matrix.project.command }}
294+
295+
- name: Run vite-plus commands again (cache run) in ${{ matrix.project.name }}
296+
working-directory: ${{ runner.temp }}/vite-plus-ecosystem-ci/${{ matrix.project.name }}${{ matrix.project.directory && format('/{0}', matrix.project.directory) || '' }}
297+
env:
298+
VITE_LOG: debug
299+
VITE_LOG_OUTPUT: chrome-json
290300
run: ${{ matrix.project.command }}
291301

302+
- name: Collect trace files
303+
if: always()
304+
shell: bash
305+
run: |
306+
mkdir -p ${{ runner.temp }}/trace-artifacts
307+
# Chrome tracing writes trace-*.json in the cwd of the process
308+
find ${{ runner.temp }}/vite-plus-ecosystem-ci/${{ matrix.project.name }} -name 'trace-*.json' -exec cp {} ${{ runner.temp }}/trace-artifacts/ \; 2>/dev/null || true
309+
# Also check the workspace root
310+
find $GITHUB_WORKSPACE -maxdepth 1 -name 'trace-*.json' -exec cp {} ${{ runner.temp }}/trace-artifacts/ \; 2>/dev/null || true
311+
ls -la ${{ runner.temp }}/trace-artifacts/ 2>/dev/null || echo "No trace files found"
312+
313+
- name: Upload trace artifacts
314+
if: always()
315+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
316+
with:
317+
name: trace-${{ matrix.project.name }}-${{ matrix.os }}
318+
path: ${{ runner.temp }}/trace-artifacts/
319+
retention-days: 7
320+
if-no-files-found: ignore
321+
292322
notify-failure:
293323
name: Notify on failure
294324
runs-on: ubuntu-latest

Cargo.toml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ dunce = "1.0.5"
8383
fast-glob = "1.0.0"
8484
flate2 = { version = "=1.1.9", features = ["zlib-rs"] }
8585
form_urlencoded = "1.2.1"
86-
fspy = { git = "ssh://git@github.com/voidzero-dev/vite-task.git", rev = "9e1287e797190ea29793655b239cdaa7a55edd21" }
86+
fspy = { git = "ssh://git@github.com/voidzero-dev/vite-task.git", rev = "9ed02855949883fbb77d5f83535082decc516230" }
8787
futures = "0.3.31"
8888
futures-util = "0.3.31"
8989
glob = "0.3.2"
@@ -182,15 +182,15 @@ vfs = "0.12.1"
182182
vite_command = { path = "crates/vite_command" }
183183
vite_error = { path = "crates/vite_error" }
184184
vite_js_runtime = { path = "crates/vite_js_runtime" }
185-
vite_glob = { git = "ssh://git@github.com/voidzero-dev/vite-task.git", rev = "9e1287e797190ea29793655b239cdaa7a55edd21" }
185+
vite_glob = { git = "ssh://git@github.com/voidzero-dev/vite-task.git", rev = "9ed02855949883fbb77d5f83535082decc516230" }
186186
vite_install = { path = "crates/vite_install" }
187187
vite_migration = { path = "crates/vite_migration" }
188188
vite_shared = { path = "crates/vite_shared" }
189189
vite_static_config = { path = "crates/vite_static_config" }
190-
vite_path = { git = "ssh://git@github.com/voidzero-dev/vite-task.git", rev = "9e1287e797190ea29793655b239cdaa7a55edd21" }
191-
vite_str = { git = "ssh://git@github.com/voidzero-dev/vite-task.git", rev = "9e1287e797190ea29793655b239cdaa7a55edd21" }
192-
vite_task = { git = "ssh://git@github.com/voidzero-dev/vite-task.git", rev = "9e1287e797190ea29793655b239cdaa7a55edd21" }
193-
vite_workspace = { git = "ssh://git@github.com/voidzero-dev/vite-task.git", rev = "9e1287e797190ea29793655b239cdaa7a55edd21" }
190+
vite_path = { git = "ssh://git@github.com/voidzero-dev/vite-task.git", rev = "9ed02855949883fbb77d5f83535082decc516230" }
191+
vite_str = { git = "ssh://git@github.com/voidzero-dev/vite-task.git", rev = "9ed02855949883fbb77d5f83535082decc516230" }
192+
vite_task = { git = "ssh://git@github.com/voidzero-dev/vite-task.git", rev = "9ed02855949883fbb77d5f83535082decc516230" }
193+
vite_workspace = { git = "ssh://git@github.com/voidzero-dev/vite-task.git", rev = "9ed02855949883fbb77d5f83535082decc516230" }
194194
walkdir = "2.5.0"
195195
wax = "0.6.0"
196196
which = "8.0.0"

crates/vite_global_cli/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ fn print_invalid_subcommand_error(error: &clap::Error) -> bool {
9292
#[tokio::main]
9393
async fn main() -> ExitCode {
9494
// Initialize tracing
95-
vite_shared::init_tracing();
95+
let _tracing_guard = vite_shared::init_tracing();
9696

9797
// Check for shim mode (invoked as node, npm, or npx)
9898
let args: Vec<String> = std::env::args().collect();

crates/vite_shared/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ directories = { workspace = true }
1212
owo-colors = { workspace = true }
1313
serde = { workspace = true }
1414
serde_json = { workspace = true }
15+
tracing = { workspace = true }
16+
tracing-chrome = { workspace = true }
1517
tracing-subscriber = { workspace = true }
1618
vite_path = { workspace = true }
1719
vite_str = { workspace = true }

crates/vite_shared/src/env_vars.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ pub const VITE_PLUS_HOME: &str = "VITE_PLUS_HOME";
1818
/// Log filter string for `tracing_subscriber` (e.g. `"debug"`, `"vite_task=trace"`).
1919
pub const VITE_LOG: &str = "VITE_LOG";
2020

21+
/// Output mode for tracing (e.g. `"chrome-json"` for Chrome DevTools timeline).
22+
pub const VITE_LOG_OUTPUT: &str = "VITE_LOG_OUTPUT";
23+
2124
/// NPM registry URL (lowercase form, highest priority).
2225
pub const NPM_CONFIG_REGISTRY: &str = "npm_config_registry";
2326

crates/vite_shared/src/tracing.rs

Lines changed: 71 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,84 @@
11
//! Tracing initialization for vite-plus
2+
//!
3+
//! ## Environment Variables
4+
//! - `VITE_LOG`: Controls log filtering (e.g., `"debug"`, `"vite_task=trace"`)
5+
//! - `VITE_LOG_OUTPUT`: Output format — `"chrome-json"` for Chrome DevTools timeline,
6+
//! `"readable"` for pretty-printed output, or default stdout.
27
3-
use std::sync::OnceLock;
8+
use std::any::Any;
9+
use std::sync::atomic::AtomicBool;
410

11+
use tracing_chrome::ChromeLayerBuilder;
512
use tracing_subscriber::{
613
filter::{LevelFilter, Targets},
14+
fmt::{self, format::FmtSpan},
715
prelude::*,
816
};
917

1018
use crate::env_vars;
1119

12-
/// Initialize tracing with VITE_LOG environment variable.
20+
static IS_INITIALIZED: AtomicBool = AtomicBool::new(false);
21+
22+
/// Initialize tracing with `VITE_LOG` and `VITE_LOG_OUTPUT` environment variables.
1323
///
14-
/// Uses `OnceLock` to ensure tracing is only initialized once,
15-
/// even if called multiple times.
24+
/// Returns an optional guard that must be kept alive for the duration of the
25+
/// program when using file-based output (e.g., `chrome-json`). Dropping the
26+
/// guard flushes and finalizes the trace file.
1627
///
17-
/// # Environment Variables
18-
/// - `VITE_LOG`: Controls log filtering (e.g., "debug", "vite_task=trace")
19-
pub fn init_tracing() {
20-
static TRACING: OnceLock<()> = OnceLock::new();
21-
TRACING.get_or_init(|| {
22-
tracing_subscriber::registry()
23-
.with(
24-
std::env::var(env_vars::VITE_LOG)
25-
.map_or_else(
26-
|_| Targets::new(),
27-
|env_var| {
28-
use std::str::FromStr;
29-
Targets::from_str(&env_var).unwrap_or_default()
30-
},
31-
)
32-
// disable brush-parser tracing
33-
.with_targets([("tokenize", LevelFilter::OFF), ("parse", LevelFilter::OFF)]),
34-
)
35-
.with(tracing_subscriber::fmt::layer())
36-
.init();
37-
});
28+
/// Uses `AtomicBool` to ensure tracing is only initialized once.
29+
pub fn init_tracing() -> Option<Box<dyn Any + Send>> {
30+
if IS_INITIALIZED.swap(true, std::sync::atomic::Ordering::SeqCst) {
31+
return None;
32+
}
33+
34+
let Ok(env_var) = std::env::var(env_vars::VITE_LOG) else {
35+
// Tracing is disabled by default (performance sensitive)
36+
return None;
37+
};
38+
39+
let targets = {
40+
use std::str::FromStr;
41+
Targets::from_str(&env_var)
42+
.unwrap_or_default()
43+
// disable brush-parser tracing
44+
.with_targets([("tokenize", LevelFilter::OFF), ("parse", LevelFilter::OFF)])
45+
};
46+
47+
let output_mode = std::env::var(env_vars::VITE_LOG_OUTPUT)
48+
.unwrap_or_else(|_| "stdout".to_string());
49+
50+
match output_mode.as_str() {
51+
"chrome-json" => {
52+
let (chrome_layer, guard) = ChromeLayerBuilder::new()
53+
.trace_style(tracing_chrome::TraceStyle::Async)
54+
.include_args(true)
55+
.build();
56+
tracing_subscriber::registry()
57+
.with(targets)
58+
.with(chrome_layer)
59+
.init();
60+
Some(Box::new(guard))
61+
}
62+
"readable" => {
63+
tracing_subscriber::registry()
64+
.with(targets)
65+
.with(
66+
fmt::layer()
67+
.pretty()
68+
.with_span_events(FmtSpan::NONE)
69+
.with_level(true)
70+
.with_target(false),
71+
)
72+
.init();
73+
None
74+
}
75+
_ => {
76+
// Default: stdout with span events
77+
tracing_subscriber::registry()
78+
.with(targets)
79+
.with(fmt::layer().with_span_events(FmtSpan::CLOSE | FmtSpan::ENTER))
80+
.init();
81+
None
82+
}
83+
}
3884
}

0 commit comments

Comments
 (0)