-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Add a helper for logging only once #10291
Comments
The log macros are already macros. We can probably add warn_once!() variants that create a static bool per call-site. Might be nicer than a system local argument. |
Yeah, I'm open to either approach honestly. |
No experience with singletons or macros in rust, but giving this a go! Using https://github.com/Luthaf/log-once as an example, I managed to cobble together the following PoC: This works, but uses a singleton hashset. we might not want this as our 'once' determiner. Doing something like Any idea how to statically define a unique boolean per call @JMS55 ? |
Simplest solution I can think of is a fn example_system(res: Res<MyResource>) {
if res.is_invalid() {
warn_once!("my_resource_invalid_tag", "Resource is invalid! Happened at: {:?}", std::time::SystemTime::now());
}
} |
The macro will expand at the callsite, resulting in a unique static |
Is it clear that "build a log only once helper" is the right approach here? For example, another solution is a log sampling method/functionality. I know it's not Rust, and I know it's not in the Go std lib, but take a look a Zerolog in the Go ecosystem: https://pkg.go.dev/github.com/rs/zerolog#readme-log-sampling sampled := log.Sample(&zerolog.BasicSampler{N: 10})
sampled.Info().Msg("will be logged every 10 messages")
// Output: {"time":1494567715,"level":"info","message":"will be logged every 10 messages"} Not saying to ape this as is, I'm just sharing an example of how a sampling solution could be flexible here without (arguably) going so far as over-engineering. |
If going with the impl Local<'_, bool> {
fn set_false_if(&mut self, condition: bool) -> bool {
if self.0 {
self.0 = false;
condition
} else {
false
}
}
} |
Hmmm... You are raising some good points, @mgi388. I'm also not really sure why macro's are even used at all for logging, aside from mimicking fn my_system(mut c: Commands) {
let name = "mgi";
c.log(Level::Info, format!("Hello, {}!", name)).once("token");
c.log_warn("spam");
} In any case, lets prevent scope creep. I think that the log_once!() macro @emesare offers is a great solution. I didnt know macro symbols are unique per macro, thanks for pointing it out! Its concise, low-overhead, easy-to-use, and it feels like magic, since the booleans are hidden within the macro. Apologies for waiting quite long for continuing this. Hope to start working on it Soon (tm) |
Macro are used for logging so that format which creates strings is not executed if that log level is disabled |
Ah of course, thanks @mockersf ! |
# Objective Fixes #10291 This adds a way to easily log messages once within system which are called every frame. ## Solution Opted for a macro-based approach. The fact that the 'once' call is tracked per call site makes the `log_once!()` macro very versatile and easy-to-use. I suspect it will be very handy for all of us, but especially beginners, to get some initial feedback from systems without spamming up the place! I've made the macro's return its internal `has_fired` state, for situations in which that might be useful to know (trigger something else alongside the log, for example). Please let me know if I placed the macro's in the right location, and if you would like me to do something more clever with the macro's themselves, since its looking quite copy-pastey at the moment. I've tried ways to replace 5 with 1 macro's, but no success yet. One downside of this approach is: Say you wish to warn the user if a resource is invalid. In this situation, the `resource.is_valid()` check would still be performed every frame: ```rust fn my_system(my_res: Res<MyResource>) { if !my_res.is_valid() { warn_once!("resource is invalid!"); } } ``` If you want to prevent that, you would still need to introduce a local boolean. I don't think this is a very big deal, as expensive checks shouldn't be called every frame in any case. ## Changelog Added: `trace_once!()`, `debug_once!()`, `info_once!()`, `warn_once!()`, and `error_once!()` log macros which fire only once per call site.
What problem does this solve or what need does it fill?
We commonly need to log a warning in a system, but don't want to spam the users.
What solution would you like?
Add a system param that stores a local which is flipped once:
What alternative(s) have you considered?
We could handle this at the logging level, but this is likely to be over specific and there's no clear place to store the state.
We could handle this at the run condition level, but that delocalizes logic and we may not want to stop the system from running again.
Additional context
Suggested by @JMS55 after reviewing #9873
The text was updated successfully, but these errors were encountered: