Skip to content

Commit e7f93df

Browse files
committed
Fix {tid} incorrectly outputting TID of thread pool in AsyncPoolSink
1 parent 3bfb3c6 commit e7f93df

File tree

6 files changed

+87
-24
lines changed

6 files changed

+87
-24
lines changed

clippy.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# TODO: Remove this in the next minor version (After `RecordOwned` is boxed in `SendToChannelErrorDropped`)
2+
large-error-threshold = 136

spdlog/src/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ pub enum SendToChannelError {
174174
#[non_exhaustive]
175175
pub enum SendToChannelErrorDropped {
176176
/// A `log` operation and a record are dropped.
177+
// TODO: Box the `RecordOwned` in the next minor version, as it's a bit large.
177178
Record(RecordOwned),
178179
/// A `flush` operation is dropped.
179180
Flush,

spdlog/src/formatter/pattern_formatter/pattern/process_id.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ impl Pattern for ProcessId {
3030
}
3131
}
3232

33+
// TODO: We can cache the PID someway to improve the performance, but remember
34+
// to test the case of process forking.
35+
3336
#[cfg(target_family = "unix")]
3437
#[must_use]
3538
fn get_current_process_id() -> u64 {

spdlog/src/formatter/pattern_formatter/pattern/thread_id.rs

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,10 @@ pub struct ThreadId;
2323
impl Pattern for ThreadId {
2424
fn format(
2525
&self,
26-
_record: &Record,
26+
record: &Record,
2727
dest: &mut StringBuf,
2828
_ctx: &mut PatternContext,
2929
) -> crate::Result<()> {
30-
let tid = get_current_thread_id();
31-
write!(dest, "{}", tid).map_err(Error::FormatRecord)
30+
write!(dest, "{}", record.tid()).map_err(Error::FormatRecord)
3231
}
3332
}
34-
35-
#[cfg(target_os = "linux")]
36-
#[must_use]
37-
fn get_current_thread_id() -> u64 {
38-
let tid = unsafe { libc::gettid() };
39-
tid as u64
40-
}
41-
42-
#[cfg(target_os = "macos")]
43-
#[must_use]
44-
fn get_current_thread_id() -> u64 {
45-
let tid = unsafe { libc::pthread_self() };
46-
tid as u64
47-
}
48-
49-
#[cfg(target_os = "windows")]
50-
#[must_use]
51-
fn get_current_thread_id() -> u64 {
52-
let tid = unsafe { winapi::um::processthreadsapi::GetCurrentThreadId() };
53-
tid as u64
54-
}

spdlog/src/record.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use std::{
44
borrow::{Borrow, Cow},
5+
cell::RefCell,
56
time::SystemTime,
67
};
78

@@ -33,6 +34,7 @@ struct RecordInner {
3334
level: Level,
3435
source_location: Option<SourceLocation>,
3536
time: SystemTime,
37+
tid: u64,
3638
}
3739

3840
impl<'a> Record<'a> {
@@ -51,6 +53,7 @@ impl<'a> Record<'a> {
5153
level,
5254
source_location: None,
5355
time: SystemTime::now(),
56+
tid: get_current_tid(),
5457
}),
5558
}
5659
}
@@ -106,6 +109,13 @@ impl<'a> Record<'a> {
106109
self.inner.time
107110
}
108111

112+
/// Gets the TID when the record was created.
113+
// TODO: Public this new method to users in the next minor version
114+
#[must_use]
115+
pub(crate) fn tid(&self) -> u64 {
116+
self.inner.tid
117+
}
118+
109119
// When adding more getters, also add to `RecordOwned`
110120

111121
#[cfg(feature = "log")]
@@ -127,6 +137,9 @@ impl<'a> Record<'a> {
127137
level: record.level().into(),
128138
source_location: SourceLocation::from_log_crate_record(record),
129139
time,
140+
// For records from `log` crate, they never seem to come from different threads, so
141+
// getting the current TID here should be correct
142+
tid: get_current_tid(),
130143
}),
131144
}
132145
}
@@ -243,3 +256,32 @@ impl<'a> RecordBuilder<'a> {
243256
self.record
244257
}
245258
}
259+
260+
fn get_current_tid() -> u64 {
261+
#[cfg(target_os = "linux")]
262+
#[must_use]
263+
fn get_current_tid_inner() -> u64 {
264+
let tid = unsafe { libc::gettid() };
265+
tid as u64
266+
}
267+
268+
#[cfg(target_os = "macos")]
269+
#[must_use]
270+
fn get_current_tid_inner() -> u64 {
271+
let tid = unsafe { libc::pthread_self() };
272+
tid as u64
273+
}
274+
275+
#[cfg(target_os = "windows")]
276+
#[must_use]
277+
fn get_current_tid_inner() -> u64 {
278+
let tid = unsafe { winapi::um::processthreadsapi::GetCurrentThreadId() };
279+
tid as u64
280+
}
281+
282+
thread_local! {
283+
static TID: RefCell<Option<u64>> = RefCell::new(None);
284+
}
285+
286+
TID.with(|tid| *tid.borrow_mut().get_or_insert_with(get_current_tid_inner))
287+
}

spdlog/tests/pattern.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,3 +430,40 @@ fn test_builtin_patterns() {
430430
check(pattern!("{tid}"), None as Option<&str>, vec![OS_ID_RANGE]);
431431
check(pattern!("{eol}"), Some("{eol}"), vec![]);
432432
}
433+
434+
#[cfg(feature = "multi-thread")]
435+
#[test]
436+
fn test_different_context_thread() {
437+
use std::time::Duration;
438+
439+
use spdlog::{sink::AsyncPoolSink, ThreadPool};
440+
441+
let formatter = Box::new(PatternFormatter::new(pattern!("{tid}{eol}")));
442+
let thread_pool = Arc::new(ThreadPool::builder().build().unwrap());
443+
let buffer_sink = Arc::new(
444+
WriteSink::builder()
445+
.formatter(formatter)
446+
.target(Vec::new())
447+
.build()
448+
.unwrap(),
449+
);
450+
let sinks: [Arc<dyn Sink>; 2] = [
451+
buffer_sink.clone(),
452+
Arc::new(
453+
AsyncPoolSink::builder()
454+
.sink(buffer_sink.clone())
455+
.thread_pool(thread_pool)
456+
.build()
457+
.unwrap(),
458+
),
459+
];
460+
let logger = Arc::new(Logger::builder().sinks(sinks).build().unwrap());
461+
462+
info!(logger: logger, "");
463+
std::thread::sleep(Duration::from_millis(200));
464+
465+
let buffer = String::from_utf8(buffer_sink.clone_target()).unwrap();
466+
let buffer = buffer.lines().collect::<Vec<_>>();
467+
assert_eq!(buffer.len(), 2);
468+
buffer.windows(2).for_each(|w| assert_eq!(w[0], w[1]))
469+
}

0 commit comments

Comments
 (0)