Documentation ¶
Overview ¶
Example ¶
package main import ( "os" "log/slog" "github.com/m-mizutani/masq" ) type EmailAddr string func main() { u := struct { ID string Email EmailAddr }{ ID: "u123", Email: "mizutani@hey.com", } logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ ReplaceAttr: masq.New(masq.WithType[EmailAddr]()), })) logger.Info("hello", slog.Any("user", u)) }
Output:
Index ¶
- Constants
- func New(options ...Option) func(groups []string, a slog.Attr) slog.Attr
- type Censor
- type Censors
- type Filter
- type Option
- func WithAllowedType(types ...reflect.Type) Option
- func WithCensor(censor Censor, redactors ...Redactor) Option
- func WithContain(target string, redactors ...Redactor) Option
- func WithFieldName(fieldName string, redactors ...Redactor) Option
- func WithFieldPrefix(fieldName string, redactors ...Redactor) Option
- func WithRedactMessage(message string) Option
- func WithRegex(target *regexp.Regexp, redactors ...Redactor) Option
- func WithTag(tag string, redactors ...Redactor) Option
- func WithType[T any](redactors ...Redactor) Option
- type Redactor
- type Redactors
Examples ¶
Constants ¶
const (
DefaultRedactMessage = "[REDACTED]"
)
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Censor ¶ added in v0.1.4
Censor is a function to check if the field should be redacted. It receives field name, value, and tag of struct if the value is in struct. If the field should be redacted, it returns true.
type Option ¶
type Option func(m *masq)
func WithAllowedType ¶
WithAllowedType is an option to allow the type to be redacted. If the field is matched with the target type, the field will not be redacted.
func WithCensor ¶ added in v0.1.4
WithCensor is an option to add a censor function to masq. If the censor function returns true, the field will be redacted. The redactor functions will be applied to the field. If the redactor functions return true, the redaction will be stopped. If the all redactor functions return false, the default redactor will be applied. The default redactor redacts the field with the redact message.
func WithContain ¶ added in v0.1.4
WithContain is an option to check if the field contains the target string. If the field contains the target string, the field will be redacted.
Example ¶
package main import ( "encoding/json" "io" "os" "log/slog" "github.com/m-mizutani/masq" ) func newLogger(w io.Writer, f func(groups []string, a slog.Attr) slog.Attr) *slog.Logger { return slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions{ ReplaceAttr: f, })) } type fixedTimeWriter struct { buf []byte } func (x *fixedTimeWriter) Write(p []byte) (n int, err error) { x.buf = append(x.buf, p...) return len(p), nil } func (x *fixedTimeWriter) Flush() { var m map[string]any if err := json.Unmarshal(x.buf, &m); err != nil { panic("failed to unmarshal") } m["time"] = "2022-12-25T09:00:00.123456789" raw, err := json.Marshal(m) if err != nil { panic("failed to marshal") } if _, err := os.Stdout.Write(raw); err != nil { panic("can not output") } } func main() { out := &fixedTimeWriter{} const issuedToken = "abcd1234" authHeader := "Authorization: Bearer " + issuedToken logger := newLogger(out, masq.New(masq.WithContain("abcd1234"))) logger.With("auth", authHeader).Info("send header") out.Flush() }
Output: {"auth":"[REDACTED]","level":"INFO","msg":"send header","time":"2022-12-25T09:00:00.123456789"}
func WithFieldName ¶
WithFieldName is an option to check if the field name is matched with the target field name. If the field name is the target field name, the field will be redacted.
Example ¶
package main import ( "encoding/json" "io" "os" "log/slog" "github.com/m-mizutani/masq" ) func newLogger(w io.Writer, f func(groups []string, a slog.Attr) slog.Attr) *slog.Logger { return slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions{ ReplaceAttr: f, })) } type fixedTimeWriter struct { buf []byte } func (x *fixedTimeWriter) Write(p []byte) (n int, err error) { x.buf = append(x.buf, p...) return len(p), nil } func (x *fixedTimeWriter) Flush() { var m map[string]any if err := json.Unmarshal(x.buf, &m); err != nil { panic("failed to unmarshal") } m["time"] = "2022-12-25T09:00:00.123456789" raw, err := json.Marshal(m) if err != nil { panic("failed to marshal") } if _, err := os.Stdout.Write(raw); err != nil { panic("can not output") } } func main() { out := &fixedTimeWriter{} type myRecord struct { ID string Phone string } record := myRecord{ ID: "m-mizutani", Phone: "090-0000-0000", } logger := newLogger(out, masq.New(masq.WithFieldName("Phone"))) logger.With("record", record).Info("Got record") out.Flush() }
Output: {"level":"INFO","msg":"Got record","record":{"ID":"m-mizutani","Phone":"[REDACTED]"},"time":"2022-12-25T09:00:00.123456789"}
func WithFieldPrefix ¶
WithFieldPrefix is an option to check if the field name has the target prefix. If the field name has the target prefix, the field will be redacted.
Example ¶
package main import ( "encoding/json" "io" "os" "log/slog" "github.com/m-mizutani/masq" ) func newLogger(w io.Writer, f func(groups []string, a slog.Attr) slog.Attr) *slog.Logger { return slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions{ ReplaceAttr: f, })) } type fixedTimeWriter struct { buf []byte } func (x *fixedTimeWriter) Write(p []byte) (n int, err error) { x.buf = append(x.buf, p...) return len(p), nil } func (x *fixedTimeWriter) Flush() { var m map[string]any if err := json.Unmarshal(x.buf, &m); err != nil { panic("failed to unmarshal") } m["time"] = "2022-12-25T09:00:00.123456789" raw, err := json.Marshal(m) if err != nil { panic("failed to marshal") } if _, err := os.Stdout.Write(raw); err != nil { panic("can not output") } } func main() { out := &fixedTimeWriter{} type myRecord struct { ID string SecurePhone string } record := myRecord{ ID: "m-mizutani", SecurePhone: "090-0000-0000", } logger := newLogger(out, masq.New(masq.WithFieldPrefix("Secure"))) logger.With("record", record).Info("Got record") out.Flush() }
Output: {"level":"INFO","msg":"Got record","record":{"ID":"m-mizutani","SecurePhone":"[REDACTED]"},"time":"2022-12-25T09:00:00.123456789"}
func WithRedactMessage ¶ added in v0.1.1
WithRedactMessage is an option to set the redact message. The default redact message is `[REDACTED]`.
Example ¶
package main import ( "encoding/json" "io" "os" "log/slog" "github.com/m-mizutani/masq" ) func newLogger(w io.Writer, f func(groups []string, a slog.Attr) slog.Attr) *slog.Logger { return slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions{ ReplaceAttr: f, })) } type fixedTimeWriter struct { buf []byte } func (x *fixedTimeWriter) Write(p []byte) (n int, err error) { x.buf = append(x.buf, p...) return len(p), nil } func (x *fixedTimeWriter) Flush() { var m map[string]any if err := json.Unmarshal(x.buf, &m); err != nil { panic("failed to unmarshal") } m["time"] = "2022-12-25T09:00:00.123456789" raw, err := json.Marshal(m) if err != nil { panic("failed to marshal") } if _, err := os.Stdout.Write(raw); err != nil { panic("can not output") } } func main() { out := &fixedTimeWriter{} type myRecord struct { ID string Phone string } record := myRecord{ ID: "m-mizutani", Phone: "090-0000-0000", } logger := newLogger(out, masq.New( masq.WithFieldName("Phone"), masq.WithRedactMessage("****"), )) logger.With("record", record).Info("Got record") out.Flush() }
Output: {"level":"INFO","msg":"Got record","record":{"ID":"m-mizutani","Phone":"****"},"time":"2022-12-25T09:00:00.123456789"}
func WithRegex ¶
WithRegex is an option to check if the field matches the target regex. If the field matches the target regex, the field will be redacted.
Example ¶
package main import ( "encoding/json" "io" "os" "regexp" "log/slog" "github.com/m-mizutani/masq" ) func newLogger(w io.Writer, f func(groups []string, a slog.Attr) slog.Attr) *slog.Logger { return slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions{ ReplaceAttr: f, })) } type fixedTimeWriter struct { buf []byte } func (x *fixedTimeWriter) Write(p []byte) (n int, err error) { x.buf = append(x.buf, p...) return len(p), nil } func (x *fixedTimeWriter) Flush() { var m map[string]any if err := json.Unmarshal(x.buf, &m); err != nil { panic("failed to unmarshal") } m["time"] = "2022-12-25T09:00:00.123456789" raw, err := json.Marshal(m) if err != nil { panic("failed to marshal") } if _, err := os.Stdout.Write(raw); err != nil { panic("can not output") } } func main() { out := &fixedTimeWriter{} type myRecord struct { ID string Phone string } record := myRecord{ ID: "m-mizutani", Phone: "090-0000-0000", } logger := newLogger(out, masq.New( masq.WithRegex(regexp.MustCompile(`^\d{3}-\d{4}-\d{4}$`)), )) logger.With("record", record).Info("Got record") out.Flush() }
Output: {"level":"INFO","msg":"Got record","record":{"ID":"m-mizutani","Phone":"[REDACTED]"},"time":"2022-12-25T09:00:00.123456789"}
func WithTag ¶
WithTag is an option to check if the field is matched with the target struct tag in `masq:"xxx"`. If the field has the target tag, the field will be redacted.
Example ¶
package main import ( "encoding/json" "io" "os" "log/slog" "github.com/m-mizutani/masq" ) func newLogger(w io.Writer, f func(groups []string, a slog.Attr) slog.Attr) *slog.Logger { return slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions{ ReplaceAttr: f, })) } type fixedTimeWriter struct { buf []byte } func (x *fixedTimeWriter) Write(p []byte) (n int, err error) { x.buf = append(x.buf, p...) return len(p), nil } func (x *fixedTimeWriter) Flush() { var m map[string]any if err := json.Unmarshal(x.buf, &m); err != nil { panic("failed to unmarshal") } m["time"] = "2022-12-25T09:00:00.123456789" raw, err := json.Marshal(m) if err != nil { panic("failed to marshal") } if _, err := os.Stdout.Write(raw); err != nil { panic("can not output") } } func main() { out := &fixedTimeWriter{} type myRecord struct { ID string EMail string `masq:"secret"` } record := myRecord{ ID: "m-mizutani", EMail: "mizutani@hey.com", } logger := newLogger(out, masq.New(masq.WithTag("secret"))) logger.With("record", record).Info("Got record") out.Flush() }
Output: {"level":"INFO","msg":"Got record","record":{"EMail":"[REDACTED]","ID":"m-mizutani"},"time":"2022-12-25T09:00:00.123456789"}
func WithType ¶
WithType is an option to check if the field is matched with the target type. If the field is the target type, the field will be redacted.
Example ¶
package main import ( "encoding/json" "io" "os" "log/slog" "github.com/m-mizutani/masq" ) func newLogger(w io.Writer, f func(groups []string, a slog.Attr) slog.Attr) *slog.Logger { return slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions{ ReplaceAttr: f, })) } type fixedTimeWriter struct { buf []byte } func (x *fixedTimeWriter) Write(p []byte) (n int, err error) { x.buf = append(x.buf, p...) return len(p), nil } func (x *fixedTimeWriter) Flush() { var m map[string]any if err := json.Unmarshal(x.buf, &m); err != nil { panic("failed to unmarshal") } m["time"] = "2022-12-25T09:00:00.123456789" raw, err := json.Marshal(m) if err != nil { panic("failed to marshal") } if _, err := os.Stdout.Write(raw); err != nil { panic("can not output") } } func main() { out := &fixedTimeWriter{} type password string type myRecord struct { ID string Password password } record := myRecord{ ID: "m-mizutani", Password: "abcd1234", } logger := newLogger(out, masq.New(masq.WithType[password]())) logger.With("record", record).Info("Got record") out.Flush() }
Output: {"level":"INFO","msg":"Got record","record":{"ID":"m-mizutani","Password":"[REDACTED]"},"time":"2022-12-25T09:00:00.123456789"}
type Redactor ¶ added in v0.1.4
Redactor is a function to redact value. It receives source and destination value. If the redaction is done, it must return true. If the redaction is not done, it must return false. If the redaction is not done, the next redactor will be applied. If all redactors are not done, the default redactor will be applied.
func MaskWithSymbol ¶ added in v0.1.4
MaskWithSymbol is a redactor to redact string value with masked string that have the same length as the source string value. It can help the developer to know the length of the string value. The returned Redact function always returns true if the source value is string. Otherwise, it returns false.
Example ¶
out := &fixedTimeWriter{} type myRecord struct { ID string Phone string Email string } record := myRecord{ ID: "m-mizutani", Phone: "090-0000-0000", // too long email address Email: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@example.com", } logger := newLogger(out, masq.New( masq.WithFieldName("Phone", masq.MaskWithSymbol('*', 32)), masq.WithFieldName("Email", masq.MaskWithSymbol('*', 12)), )) logger.With("record", record).Info("Got record") out.Flush()
Output: {"level":"INFO","msg":"Got record","record":{"Email":"************ (remained 36 chars)","ID":"m-mizutani","Phone":"*************"},"time":"2022-12-25T09:00:00.123456789"}
func RedactString ¶ added in v0.1.4
RedactString is a redactor to redact string value. It receives a function to redact string. The function receives the string value and returns the redacted string value. The returned Redact function always returns true if the source value is string. Otherwise, it returns false.
Example ¶
package main import ( "encoding/json" "io" "os" "log/slog" "github.com/m-mizutani/masq" ) func newLogger(w io.Writer, f func(groups []string, a slog.Attr) slog.Attr) *slog.Logger { return slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions{ ReplaceAttr: f, })) } type fixedTimeWriter struct { buf []byte } func (x *fixedTimeWriter) Write(p []byte) (n int, err error) { x.buf = append(x.buf, p...) return len(p), nil } func (x *fixedTimeWriter) Flush() { var m map[string]any if err := json.Unmarshal(x.buf, &m); err != nil { panic("failed to unmarshal") } m["time"] = "2022-12-25T09:00:00.123456789" raw, err := json.Marshal(m) if err != nil { panic("failed to marshal") } if _, err := os.Stdout.Write(raw); err != nil { panic("can not output") } } func main() { out := &fixedTimeWriter{} type myRecord struct { ID string Phone string Email string } record := myRecord{ ID: "m-mizutani", Phone: "090-0000-1234", Email: "mizutani@hey.com", } logger := newLogger(out, masq.New( // custom redactor masq.WithFieldName("Phone", masq.RedactString(func(s string) string { return "****-" + s[len(s)-4:] }), ), // default redactor masq.WithFieldName("Email"), )) logger.With("record", record).Info("Got record") out.Flush() }
Output: {"level":"INFO","msg":"Got record","record":{"Email":"[REDACTED]","ID":"m-mizutani","Phone":"****-1234"},"time":"2022-12-25T09:00:00.123456789"}