-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement RuntimePattern
#45
Conversation
6fba4aa
to
cde1dc1
Compare
cde1dc1
to
fd2c3cf
Compare
Nice work. But I believe we need further discussion on this to avoid any potential security vulnerabilities. There are just too many severe security vulnerabilities in logging libraries. While it is essential to be able to parse pattern template strings at runtime to support features like configuration files, is it necessary to allow the user to build the "pattern registry" at runtime? In the current design, the registry is basically a Thus, I believe it is more appropriate to only allow building the pattern registry at compile time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally LGTM except for some small problems listed. And we need further discussion on the security problem I just commented in the PR discussion thread before this PR can actually land.
@@ -428,7 +432,7 @@ impl PatternContext { | |||
/// There are 2 approaches to create your own pattern: | |||
/// - Define a new type and implements this trait; | |||
/// - Use the [`pattern`] macro to create a pattern from a template string. | |||
pub trait Pattern: Send + Sync { | |||
pub trait Pattern: Send + Sync + DynClone { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does Pattern
requires Clone
after the change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatter
requires Clone
to be implemented since 78e359c, so that we can implement set_formatter
for combined sink
spdlog-rs/spdlog/src/sink/async_sink/async_pool_sink.rs
Lines 86 to 92 in 0a2489c
/// For [`AsyncPoolSink`], the function performs the same call to all | |
/// internal sinks. | |
fn set_formatter(&self, formatter: Box<dyn Formatter>) { | |
for sink in &self.backend.sinks { | |
sink.set_formatter(formatter.clone_box()) | |
} | |
} |
Before this PR, all patterns are actual types, present in the generic P
of PatternFormatter<P>
, also all patterns implemented Clone
, so we didn't explicitly bound Clone
for trait Pattern
.
But with runtime pattern, we now have Box<dyn Pattern>
which doesn't implement Clone
, if we impl Clone for Box<dyn Pattern>
, we have to bound Clone
on trait Pattern
, and DynClone
make it possible with object-safe.
I agree with your security concerns, but I'm still hesitant to drop the custom pattern support for So I decided to change the built-in patterns in the registry to a compile-time array (the type would be From the information so far, I'm still not sure if I should be for or against dropping custom patterns. However, deserializing from config files is not currently planned to support custom patterns, as the build will be done internally by |
Well, custom pattern support itself is not the root cause of the security problem. The whole point is, we can provide custom pattern support, provided that the set of custom patterns provided by the user must be determined at compile time. For security's sake, we just cannot let the user build the set of custom patterns at runtime. The idea of custom patterns itself has nothing wrong. As for implementation, maybe we can introduce a new macro named let patterns = pattern_set!{
{$mypat} => MyPattern::default,
{$myotherpat} => MyOtherPattern::default,
}; The implementation may take some time. If you are in a hurry to land this PR, maybe we can just land first and then implement the custom pattern support in future PRs. |
Nice point, I see.
Or maybe it would be better to just implement a new let pattern: RuntimePattern = runtime_pattern!(template_str, {$custom} => Custom::default); |
I plan to release v0.4.0 with the 2 new features RuntimePattern and Config. So RuntimePattern just needs to be done before Config PR is ready to be merged. There's no clear timeline at the moment, but there should be plenty of time, so we are not in a hurry to merge this PR :) |
I think this is better. It is consistent with existing |
I quickly go through the code in this PR and I found it a good starting point for implementing the I believe what left for me to do is just to remove |
I have added the The documentation of the |
Now the feature should be completed. Seems that I cannot request a review from the PR author through GitHub, so have a review @SpriteOvO . |
@Lancern Thanks! I'm gonna review it in the next few days. And happy new year! 🎉 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have left some comments, and feel free to discuss about them. If there is no objection, I will apply these changes and finish the rest of the work of the PR.
registry.register_custom(#name_literal, Box::new(|| Box::new(#factory()))) | ||
.expect("unexpected panic, please report a bug to spdlog-rs"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmm, I think we should pass an array of custom patterns into the registry, and storing it in a separated field of PatternRegistry
. Otherwise there is not much difference compare to the previous struct RuntimePatternBuilder
approach, it's still building a set of custom patterns at runtime.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmm, I think we should pass an array of custom patterns into the registry, and storing it in a separated field of
PatternRegistry
. Otherwise there is not much difference compare to the previousstruct RuntimePatternBuilder
approach, it's still building a set of custom patterns at runtime.
The idea is actually more complicated than I expected, so let's just keep it that way.
a2b7cbe
to
71b4fd2
Compare
38cf870
to
62d2abf
Compare
I removed the dependency The reason for using self-reference is that the Once that's fine, I think this PR might be ready to merge, I'll do some final checks. I apologize for the long delay. |
d392e0c
to
cb21cb0
Compare
@SpriteOvO I'll review it as soon as I get some free time before this weekend! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly good, just a single NIT in the inline comments and it's ready to go!
&self, | ||
template: Template, | ||
mut style_range_seen: bool, | ||
) -> PatternParserResult<Patterns> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this function can be inlined into synthesis
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
build_patterns
will recursively call itself with an style_range_seen = true
argument, while synthesis
calls it initially with style_range_seen = false
.
Keeping this way we can hide the initial value of this argument instead of the caller being responsible for specifying it.
cb21cb0
to
03da466
Compare
03da466
to
0c4d130
Compare
0c4d130
to
1d1ad02
Compare
Cleared some doc and rebased to branch |
This PR introduces
RuntimePattern
to implement the ability of building a patterns at runtime, this also allows us to implement serialization for loggers (#25) containingPatternFormatter
in the future.Basically, this PR did:
Split pattern template parser from crate
spdlog-macros
to a separate cratespdlog-internal
. so that the runtime builder and compile-time builder can shared the same parser code.Creating a separate crate seems to be the only way to share code between lib crate and proc-macro crate, or maybe we could publish a generic crate for the pattern feature, which would allow more other crates to use it. @Lancern Are you interested in this? Since you are the author of the pattern feature, to publish such a crate I think you are the best person to do it if you are interested.
Implement
Clone
for allPattern
types by usingdyn-clone
crate, as formatters are required to be clonable,Box<dyn Pattern>
are also need to be clonable.Add
RuntimePattern
and(Removed, added aRuntimePatternBuilder
runtime_pattern!
macro instead).Documentation improvements.