Coverage Report

Created: 2025-08-29 06:13

/rust/registry/src/index.crates.io-6f17d22bba15001f/tracing-log-0.1.4/src/lib.rs
Line
Count
Source (jump to first uncovered line)
1
//! Adapters for connecting unstructured log records from the `log` crate into
2
//! the `tracing` ecosystem.
3
//!
4
//! # Overview
5
//!
6
//! [`tracing`] is a framework for instrumenting Rust programs with context-aware,
7
//! structured, event-based diagnostic information. This crate provides
8
//! compatibility layers for using `tracing` alongside the logging facade provided
9
//! by the [`log`] crate.
10
//!
11
//! This crate provides:
12
//!
13
//! - [`AsTrace`] and [`AsLog`] traits for converting between `tracing` and `log` types.
14
//! - [`LogTracer`], a [`log::Log`] implementation that consumes [`log::Record`]s
15
//!   and outputs them as [`tracing::Event`].
16
//! - An [`env_logger`] module, with helpers for using the [`env_logger` crate]
17
//!   with `tracing` (optional, enabled by the `env-logger` feature).
18
//!
19
//! *Compiler support: [requires `rustc` 1.56+][msrv]*
20
//!
21
//! [msrv]: #supported-rust-versions
22
//!
23
//! # Usage
24
//!
25
//! ## Convert log records to tracing `Event`s
26
//!
27
//! To convert [`log::Record`]s as [`tracing::Event`]s, set `LogTracer` as the default
28
//! logger by calling its [`init`] or [`init_with_filter`] methods.
29
//!
30
//! ```rust
31
//! # use std::error::Error;
32
//! use tracing_log::LogTracer;
33
//! use log;
34
//!
35
//! # fn main() -> Result<(), Box<Error>> {
36
//! LogTracer::init()?;
37
//!
38
//! // will be available for Subscribers as a tracing Event
39
//! log::trace!("an example trace log");
40
//! # Ok(())
41
//! # }
42
//! ```
43
//!
44
//! This conversion does not convert unstructured data in log records (such as
45
//! values passed as format arguments to the `log!` macro) to structured
46
//! `tracing` fields. However, it *does* attach these new events to to the
47
//! span that was currently executing when the record was logged. This is the
48
//! primary use-case for this library: making it possible to locate the log
49
//! records emitted by dependencies which use `log` within the context of a
50
//! trace.
51
//!
52
//! ## Convert tracing `Event`s to logs
53
//!
54
//! Enabling the ["log" and "log-always" feature flags][flags] on the `tracing`
55
//! crate will cause all `tracing` spans and events to emit `log::Record`s as
56
//! they occur.
57
//!
58
//! ## Caution: Mixing both conversions
59
//!
60
//! Note that logger implementations that convert log records to trace events
61
//! should not be used with `Subscriber`s that convert trace events _back_ into
62
//! log records (such as the `TraceLogger`), as doing so will result in the
63
//! event recursing between the subscriber and the logger forever (or, in real
64
//! life, probably overflowing the call stack).
65
//!
66
//! If the logging of trace events generated from log records produced by the
67
//! `log` crate is desired, either the `log` crate should not be used to
68
//! implement this logging, or an additional layer of filtering will be
69
//! required to avoid infinitely converting between `Event` and `log::Record`.
70
//!
71
//! # Feature Flags
72
//! * `trace-logger`: enables an experimental `log` subscriber, deprecated since
73
//!   version 0.1.1.
74
//! * `log-tracer`: enables the `LogTracer` type (on by default)
75
//! * `env_logger`: enables the `env_logger` module, with helpers for working
76
//!   with the [`env_logger` crate].
77
//! * `interest-cache`: makes it possible to configure an interest cache for
78
//!   logs emitted through the `log` crate (see [`Builder::with_interest_cache`]); requires `std`
79
//!
80
//! ## Supported Rust Versions
81
//!
82
//! Tracing is built against the latest stable release. The minimum supported
83
//! version is 1.56. The current Tracing version is not guaranteed to build on
84
//! Rust versions earlier than the minimum supported version.
85
//!
86
//! Tracing follows the same compiler support policies as the rest of the Tokio
87
//! project. The current stable Rust compiler and the three most recent minor
88
//! versions before it will always be supported. For example, if the current
89
//! stable compiler version is 1.69, the minimum supported version will not be
90
//! increased past 1.66, three minor versions prior. Increasing the minimum
91
//! supported compiler version is not considered a semver breaking change as
92
//! long as doing so complies with this policy.
93
//!
94
//! [`init`]: LogTracer::init
95
//! [`init_with_filter`]: LogTracer::init_with_filter
96
//! [`tracing`]: https://crates.io/crates/tracing
97
//! [`env_logger` crate]: https://crates.io/crates/env-logger
98
//! [`tracing::Subscriber`]: https://docs.rs/tracing/latest/tracing/trait.Subscriber.html
99
//! [`Subscriber`]: https://docs.rs/tracing/latest/tracing/trait.Subscriber.html
100
//! [`tracing::Event`]: https://docs.rs/tracing/latest/tracing/struct.Event.html
101
//! [flags]: https://docs.rs/tracing/latest/tracing/#crate-feature-flags
102
//! [`Builder::with_interest_cache`]: log_tracer::Builder::with_interest_cache
103
#![doc(
104
    html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png",
105
    issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/"
106
)]
107
#![cfg_attr(docsrs, feature(doc_cfg), deny(rustdoc::broken_intra_doc_links))]
108
#![warn(
109
    missing_debug_implementations,
110
    missing_docs,
111
    rust_2018_idioms,
112
    unreachable_pub,
113
    bad_style,
114
    dead_code,
115
    improper_ctypes,
116
    non_shorthand_field_patterns,
117
    no_mangle_generic_items,
118
    overflowing_literals,
119
    path_statements,
120
    patterns_in_fns_without_body,
121
    private_in_public,
122
    unconditional_recursion,
123
    unused,
124
    unused_allocation,
125
    unused_comparisons,
126
    unused_parens,
127
    while_true
128
)]
129
use once_cell::sync::Lazy;
130
131
use std::{fmt, io};
132
133
use tracing_core::{
134
    callsite::{self, Callsite},
135
    dispatcher,
136
    field::{self, Field, Visit},
137
    identify_callsite,
138
    metadata::{Kind, Level},
139
    subscriber, Event, Metadata,
140
};
141
142
#[cfg(feature = "log-tracer")]
143
#[cfg_attr(docsrs, doc(cfg(feature = "log-tracer")))]
144
pub mod log_tracer;
145
146
#[cfg(feature = "trace-logger")]
147
#[cfg_attr(docsrs, doc(cfg(feature = "trace-logger")))]
148
pub mod trace_logger;
149
150
#[cfg(feature = "log-tracer")]
151
#[cfg_attr(docsrs, doc(cfg(feature = "log-tracer")))]
152
#[doc(inline)]
153
pub use self::log_tracer::LogTracer;
154
155
#[cfg(feature = "trace-logger")]
156
#[cfg_attr(docsrs, doc(cfg(feature = "trace-logger")))]
157
#[deprecated(
158
    since = "0.1.1",
159
    note = "use the `tracing` crate's \"log\" feature flag instead"
160
)]
161
#[allow(deprecated)]
162
#[doc(inline)]
163
pub use self::trace_logger::TraceLogger;
164
165
#[cfg(feature = "env_logger")]
166
#[cfg_attr(docsrs, doc(cfg(feature = "env_logger")))]
167
#[deprecated(
168
    since = "0.1.4",
169
    note = "use `tracing-subscriber`'s `fmt::Subscriber` instead"
170
)]
171
pub mod env_logger;
172
173
pub use log;
174
175
#[cfg(all(feature = "interest-cache", feature = "log-tracer", feature = "std"))]
176
mod interest_cache;
177
178
#[cfg(all(feature = "interest-cache", feature = "log-tracer", feature = "std"))]
179
#[cfg_attr(
180
    docsrs,
181
    doc(cfg(all(feature = "interest-cache", feature = "log-tracer", feature = "std")))
182
)]
183
pub use crate::interest_cache::InterestCacheConfig;
184
185
/// Format a log record as a trace event in the current span.
186
0
pub fn format_trace(record: &log::Record<'_>) -> io::Result<()> {
187
0
    dispatch_record(record);
188
0
    Ok(())
189
0
}
190
191
// XXX(eliza): this is factored out so that we don't have to deal with the pub
192
// function `format_trace`'s `Result` return type...maybe we should get rid of
193
// that in 0.2...
194
0
pub(crate) fn dispatch_record(record: &log::Record<'_>) {
195
0
    dispatcher::get_default(|dispatch| {
196
0
        let filter_meta = record.as_trace();
197
0
        if !dispatch.enabled(&filter_meta) {
198
0
            return;
199
0
        }
200
0
201
0
        let (_, keys, meta) = loglevel_to_cs(record.level());
202
0
203
0
        let log_module = record.module_path();
204
0
        let log_file = record.file();
205
0
        let log_line = record.line();
206
0
207
0
        let module = log_module.as_ref().map(|s| s as &dyn field::Value);
208
0
        let file = log_file.as_ref().map(|s| s as &dyn field::Value);
209
0
        let line = log_line.as_ref().map(|s| s as &dyn field::Value);
210
0
211
0
        dispatch.event(&Event::new(
212
0
            meta,
213
0
            &meta.fields().value_set(&[
214
0
                (&keys.message, Some(record.args() as &dyn field::Value)),
215
0
                (&keys.target, Some(&record.target())),
216
0
                (&keys.module, module),
217
0
                (&keys.file, file),
218
0
                (&keys.line, line),
219
0
            ]),
220
0
        ));
221
0
    });
222
0
}
223
224
/// Trait implemented for `tracing` types that can be converted to a `log`
225
/// equivalent.
226
pub trait AsLog: crate::sealed::Sealed {
227
    /// The `log` type that this type can be converted into.
228
    type Log;
229
    /// Returns the `log` equivalent of `self`.
230
    fn as_log(&self) -> Self::Log;
231
}
232
233
/// Trait implemented for `log` types that can be converted to a `tracing`
234
/// equivalent.
235
pub trait AsTrace: crate::sealed::Sealed {
236
    /// The `tracing` type that this type can be converted into.
237
    type Trace;
238
    /// Returns the `tracing` equivalent of `self`.
239
    fn as_trace(&self) -> Self::Trace;
240
}
241
242
impl<'a> crate::sealed::Sealed for Metadata<'a> {}
243
244
impl<'a> AsLog for Metadata<'a> {
245
    type Log = log::Metadata<'a>;
246
0
    fn as_log(&self) -> Self::Log {
247
0
        log::Metadata::builder()
248
0
            .level(self.level().as_log())
249
0
            .target(self.target())
250
0
            .build()
251
0
    }
252
}
253
impl<'a> crate::sealed::Sealed for log::Metadata<'a> {}
254
255
impl<'a> AsTrace for log::Metadata<'a> {
256
    type Trace = Metadata<'a>;
257
0
    fn as_trace(&self) -> Self::Trace {
258
0
        let cs_id = identify_callsite!(loglevel_to_cs(self.level()).0);
259
0
        Metadata::new(
260
0
            "log record",
261
0
            self.target(),
262
0
            self.level().as_trace(),
263
0
            None,
264
0
            None,
265
0
            None,
266
0
            field::FieldSet::new(FIELD_NAMES, cs_id),
267
0
            Kind::EVENT,
268
0
        )
269
0
    }
270
}
271
272
struct Fields {
273
    message: field::Field,
274
    target: field::Field,
275
    module: field::Field,
276
    file: field::Field,
277
    line: field::Field,
278
}
279
280
static FIELD_NAMES: &[&str] = &[
281
    "message",
282
    "log.target",
283
    "log.module_path",
284
    "log.file",
285
    "log.line",
286
];
287
288
impl Fields {
289
0
    fn new(cs: &'static dyn Callsite) -> Self {
290
0
        let fieldset = cs.metadata().fields();
291
0
        let message = fieldset.field("message").unwrap();
292
0
        let target = fieldset.field("log.target").unwrap();
293
0
        let module = fieldset.field("log.module_path").unwrap();
294
0
        let file = fieldset.field("log.file").unwrap();
295
0
        let line = fieldset.field("log.line").unwrap();
296
0
        Fields {
297
0
            message,
298
0
            target,
299
0
            module,
300
0
            file,
301
0
            line,
302
0
        }
303
0
    }
304
}
305
306
macro_rules! log_cs {
307
    ($level:expr, $cs:ident, $meta:ident, $ty:ident) => {
308
        struct $ty;
309
        static $cs: $ty = $ty;
310
        static $meta: Metadata<'static> = Metadata::new(
311
            "log event",
312
            "log",
313
            $level,
314
            ::core::option::Option::None,
315
            ::core::option::Option::None,
316
            ::core::option::Option::None,
317
            field::FieldSet::new(FIELD_NAMES, identify_callsite!(&$cs)),
318
            Kind::EVENT,
319
        );
320
321
        impl callsite::Callsite for $ty {
322
0
            fn set_interest(&self, _: subscriber::Interest) {}
Unexecuted instantiation: <tracing_log::TraceCallsite as tracing_core::callsite::Callsite>::set_interest
Unexecuted instantiation: <tracing_log::DebugCallsite as tracing_core::callsite::Callsite>::set_interest
Unexecuted instantiation: <tracing_log::InfoCallsite as tracing_core::callsite::Callsite>::set_interest
Unexecuted instantiation: <tracing_log::WarnCallsite as tracing_core::callsite::Callsite>::set_interest
Unexecuted instantiation: <tracing_log::ErrorCallsite as tracing_core::callsite::Callsite>::set_interest
323
0
            fn metadata(&self) -> &'static Metadata<'static> {
324
0
                &$meta
325
0
            }
Unexecuted instantiation: <tracing_log::TraceCallsite as tracing_core::callsite::Callsite>::metadata
Unexecuted instantiation: <tracing_log::DebugCallsite as tracing_core::callsite::Callsite>::metadata
Unexecuted instantiation: <tracing_log::InfoCallsite as tracing_core::callsite::Callsite>::metadata
Unexecuted instantiation: <tracing_log::WarnCallsite as tracing_core::callsite::Callsite>::metadata
Unexecuted instantiation: <tracing_log::ErrorCallsite as tracing_core::callsite::Callsite>::metadata
326
        }
327
    };
328
}
329
330
log_cs!(
331
    tracing_core::Level::TRACE,
332
    TRACE_CS,
333
    TRACE_META,
334
    TraceCallsite
335
);
336
log_cs!(
337
    tracing_core::Level::DEBUG,
338
    DEBUG_CS,
339
    DEBUG_META,
340
    DebugCallsite
341
);
342
log_cs!(tracing_core::Level::INFO, INFO_CS, INFO_META, InfoCallsite);
343
log_cs!(tracing_core::Level::WARN, WARN_CS, WARN_META, WarnCallsite);
344
log_cs!(
345
    tracing_core::Level::ERROR,
346
    ERROR_CS,
347
    ERROR_META,
348
    ErrorCallsite
349
);
350
351
0
static TRACE_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&TRACE_CS));
352
0
static DEBUG_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&DEBUG_CS));
353
0
static INFO_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&INFO_CS));
354
0
static WARN_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&WARN_CS));
355
0
static ERROR_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&ERROR_CS));
356
357
0
fn level_to_cs(level: Level) -> (&'static dyn Callsite, &'static Fields) {
358
0
    match level {
359
0
        Level::TRACE => (&TRACE_CS, &*TRACE_FIELDS),
360
0
        Level::DEBUG => (&DEBUG_CS, &*DEBUG_FIELDS),
361
0
        Level::INFO => (&INFO_CS, &*INFO_FIELDS),
362
0
        Level::WARN => (&WARN_CS, &*WARN_FIELDS),
363
0
        Level::ERROR => (&ERROR_CS, &*ERROR_FIELDS),
364
    }
365
0
}
366
367
0
fn loglevel_to_cs(
368
0
    level: log::Level,
369
0
) -> (
370
0
    &'static dyn Callsite,
371
0
    &'static Fields,
372
0
    &'static Metadata<'static>,
373
0
) {
374
0
    match level {
375
0
        log::Level::Trace => (&TRACE_CS, &*TRACE_FIELDS, &TRACE_META),
376
0
        log::Level::Debug => (&DEBUG_CS, &*DEBUG_FIELDS, &DEBUG_META),
377
0
        log::Level::Info => (&INFO_CS, &*INFO_FIELDS, &INFO_META),
378
0
        log::Level::Warn => (&WARN_CS, &*WARN_FIELDS, &WARN_META),
379
0
        log::Level::Error => (&ERROR_CS, &*ERROR_FIELDS, &ERROR_META),
380
    }
381
0
}
382
383
impl<'a> crate::sealed::Sealed for log::Record<'a> {}
384
385
impl<'a> AsTrace for log::Record<'a> {
386
    type Trace = Metadata<'a>;
387
0
    fn as_trace(&self) -> Self::Trace {
388
0
        let cs_id = identify_callsite!(loglevel_to_cs(self.level()).0);
389
0
        Metadata::new(
390
0
            "log record",
391
0
            self.target(),
392
0
            self.level().as_trace(),
393
0
            self.file(),
394
0
            self.line(),
395
0
            self.module_path(),
396
0
            field::FieldSet::new(FIELD_NAMES, cs_id),
397
0
            Kind::EVENT,
398
0
        )
399
0
    }
400
}
401
402
impl crate::sealed::Sealed for tracing_core::Level {}
403
404
impl AsLog for tracing_core::Level {
405
    type Log = log::Level;
406
0
    fn as_log(&self) -> log::Level {
407
0
        match *self {
408
0
            tracing_core::Level::ERROR => log::Level::Error,
409
0
            tracing_core::Level::WARN => log::Level::Warn,
410
0
            tracing_core::Level::INFO => log::Level::Info,
411
0
            tracing_core::Level::DEBUG => log::Level::Debug,
412
0
            tracing_core::Level::TRACE => log::Level::Trace,
413
        }
414
0
    }
415
}
416
417
impl crate::sealed::Sealed for log::Level {}
418
419
impl AsTrace for log::Level {
420
    type Trace = tracing_core::Level;
421
    #[inline]
422
0
    fn as_trace(&self) -> tracing_core::Level {
423
0
        match self {
424
0
            log::Level::Error => tracing_core::Level::ERROR,
425
0
            log::Level::Warn => tracing_core::Level::WARN,
426
0
            log::Level::Info => tracing_core::Level::INFO,
427
0
            log::Level::Debug => tracing_core::Level::DEBUG,
428
0
            log::Level::Trace => tracing_core::Level::TRACE,
429
        }
430
0
    }
431
}
432
433
impl crate::sealed::Sealed for log::LevelFilter {}
434
435
impl AsTrace for log::LevelFilter {
436
    type Trace = tracing_core::LevelFilter;
437
    #[inline]
438
0
    fn as_trace(&self) -> tracing_core::LevelFilter {
439
0
        match self {
440
0
            log::LevelFilter::Off => tracing_core::LevelFilter::OFF,
441
0
            log::LevelFilter::Error => tracing_core::LevelFilter::ERROR,
442
0
            log::LevelFilter::Warn => tracing_core::LevelFilter::WARN,
443
0
            log::LevelFilter::Info => tracing_core::LevelFilter::INFO,
444
0
            log::LevelFilter::Debug => tracing_core::LevelFilter::DEBUG,
445
0
            log::LevelFilter::Trace => tracing_core::LevelFilter::TRACE,
446
        }
447
0
    }
448
}
449
450
impl crate::sealed::Sealed for tracing_core::LevelFilter {}
451
452
impl AsLog for tracing_core::LevelFilter {
453
    type Log = log::LevelFilter;
454
    #[inline]
455
0
    fn as_log(&self) -> Self::Log {
456
0
        match *self {
457
0
            tracing_core::LevelFilter::OFF => log::LevelFilter::Off,
458
0
            tracing_core::LevelFilter::ERROR => log::LevelFilter::Error,
459
0
            tracing_core::LevelFilter::WARN => log::LevelFilter::Warn,
460
0
            tracing_core::LevelFilter::INFO => log::LevelFilter::Info,
461
0
            tracing_core::LevelFilter::DEBUG => log::LevelFilter::Debug,
462
0
            tracing_core::LevelFilter::TRACE => log::LevelFilter::Trace,
463
        }
464
0
    }
465
}
466
/// Extends log `Event`s to provide complete `Metadata`.
467
///
468
/// In `tracing-log`, an `Event` produced by a log (through [`AsTrace`]) has an hard coded
469
/// "log" target and no `file`, `line`, or `module_path` attributes. This happens because `Event`
470
/// requires its `Metadata` to be `'static`, while [`log::Record`]s provide them with a generic
471
/// lifetime.
472
///
473
/// However, these values are stored in the `Event`'s fields and
474
/// the [`normalized_metadata`] method allows to build a new `Metadata`
475
/// that only lives as long as its source `Event`, but provides complete
476
/// data.
477
///
478
/// It can typically be used by `Subscriber`s when processing an `Event`,
479
/// to allow accessing its complete metadata in a consistent way,
480
/// regardless of the source of its source.
481
///
482
/// [`normalized_metadata`]: NormalizeEvent#normalized_metadata
483
pub trait NormalizeEvent<'a>: crate::sealed::Sealed {
484
    /// If this `Event` comes from a `log`, this method provides a new
485
    /// normalized `Metadata` which has all available attributes
486
    /// from the original log, including `file`, `line`, `module_path`
487
    /// and `target`.
488
    /// Returns `None` is the `Event` is not issued from a `log`.
489
    fn normalized_metadata(&'a self) -> Option<Metadata<'a>>;
490
    /// Returns whether this `Event` represents a log (from the `log` crate)
491
    fn is_log(&self) -> bool;
492
}
493
494
impl<'a> crate::sealed::Sealed for Event<'a> {}
495
496
impl<'a> NormalizeEvent<'a> for Event<'a> {
497
0
    fn normalized_metadata(&'a self) -> Option<Metadata<'a>> {
498
0
        let original = self.metadata();
499
0
        if self.is_log() {
500
0
            let mut fields = LogVisitor::new_for(self, level_to_cs(*original.level()).1);
501
0
            self.record(&mut fields);
502
0
503
0
            Some(Metadata::new(
504
0
                "log event",
505
0
                fields.target.unwrap_or("log"),
506
0
                *original.level(),
507
0
                fields.file,
508
0
                fields.line.map(|l| l as u32),
509
0
                fields.module_path,
510
0
                field::FieldSet::new(&["message"], original.callsite()),
511
0
                Kind::EVENT,
512
0
            ))
513
        } else {
514
0
            None
515
        }
516
0
    }
517
518
0
    fn is_log(&self) -> bool {
519
0
        self.metadata().callsite() == identify_callsite!(level_to_cs(*self.metadata().level()).0)
520
0
    }
521
}
522
523
struct LogVisitor<'a> {
524
    target: Option<&'a str>,
525
    module_path: Option<&'a str>,
526
    file: Option<&'a str>,
527
    line: Option<u64>,
528
    fields: &'static Fields,
529
}
530
531
impl<'a> LogVisitor<'a> {
532
    // We don't actually _use_ the provided event argument; it is simply to
533
    // ensure that the `LogVisitor` does not outlive the event whose fields it
534
    // is visiting, so that the reference casts in `record_str` are safe.
535
0
    fn new_for(_event: &'a Event<'a>, fields: &'static Fields) -> Self {
536
0
        Self {
537
0
            target: None,
538
0
            module_path: None,
539
0
            file: None,
540
0
            line: None,
541
0
            fields,
542
0
        }
543
0
    }
544
}
545
546
impl<'a> Visit for LogVisitor<'a> {
547
0
    fn record_debug(&mut self, _field: &Field, _value: &dyn fmt::Debug) {}
548
549
0
    fn record_u64(&mut self, field: &Field, value: u64) {
550
0
        if field == &self.fields.line {
551
0
            self.line = Some(value);
552
0
        }
553
0
    }
554
555
0
    fn record_str(&mut self, field: &Field, value: &str) {
556
0
        unsafe {
557
0
            // The `Visit` API erases the string slice's lifetime. However, we
558
0
            // know it is part of the `Event` struct with a lifetime of `'a`. If
559
0
            // (and only if!) this `LogVisitor` was constructed with the same
560
0
            // lifetime parameter `'a` as the event in question, it's safe to
561
0
            // cast these string slices to the `'a` lifetime.
562
0
            if field == &self.fields.file {
563
0
                self.file = Some(&*(value as *const _));
564
0
            } else if field == &self.fields.target {
565
0
                self.target = Some(&*(value as *const _));
566
0
            } else if field == &self.fields.module {
567
0
                self.module_path = Some(&*(value as *const _));
568
0
            }
569
        }
570
0
    }
571
}
572
573
mod sealed {
574
    pub trait Sealed {}
575
}
576
577
#[cfg(test)]
578
mod test {
579
    use super::*;
580
581
    fn test_callsite(level: log::Level) {
582
        let record = log::Record::builder()
583
            .args(format_args!("Error!"))
584
            .level(level)
585
            .target("myApp")
586
            .file(Some("server.rs"))
587
            .line(Some(144))
588
            .module_path(Some("server"))
589
            .build();
590
591
        let meta = record.as_trace();
592
        let (cs, _keys, _) = loglevel_to_cs(record.level());
593
        let cs_meta = cs.metadata();
594
        assert_eq!(
595
            meta.callsite(),
596
            cs_meta.callsite(),
597
            "actual: {:#?}\nexpected: {:#?}",
598
            meta,
599
            cs_meta
600
        );
601
        assert_eq!(meta.level(), &level.as_trace());
602
    }
603
604
    #[test]
605
    fn error_callsite_is_correct() {
606
        test_callsite(log::Level::Error);
607
    }
608
609
    #[test]
610
    fn warn_callsite_is_correct() {
611
        test_callsite(log::Level::Warn);
612
    }
613
614
    #[test]
615
    fn info_callsite_is_correct() {
616
        test_callsite(log::Level::Info);
617
    }
618
619
    #[test]
620
    fn debug_callsite_is_correct() {
621
        test_callsite(log::Level::Debug);
622
    }
623
624
    #[test]
625
    fn trace_callsite_is_correct() {
626
        test_callsite(log::Level::Trace);
627
    }
628
}