From cbe6ebae0121e552cd6fab8748de738c8197c74b Mon Sep 17 00:00:00 2001 From: Spike^ekipS Date: Fri, 21 Dec 2018 20:40:31 +0900 Subject: [PATCH] support log rotate --- cmd/sebak/cmd/run.go | 154 +++++++++++++++++++++++++++++++++---------- go.mod | 2 + go.sum | 4 ++ lib/common/log.go | 23 +++++++ 4 files changed, 148 insertions(+), 35 deletions(-) diff --git a/cmd/sebak/cmd/run.go b/cmd/sebak/cmd/run.go index 685c0f3dc..cb8c7ce7f 100644 --- a/cmd/sebak/cmd/run.go +++ b/cmd/sebak/cmd/run.go @@ -44,7 +44,15 @@ var ( flagDebugPProf bool = common.GetENVValue("SEBAK_DEBUG_PPROF", "0") == "1" flagKPSecretSeed string = common.GetENVValue("SEBAK_SECRET_SEED", "") flagLog string = common.GetENVValue("SEBAK_LOG", "") + flagLogRotateMaxSize string = common.GetENVValue("SEBAK_LOG_ROTATE_MAX_SIZE", "100") + flagLogRotateMaxCount string = common.GetENVValue("SEBAK_LOG_ROTATE_MAX_COUNT", "0") + flagLogRotateMaxDays string = common.GetENVValue("SEBAK_LOG_ROTATE_MAX_DAYS", "0") + flagLogRotateUncompress bool = common.GetENVValue("SEBAK_LOG_ROTATE_UNCOMPRESS", "0") == "1" flagHTTPLog string = common.GetENVValue("SEBAK_HTTP_LOG", "") + flagHTTPLogRotateMaxSize string = common.GetENVValue("SEBAK_HTTP_LOG_ROTATE_MAX_SIZE", "100") + flagHTTPLogRotateMaxCount string = common.GetENVValue("SEBAK_HTTP_LOG_ROTATE_MAX_COUNT", "0") + flagHTTPLogRotateMaxDays string = common.GetENVValue("SEBAK_HTTP_LOG_ROTATE_MAX_DAYS", "0") + flagHTTPLogRotateUncompress bool = common.GetENVValue("SEBAK_HTTP_LOG_ROTATE_UNCOMPRESS", "0") == "1" flagLogLevel string = common.GetENVValue("SEBAK_LOG_LEVEL", defaultLogLevel.String()) flagLogFormat string = common.GetENVValue("SEBAK_LOG_FORMAT", defaultLogFormat) flagNetworkID string = common.GetENVValue("SEBAK_NETWORK_ID", "") @@ -120,8 +128,14 @@ var ( watchInterval time.Duration discoveryEndpoints []*common.Endpoint - logLevel logging.Lvl - log logging.Logger = logging.New("module", "main") + logLevel logging.Lvl + log logging.Logger = logging.New("module", "main") + logRotateMaxSize int + logRotateMaxCount int + logRotateMaxDays int + httpLogRotateMaxSize int + httpLogRotateMaxCount int + httpLogRotateMaxDays int ) func init() { @@ -182,7 +196,15 @@ func init() { nodeCmd.Flags().StringVar(&flagLogLevel, "log-level", flagLogLevel, "log level, {crit, error, warn, info, debug}") nodeCmd.Flags().StringVar(&flagLogFormat, "log-format", flagLogFormat, "log format, {terminal, json}") nodeCmd.Flags().StringVar(&flagLog, "log", flagLog, "set log file") + nodeCmd.Flags().StringVar(&flagLogRotateMaxSize, "log-rotate-max-size", flagLogRotateMaxSize, "max size of rotate log") + nodeCmd.Flags().StringVar(&flagLogRotateMaxCount, "log-rotate-max-count", flagLogRotateMaxCount, "max count of rotated logs") + nodeCmd.Flags().StringVar(&flagLogRotateMaxDays, "log-rotate-max-days", flagLogRotateMaxDays, "max days of rotated logs") + nodeCmd.Flags().BoolVar(&flagLogRotateUncompress, "log-rotate-uncompress", flagLogRotateUncompress, "disable compression of rotate log") nodeCmd.Flags().StringVar(&flagHTTPLog, "http-log", flagHTTPLog, "set log file for HTTP request") + nodeCmd.Flags().StringVar(&flagHTTPLogRotateMaxSize, "http-log-rotate-max-size", flagHTTPLogRotateMaxSize, "max size of rotate http log") + nodeCmd.Flags().StringVar(&flagHTTPLogRotateMaxCount, "http-log-rotate-max-count", flagHTTPLogRotateMaxCount, "max count of rotated http logs") + nodeCmd.Flags().StringVar(&flagHTTPLogRotateMaxDays, "http-log-rotate-max-days", flagHTTPLogRotateMaxDays, "max days of rotated http logs") + nodeCmd.Flags().BoolVar(&flagHTTPLogRotateUncompress, "http-log-rotate-uncompress", flagHTTPLogRotateUncompress, "disable compression of rotate http log") nodeCmd.Flags().BoolVar(&flagVerbose, "verbose", flagVerbose, "verbose") nodeCmd.Flags().StringVar(&flagBindURL, "bind", flagBindURL, "bind to listen on") nodeCmd.Flags().StringVar(&flagJSONRPCBindURL, "jsonrpc-bind", flagJSONRPCBindURL, "bind to listen on for jsonrpc") @@ -339,6 +361,54 @@ func parseFlagDiscovery(l cmdcommon.ListFlags) (endpoints []*common.Endpoint, er return } +func parseLogRotateMaxSize(option, value string) int { + if len(value) < 1 { + return 0 + } + + var s int64 + var err error + if s, err = strconv.ParseInt(value, 10, 64); err != nil { + cmdcommon.PrintFlagsError(nodeCmd, option, err) + } else if s < 0 { + cmdcommon.PrintFlagsError(nodeCmd, option, fmt.Errorf("greater than 0")) + } + + return int(s) +} + +func parseLogRotateMaxCount(option, value string) int { + if len(value) < 1 { + return 100 // 100M + } + + var s int64 + var err error + if s, err = strconv.ParseInt(value, 10, 64); err != nil { + cmdcommon.PrintFlagsError(nodeCmd, option, err) + } else if s < 0 { + cmdcommon.PrintFlagsError(nodeCmd, option, fmt.Errorf("greater than 0")) + } + + return int(s) +} + +func parseLogRotateMaxDays(option, value string) int { + if len(value) < 1 { + return 0 + } + + var s int64 + var err error + if s, err = strconv.ParseInt(value, 10, 64); err != nil { + cmdcommon.PrintFlagsError(nodeCmd, option, err) + } else if s < 0 { + cmdcommon.PrintFlagsError(nodeCmd, option, fmt.Errorf("greater than 0")) + } + + return int(s) +} + func parseFlagsNode() { var err error @@ -516,48 +586,62 @@ func parseFlagsNode() { cmdcommon.PrintFlagsError(nodeCmd, "--log-level", err) } - var logFormatter logging.Format - switch flagLogFormat { - case "terminal": - if isatty.IsTerminal(os.Stdout.Fd()) && len(flagLog) < 1 { - logFormatter = logging.TerminalFormat() + var logHandler logging.Handler + { // global log + var logFormatter logging.Format + switch flagLogFormat { + case "terminal": + if isatty.IsTerminal(os.Stdout.Fd()) && len(flagLog) < 1 { + logFormatter = logging.TerminalFormat() + } else { + logFormatter = logging.LogfmtFormat() + } + case "json": + logFormatter = common.JsonFormatEx(false, true) + default: + cmdcommon.PrintFlagsError(nodeCmd, "--log-format", fmt.Errorf("'%s'", flagLogFormat)) + } + + if len(flagLog) < 1 { + logHandler = logging.StreamHandler(os.Stdout, logFormatter) } else { - logFormatter = logging.LogfmtFormat() + logRotateMaxSize = parseLogRotateMaxSize("--log-rotate-max-size", flagLogRotateMaxSize) + logRotateMaxCount = parseLogRotateMaxSize("--log-rotate-max-count", flagLogRotateMaxCount) + logRotateMaxDays = parseLogRotateMaxDays("--log-rotate-max-days", flagLogRotateMaxDays) + + logHandler = common.NewRotateHandler( + flagLog, logFormatter, + logRotateMaxSize, logRotateMaxDays, logRotateMaxCount, !flagLogRotateUncompress, + ) } - case "json": - logFormatter = common.JsonFormatEx(false, true) - default: - cmdcommon.PrintFlagsError(nodeCmd, "--log-format", fmt.Errorf("'%s'", flagLogFormat)) - } - logHandler := logging.StreamHandler(os.Stdout, logFormatter) - if len(flagLog) > 0 { - if logHandler, err = logging.FileHandler(flagLog, logFormatter); err != nil { - cmdcommon.PrintFlagsError(nodeCmd, "--log", err) + if logLevel == logging.LvlDebug { // only debug produces `caller` data + logHandler = logging.CallerFileHandler(logHandler) } - } + logHandler = logging.LvlFilterHandler(logLevel, logHandler) + log.SetHandler(logHandler) - if logLevel == logging.LvlDebug { // only debug produces `caller` data - logHandler = logging.CallerFileHandler(logHandler) + runner.SetLogging(logLevel, logHandler) + consensus.SetLogging(logLevel, logHandler) + network.SetLogging(logLevel, logHandler) + sync.SetLogging(logLevel, logHandler) } - logHandler = logging.LvlFilterHandler(logLevel, logHandler) - log.SetHandler(logHandler) - runner.SetLogging(logLevel, logHandler) - consensus.SetLogging(logLevel, logHandler) - network.SetLogging(logLevel, logHandler) - sync.SetLogging(logLevel, logHandler) + { // http log + // if without http-log, http log messages will be in `network.log` + if len(flagHTTPLog) < 1 { + network.SetHTTPLogging(logLevel, logHandler) + } else { + httpLogRotateMaxSize = parseLogRotateMaxSize("--http-log-rotate-max-size", flagHTTPLogRotateMaxSize) + httpLogRotateMaxCount = parseLogRotateMaxSize("--http-log-rotate-max-count", flagHTTPLogRotateMaxCount) + httpLogRotateMaxDays = parseLogRotateMaxDays("--http-log-rotate-max-days", flagHTTPLogRotateMaxDays) - // if without http-log, http log messages will be in `network.log` - if len(flagHTTPLog) < 1 { - network.SetHTTPLogging(logLevel, logHandler) - } else { - // In `http-log`, http log will be json format - httpLogHandler, err := logging.FileHandler(flagHTTPLog, common.JsonFormatEx(false, true)) - if err != nil { - cmdcommon.PrintFlagsError(nodeCmd, "--http-log", err) + httpLogHandler := common.NewRotateHandler( + flagHTTPLog, common.JsonFormatEx(false, true), // In `http-log`, http log will be json format + httpLogRotateMaxSize, httpLogRotateMaxDays, httpLogRotateMaxCount, !flagHTTPLogRotateUncompress, + ) + network.SetHTTPLogging(logging.LvlDebug, httpLogHandler) // httpLog only use `Debug` } - network.SetHTTPLogging(logging.LvlDebug, httpLogHandler) // httpLog only use `Debug` } // checking `--discovery` diff --git a/go.mod b/go.mod index f62b484ba..b9ab80b41 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ require ( github.com/GianlucaGuarini/go-observable v0.0.0-20180829201609-d386f0081a66 github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect github.com/allegro/bigcache v1.1.0 // indirect + github.com/beevik/ntp v0.2.0 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect github.com/btcsuite/btcd v0.0.0-20180810000619-f899737d7f27 // indirect github.com/btcsuite/btcutil v0.0.0-20170726183619-501929d3d046 @@ -54,6 +55,7 @@ require ( golang.org/x/text v0.3.0 // indirect gopkg.in/fsnotify.v1 v1.4.7 // indirect gopkg.in/karalabe/cookiejar.v2 v2.0.0-20150724131613-8dcd6a7f4951 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.2.1 ) diff --git a/go.sum b/go.sum index 6e2a6edcc..6d3858788 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7I github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= github.com/allegro/bigcache v1.1.0 h1:MLuIKTjdxDc+qsG2rhjsYjsHQC5LUGjIWzutg7M+W68= github.com/allegro/bigcache v1.1.0/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw= +github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/btcsuite/btcd v0.0.0-20180810000619-f899737d7f27 h1:WU7sAs3XGB9kUkEum8TfmtKl8seYpgyNplGgifi6ZgE= @@ -108,6 +110,8 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/karalabe/cookiejar.v2 v2.0.0-20150724131613-8dcd6a7f4951 h1:DMTcQRFbEH62YPRWwOI647s2e5mHda3oBPMHfrLs2bw= gopkg.in/karalabe/cookiejar.v2 v2.0.0-20150724131613-8dcd6a7f4951/go.mod h1:owOxCRGGeAx1uugABik6K9oeNu1cgxP/R9ItzLDxNWA= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= diff --git a/lib/common/log.go b/lib/common/log.go index 7f7698ae1..6b840a001 100644 --- a/lib/common/log.go +++ b/lib/common/log.go @@ -3,11 +3,13 @@ package common import ( "encoding/json" "fmt" + "io" "os" "reflect" "time" logging "github.com/inconshreveable/log15" + lumberjack "gopkg.in/natefinch/lumberjack.v2" "boscoin.io/sebak/lib/errors" ) @@ -112,3 +114,24 @@ func (l nopLogger) Info(msg string, ctx ...interface{}) {} func (l nopLogger) Warn(msg string, ctx ...interface{}) {} func (l nopLogger) Error(msg string, ctx ...interface{}) {} func (l nopLogger) Crit(msg string, ctx ...interface{}) {} + +type closingHandler struct { + io.WriteCloser + logging.Handler +} + +func (h *closingHandler) Close() error { + return h.WriteCloser.Close() +} + +func NewRotateHandler(path string, fmtr logging.Format, maxSize, maxAge, maxBackups int, compress bool) logging.Handler { + wc := &lumberjack.Logger{ + Filename: path, + MaxSize: maxSize, + MaxBackups: maxBackups, + MaxAge: maxAge, + Compress: compress, + } + + return closingHandler{wc, logging.StreamHandler(wc, fmtr)} +}