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 tracing_chrome::{ChromeLayerBuilder, FlushGuard};
34use tracing_subscriber::{Layer, filter, layer::SubscriberExt, util::SubscriberInitExt};
35
36#[napi]
37pub fn get_target_triple() -> &'static str {
38    env!("VERGEN_CARGO_TARGET_TRIPLE")
39}
40
41pub trait MapErr<T>: Into<Result<T, anyhow::Error>> {
42    fn convert_err(self) -> napi::Result<T> {
43        self.into()
44            .map_err(|err| napi::Error::new(Status::GenericFailure, format!("{err:?}")))
45    }
46}
47
48impl<T> MapErr<T> for Result<T, anyhow::Error> {}
49
50/// An opaque type potentially wrapping a [`dhat::Profiler`] instance. If we
51/// were not compiled with dhat support, this is an empty struct.
52#[cfg(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc"))]
53#[non_exhaustive]
54pub struct DhatProfilerGuard(dhat::Profiler);
55
56/// An opaque type potentially wrapping a [`dhat::Profiler`] instance. If we
57/// were not compiled with dhat support, this is an empty struct.
58///
59/// [`dhat::Profiler`]: https://docs.rs/dhat/latest/dhat/struct.Profiler.html
60#[cfg(not(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc")))]
61#[non_exhaustive]
62pub struct DhatProfilerGuard;
63
64impl DhatProfilerGuard {
65    /// Constructs an instance if we were compiled with dhat support.
66    pub fn try_init() -> Option<Self> {
67        #[cfg(feature = "__internal_dhat-heap")]
68        {
69            println!("[dhat-heap]: Initializing heap profiler");
70            Some(Self(dhat::Profiler::new_heap()))
71        }
72        #[cfg(feature = "__internal_dhat-ad-hoc")]
73        {
74            println!("[dhat-ad-hoc]: Initializing ad-hoc profiler");
75            Some(Self(dhat::Profiler::new_ad_hoc()))
76        }
77        #[cfg(not(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc")))]
78        {
79            None
80        }
81    }
82}
83
84impl Drop for DhatProfilerGuard {
85    fn drop(&mut self) {
86        #[cfg(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc"))]
87        println!("[dhat]: Teardown profiler");
88    }
89}
90
91/// Initialize tracing subscriber to emit traces. This configures subscribers
92/// for Trace Event Format <https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview>.
93#[napi]
94pub fn init_custom_trace_subscriber(
95    trace_out_file_path: Option<String>,
96) -> napi::Result<External<RefCell<Option<FlushGuard>>>> {
97    let trace_out_file_path = trace_out_file_path.map(PathBuf::from);
98
99    let mut layer = ChromeLayerBuilder::new().include_args(true);
100    if let Some(trace_out_file) = trace_out_file_path {
101        let dir = trace_out_file
102            .parent()
103            .ok_or_else(|| anyhow!("Not able to find path to the trace output"))
104            .convert_err()?;
105        std::fs::create_dir_all(dir)?;
106
107        layer = layer.file(trace_out_file);
108    }
109
110    let (chrome_layer, guard) = layer.build();
111    tracing_subscriber::registry()
112        .with(chrome_layer.with_filter(filter::filter_fn(|metadata| {
113            !metadata.target().contains("cranelift") && !metadata.name().contains("log ")
114        })))
115        .try_init()
116        .expect("Failed to register tracing subscriber");
117
118    let guard_cell = RefCell::new(Some(guard));
119    Ok(External::new(guard_cell))
120}
121
122/// Teardown currently running tracing subscriber to flush out remaining traces.
123/// This should be called when parent node.js process exits, otherwise generated
124/// trace may drop traces in the buffer.
125#[napi]
126pub fn teardown_trace_subscriber(guard_external: External<RefCell<Option<FlushGuard>>>) {
127    let guard_cell = &*guard_external;
128
129    if let Some(guard) = guard_cell.take() {
130        drop(guard);
131    }
132}