Attribute for skipping field of struct in Debug derives?
Could we have something like this?
#[derive(Debug)]
struct Foo {
pub a: A,
pub b: B,
#[skip_derive]
pub c: C, // especially useful if C : !Debug
}
This could also feasibly be applied to other auto-derivations, of course (not just Debug).
At minimum we could certainly do it in a library with Macros 1.1 (then it would need a different name like
#[derive(DebugEx)]).Alex Burka at 2016-10-07 04:57:36
Yeah, that would be a step forward at least. Would be nice to have it work for the built-in Debug though, I think.
Alexander Regueiro at 2016-10-07 13:42:32
I started such a library a few days ago that does that: https://github.com/mcarton/rust-derivative. It's not finished, not really documented, not published on crates.io, but the POC is there :sweat_smile:
Martin Carton at 2016-10-07 14:38:45
Cool, thanks for sharing that. Is Macros 1.1 already fully implemented in nightly then? I may give it a go shortly.
On 7 Oct 2016, at 15:39, Martin Carton notifications@github.com wrote:
I started such a library a few days ago that does that: https://github.com/mcarton/rust-derivative https://github.com/mcarton/rust-derivative. It's not finished, not really documented, not published on crates.io, but the POC is there 😅
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/37009#issuecomment-252269933, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEF3C1_mt5g26LCXeOHH8_2Xl8oPozmks5qxlmXgaJpZM4KQgfg.
Alexander Regueiro at 2016-10-07 14:40:47
I'm wondering with all the recent Macro 2.0 developments whether the derive attribute macro might become a crate of its own in the future, such that it could be enhanced without changes to the actual compiler. A feature like this would then be much easier to get implemented, I suspect. Thoughts, @jseyfried @Manishearth?
Alexander Regueiro at 2018-02-03 03:20:32
Custom derives can already be implemented outside of the compiler.
Steven Fackler at 2018-02-03 03:26:34
@sfackler You misunderstand. I mean the workings of the derive attribute macro itself.
Alexander Regueiro at 2018-02-03 03:40:12
How would pulling
libsyntax_ext::derivinginto a different crate make this feature easier to implement? Difficulty of implementation is not the limiting factor here in any case.Steven Fackler at 2018-02-03 03:58:07
It actually is. The stage1 compiler cannot depend on proc macros IIRC. I suppose you could still make it work with some shimming of libproc_macro and including it directly in libsyntax.
On Feb 3, 2018 9:28 AM, "Steven Fackler" notifications@github.com wrote:
How would pulling libsyntax_ext::deriving into a different crate make this feature easier to implement? Difficulty of implementation is not the limiting factor here in any case.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/37009#issuecomment-362777223, or mute the thread https://github.com/notifications/unsubscribe-auth/ABivSM9JAEoWXYntq2eAop_hqxcPNJBLks5tQ9llgaJpZM4KQgfg .
Manish Goregaokar at 2018-02-03 04:13:30
But that would mean that deriving can't be pulled out to a proc macro, not that pulling it out to a proc macro would make it easier to add extra control attributes, right?
Steven Fackler at 2018-02-03 04:16:58
I was thinking more of maintainability and neat, elegant separation of concerns. Not sure on the details of what @Manishearth just said, but that could be an interesting point.
Alexander Regueiro at 2018-02-03 04:23:06
Yes.
On Feb 3, 2018 9:47 AM, "Steven Fackler" notifications@github.com wrote:
But that would mean that deriving can't be pulled out to a proc macro, not that pulling it out to a proc macro would make it easier to add extra control attributes, right?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/37009#issuecomment-362778267, or mute the thread https://github.com/notifications/unsubscribe-auth/ABivSJDNTB2oca9ltELAfA1bGF__wJolks5tQ93NgaJpZM4KQgfg .
Manish Goregaokar at 2018-02-03 04:30:33
Is there no elegant way to get around this restriction?
Alexander Regueiro at 2018-02-03 04:45:10
I'm not 100% clear on whether this restriction will be a problem here.
@eddyb knows
Manish Goregaokar at 2018-02-03 04:46:54
Kind of digging up a buried corpse, but the crate https://crates.io/crates/derivative does that with
#[derivative(Debug="ignore")]I think the issue can be closed with this. Thank you @mcarton!
irexiz at 2020-05-21 08:40:35
A way of skipping fields in #[derive(Debug)] would be particularly useful for structs that have to use PhantomData.
Allen-Webb at 2021-06-16 16:01:40
The feature is also helpful for structs that have sensitive data like AWS s3 access_key_id & secret_access_key.
Xuanwo at 2022-03-11 10:37:33
For me, the problem often arises when using 3rd party libraries that don't implement
Debugon their types, which disallows me from usingderive(Debug)on my own types.Sometimes all I need is just a quick way to derive
Debugon my type rather than manually implementing it, so I'm ok with skipping a field. So I'm fairly certain that this would be incredibly helpful if it were in the std library(While libraries exist which can do this, it would be nice to not have to rely on them)
Cherry at 2023-03-04 14:38:33
I think that the issue of deriving
Debugfor 3rd party types is a separate issue @MolotovCherry.
Regarding skipping fields, serde has a similar mechanism for serialization:
#[derive(Serialize) struct MyStruct { // serialized always name: String, // serialized never #[serde(skip)] aws_secret: String, // serialized when `Option::is_none(&my_struct.extra)` is `false` #[serde(skip_serializing_if = "Option::is_none")] extra: Option<String> }Debug could work similarly:
#[derive(Debug) struct MyStruct { // debug always name: String, // debug never #[debug(skip)] aws_secret: String, // serialized when `Option::is_none(&my_struct.extra)` is `false` #[debug(skip_if = "Option::is_none")] extra: Option<String> }The API is can be a bit simpler compared to
serde, asserdehas separate mechanisms for skipping serialization and de-serialization.Aljaž Mur Eržen at 2023-11-26 09:57:00
@aljazerzen I think you misunderstand me.
Implementing a 3rd party trait for a 3rd party type is not allowed due to the orphan rule (though I suppose a workaround would be possible). I'm not arguing to overturn the orphan rule (or overturn it for only 1 specific instance).
I'm talking about skipping fields in my own types which derive debug, but can't derive debug, because a third party type doesn't. Which is related to what this issue is about (and could be solved by it)
#[derive(Debug)] struct MyType { other_field: u64, // this third party type didn't implement Debug, now I can't derive debug // but I don't care about getting the details of ThirdPartyType, I just want to quickly debug MyType // having to do a manual Debug impl just to skip it would be cumbersome. I just want to program! // // If I do want to show data for ThirdPartyType, I will manually implement it, // but I don't need to nor want to right now // // the following would be nice #[debug(skip)] foo: ThirdPartyType }Cherry at 2023-11-26 14:30:13
Yes, I didn't understand what you meant. This is very related and a good argument for the feature.
Aljaž Mur Eržen at 2023-11-27 09:24:59
Alternatively, perhaps
#[derive(Debug)]could have a flag or variant that just silently skips types without theDebugtrait. I'm hitting this a lot when trying to write code which interoperates between things likeitertoolsandndarray, since a lot of stuff initertoolsdemandsDebug, and a bunch of stuff inndarraydoesn't provide it.Can someone summarize the current (EOY '23) best workaround?
David Beaumont at 2023-12-25 16:39:53
Alternatively, perhaps
#[derive(Debug)]could have a flag or variant that just silently skips types without theDebugtrait.I have several cases where my struct contains a binary byte slice with stuff that isn't interesting for debugging, or outright shouldn't be logged -- think crypto keys. Just because it implements
Debugdoesn't mean I want it in my debug output.Tv at 2024-01-01 23:52:19
Alternatively, perhaps #[derive(Debug)] could have a flag or variant that just silently skips types without the Debug trait.
Note that this is currently not possible, because deriving happens before type checking.
Jakub Beránek at 2024-01-03 10:58:05
Can someone summarize the current (EOY '23) best workaround?
Use derivative - an alternative derive for implementing
std::fmt::Debug.Aljaž Mur Eržen at 2024-01-03 15:07:52
We need this feature so much because we don't want to expose private keys and credentials when debugging.
Mahmoud at 2024-05-03 17:02:02
As an alternative, you can also achieve that by wrapping sensitive data into a
Secretnewtype, e.g. usingsecrecy.Jakub Beránek at 2024-05-03 20:36:47
No! That's cheating! We need a built-in thing and not a third party crate, btw!
Mahmoud at 2024-05-03 21:28:27
Can someone summarize the current (EOY '23) best workaround?
Use derivative - an alternative derive for implementing
std::fmt::Debug.Derivative is effectively unmaintained, there are a couple alternatives but it really is needed built-in IMO
Émile Fugulin at 2024-05-04 21:28:05
We need this feature so much because we don't want to expose private keys and credentials when debugging.
Same use case here, it would be great to have such a
skipattribute.Geovane Fedrecheski at 2024-05-28 12:22:42
This also goes as cheating but a wrapper type isn’t exactly much code:
use std::fmt::Debug; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; struct NoDebug<T> { inner: T, } impl<T> Debug for NoDebug<T> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("skipped").finish() } } impl<T> From<T> for NoDebug<T> { fn from(value: T) -> Self { Self { inner: value } } } impl<T> Deref for NoDebug<T> { type Target = T; fn deref(&self) -> &Self::Target { &self.inner } } impl<T> DerefMut for NoDebug<T> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } impl<T> Default for NoDebug<T> where T: Default, { fn default() -> Self { Self { inner: T::default(), } } }Whatever fields shouldn’t appear in the debugging output can be wrapped then:
#[derive(Debug, Default)] struct Debuggable { hidden: NoDebug<PhantomData<i32>>, visible: i32, } fn main() { dbg!(Debuggable::default()); }This prints:
Debuggable::default() = Debuggable { hidden: skipped, visible: 0, }Wladimir Palant at 2024-07-04 19:40:59
+1 this would be a super useful feature :)
Peter Whidden at 2024-08-29 17:10:33
+3.
This would ease:
+1: debugging (skipping large, useless, or non-Debug fields) +1: security compliance (skipping credentials), especially in regulated industries +1: HIPPA compliance (PII, PHI).
barries at 2024-09-02 15:24:37
@barries If the difference between HIPAA compliance and non-compliance is a
#[derive(Debug)]then you severely need to revisit your data security practices and threat model. Information security should not be relevant to this particular conversation whatsoever; this is not a security feature.Josh Junon at 2024-09-02 17:23:45
Given the prevalence of using debug for logging in-flight data, I disagree.
On Mon, Sep 2, 2024 at 1:24 PM Josh Junon @.***> wrote:
@barries https://github.com/barries If the difference between HIPAA compliance and non-compliance is a #[derive(Debug)] then you severely need to revisit your data security practices and threat model. Information security should not be relevant to this particular conversation whatsoever; this is not a security feature.
— Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/37009#issuecomment-2325127548, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAEXVA75KFGTLRXLEYNNWE3ZUSNLTAVCNFSM4CSCA7QKU5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TEMZSGUYTENZVGQ4A . You are receiving this because you were mentioned.Message ID: @.***>
barries at 2024-09-02 19:32:26
+1, this would be great for ergonomics.
David Pacsuta at 2024-12-07 09:14:08
For people watching this ticket; the crate
derive_morehas (somewhat) recently added support for this in their 1.0 release.Arjen at 2024-12-07 09:18:59
This is actually being actively worked on, somehow the issues don't seem to be linked in any way.
https://github.com/rust-lang/libs-team/issues/334
https://github.com/rust-lang/rust/issues/121050
Vojtěch Doležal at 2024-12-16 13:08:50
Having such an attribute would help with various compliance requirements, such as HIPPA, by making it provable from the source code that the secured value cannot be logged, even by accident, because it is prevented at compile time.
JEleniel at 2025-01-28 15:39:15
You can get that guarantee by using different types for secret values (see the secrecy crate, which does exactly that). That's even safer, because you can't forget to add an attribute to such field.
Jakub Beránek at 2025-01-28 15:57:32