Skip to content

Commit 3b09c60

Browse files
pixlwavepoljar
andcommitted
ffi: Wrap the tracing text layers inside a reload layer.
The generics have been removed from text_layers() to make this possible. --------- Co-authored-by: Damir Jelić <poljar@termina.org.uk>
1 parent fcdb63d commit 3b09c60

File tree

1 file changed

+151
-128
lines changed

1 file changed

+151
-128
lines changed

bindings/matrix-sdk-ffi/src/platform.rs

Lines changed: 151 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -14,164 +14,181 @@ use tracing_subscriber::{
1414
time::FormatTime,
1515
FormatEvent, FormatFields, FormattedFields,
1616
},
17-
layer::SubscriberExt as _,
17+
layer::{Layered, SubscriberExt as _},
1818
registry::LookupSpan,
19+
reload::{self, Handle},
1920
util::SubscriberInitExt as _,
20-
Layer,
21+
EnvFilter, Layer, Registry,
2122
};
2223

2324
use crate::{error::ClientError, tracing::LogLevel};
2425

25-
fn text_layers<S>(config: TracingConfiguration) -> impl Layer<S>
26-
where
27-
S: Subscriber + for<'a> LookupSpan<'a>,
28-
{
29-
// Adjusted version of tracing_subscriber::fmt::Format
30-
struct EventFormatter {
31-
display_timestamp: bool,
32-
display_level: bool,
33-
}
26+
// Adjusted version of tracing_subscriber::fmt::Format
27+
struct EventFormatter {
28+
display_timestamp: bool,
29+
display_level: bool,
30+
}
3431

35-
impl EventFormatter {
36-
fn new() -> Self {
37-
Self { display_timestamp: true, display_level: true }
38-
}
32+
impl EventFormatter {
33+
fn new() -> Self {
34+
Self { display_timestamp: true, display_level: true }
35+
}
3936

40-
#[cfg(target_os = "android")]
41-
fn for_logcat() -> Self {
42-
// Level and time are already captured by logcat separately
43-
Self { display_timestamp: false, display_level: false }
44-
}
37+
#[cfg(target_os = "android")]
38+
fn for_logcat() -> Self {
39+
// Level and time are already captured by logcat separately
40+
Self { display_timestamp: false, display_level: false }
41+
}
4542

46-
fn format_timestamp(&self, writer: &mut fmt::format::Writer<'_>) -> std::fmt::Result {
47-
if fmt::time::SystemTime.format_time(writer).is_err() {
48-
writer.write_str("<unknown time>")?;
49-
}
50-
Ok(())
43+
fn format_timestamp(&self, writer: &mut fmt::format::Writer<'_>) -> std::fmt::Result {
44+
if fmt::time::SystemTime.format_time(writer).is_err() {
45+
writer.write_str("<unknown time>")?;
5146
}
47+
Ok(())
48+
}
5249

53-
fn write_filename(
54-
&self,
55-
writer: &mut fmt::format::Writer<'_>,
56-
filename: &str,
57-
) -> std::fmt::Result {
58-
const CRATES_IO_PATH_MATCHER: &str = ".cargo/registry/src/index.crates.io";
59-
let crates_io_filename = filename
60-
.split_once(CRATES_IO_PATH_MATCHER)
61-
.and_then(|(_, rest)| rest.split_once('/').map(|(_, rest)| rest));
62-
63-
if let Some(filename) = crates_io_filename {
64-
writer.write_str("<crates.io>/")?;
65-
writer.write_str(filename)
66-
} else {
67-
writer.write_str(filename)
68-
}
50+
fn write_filename(
51+
&self,
52+
writer: &mut fmt::format::Writer<'_>,
53+
filename: &str,
54+
) -> std::fmt::Result {
55+
const CRATES_IO_PATH_MATCHER: &str = ".cargo/registry/src/index.crates.io";
56+
let crates_io_filename = filename
57+
.split_once(CRATES_IO_PATH_MATCHER)
58+
.and_then(|(_, rest)| rest.split_once('/').map(|(_, rest)| rest));
59+
60+
if let Some(filename) = crates_io_filename {
61+
writer.write_str("<crates.io>/")?;
62+
writer.write_str(filename)
63+
} else {
64+
writer.write_str(filename)
6965
}
7066
}
67+
}
7168

72-
impl<S, N> FormatEvent<S, N> for EventFormatter
73-
where
74-
S: Subscriber + for<'a> LookupSpan<'a>,
75-
N: for<'a> FormatFields<'a> + 'static,
76-
{
77-
fn format_event(
78-
&self,
79-
ctx: &fmt::FmtContext<'_, S, N>,
80-
mut writer: fmt::format::Writer<'_>,
81-
event: &tracing_core::Event<'_>,
82-
) -> std::fmt::Result {
83-
let meta = event.metadata();
84-
85-
if self.display_timestamp {
86-
self.format_timestamp(&mut writer)?;
87-
writer.write_char(' ')?;
88-
}
69+
impl<S, N> FormatEvent<S, N> for EventFormatter
70+
where
71+
S: Subscriber + for<'a> LookupSpan<'a>,
72+
N: for<'a> FormatFields<'a> + 'static,
73+
{
74+
fn format_event(
75+
&self,
76+
ctx: &fmt::FmtContext<'_, S, N>,
77+
mut writer: fmt::format::Writer<'_>,
78+
event: &tracing_core::Event<'_>,
79+
) -> std::fmt::Result {
80+
let meta = event.metadata();
81+
82+
if self.display_timestamp {
83+
self.format_timestamp(&mut writer)?;
84+
writer.write_char(' ')?;
85+
}
8986

90-
if self.display_level {
91-
// For info and warn, add a padding space to the left
92-
write!(writer, "{:>5} ", meta.level())?;
93-
}
87+
if self.display_level {
88+
// For info and warn, add a padding space to the left
89+
write!(writer, "{:>5} ", meta.level())?;
90+
}
9491

95-
write!(writer, "{}: ", meta.target())?;
92+
write!(writer, "{}: ", meta.target())?;
9693

97-
ctx.format_fields(writer.by_ref(), event)?;
94+
ctx.format_fields(writer.by_ref(), event)?;
9895

99-
if let Some(filename) = meta.file() {
100-
writer.write_str(" | ")?;
101-
self.write_filename(&mut writer, filename)?;
102-
if let Some(line_number) = meta.line() {
103-
write!(writer, ":{line_number}")?;
104-
}
96+
if let Some(filename) = meta.file() {
97+
writer.write_str(" | ")?;
98+
self.write_filename(&mut writer, filename)?;
99+
if let Some(line_number) = meta.line() {
100+
write!(writer, ":{line_number}")?;
105101
}
102+
}
106103

107-
if let Some(scope) = ctx.event_scope() {
108-
writer.write_str(" | spans: ")?;
104+
if let Some(scope) = ctx.event_scope() {
105+
writer.write_str(" | spans: ")?;
109106

110-
let mut first = true;
107+
let mut first = true;
111108

112-
for span in scope.from_root() {
113-
if !first {
114-
writer.write_str(" > ")?;
115-
}
109+
for span in scope.from_root() {
110+
if !first {
111+
writer.write_str(" > ")?;
112+
}
116113

117-
first = false;
114+
first = false;
118115

119-
write!(writer, "{}", span.name())?;
116+
write!(writer, "{}", span.name())?;
120117

121-
if let Some(fields) = &span.extensions().get::<FormattedFields<N>>() {
122-
if !fields.is_empty() {
123-
write!(writer, "{{{fields}}}")?;
124-
}
118+
if let Some(fields) = &span.extensions().get::<FormattedFields<N>>() {
119+
if !fields.is_empty() {
120+
write!(writer, "{{{fields}}}")?;
125121
}
126122
}
127123
}
128-
129-
writeln!(writer)
130124
}
131-
}
132125

133-
let file_layer = config.write_to_files.map(|c| {
134-
let mut builder = RollingFileAppender::builder()
135-
.rotation(Rotation::HOURLY)
136-
.filename_prefix(&c.file_prefix);
126+
writeln!(writer)
127+
}
128+
}
137129

138-
if let Some(max_files) = c.max_files {
139-
builder = builder.max_log_files(max_files as usize)
140-
}
141-
if let Some(file_suffix) = c.file_suffix {
142-
builder = builder.filename_suffix(file_suffix)
143-
}
130+
// Another fields formatter is necessary because of this bug
131+
// https://github.com/tokio-rs/tracing/issues/1372. Using a new
132+
// formatter for the fields forces to record them in different span
133+
// extensions, and thus remove the duplicated fields in the span.
134+
#[derive(Default)]
135+
struct FieldsFormatterForFiles(DefaultFields);
136+
137+
impl<'writer> FormatFields<'writer> for FieldsFormatterForFiles {
138+
fn format_fields<R: RecordFields>(
139+
&self,
140+
writer: Writer<'writer>,
141+
fields: R,
142+
) -> std::fmt::Result {
143+
self.0.format_fields(writer, fields)
144+
}
145+
}
144146

145-
let writer = builder.build(&c.path).expect("Failed to create a rolling file appender.");
146-
147-
// Another fields formatter is necessary because of this bug
148-
// https://github.com/tokio-rs/tracing/issues/1372. Using a new
149-
// formatter for the fields forces to record them in different span
150-
// extensions, and thus remove the duplicated fields in the span.
151-
#[derive(Default)]
152-
struct FieldsFormatterForFiles(DefaultFields);
153-
154-
impl<'writer> FormatFields<'writer> for FieldsFormatterForFiles {
155-
fn format_fields<R: RecordFields>(
156-
&self,
157-
writer: Writer<'writer>,
158-
fields: R,
159-
) -> std::fmt::Result {
160-
self.0.format_fields(writer, fields)
147+
type ReloadHandle = Handle<
148+
tracing_subscriber::fmt::Layer<
149+
Layered<EnvFilter, Registry>,
150+
FieldsFormatterForFiles,
151+
EventFormatter,
152+
RollingFileAppender,
153+
>,
154+
Layered<EnvFilter, Registry>,
155+
>;
156+
157+
fn text_layers(
158+
config: TracingConfiguration,
159+
) -> (impl Layer<Layered<EnvFilter, Registry>>, Option<ReloadHandle>) {
160+
let (file_layer, reload_handle) = config
161+
.write_to_files
162+
.map(|c| {
163+
let mut builder = RollingFileAppender::builder()
164+
.rotation(Rotation::HOURLY)
165+
.filename_prefix(&c.file_prefix);
166+
167+
if let Some(max_files) = c.max_files {
168+
builder = builder.max_log_files(max_files as usize)
169+
};
170+
if let Some(file_suffix) = c.file_suffix {
171+
builder = builder.filename_suffix(file_suffix)
161172
}
162-
}
163173

164-
fmt::layer()
165-
.fmt_fields(FieldsFormatterForFiles::default())
166-
.event_format(EventFormatter::new())
167-
// EventFormatter doesn't support ANSI colors anyways, but the
168-
// default field formatter does, which is unhelpful for iOS +
169-
// Android logs, but enabled by default.
170-
.with_ansi(false)
171-
.with_writer(writer)
172-
});
174+
let writer = builder.build(&c.path).expect("Failed to create a rolling file appender.");
173175

174-
Layer::and_then(
176+
let layer = fmt::layer()
177+
.fmt_fields(FieldsFormatterForFiles::default())
178+
.event_format(EventFormatter::new())
179+
// EventFormatter doesn't support ANSI colors anyways, but the
180+
// default field formatter does, which is unhelpful for iOS +
181+
// Android logs, but enabled by default.
182+
.with_ansi(false)
183+
.with_writer(writer);
184+
185+
let (layer, reload_handle) = reload::Layer::new(layer);
186+
187+
(layer, reload_handle)
188+
})
189+
.unzip();
190+
191+
let layers = Layer::and_then(
175192
file_layer,
176193
config.write_to_stdout_or_system.then(|| {
177194
// Another fields formatter is necessary because of this bug
@@ -209,7 +226,9 @@ where
209226
"org.matrix.rust.sdk".to_owned(),
210227
));
211228
}),
212-
)
229+
);
230+
231+
(layers, reload_handle)
213232
}
214233

215234
/// Configuration to save logs to (rotated) log-files.
@@ -359,6 +378,7 @@ struct SentryLoggingCtx {
359378
}
360379

361380
struct LoggingCtx {
381+
reload_handle: Option<ReloadHandle>,
362382
#[cfg(feature = "sentry")]
363383
sentry: Option<SentryLoggingCtx>,
364384
}
@@ -463,20 +483,23 @@ impl TracingConfiguration {
463483
} else {
464484
(None, None)
465485
};
486+
let (text_layers, reload_handle) = crate::platform::text_layers(self);
487+
466488
tracing_subscriber::registry()
467489
.with(tracing_subscriber::EnvFilter::new(&env_filter))
468-
.with(crate::platform::text_layers(self))
490+
.with(text_layers)
469491
.with(sentry_layer)
470492
.init();
471-
logging_ctx = LoggingCtx { sentry: sentry_logging_ctx };
493+
logging_ctx = LoggingCtx { reload_handle, sentry: sentry_logging_ctx };
472494
}
473495
#[cfg(not(feature = "sentry"))]
474496
{
497+
let (text_layers, reload_handle) = crate::platform::text_layers(self);
475498
tracing_subscriber::registry()
476499
.with(tracing_subscriber::EnvFilter::new(&env_filter))
477-
.with(crate::platform::text_layers(self))
500+
.with(text_layers)
478501
.init();
479-
logging_ctx = LoggingCtx {};
502+
logging_ctx = LoggingCtx { reload_handle };
480503
}
481504

482505
// Log the log levels 🧠.

0 commit comments

Comments
 (0)