I need to print all form requests to log, for later debugging. I need to have something like this, where formInput
are different kind of structs. (All defined in my code.)
type SomeFormInput {
Name string
Age int
}
func handleForm(formInput interface{}) {
...
logger.Logf("%+v", formInput);
}
However, some of the forms contain "secret" data that needs to be sanitized before logging - specifically, passwords.
What is the best and easiest way to do this, without losing the generality of handleForm
?
I still need it to accept interface{}
.
I can use tags if needed.
type SomeFormInput struct {
Name string
Password string `hide:"true"` // something like this
}
There is no completely general solution to this. There are only specific solutions with different trade-offs.
Perhaps the most general solution would be to write a function that inspects each form type with reflection, and omits any sensitive fields in the output.
logger.Logf("%s", stripPassword(formInput));
This has the side effect of no longer using the %+v
verb, which often won't matter, but if your type implements the fmt.Formatter interface, it will change behavior. But then again, your goal is to change behavior, so...
Which leads to a second option:
You could implement a custom Format()
method on your type, to cause %+v
(or %v
or %s
) to output whatever you desire (omitting private fields).
Along the same lines, but easier, if you're logging (or willing to log) JSON output, just implement your own json.Marshaler
for each type.
Example:
func (i *SomeFormInput) MarshalJSON() ([]byte, error) {
intermediate := struct{
*SomeFormInput
Password struct{} `json:"-"` // Occlude Password field in the embedded struct
MarshalJSON struct{} `json:"-"` // Occlude MarshalJSON method on embedded struct, to avoid infinite loop
}{
SomeFormInput: i,
}
return json.Marshal(intermediate)
}
A similar option is to use the json:"-"
tag for fields that should not be output.
Example:
type SomeFormInput struct {
Name string
Password string `json:"-"`
}
And as a final option, you could filter the log output, prior to sending it to the logger. If you're using JSON, you could parse the data using the tokenizing json.Decoder, to omit only the keys you want. For arbitrary text, perhaps a regular expression could be used.
For most applications I work on, where I practically always use JSON logging, I would probably prefer option #4, followed by #5.