package log // Copied from https://github.com/whuang8/redactrus (MIT License) // Copyright (c) 2018 William Huang import ( "fmt" "reflect" "regexp" "github.com/sirupsen/logrus" ) // Hook is a logrus hook for redacting information from logs type Hook struct { // Messages with a log level not contained in this array // will not be dispatched. If empty, all messages will be dispatched. AcceptedLevels []logrus.Level RedactionList []string redactionKeys []*regexp.Regexp } // Levels returns the user defined AcceptedLevels // If AcceptedLevels is empty, all logrus levels are returned func (h *Hook) Levels() []logrus.Level { if len(h.AcceptedLevels) == 0 { return logrus.AllLevels } return h.AcceptedLevels } // Fire redacts values in a log Entry that match // with keys defined in the RedactionList func (h *Hook) Fire(e *logrus.Entry) error { if err := h.initRedaction(); err != nil { return err } for _, re := range h.redactionKeys { // Redact based on key matching in Data fields for k, v := range e.Data { if re.MatchString(k) { e.Data[k] = "[REDACTED]" continue } // Redact based on value matching in Data fields switch reflect.TypeOf(v).Kind() { case reflect.String: e.Data[k] = re.ReplaceAllString(v.(string), "$1[REDACTED]$2") continue case reflect.Map: s := fmt.Sprintf("%+v", v) e.Data[k] = re.ReplaceAllString(s, "$1[REDACTED]$2") continue } } // Redact based on text matching in the Message field e.Message = re.ReplaceAllString(e.Message, "$1[REDACTED]$2") } return nil } func (h *Hook) initRedaction() error { if len(h.redactionKeys) == 0 { for _, redactionKey := range h.RedactionList { re, err := regexp.Compile(redactionKey) if err != nil { return err } h.redactionKeys = append(h.redactionKeys, re) } } return nil } func (h *Hook) redact(msg string) (string, error) { if err := h.initRedaction(); err != nil { return msg, err } for _, re := range h.redactionKeys { msg = re.ReplaceAllString(msg, "$1[REDACTED]$2") } return msg, nil }