@@ -29,7 +29,7 @@ fn is_tracing_enabled() -> bool {
2929#[ cfg_attr( feature = "tracing" , instrument( level = "trace" , name = "main" ) ) ]
3030fn main ( ) {
3131 #[ cfg( feature = "tracing" ) ]
32- let _guard = setup_tracing ( ) ;
32+ let guard = setup_tracing ( is_profiling_enabled ( ) ) ;
3333
3434 let start_time = Instant :: now ( ) ;
3535
@@ -183,7 +183,12 @@ fn main() {
183183 }
184184
185185 #[ cfg( feature = "tracing" ) ]
186- build. report_step_graph ( & tracing_dir) ;
186+ {
187+ build. report_step_graph ( & tracing_dir) ;
188+ if let Some ( guard) = guard {
189+ guard. copy_to_dir ( & tracing_dir) ;
190+ }
191+ }
187192
188193 if tracing_enabled {
189194 eprintln ! ( "Tracing/profiling output has been written to {}" , latest_trace_dir. display( ) ) ;
@@ -257,25 +262,53 @@ fn check_version(config: &Config) -> Option<String> {
257262// - `tracing`'s `#[instrument(..)]` macro will need to be gated like `#![cfg_attr(feature =
258263// "tracing", instrument(..))]`.
259264#[ cfg( feature = "tracing" ) ]
260- fn setup_tracing ( ) -> impl Drop {
265+ fn setup_tracing ( profiling_enabled : bool ) -> Option < TracingGuard > {
266+ use std:: fs:: File ;
267+ use std:: io:: BufWriter ;
268+
261269 use tracing_forest:: ForestLayer ;
262270 use tracing_subscriber:: EnvFilter ;
263271 use tracing_subscriber:: layer:: SubscriberExt ;
264272
265273 let filter = EnvFilter :: from_env ( "BOOTSTRAP_TRACING" ) ;
266274
267- let mut chrome_layer = tracing_chrome :: ChromeLayerBuilder :: new ( ) . include_args ( true ) ;
275+ let registry = tracing_subscriber :: registry ( ) . with ( filter ) . with ( ForestLayer :: default ( ) ) ;
268276
269- // Writes the Chrome profile to trace-<unix-timestamp>.json if enabled
270- if !is_profiling_enabled ( ) {
271- chrome_layer = chrome_layer. writer ( io:: sink ( ) ) ;
272- }
277+ let guard = if profiling_enabled {
278+ // When we're creating this layer, we do not yet know the location of the tracing output
279+ // directory, because it is stored in the output directory determined after Config is parsed,
280+ // but we already want to make tracing calls during (and before) config parsing.
281+ // So we store the output into a temporary file, and then move it to the tracing directory
282+ // before bootstrap ends.
283+ let tempdir = tempfile:: TempDir :: new ( ) . expect ( "Cannot create temporary directory" ) ;
284+ let chrome_tracing_path = tempdir. path ( ) . join ( "bootstrap-trace.json" ) ;
285+ let file = BufWriter :: new ( File :: create ( & chrome_tracing_path) . unwrap ( ) ) ;
273286
274- let ( chrome_layer, _guard) = chrome_layer. build ( ) ;
287+ let chrome_layer =
288+ tracing_chrome:: ChromeLayerBuilder :: new ( ) . writer ( file) . include_args ( true ) ;
289+ let ( chrome_layer, guard) = chrome_layer. build ( ) ;
275290
276- let registry =
277- tracing_subscriber:: registry ( ) . with ( filter) . with ( ForestLayer :: default ( ) ) . with ( chrome_layer) ;
291+ tracing:: subscriber:: set_global_default ( registry. with ( chrome_layer) ) . unwrap ( ) ;
292+ Some ( TracingGuard { guard, _tempdir : tempdir, chrome_tracing_path } )
293+ } else {
294+ tracing:: subscriber:: set_global_default ( registry) . unwrap ( ) ;
295+ None
296+ } ;
278297
279- tracing:: subscriber:: set_global_default ( registry) . unwrap ( ) ;
280- _guard
298+ guard
299+ }
300+
301+ #[ cfg( feature = "tracing" ) ]
302+ struct TracingGuard {
303+ guard : tracing_chrome:: FlushGuard ,
304+ _tempdir : tempfile:: TempDir ,
305+ chrome_tracing_path : std:: path:: PathBuf ,
306+ }
307+
308+ #[ cfg( feature = "tracing" ) ]
309+ impl TracingGuard {
310+ fn copy_to_dir ( self , dir : & std:: path:: Path ) {
311+ drop ( self . guard ) ;
312+ std:: fs:: rename ( & self . chrome_tracing_path , dir. join ( "chrome-trace.json" ) ) . unwrap ( ) ;
313+ }
281314}
0 commit comments