176 lines
4 KiB
Go
176 lines
4 KiB
Go
package logformat
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
log "github.com/mgutz/logxi/v1"
|
|
)
|
|
|
|
const (
|
|
styledefault = iota
|
|
stylejson
|
|
)
|
|
|
|
// NewVaultLogger creates a new logger with the specified level and a Vault
|
|
// formatter
|
|
func NewVaultLogger(level int) log.Logger {
|
|
logger := log.New("vault")
|
|
return setLevelFormatter(logger, level, createVaultFormatter())
|
|
}
|
|
|
|
// NewVaultLoggerWithWriter creates a new logger with the specified level and
|
|
// writer and a Vault formatter
|
|
func NewVaultLoggerWithWriter(w io.Writer, level int) log.Logger {
|
|
logger := log.NewLogger(w, "vault")
|
|
return setLevelFormatter(logger, level, createVaultFormatter())
|
|
}
|
|
|
|
// Sets the level and formatter on the log, which must be a DefaultLogger
|
|
func setLevelFormatter(logger log.Logger, level int, formatter log.Formatter) log.Logger {
|
|
logger.(*log.DefaultLogger).SetLevel(level)
|
|
logger.(*log.DefaultLogger).SetFormatter(formatter)
|
|
return logger
|
|
}
|
|
|
|
// Creates a formatter, checking env vars for the style
|
|
func createVaultFormatter() log.Formatter {
|
|
ret := &vaultFormatter{
|
|
Mutex: &sync.Mutex{},
|
|
}
|
|
logFormat := os.Getenv("VAULT_LOG_FORMAT")
|
|
if logFormat == "" {
|
|
logFormat = os.Getenv("LOGXI_FORMAT")
|
|
}
|
|
switch strings.ToLower(logFormat) {
|
|
case "json", "vault_json", "vault-json", "vaultjson":
|
|
ret.style = stylejson
|
|
default:
|
|
ret.style = styledefault
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// Thread safe formatter
|
|
type vaultFormatter struct {
|
|
*sync.Mutex
|
|
style int
|
|
module string
|
|
}
|
|
|
|
func (v *vaultFormatter) Format(writer io.Writer, level int, msg string, args []interface{}) {
|
|
currTime := time.Now()
|
|
v.Lock()
|
|
defer v.Unlock()
|
|
switch v.style {
|
|
case stylejson:
|
|
v.formatJSON(writer, currTime, level, msg, args)
|
|
default:
|
|
v.formatDefault(writer, currTime, level, msg, args)
|
|
}
|
|
}
|
|
|
|
func (v *vaultFormatter) formatDefault(writer io.Writer, currTime time.Time, level int, msg string, args []interface{}) {
|
|
// Write a trailing newline
|
|
defer writer.Write([]byte("\n"))
|
|
|
|
writer.Write([]byte(currTime.Local().Format("2006/01/02 15:04:05.000000")))
|
|
|
|
switch level {
|
|
case log.LevelCritical:
|
|
writer.Write([]byte(" [CRIT ] "))
|
|
case log.LevelError:
|
|
writer.Write([]byte(" [ERROR] "))
|
|
case log.LevelWarn:
|
|
writer.Write([]byte(" [WARN ] "))
|
|
case log.LevelInfo:
|
|
writer.Write([]byte(" [INFO ] "))
|
|
case log.LevelDebug:
|
|
writer.Write([]byte(" [DEBUG] "))
|
|
case log.LevelTrace:
|
|
writer.Write([]byte(" [TRACE] "))
|
|
default:
|
|
writer.Write([]byte(" [ALL ] "))
|
|
}
|
|
|
|
if v.module != "" {
|
|
writer.Write([]byte(fmt.Sprintf("(%s) ", v.module)))
|
|
}
|
|
|
|
writer.Write([]byte(msg))
|
|
|
|
if args != nil && len(args) > 0 {
|
|
if len(args)%2 != 0 {
|
|
args = append(args, "[unknown!]")
|
|
}
|
|
|
|
writer.Write([]byte(":"))
|
|
|
|
for i := 0; i < len(args); i = i + 2 {
|
|
var quote string
|
|
switch args[i+1].(type) {
|
|
case string:
|
|
if strings.ContainsRune(args[i+1].(string), ' ') {
|
|
quote = `"`
|
|
}
|
|
}
|
|
writer.Write([]byte(fmt.Sprintf(" %s=%s%v%s", args[i], quote, args[i+1], quote)))
|
|
}
|
|
}
|
|
}
|
|
|
|
func (v *vaultFormatter) formatJSON(writer io.Writer, currTime time.Time, level int, msg string, args []interface{}) {
|
|
vals := map[string]interface{}{
|
|
"@message": msg,
|
|
"@timestamp": currTime.Format("2006-01-02T15:04:05.000000Z07:00"),
|
|
}
|
|
|
|
var levelStr string
|
|
switch level {
|
|
case log.LevelCritical:
|
|
levelStr = "critical"
|
|
case log.LevelError:
|
|
levelStr = "error"
|
|
case log.LevelWarn:
|
|
levelStr = "warn"
|
|
case log.LevelInfo:
|
|
levelStr = "info"
|
|
case log.LevelDebug:
|
|
levelStr = "debug"
|
|
case log.LevelTrace:
|
|
levelStr = "trace"
|
|
default:
|
|
levelStr = "all"
|
|
}
|
|
|
|
vals["@level"] = levelStr
|
|
|
|
if v.module != "" {
|
|
vals["@module"] = v.module
|
|
}
|
|
|
|
if args != nil && len(args) > 0 {
|
|
|
|
if len(args)%2 != 0 {
|
|
args = append(args, "[unknown!]")
|
|
}
|
|
|
|
for i := 0; i < len(args); i = i + 2 {
|
|
if _, ok := args[i].(string); !ok {
|
|
// As this is the logging function not much we can do here
|
|
// without injecting into logs...
|
|
continue
|
|
}
|
|
vals[args[i].(string)] = args[i+1]
|
|
}
|
|
}
|
|
|
|
enc := json.NewEncoder(writer)
|
|
enc.Encode(vals)
|
|
}
|