Reputation: 2868
I am trying to achieve something like this:
error
message with some captured variables;error
message;error
message to user eventually;Apparently this can be done in a few lines of code, but it is a bit tedious since i need this pattern heavily everywhere in my project, i mean like below:
let var_a = 233;
let err = format!("some custom error message, var_a: {}", var_a);
// Here i do the logging with the `tokio-rs/tracing` macros.
error!(err = %err, "some custom error message");
// The s_errs will be eventually showed to end users.
s_errs.append(err);
I am trying to achieve this with a macro which wraps the tokio-rs/tracing
macros but return the constructed err
message:
#[macro_export]
macro_rules! log_usr_err {
($($arg:tt)+) => (
error!($($arg)+)
format!($($arg)+)
);
}
so i can just use this macro in my project to simplify the coding a bit:
let err = log_usr_err!("some custom error message, {}", var_a = var_a);
// The s_errs will be eventually showed to end users.
s_errs.append(err);
but stuck at the compile error:
error: macro expansion ignores token `format` and any following
How should i return the formatted string from my log_urs_err!
macro?
Coz in the future in want to include the accurate file!
info and the line!
info also in my logs, thus i think via macro is the right direction to go, or there is some better approach?
Upvotes: 0
Views: 847
Reputation: 10218
Let's just try and look at what the expanded code would look like in your case. Reiterating the code in question:
#[macro_export]
macro_rules! log_usr_err {
($($arg:tt)+) => (
error!($($arg)+)
format!($($arg)+)
);
}
let err = log_usr_err!("some custom error message, {}", var_a = var_a);
If we try to literally substitute the result of macro expansion, we'd get the following:
let err = error!("some custom error message, {}", var_a = var_a)
format!("some custom error message, {}", var_a = var_a);
This is obviously not valid Rust.
The problem is that your macro is currently written to expand to the list of statements, i.e. to some self-contained part of the code (of course, after adding the necessary semicolon between error
and format
). It can be, for example, a function body (playground):
macro_rules! log_usr_err {
($($arg:tt)+) => (
error!($($arg)+);
format!($($arg)+)
);
}
fn err() {
log_usr_err!("test");
}
But you'd like to use this macro in expression position, i.e. to assign the value returned from it to the variable. For this, macro must expand to the expression, not to statements.
So, what to do? The change is, in fact, quite simple: a set of statements can be converted to expression by wrapping them in a block, since blocks are expressions:
macro_rules! log_usr_err {
($($arg:tt)+) => ({
error!($($arg)+);
format!($($arg)+)
});
}
Note the extra braces around the macro content. With this change, your code compiles.
Upvotes: 2