next_swc_napi/
util.rs

1/*
2Copyright (c) 2017 The swc Project Developers
3
4Permission is hereby granted, free of charge, to any
5person obtaining a copy of this software and associated
6documentation files (the "Software"), to deal in the
7Software without restriction, including without
8limitation the rights to use, copy, modify, merge,
9publish, distribute, sublicense, and/or sell copies of
10the Software, and to permit persons to whom the Software
11is furnished to do so, subject to the following
12conditions:
13
14The above copyright notice and this permission notice
15shall be included in all copies or substantial portions
16of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
19ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
20TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
21PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
22SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
25IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26DEALINGS IN THE SOFTWARE.
27*/
28
29use std::{cell::RefCell, env, path::PathBuf};
30
31use anyhow::anyhow;
32use napi::bindgen_prelude::{External, Status};
33use napi_derive::napi;
34use tracing_chrome::{ChromeLayerBuilder, FlushGuard};
35use tracing_subscriber::{Layer, filter, layer::SubscriberExt, util::SubscriberInitExt};
36
37#[napi]
38pub fn get_target_triple() -> &'static str {
39    env!("VERGEN_CARGO_TARGET_TRIPLE")
40}
41
42pub trait MapErr<T>: Into<Result<T, anyhow::Error>> {
43    fn convert_err(self) -> napi::Result<T> {
44        self.into()
45            .map_err(|err| napi::Error::new(Status::GenericFailure, format!("{err:?}")))
46    }
47}
48
49impl<T> MapErr<T> for Result<T, anyhow::Error> {}
50
51/// An opaque type potentially wrapping a [`dhat::Profiler`] instance. If we
52/// were not compiled with dhat support, this is an empty struct.
53#[cfg(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc"))]
54#[non_exhaustive]
55pub struct DhatProfilerGuard(dhat::Profiler);
56
57/// An opaque type potentially wrapping a [`dhat::Profiler`] instance. If we
58/// were not compiled with dhat support, this is an empty struct.
59///
60/// [`dhat::Profiler`]: https://docs.rs/dhat/latest/dhat/struct.Profiler.html
61#[cfg(not(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc")))]
62#[non_exhaustive]
63pub struct DhatProfilerGuard;
64
65impl DhatProfilerGuard {
66    /// Constructs an instance if we were compiled with dhat support.
67    pub fn try_init() -> Option<Self> {
68        #[cfg(feature = "__internal_dhat-heap")]
69        {
70            println!("[dhat-heap]: Initializing heap profiler");
71            Some(Self(dhat::Profiler::new_heap()))
72        }
73        #[cfg(feature = "__internal_dhat-ad-hoc")]
74        {
75            println!("[dhat-ad-hoc]: Initializing ad-hoc profiler");
76            Some(Self(dhat::Profiler::new_ad_hoc()))
77        }
78        #[cfg(not(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc")))]
79        {
80            None
81        }
82    }
83}
84
85impl Drop for DhatProfilerGuard {
86    fn drop(&mut self) {
87        #[cfg(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc"))]
88        println!("[dhat]: Teardown profiler");
89    }
90}
91
92/// Initialize tracing subscriber to emit traces. This configures subscribers
93/// for Trace Event Format <https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview>.
94#[napi]
95pub fn init_custom_trace_subscriber(
96    trace_out_file_path: Option<String>,
97) -> napi::Result<External<RefCell<Option<FlushGuard>>>> {
98    let trace_out_file_path = trace_out_file_path.map(PathBuf::from);
99
100    let mut layer = ChromeLayerBuilder::new().include_args(true);
101    if let Some(trace_out_file) = trace_out_file_path {
102        let dir = trace_out_file
103            .parent()
104            .ok_or_else(|| anyhow!("Not able to find path to the trace output"))
105            .convert_err()?;
106        std::fs::create_dir_all(dir)?;
107
108        layer = layer.file(trace_out_file);
109    }
110
111    let (chrome_layer, guard) = layer.build();
112    tracing_subscriber::registry()
113        .with(chrome_layer.with_filter(filter::filter_fn(|metadata| {
114            !metadata.target().contains("cranelift") && !metadata.name().contains("log ")
115        })))
116        .try_init()
117        .expect("Failed to register tracing subscriber");
118
119    let guard_cell = RefCell::new(Some(guard));
120    Ok(External::new(guard_cell))
121}
122
123/// Teardown currently running tracing subscriber to flush out remaining traces.
124/// This should be called when parent node.js process exits, otherwise generated
125/// trace may drop traces in the buffer.
126#[napi]
127pub fn teardown_trace_subscriber(guard_external: External<RefCell<Option<FlushGuard>>>) {
128    let guard_cell = &*guard_external;
129
130    if let Some(guard) = guard_cell.take() {
131        drop(guard);
132    }
133}