1use solar_interface::diagnostics::DiagCtxt;
4
5#[cfg(feature = "tracing")]
6use solar_sema::ast::Either;
7#[cfg(feature = "tracing")]
8use std::io;
9
10#[cfg(feature = "mimalloc")]
11use mimalloc as _;
12#[cfg(all(feature = "jemalloc", unix))]
13use tikv_jemallocator as _;
14
15cfg_if::cfg_if! {
18 if #[cfg(debug_assertions)] {
19 type AllocatorInner = std::alloc::System;
20 } else if #[cfg(feature = "mimalloc")] {
21 type AllocatorInner = mimalloc::MiMalloc;
22 } else if #[cfg(all(feature = "jemalloc", unix))] {
23 type AllocatorInner = tikv_jemallocator::Jemalloc;
24 } else {
25 type AllocatorInner = std::alloc::System;
26 }
27}
28
29cfg_if::cfg_if! {
30 if #[cfg(feature = "tracy-allocator")] {
31 pub(super) type WrappedAllocator = tracing_tracy::client::ProfiledAllocator<AllocatorInner>;
32 pub(super) const fn new_wrapped_allocator() -> WrappedAllocator {
33 Allocator::new(AllocatorInner {}, 100)
34 }
35 } else {
36 pub(super) type WrappedAllocator = AllocatorInner;
37 pub(super) const fn new_wrapped_allocator() -> WrappedAllocator {
38 AllocatorInner {}
39 }
40 }
41}
42
43pub type Allocator = WrappedAllocator;
45
46pub const fn new_allocator() -> Allocator {
48 new_wrapped_allocator()
49}
50
51#[derive(Default)]
53pub enum LogDestination {
54 #[default]
56 Stdout,
57 Stderr,
59}
60
61#[cfg(feature = "tracing")]
62impl<'a> tracing_subscriber::fmt::MakeWriter<'a> for LogDestination {
63 type Writer = Either<io::Stdout, io::Stderr>;
64
65 fn make_writer(&'a self) -> Self::Writer {
66 match self {
67 Self::Stdout => Either::Left(io::stdout()),
68 Self::Stderr => Either::Right(io::stderr()),
69 }
70 }
71}
72
73#[must_use]
75pub fn init_logger(dst: LogDestination) -> impl Sized {
76 #[cfg(not(feature = "tracing"))]
77 {
78 let _ = dst;
79 if std::env::var_os("RUST_LOG").is_some() {
80 let msg = "`RUST_LOG` is set, but \"tracing\" support was not enabled at compile time";
81 DiagCtxt::new_early().warn(msg).emit();
82 }
83 if std::env::var_os("SOLAR_PROFILE").is_some() {
84 let msg =
85 "`SOLAR_PROFILE` is set, but \"tracing\" support was not enabled at compile time";
86 DiagCtxt::new_early().warn(msg).emit();
87 }
88 }
89
90 #[cfg(feature = "tracing")]
91 match try_init_logger(dst) {
92 Ok(guard) => guard,
93 Err(e) => DiagCtxt::new_early().fatal(e).emit(),
94 }
95}
96
97#[cfg(feature = "tracing")]
98fn try_init_logger(dst: LogDestination) -> Result<impl Sized, String> {
99 use tracing_subscriber::prelude::*;
100
101 let (profile_layer, guard) = match std::env::var("SOLAR_PROFILE").as_deref() {
102 Ok("chrome") => {
103 if !cfg!(feature = "tracing-chrome") {
104 return Err("chrome profiler support is not compiled in".to_string());
105 }
106 let (layer, guard) = chrome_layer();
107 (Some(layer.boxed()), Some(guard))
108 }
109 Ok("tracy") => {
110 if !cfg!(feature = "tracy") {
111 return Err("tracy profiler support is not compiled in".to_string());
112 }
113 (Some(tracy_layer().boxed()), Default::default())
114 }
115 Ok("samply") => {
116 if !cfg!(feature = "tracing-samply") {
117 return Err("samply profiler support is not compiled in".to_string());
118 }
119 (Some(samply_layer().map_err(|e| e.to_string())?.boxed()), Default::default())
120 }
121 Ok(s) => {
122 return Err(format!(
123 "unknown profiler '{s}'; valid values: 'chrome', 'tracy', 'samply'"
124 ));
125 }
126 Err(_) => Default::default(),
127 };
128 tracing_subscriber::Registry::default()
129 .with(tracing_subscriber::EnvFilter::from_default_env())
130 .with(profile_layer)
131 .with(tracing_subscriber::fmt::layer().with_writer(dst))
132 .try_init()
133 .map(|()| guard)
134 .map_err(|e| e.to_string())
135}
136
137#[cfg(feature = "tracing")]
138#[cfg(feature = "tracy")]
139fn tracy_layer() -> tracing_tracy::TracyLayer<impl tracing_tracy::Config> {
140 struct Config(tracing_subscriber::fmt::format::DefaultFields);
141 impl tracing_tracy::Config for Config {
142 type Formatter = tracing_subscriber::fmt::format::DefaultFields;
143 fn formatter(&self) -> &Self::Formatter {
144 &self.0
145 }
146 fn format_fields_in_zone_name(&self) -> bool {
147 false
148 }
149 }
150
151 tracing_tracy::client::register_demangler!();
152
153 tracing_tracy::TracyLayer::new(Config(Default::default()))
154}
155#[cfg(feature = "tracing")]
156#[cfg(not(feature = "tracy"))]
157fn tracy_layer() -> tracing_subscriber::layer::Identity {
158 tracing_subscriber::layer::Identity::new()
159}
160
161#[cfg(feature = "tracing")]
162#[cfg(feature = "tracing-chrome")]
163fn chrome_layer<S>() -> (tracing_chrome::ChromeLayer<S>, tracing_chrome::FlushGuard)
164where
165 S: tracing::Subscriber
166 + for<'span> tracing_subscriber::registry::LookupSpan<'span>
167 + Send
168 + Sync,
169{
170 tracing_chrome::ChromeLayerBuilder::new().include_args(true).build()
171}
172#[cfg(feature = "tracing")]
173#[cfg(not(feature = "tracing-chrome"))]
174fn chrome_layer() -> (tracing_subscriber::layer::Identity, ()) {
175 (tracing_subscriber::layer::Identity::new(), ())
176}
177
178#[cfg(feature = "tracing")]
179#[cfg(feature = "tracing-samply")]
180fn samply_layer() -> std::io::Result<tracing_samply::SamplyLayer> {
181 tracing_samply::SamplyLayer::new()
182}
183#[cfg(feature = "tracing")]
184#[cfg(not(feature = "tracing-samply"))]
185fn samply_layer() -> std::io::Result<tracing_subscriber::layer::Identity> {
186 Ok(tracing_subscriber::layer::Identity::new())
187}
188
189