Skip to content

Commit 248aae9

Browse files
authored
Merge pull request #852 from sdroege/bool-error-gstr
glib: Use actual function name in `glib::BoolError` and include function name/source file/line number in structured logs
2 parents 3cc1064 + 83557ec commit 248aae9

File tree

4 files changed

+131
-38
lines changed

4 files changed

+131
-38
lines changed

glib/src/error.rs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -158,30 +158,46 @@ pub trait ErrorDomain: Copy {
158158
#[macro_export]
159159
macro_rules! bool_error(
160160
// Plain strings
161-
($msg:expr) => {
162-
$crate::BoolError::new($msg, file!(), module_path!(), line!())
163-
};
161+
($msg:expr) => {{
162+
$crate::BoolError::new(
163+
$msg,
164+
file!(),
165+
$crate::function_name!(),
166+
line!(),
167+
)
168+
}};
164169

165170
// Format strings
166-
($($msg:tt)*) => { {
167-
$crate::BoolError::new(format!($($msg)*), file!(), module_path!(), line!())
171+
($($msg:tt)*) => {{
172+
$crate::BoolError::new(
173+
format!($($msg)*),
174+
file!(),
175+
$crate::function_name!(),
176+
line!(),
177+
)
168178
}};
169179
);
170180

171181
#[macro_export]
172182
macro_rules! result_from_gboolean(
173183
// Plain strings
174-
($ffi_bool:expr, $msg:expr) => {
175-
$crate::BoolError::from_glib($ffi_bool, $msg, file!(), module_path!(), line!())
176-
};
184+
($ffi_bool:expr, $msg:expr) => {{
185+
$crate::BoolError::from_glib(
186+
$ffi_bool,
187+
$msg,
188+
file!(),
189+
$crate::function_name!(),
190+
line!(),
191+
)
192+
}};
177193

178194
// Format strings
179-
($ffi_bool:expr, $($msg:tt)*) => { {
195+
($ffi_bool:expr, $($msg:tt)*) => {{
180196
$crate::BoolError::from_glib(
181197
$ffi_bool,
182198
format!($($msg)*),
183199
file!(),
184-
module_path!(),
200+
$crate::function_name!(),
185201
line!(),
186202
)
187203
}};

glib/src/lib.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,49 @@ pub use self::variant_dict::VariantDict;
4848
pub use self::variant_iter::{VariantIter, VariantStrIter};
4949
pub use self::variant_type::{VariantTy, VariantTyIterator, VariantType};
5050

51+
// Hack for the time being to retrieve the current function's name as a string.
52+
// Based on the stdext cratelicensed under the MIT license.
53+
//
54+
// Copyright (c) 2020 Igor Aleksanov
55+
//
56+
// Previous attempts to get such a macro into std:
57+
// * https://github.com/rust-lang/rfcs/pull/466
58+
// * https://github.com/rust-lang/rfcs/pull/1719
59+
// * https://github.com/rust-lang/rfcs/issues/1743
60+
// * https://github.com/rust-lang/rfcs/pull/2818
61+
// * ...
62+
// rustdoc-stripper-ignore-next
63+
/// This macro returns the name of the enclosing function.
64+
/// As the internal implementation is based on the [`std::any::type_name`], this macro derives
65+
/// all the limitations of this function.
66+
///
67+
/// ## Examples
68+
///
69+
/// ```rust
70+
/// mod bar {
71+
/// pub fn sample_function() {
72+
/// assert!(glib::function_name!().ends_with("bar::sample_function"));
73+
/// }
74+
/// }
75+
///
76+
/// bar::sample_function();
77+
/// ```
78+
///
79+
/// [`std::any::type_name`]: https://doc.rust-lang.org/std/any/fn.type_name.html
80+
#[macro_export]
81+
macro_rules! function_name {
82+
() => {{
83+
// Okay, this is ugly, I get it. However, this is the best we can get on a stable rust.
84+
fn f() {}
85+
fn type_name_of<T>(_: T) -> &'static str {
86+
std::any::type_name::<T>()
87+
}
88+
let name = type_name_of(f);
89+
// `3` is the length of the `::f`.
90+
&name[..name.len() - 3]
91+
}};
92+
}
93+
5194
pub mod clone;
5295
#[macro_use]
5396
pub mod wrapper;

glib/src/log.rs

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -859,36 +859,57 @@ macro_rules! g_printerr {
859859
/// ```
860860
#[macro_export]
861861
macro_rules! log_structured {
862-
($log_domain:expr, $log_level:expr, {$($key:expr => $format:expr $(,$arg:expr)* $(,)?);+ $(;)?} $(,)?) => {
863-
(|| {
864-
let log_domain = <Option<&str> as std::convert::From<_>>::from($log_domain);
865-
let log_domain_str = log_domain.unwrap_or_default();
866-
let level: $crate::LogLevel = $log_level;
867-
let field_count =
868-
<[()]>::len(&[$($crate::log_structured_inner!(@clear $key)),+])
869-
+ log_domain.map(|_| 2usize).unwrap_or(1usize);
870-
871-
$crate::log_structured_array(
872-
level,
873-
&[
874-
$crate::LogField::new(
875-
$crate::gstr!("PRIORITY"),
876-
level.priority().as_bytes(),
877-
),
878-
$(
879-
$crate::LogField::new(
880-
$crate::log_structured_inner!(@key $key),
881-
$crate::log_structured_inner!(@value $format $(,$arg)*),
882-
),
883-
)+
862+
($log_domain:expr, $log_level:expr, {$($key:expr => $format:expr $(,$arg:expr)* $(,)?);+ $(;)?} $(,)?) => {{
863+
let log_domain = <Option<&str> as std::convert::From<_>>::from($log_domain);
864+
let log_domain_str = log_domain.unwrap_or_default();
865+
let level: $crate::LogLevel = $log_level;
866+
let field_count =
867+
<[()]>::len(&[$($crate::log_structured_inner!(@clear $key)),+])
868+
+ log_domain.map(|_| 2usize).unwrap_or(1usize)
869+
+ 3;
870+
871+
let mut line = [0u8; 32]; // 32 decimal digits of line numbers should be enough!
872+
let line = {
873+
use std::io::Write;
874+
875+
let mut cursor = std::io::Cursor::new(&mut line[..]);
876+
std::write!(&mut cursor, "{}", line!()).unwrap();
877+
let pos = cursor.position() as usize;
878+
&line[..pos]
879+
};
880+
881+
$crate::log_structured_array(
882+
level,
883+
&[
884+
$crate::LogField::new(
885+
$crate::gstr!("PRIORITY"),
886+
level.priority().as_bytes(),
887+
),
888+
$crate::LogField::new(
889+
$crate::gstr!("CODE_FILE"),
890+
file!().as_bytes(),
891+
),
892+
$crate::LogField::new(
893+
$crate::gstr!("CODE_LINE"),
894+
line,
895+
),
896+
$crate::LogField::new(
897+
$crate::gstr!("CODE_FUNC"),
898+
$crate::function_name!().as_bytes(),
899+
),
900+
$(
884901
$crate::LogField::new(
885-
$crate::gstr!("GLIB_DOMAIN"),
886-
log_domain_str.as_bytes(),
902+
$crate::log_structured_inner!(@key $key),
903+
$crate::log_structured_inner!(@value $format $(,$arg)*),
887904
),
888-
][0..field_count],
889-
)
890-
})()
891-
};
905+
)+
906+
$crate::LogField::new(
907+
$crate::gstr!("GLIB_DOMAIN"),
908+
log_domain_str.as_bytes(),
909+
),
910+
][0..field_count],
911+
)
912+
}};
892913
}
893914

894915
#[doc(hidden)]

glib/tests/structured_log.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,22 @@ fn structured_log() {
8282
)
8383
})
8484
.collect::<Vec<_>>();
85+
86+
let path = if cfg!(windows) {
87+
"glib\\tests\\structured_log.rs"
88+
} else {
89+
"glib/tests/structured_log.rs"
90+
};
91+
8592
assert_eq!(
8693
log[0],
8794
(
8895
LogLevel::Message,
8996
vec![
9097
("PRIORITY", "5" as &str),
98+
("CODE_FILE", path as &str),
99+
("CODE_LINE", "30" as &str),
100+
("CODE_FUNC", "structured_log::structured_log" as &str),
91101
("MY_META", "abc"),
92102
("MESSAGE", "normal with meta"),
93103
("MY_META2", "def"),
@@ -101,6 +111,9 @@ fn structured_log() {
101111
LogLevel::Message,
102112
vec![
103113
("PRIORITY", "5" as &str),
114+
("CODE_FILE", path as &str),
115+
("CODE_LINE", "40" as &str),
116+
("CODE_FUNC", "structured_log::structured_log" as &str),
104117
("MY_META", "abc"),
105118
("MESSAGE", "formatted with meta: 123 456"),
106119
("MY_META2", "defghi"),

0 commit comments

Comments
 (0)