mirror of https://github.com/tidwall/tile38.git
Merge branch 'iwpnd-feat/json-logs'
This commit is contained in:
commit
5f41a687bf
|
@ -10,6 +10,7 @@ import (
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -17,6 +18,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
"github.com/tidwall/tile38/core"
|
"github.com/tidwall/tile38/core"
|
||||||
"github.com/tidwall/tile38/internal/hservice"
|
"github.com/tidwall/tile38/internal/hservice"
|
||||||
"github.com/tidwall/tile38/internal/log"
|
"github.com/tidwall/tile38/internal/log"
|
||||||
|
@ -76,6 +78,7 @@ Basic Options:
|
||||||
-p port : listening port (default: 9851)
|
-p port : listening port (default: 9851)
|
||||||
-d path : data directory (default: data)
|
-d path : data directory (default: data)
|
||||||
-s socket : listen on unix socket file
|
-s socket : listen on unix socket file
|
||||||
|
-l encoding : set log encoding to json or text (default: text)
|
||||||
-q : no logging. totally silent output
|
-q : no logging. totally silent output
|
||||||
-v : enable verbose logging
|
-v : enable verbose logging
|
||||||
-vv : enable very verbose logging
|
-vv : enable very verbose logging
|
||||||
|
@ -88,6 +91,7 @@ Advanced Options:
|
||||||
--http-transport yes/no : HTTP transport (default: yes)
|
--http-transport yes/no : HTTP transport (default: yes)
|
||||||
--protected-mode yes/no : protected mode (default: yes)
|
--protected-mode yes/no : protected mode (default: yes)
|
||||||
--nohup : do not exit on SIGHUP
|
--nohup : do not exit on SIGHUP
|
||||||
|
--logjson : log json (default: text)
|
||||||
|
|
||||||
Developer Options:
|
Developer Options:
|
||||||
--dev : enable developer mode
|
--dev : enable developer mode
|
||||||
|
@ -256,6 +260,7 @@ Developer Options:
|
||||||
unixSocket string
|
unixSocket string
|
||||||
verbose bool
|
verbose bool
|
||||||
veryVerbose bool
|
veryVerbose bool
|
||||||
|
logEncoding string
|
||||||
quiet bool
|
quiet bool
|
||||||
pidfile string
|
pidfile string
|
||||||
cpuprofile string
|
cpuprofile string
|
||||||
|
@ -268,6 +273,7 @@ Developer Options:
|
||||||
flag.StringVar(&host, "h", "", "The listening host")
|
flag.StringVar(&host, "h", "", "The listening host")
|
||||||
flag.StringVar(&unixSocket, "s", "", "Listen on a unix socket")
|
flag.StringVar(&unixSocket, "s", "", "Listen on a unix socket")
|
||||||
flag.StringVar(&dir, "d", "data", "The data directory")
|
flag.StringVar(&dir, "d", "data", "The data directory")
|
||||||
|
flag.StringVar(&logEncoding, "l", "text", "The log encoding json or text (default: text)")
|
||||||
flag.BoolVar(&verbose, "v", false, "Enable verbose logging")
|
flag.BoolVar(&verbose, "v", false, "Enable verbose logging")
|
||||||
flag.BoolVar(&quiet, "q", false, "Quiet logging. Totally silent")
|
flag.BoolVar(&quiet, "q", false, "Quiet logging. Totally silent")
|
||||||
flag.BoolVar(&veryVerbose, "vv", false, "Enable very verbose logging")
|
flag.BoolVar(&veryVerbose, "vv", false, "Enable very verbose logging")
|
||||||
|
@ -276,6 +282,17 @@ Developer Options:
|
||||||
flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
|
flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
if logEncoding == "json" {
|
||||||
|
log.LogJSON = true
|
||||||
|
data, _ := os.ReadFile(filepath.Join(dir, "config"))
|
||||||
|
if gjson.GetBytes(data, "logconfig.encoding").String() == "json" {
|
||||||
|
c := gjson.GetBytes(data, "logconfig").String()
|
||||||
|
log.Build(c)
|
||||||
|
} else {
|
||||||
|
log.Build("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var logw io.Writer = os.Stderr
|
var logw io.Writer = os.Stderr
|
||||||
if quiet {
|
if quiet {
|
||||||
logw = ioutil.Discard
|
logw = ioutil.Discard
|
||||||
|
@ -292,6 +309,7 @@ Developer Options:
|
||||||
} else {
|
} else {
|
||||||
log.Level = 1
|
log.Level = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
core.DevMode = devMode
|
core.DevMode = devMode
|
||||||
core.ShowDebugMessages = veryVerbose
|
core.ShowDebugMessages = veryVerbose
|
||||||
|
|
||||||
|
@ -409,17 +427,22 @@ Developer Options:
|
||||||
saddr = fmt.Sprintf("Port: %d", port)
|
saddr = fmt.Sprintf("Port: %d", port)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(logw, `
|
if log.LogJSON {
|
||||||
_____ _ _ ___ ___
|
log.Printf(`Tile38 %s%s %d bit (%s/%s) %s%s, PID: %d. Visit tile38.com/sponsor to support the project`,
|
||||||
|_ _|_| |___|_ | . | Tile38 %s%s %d bit (%s/%s)
|
core.Version, gitsha, strconv.IntSize, runtime.GOARCH, runtime.GOOS, hostd, saddr, os.Getpid())
|
||||||
| | | | | -_|_ | . | %s%s, PID: %d
|
} else {
|
||||||
|_| |_|_|___|___|___| tile38.com
|
fmt.Fprintf(logw, `
|
||||||
|
_____ _ _ ___ ___
|
||||||
|
|_ _|_| |___|_ | . | Tile38 %s%s %d bit (%s/%s)
|
||||||
|
| | | | | -_|_ | . | %s%s, PID: %d
|
||||||
|
|_| |_|_|___|___|___| tile38.com
|
||||||
|
|
||||||
Please consider sponsoring Tile38 development, especially if your company
|
Please consider sponsoring Tile38 development, especially if your company
|
||||||
benefits from this software. Visit tile38.com/sponsor today to learn more.
|
benefits from this software. Visit tile38.com/sponsor today to learn more.
|
||||||
|
|
||||||
`, core.Version, gitsha, strconv.IntSize, runtime.GOARCH, runtime.GOOS, hostd,
|
`, core.Version, gitsha, strconv.IntSize, runtime.GOARCH, runtime.GOOS, hostd,
|
||||||
saddr, os.Getpid())
|
saddr, os.Getpid())
|
||||||
|
}
|
||||||
|
|
||||||
if pidferr != nil {
|
if pidferr != nil {
|
||||||
log.Warnf("pidfile: %v", pidferr)
|
log.Warnf("pidfile: %v", pidferr)
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -31,6 +31,7 @@ require (
|
||||||
github.com/tidwall/sjson v1.2.4
|
github.com/tidwall/sjson v1.2.4
|
||||||
github.com/xdg/scram v1.0.3
|
github.com/xdg/scram v1.0.3
|
||||||
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da
|
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da
|
||||||
|
go.uber.org/zap v1.13.0
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1
|
||||||
google.golang.org/api v0.20.0
|
google.golang.org/api v0.20.0
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -530,11 +530,15 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
|
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
|
||||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc=
|
||||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||||
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
|
go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=
|
||||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
)
|
)
|
||||||
|
|
||||||
var mu sync.Mutex
|
var mu sync.Mutex
|
||||||
var wr io.Writer
|
var wr io.Writer
|
||||||
var tty bool
|
var tty bool
|
||||||
|
var LogJSON = false
|
||||||
|
var logger *zap.SugaredLogger
|
||||||
|
|
||||||
// Level is the log level
|
// Level is the log level
|
||||||
// 0: silent - do not log
|
// 0: silent - do not log
|
||||||
|
@ -28,6 +32,54 @@ func SetOutput(w io.Writer) {
|
||||||
wr = w
|
wr = w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build a zap logger from default or custom config
|
||||||
|
func Build(c string) error {
|
||||||
|
if c == "" {
|
||||||
|
zcfg := zap.NewProductionConfig()
|
||||||
|
|
||||||
|
// to be able to filter with Tile38 levels
|
||||||
|
zcfg.Level.SetLevel(zap.DebugLevel)
|
||||||
|
// disable caller because caller is always log.go
|
||||||
|
zcfg.DisableCaller = true
|
||||||
|
|
||||||
|
core, err := zcfg.Build()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer core.Sync()
|
||||||
|
logger = core.Sugar()
|
||||||
|
} else {
|
||||||
|
var zcfg zap.Config
|
||||||
|
err := json.Unmarshal([]byte(c), &zcfg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// to be able to filter with Tile38 levels
|
||||||
|
zcfg.Level.SetLevel(zap.DebugLevel)
|
||||||
|
// disable caller because caller is always log.go
|
||||||
|
zcfg.DisableCaller = true
|
||||||
|
|
||||||
|
core, err := zcfg.Build()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer core.Sync()
|
||||||
|
logger = core.Sugar()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a zap logger
|
||||||
|
func Set(sl *zap.SugaredLogger) {
|
||||||
|
logger = sl
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a zap logger
|
||||||
|
func Get() *zap.SugaredLogger {
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
SetOutput(os.Stderr)
|
SetOutput(os.Stderr)
|
||||||
}
|
}
|
||||||
|
@ -71,6 +123,10 @@ var emptyFormat string
|
||||||
// Infof ...
|
// Infof ...
|
||||||
func Infof(format string, args ...interface{}) {
|
func Infof(format string, args ...interface{}) {
|
||||||
if Level >= 1 {
|
if Level >= 1 {
|
||||||
|
if LogJSON {
|
||||||
|
logger.Infof(format, args...)
|
||||||
|
return
|
||||||
|
}
|
||||||
log(1, "INFO", "\x1b[36m", true, format, args...)
|
log(1, "INFO", "\x1b[36m", true, format, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +134,10 @@ func Infof(format string, args ...interface{}) {
|
||||||
// Info ...
|
// Info ...
|
||||||
func Info(args ...interface{}) {
|
func Info(args ...interface{}) {
|
||||||
if Level >= 1 {
|
if Level >= 1 {
|
||||||
|
if LogJSON {
|
||||||
|
logger.Info(args...)
|
||||||
|
return
|
||||||
|
}
|
||||||
log(1, "INFO", "\x1b[36m", false, emptyFormat, args...)
|
log(1, "INFO", "\x1b[36m", false, emptyFormat, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,6 +145,10 @@ func Info(args ...interface{}) {
|
||||||
// HTTPf ...
|
// HTTPf ...
|
||||||
func HTTPf(format string, args ...interface{}) {
|
func HTTPf(format string, args ...interface{}) {
|
||||||
if Level >= 1 {
|
if Level >= 1 {
|
||||||
|
if LogJSON {
|
||||||
|
logger.Infof(format, args...)
|
||||||
|
return
|
||||||
|
}
|
||||||
log(1, "HTTP", "\x1b[1m\x1b[30m", true, format, args...)
|
log(1, "HTTP", "\x1b[1m\x1b[30m", true, format, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,6 +156,10 @@ func HTTPf(format string, args ...interface{}) {
|
||||||
// HTTP ...
|
// HTTP ...
|
||||||
func HTTP(args ...interface{}) {
|
func HTTP(args ...interface{}) {
|
||||||
if Level >= 1 {
|
if Level >= 1 {
|
||||||
|
if LogJSON {
|
||||||
|
logger.Info(args...)
|
||||||
|
return
|
||||||
|
}
|
||||||
log(1, "HTTP", "\x1b[1m\x1b[30m", false, emptyFormat, args...)
|
log(1, "HTTP", "\x1b[1m\x1b[30m", false, emptyFormat, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +167,10 @@ func HTTP(args ...interface{}) {
|
||||||
// Errorf ...
|
// Errorf ...
|
||||||
func Errorf(format string, args ...interface{}) {
|
func Errorf(format string, args ...interface{}) {
|
||||||
if Level >= 1 {
|
if Level >= 1 {
|
||||||
|
if LogJSON {
|
||||||
|
logger.Errorf(format, args...)
|
||||||
|
return
|
||||||
|
}
|
||||||
log(1, "ERRO", "\x1b[1m\x1b[31m", true, format, args...)
|
log(1, "ERRO", "\x1b[1m\x1b[31m", true, format, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,6 +178,10 @@ func Errorf(format string, args ...interface{}) {
|
||||||
// Error ..
|
// Error ..
|
||||||
func Error(args ...interface{}) {
|
func Error(args ...interface{}) {
|
||||||
if Level >= 1 {
|
if Level >= 1 {
|
||||||
|
if LogJSON {
|
||||||
|
logger.Errorf(emptyFormat, args...)
|
||||||
|
return
|
||||||
|
}
|
||||||
log(1, "ERRO", "\x1b[1m\x1b[31m", false, emptyFormat, args...)
|
log(1, "ERRO", "\x1b[1m\x1b[31m", false, emptyFormat, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,6 +189,10 @@ func Error(args ...interface{}) {
|
||||||
// Warnf ...
|
// Warnf ...
|
||||||
func Warnf(format string, args ...interface{}) {
|
func Warnf(format string, args ...interface{}) {
|
||||||
if Level >= 1 {
|
if Level >= 1 {
|
||||||
|
if LogJSON {
|
||||||
|
logger.Warnf(format, args...)
|
||||||
|
return
|
||||||
|
}
|
||||||
log(2, "WARN", "\x1b[33m", true, format, args...)
|
log(2, "WARN", "\x1b[33m", true, format, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,6 +200,10 @@ func Warnf(format string, args ...interface{}) {
|
||||||
// Warn ...
|
// Warn ...
|
||||||
func Warn(args ...interface{}) {
|
func Warn(args ...interface{}) {
|
||||||
if Level >= 1 {
|
if Level >= 1 {
|
||||||
|
if LogJSON {
|
||||||
|
logger.Warnf(emptyFormat, args...)
|
||||||
|
return
|
||||||
|
}
|
||||||
log(2, "WARN", "\x1b[33m", false, emptyFormat, args...)
|
log(2, "WARN", "\x1b[33m", false, emptyFormat, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,6 +211,10 @@ func Warn(args ...interface{}) {
|
||||||
// Debugf ...
|
// Debugf ...
|
||||||
func Debugf(format string, args ...interface{}) {
|
func Debugf(format string, args ...interface{}) {
|
||||||
if Level >= 3 {
|
if Level >= 3 {
|
||||||
|
if LogJSON {
|
||||||
|
logger.Debugf(format, args...)
|
||||||
|
return
|
||||||
|
}
|
||||||
log(3, "DEBU", "\x1b[35m", true, format, args...)
|
log(3, "DEBU", "\x1b[35m", true, format, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,6 +222,10 @@ func Debugf(format string, args ...interface{}) {
|
||||||
// Debug ...
|
// Debug ...
|
||||||
func Debug(args ...interface{}) {
|
func Debug(args ...interface{}) {
|
||||||
if Level >= 3 {
|
if Level >= 3 {
|
||||||
|
if LogJSON {
|
||||||
|
logger.Debugf(emptyFormat, args...)
|
||||||
|
return
|
||||||
|
}
|
||||||
log(3, "DEBU", "\x1b[35m", false, emptyFormat, args...)
|
log(3, "DEBU", "\x1b[35m", false, emptyFormat, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,18 +236,29 @@ func Printf(format string, args ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print ...
|
// Print ...
|
||||||
func Print(format string, args ...interface{}) {
|
func Print(args ...interface{}) {
|
||||||
Info(args...)
|
Info(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalf ...
|
// Fatalf ...
|
||||||
func Fatalf(format string, args ...interface{}) {
|
func Fatalf(format string, args ...interface{}) {
|
||||||
|
if LogJSON {
|
||||||
|
logger.Fatalf(format, args...)
|
||||||
|
os.Exit(1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
log(1, "FATA", "\x1b[31m", true, format, args...)
|
log(1, "FATA", "\x1b[31m", true, format, args...)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal ...
|
// Fatal ...
|
||||||
func Fatal(args ...interface{}) {
|
func Fatal(args ...interface{}) {
|
||||||
|
if LogJSON {
|
||||||
|
logger.Fatalf(emptyFormat, args...)
|
||||||
|
os.Exit(1)
|
||||||
|
return
|
||||||
|
}
|
||||||
log(1, "FATA", "\x1b[31m", false, emptyFormat, args...)
|
log(1, "FATA", "\x1b[31m", false, emptyFormat, args...)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,15 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
"go.uber.org/zap/zaptest/observer"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLog(t *testing.T) {
|
func TestLog(t *testing.T) {
|
||||||
f := &bytes.Buffer{}
|
f := &bytes.Buffer{}
|
||||||
|
LogJSON = false
|
||||||
SetOutput(f)
|
SetOutput(f)
|
||||||
Printf("hello %v", "everyone")
|
Printf("hello %v", "everyone")
|
||||||
if !strings.HasSuffix(f.String(), "hello everyone\n") {
|
if !strings.HasSuffix(f.String(), "hello everyone\n") {
|
||||||
|
@ -16,10 +21,200 @@ func TestLog(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLogJSON(t *testing.T) {
|
||||||
|
|
||||||
|
LogJSON = true
|
||||||
|
Build("")
|
||||||
|
|
||||||
|
type tcase struct {
|
||||||
|
level int
|
||||||
|
format string
|
||||||
|
args string
|
||||||
|
ops func(...interface{})
|
||||||
|
fops func(string, ...interface{})
|
||||||
|
expMsg string
|
||||||
|
expLvl zapcore.Level
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := func(tc tcase) func(*testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
observedZapCore, observedLogs := observer.New(zap.DebugLevel)
|
||||||
|
Set(zap.New(observedZapCore).Sugar())
|
||||||
|
Level = tc.level
|
||||||
|
|
||||||
|
if tc.format != "" {
|
||||||
|
tc.fops(tc.format, tc.args)
|
||||||
|
} else {
|
||||||
|
tc.ops(tc.args)
|
||||||
|
}
|
||||||
|
|
||||||
|
if observedLogs.Len() < 1 {
|
||||||
|
t.Fatal("fail")
|
||||||
|
}
|
||||||
|
|
||||||
|
allLogs := observedLogs.All()
|
||||||
|
|
||||||
|
if allLogs[0].Message != tc.expMsg {
|
||||||
|
t.Fatal("fail")
|
||||||
|
}
|
||||||
|
|
||||||
|
if allLogs[0].Level != tc.expLvl {
|
||||||
|
t.Fatal("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := map[string]tcase{
|
||||||
|
"Print": {
|
||||||
|
level: 1,
|
||||||
|
args: "Print json logger",
|
||||||
|
ops: func(args ...interface{}) {
|
||||||
|
Print(args...)
|
||||||
|
},
|
||||||
|
expMsg: "Print json logger",
|
||||||
|
expLvl: zapcore.InfoLevel,
|
||||||
|
},
|
||||||
|
"Printf": {
|
||||||
|
level: 1,
|
||||||
|
format: "Printf json %v",
|
||||||
|
args: "logger",
|
||||||
|
fops: func(format string, args ...interface{}) {
|
||||||
|
Printf(format, args...)
|
||||||
|
},
|
||||||
|
expMsg: "Printf json logger",
|
||||||
|
expLvl: zapcore.InfoLevel,
|
||||||
|
},
|
||||||
|
"Info": {
|
||||||
|
level: 1,
|
||||||
|
args: "Info json logger",
|
||||||
|
ops: func(args ...interface{}) {
|
||||||
|
Info(args...)
|
||||||
|
},
|
||||||
|
expMsg: "Info json logger",
|
||||||
|
expLvl: zapcore.InfoLevel,
|
||||||
|
},
|
||||||
|
"Infof": {
|
||||||
|
level: 1,
|
||||||
|
format: "Infof json %v",
|
||||||
|
args: "logger",
|
||||||
|
fops: func(format string, args ...interface{}) {
|
||||||
|
Infof(format, args...)
|
||||||
|
},
|
||||||
|
expMsg: "Infof json logger",
|
||||||
|
expLvl: zapcore.InfoLevel,
|
||||||
|
},
|
||||||
|
"Debug": {
|
||||||
|
level: 3,
|
||||||
|
args: "Debug json logger",
|
||||||
|
ops: func(args ...interface{}) {
|
||||||
|
Debug(args...)
|
||||||
|
},
|
||||||
|
expMsg: "Debug json logger",
|
||||||
|
expLvl: zapcore.DebugLevel,
|
||||||
|
},
|
||||||
|
"Debugf": {
|
||||||
|
level: 3,
|
||||||
|
format: "Debugf json %v",
|
||||||
|
args: "logger",
|
||||||
|
fops: func(format string, args ...interface{}) {
|
||||||
|
Debugf(format, args...)
|
||||||
|
},
|
||||||
|
expMsg: "Debugf json logger",
|
||||||
|
expLvl: zapcore.DebugLevel,
|
||||||
|
},
|
||||||
|
"Warn": {
|
||||||
|
level: 2,
|
||||||
|
args: "Warn json logger",
|
||||||
|
ops: func(args ...interface{}) {
|
||||||
|
Warn(args...)
|
||||||
|
},
|
||||||
|
expMsg: "Warn json logger",
|
||||||
|
expLvl: zapcore.WarnLevel,
|
||||||
|
},
|
||||||
|
"Warnf": {
|
||||||
|
level: 2,
|
||||||
|
format: "Warnf json %v",
|
||||||
|
args: "logger",
|
||||||
|
fops: func(format string, args ...interface{}) {
|
||||||
|
Warnf(format, args...)
|
||||||
|
},
|
||||||
|
expMsg: "Warnf json logger",
|
||||||
|
expLvl: zapcore.WarnLevel,
|
||||||
|
},
|
||||||
|
"Error": {
|
||||||
|
level: 1,
|
||||||
|
args: "Error json logger",
|
||||||
|
ops: func(args ...interface{}) {
|
||||||
|
Error(args...)
|
||||||
|
},
|
||||||
|
expMsg: "Error json logger",
|
||||||
|
expLvl: zapcore.ErrorLevel,
|
||||||
|
},
|
||||||
|
"Errorf": {
|
||||||
|
level: 1,
|
||||||
|
format: "Errorf json %v",
|
||||||
|
args: "logger",
|
||||||
|
fops: func(format string, args ...interface{}) {
|
||||||
|
Errorf(format, args...)
|
||||||
|
},
|
||||||
|
expMsg: "Errorf json logger",
|
||||||
|
expLvl: zapcore.ErrorLevel,
|
||||||
|
},
|
||||||
|
"Http": {
|
||||||
|
level: 1,
|
||||||
|
args: "Http json logger",
|
||||||
|
ops: func(args ...interface{}) {
|
||||||
|
HTTP(args...)
|
||||||
|
},
|
||||||
|
expMsg: "Http json logger",
|
||||||
|
expLvl: zapcore.InfoLevel,
|
||||||
|
},
|
||||||
|
"Httpf": {
|
||||||
|
level: 1,
|
||||||
|
format: "Httpf json %v",
|
||||||
|
args: "logger",
|
||||||
|
fops: func(format string, args ...interface{}) {
|
||||||
|
HTTPf(format, args...)
|
||||||
|
},
|
||||||
|
expMsg: "Httpf json logger",
|
||||||
|
expLvl: zapcore.InfoLevel,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range tests {
|
||||||
|
t.Run(name, fn(tc))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkLogPrintf(t *testing.B) {
|
func BenchmarkLogPrintf(t *testing.B) {
|
||||||
|
LogJSON = false
|
||||||
|
Level = 1
|
||||||
SetOutput(ioutil.Discard)
|
SetOutput(ioutil.Discard)
|
||||||
t.ResetTimer()
|
t.ResetTimer()
|
||||||
for i := 0; i < t.N; i++ {
|
for i := 0; i < t.N; i++ {
|
||||||
Printf("X %s", "Y")
|
Printf("X %s", "Y")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkLogJSONPrintf(t *testing.B) {
|
||||||
|
LogJSON = true
|
||||||
|
Level = 1
|
||||||
|
|
||||||
|
ec := zap.NewProductionEncoderConfig()
|
||||||
|
ec.EncodeDuration = zapcore.NanosDurationEncoder
|
||||||
|
ec.EncodeTime = zapcore.EpochNanosTimeEncoder
|
||||||
|
enc := zapcore.NewJSONEncoder(ec)
|
||||||
|
|
||||||
|
logger := zap.New(
|
||||||
|
zapcore.NewCore(
|
||||||
|
enc,
|
||||||
|
zapcore.AddSync(ioutil.Discard),
|
||||||
|
zap.DebugLevel,
|
||||||
|
)).Sugar()
|
||||||
|
|
||||||
|
Set(logger)
|
||||||
|
t.ResetTimer()
|
||||||
|
for i := 0; i < t.N; i++ {
|
||||||
|
Printf("X %s", "Y")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -33,9 +33,10 @@ const (
|
||||||
MaxMemory = "maxmemory"
|
MaxMemory = "maxmemory"
|
||||||
AutoGC = "autogc"
|
AutoGC = "autogc"
|
||||||
KeepAlive = "keepalive"
|
KeepAlive = "keepalive"
|
||||||
|
LogConfig = "logconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
var validProperties = []string{RequirePass, LeaderAuth, ProtectedMode, MaxMemory, AutoGC, KeepAlive}
|
var validProperties = []string{RequirePass, LeaderAuth, ProtectedMode, MaxMemory, AutoGC, KeepAlive, LogConfig}
|
||||||
|
|
||||||
// Config is a tile38 config
|
// Config is a tile38 config
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -62,6 +63,8 @@ type Config struct {
|
||||||
_autoGC uint64
|
_autoGC uint64
|
||||||
_keepAliveP string
|
_keepAliveP string
|
||||||
_keepAlive int64
|
_keepAlive int64
|
||||||
|
_logConfigP interface{}
|
||||||
|
_logConfig string
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadConfig(path string) (*Config, error) {
|
func loadConfig(path string) (*Config, error) {
|
||||||
|
@ -90,7 +93,9 @@ func loadConfig(path string) (*Config, error) {
|
||||||
_maxMemoryP: gjson.Get(json, MaxMemory).String(),
|
_maxMemoryP: gjson.Get(json, MaxMemory).String(),
|
||||||
_autoGCP: gjson.Get(json, AutoGC).String(),
|
_autoGCP: gjson.Get(json, AutoGC).String(),
|
||||||
_keepAliveP: gjson.Get(json, KeepAlive).String(),
|
_keepAliveP: gjson.Get(json, KeepAlive).String(),
|
||||||
|
_logConfig: gjson.Get(json, LogConfig).String(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// load properties
|
// load properties
|
||||||
if err := config.setProperty(RequirePass, config._requirePassP, true); err != nil {
|
if err := config.setProperty(RequirePass, config._requirePassP, true); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -110,6 +115,9 @@ func loadConfig(path string) (*Config, error) {
|
||||||
if err := config.setProperty(KeepAlive, config._keepAliveP, true); err != nil {
|
if err := config.setProperty(KeepAlive, config._keepAliveP, true); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if err := config.setProperty(LogConfig, config._logConfig, true); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
config.write(false)
|
config.write(false)
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
@ -138,6 +146,9 @@ func (config *Config) write(writeProperties bool) {
|
||||||
} else {
|
} else {
|
||||||
config._keepAliveP = strconv.FormatUint(uint64(config._keepAlive), 10)
|
config._keepAliveP = strconv.FormatUint(uint64(config._keepAlive), 10)
|
||||||
}
|
}
|
||||||
|
if config._logConfig != "" {
|
||||||
|
config._logConfigP = config._logConfig
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m := make(map[string]interface{})
|
m := make(map[string]interface{})
|
||||||
|
@ -177,6 +188,11 @@ func (config *Config) write(writeProperties bool) {
|
||||||
if config._keepAliveP != "" {
|
if config._keepAliveP != "" {
|
||||||
m[KeepAlive] = config._keepAliveP
|
m[KeepAlive] = config._keepAliveP
|
||||||
}
|
}
|
||||||
|
if config._logConfigP != "" {
|
||||||
|
var lcfg map[string]interface{}
|
||||||
|
json.Unmarshal([]byte(config._logConfig), &lcfg)
|
||||||
|
m[LogConfig] = lcfg
|
||||||
|
}
|
||||||
data, err := json.MarshalIndent(m, "", "\t")
|
data, err := json.MarshalIndent(m, "", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -285,6 +301,12 @@ func (config *Config) setProperty(name, value string, fromLoad bool) error {
|
||||||
config._keepAlive = int64(keepalive)
|
config._keepAlive = int64(keepalive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case LogConfig:
|
||||||
|
if value == "" {
|
||||||
|
config._logConfig = ""
|
||||||
|
} else {
|
||||||
|
config._logConfig = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if invalid {
|
if invalid {
|
||||||
|
@ -322,6 +344,8 @@ func (config *Config) getProperty(name string) string {
|
||||||
return formatMemSize(config._maxMemory)
|
return formatMemSize(config._maxMemory)
|
||||||
case KeepAlive:
|
case KeepAlive:
|
||||||
return strconv.FormatUint(uint64(config._keepAlive), 10)
|
return strconv.FormatUint(uint64(config._keepAlive), 10)
|
||||||
|
case LogConfig:
|
||||||
|
return config._logConfig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,3 +484,9 @@ func (config *Config) setReadOnly(v bool) {
|
||||||
config._readOnly = v
|
config._readOnly = v
|
||||||
config.mu.Unlock()
|
config.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
func (config *Config) logConfig() string {
|
||||||
|
config.mu.RLock()
|
||||||
|
v := config._logConfig
|
||||||
|
config.mu.RUnlock()
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
|
@ -153,6 +153,7 @@ func Serve(opts Options) error {
|
||||||
if core.QueueFileName == "" {
|
if core.QueueFileName == "" {
|
||||||
core.QueueFileName = path.Join(opts.Dir, "queue.db")
|
core.QueueFileName = path.Join(opts.Dir, "queue.db")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Server started, Tile38 version %s, git %s", core.Version, core.GitSHA)
|
log.Infof("Server started, Tile38 version %s, git %s", core.Version, core.GitSHA)
|
||||||
|
|
||||||
// Initialize the s
|
// Initialize the s
|
||||||
|
|
Loading…
Reference in New Issue