From d037ce0c805eb94230797bab05b45333cfc8e5ae Mon Sep 17 00:00:00 2001 From: Paladz Date: Mon, 29 Jul 2019 10:32:01 +0800 Subject: [PATCH] Revert "log into file (#357)" This reverts commit bc213b29d91743bb9cb23c043f2856f47b34bb3e. --- config/config.go | 5 - log/log.go | 72 --- node/node.go | 20 +- .../lestrrat-go/file-rotatelogs/.gitignore | 22 - .../lestrrat-go/file-rotatelogs/.travis.yml | 5 - .../github.com/lestrrat-go/file-rotatelogs/LICENSE | 20 - .../lestrrat-go/file-rotatelogs/README.md | 236 --------- .../lestrrat-go/file-rotatelogs/event.go | 17 - .../lestrrat-go/file-rotatelogs/example_test.go | 56 --- .../lestrrat-go/file-rotatelogs/interface.go | 72 --- .../file-rotatelogs/internal/option/option.go | 25 - .../lestrrat-go/file-rotatelogs/internal_test.go | 41 -- .../lestrrat-go/file-rotatelogs/options.go | 82 ---- .../lestrrat-go/file-rotatelogs/rotatelogs.go | 366 -------------- .../lestrrat-go/file-rotatelogs/rotatelogs_test.go | 531 --------------------- vendor/github.com/lestrrat-go/strftime/.gitignore | 24 - vendor/github.com/lestrrat-go/strftime/.travis.yml | 5 - vendor/github.com/lestrrat-go/strftime/LICENSE | 21 - vendor/github.com/lestrrat-go/strftime/README.md | 151 ------ .../lestrrat-go/strftime/internal_test.go | 28 -- vendor/github.com/lestrrat-go/strftime/strftime.go | 219 --------- .../lestrrat-go/strftime/strftime_bench_test.go | 80 ---- .../lestrrat-go/strftime/strftime_test.go | 148 ------ vendor/github.com/lestrrat-go/strftime/writer.go | 169 ------- 24 files changed, 16 insertions(+), 2399 deletions(-) delete mode 100644 log/log.go delete mode 100644 vendor/github.com/lestrrat-go/file-rotatelogs/.gitignore delete mode 100644 vendor/github.com/lestrrat-go/file-rotatelogs/.travis.yml delete mode 100644 vendor/github.com/lestrrat-go/file-rotatelogs/LICENSE delete mode 100644 vendor/github.com/lestrrat-go/file-rotatelogs/README.md delete mode 100644 vendor/github.com/lestrrat-go/file-rotatelogs/event.go delete mode 100644 vendor/github.com/lestrrat-go/file-rotatelogs/example_test.go delete mode 100644 vendor/github.com/lestrrat-go/file-rotatelogs/interface.go delete mode 100644 vendor/github.com/lestrrat-go/file-rotatelogs/internal/option/option.go delete mode 100644 vendor/github.com/lestrrat-go/file-rotatelogs/internal_test.go delete mode 100644 vendor/github.com/lestrrat-go/file-rotatelogs/options.go delete mode 100644 vendor/github.com/lestrrat-go/file-rotatelogs/rotatelogs.go delete mode 100644 vendor/github.com/lestrrat-go/file-rotatelogs/rotatelogs_test.go delete mode 100644 vendor/github.com/lestrrat-go/strftime/.gitignore delete mode 100644 vendor/github.com/lestrrat-go/strftime/.travis.yml delete mode 100644 vendor/github.com/lestrrat-go/strftime/LICENSE delete mode 100644 vendor/github.com/lestrrat-go/strftime/README.md delete mode 100644 vendor/github.com/lestrrat-go/strftime/internal_test.go delete mode 100644 vendor/github.com/lestrrat-go/strftime/strftime.go delete mode 100644 vendor/github.com/lestrrat-go/strftime/strftime_bench_test.go delete mode 100644 vendor/github.com/lestrrat-go/strftime/strftime_test.go delete mode 100644 vendor/github.com/lestrrat-go/strftime/writer.go diff --git a/config/config.go b/config/config.go index 02d2c7cf..8b5ede84 100644 --- a/config/config.go +++ b/config/config.go @@ -134,7 +134,6 @@ func DefaultBaseConfig() BaseConfig { DBBackend: "leveldb", DBPath: "data", KeysPath: "keystore", - LogFile: "log", PrivateKeyFile: "node_key.txt", FederationFileName: "federation.json", } @@ -144,10 +143,6 @@ func (b BaseConfig) DBDir() string { return rootify(b.DBPath, b.RootDir) } -func (b BaseConfig) LogDir() string { - return rootify(b.LogFile, b.RootDir) -} - func (b BaseConfig) KeysDir() string { return rootify(b.KeysPath, b.RootDir) } diff --git a/log/log.go b/log/log.go deleted file mode 100644 index 43bcc9ca..00000000 --- a/log/log.go +++ /dev/null @@ -1,72 +0,0 @@ -package log - -import ( - "path/filepath" - "sync" - "time" - - rotatelogs "github.com/lestrrat-go/file-rotatelogs" - "github.com/sirupsen/logrus" - - "github.com/vapor/config" -) - -const ( - rotationTime int64 = 86400 - maxAge int64 = 604800 -) - -var defaultFormatter = &logrus.TextFormatter{DisableColors: true} - -func InitLogFile(config *config.Config) { - hook := newBtmHook(config.LogDir()) - logrus.AddHook(hook) -} - -type BtmHook struct { - logPath string - lock *sync.Mutex -} - -func newBtmHook(logPath string) *BtmHook { - hook := &BtmHook{lock: new(sync.Mutex)} - hook.logPath = logPath - return hook -} - -// Write a log line to an io.Writer. -func (hook *BtmHook) ioWrite(entry *logrus.Entry) error { - module := "general" - if data, ok := entry.Data["module"]; ok { - module = data.(string) - } - - logPath := filepath.Join(hook.logPath, module) - writer, err := rotatelogs.New( - logPath+".%Y%m%d", - rotatelogs.WithMaxAge(time.Duration(maxAge)*time.Second), - rotatelogs.WithRotationTime(time.Duration(rotationTime)*time.Second), - ) - if err != nil { - return err - } - - msg, err := defaultFormatter.Format(entry) - if err != nil { - return err - } - - _, err = writer.Write(msg) - return err -} - -func (hook *BtmHook) Fire(entry *logrus.Entry) error { - hook.lock.Lock() - defer hook.lock.Unlock() - return hook.ioWrite(entry) -} - -// Levels returns configured log levels. -func (hook *BtmHook) Levels() []logrus.Level { - return logrus.AllLevels -} diff --git a/node/node.go b/node/node.go index beafcf03..531ff832 100644 --- a/node/node.go +++ b/node/node.go @@ -6,6 +6,7 @@ import ( "net" "net/http" _ "net/http/pprof" + "os" "path/filepath" "reflect" @@ -25,7 +26,6 @@ import ( dbm "github.com/vapor/database/leveldb" "github.com/vapor/env" "github.com/vapor/event" - vaporLog "github.com/vapor/log" "github.com/vapor/net/websocket" "github.com/vapor/netsync" "github.com/vapor/proposal/blockproposer" @@ -66,8 +66,6 @@ func NewNode(config *cfg.Config) *Node { cmn.Exit(cmn.Fmt("Failed to load federated information:[%s]", err.Error())) } - vaporLog.InitLogFile(config) - log.WithFields(log.Fields{ "module": logModule, "pubkey": config.PrivateKey().XPub(), @@ -76,10 +74,10 @@ func NewNode(config *cfg.Config) *Node { "fed_controlprogram": hex.EncodeToString(cfg.FederationWScript(config)), }).Info() + initLogFile(config) if err := consensus.InitActiveNetParams(config.ChainID); err != nil { log.Fatalf("Failed to init ActiveNetParams:[%s]", err.Error()) } - initCommonConfig(config) // Get store @@ -190,6 +188,20 @@ func lockDataDirectory(config *cfg.Config) error { return nil } +func initLogFile(config *cfg.Config) { + if config.LogFile == "" { + return + } + cmn.EnsureDir(filepath.Dir(config.LogFile), 0700) + file, err := os.OpenFile(config.LogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + if err == nil { + log.SetOutput(file) + } else { + log.WithFields(log.Fields{"module": logModule, "err": err}).Info("using default") + } + +} + func initCommonConfig(config *cfg.Config) { cfg.CommonConfig = config } diff --git a/vendor/github.com/lestrrat-go/file-rotatelogs/.gitignore b/vendor/github.com/lestrrat-go/file-rotatelogs/.gitignore deleted file mode 100644 index 00268614..00000000 --- a/vendor/github.com/lestrrat-go/file-rotatelogs/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe diff --git a/vendor/github.com/lestrrat-go/file-rotatelogs/.travis.yml b/vendor/github.com/lestrrat-go/file-rotatelogs/.travis.yml deleted file mode 100644 index 6e1b7a91..00000000 --- a/vendor/github.com/lestrrat-go/file-rotatelogs/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: go -sudo: false -go: - - "1.10" - - tip diff --git a/vendor/github.com/lestrrat-go/file-rotatelogs/LICENSE b/vendor/github.com/lestrrat-go/file-rotatelogs/LICENSE deleted file mode 100644 index 9a7f25bb..00000000 --- a/vendor/github.com/lestrrat-go/file-rotatelogs/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 lestrrat - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/lestrrat-go/file-rotatelogs/README.md b/vendor/github.com/lestrrat-go/file-rotatelogs/README.md deleted file mode 100644 index 82a0a766..00000000 --- a/vendor/github.com/lestrrat-go/file-rotatelogs/README.md +++ /dev/null @@ -1,236 +0,0 @@ -file-rotatelogs -================== - -Provide an `io.Writer` that periodically rotates log files from within the application. Port of [File::RotateLogs](https://metacpan.org/release/File-RotateLogs) from Perl to Go. - -[![Build Status](https://travis-ci.org/lestrrat-go/file-rotatelogs.png?branch=master)](https://travis-ci.org/lestrrat-go/file-rotatelogs) - -[![GoDoc](https://godoc.org/github.com/lestrrat-go/file-rotatelogs?status.svg)](https://godoc.org/github.com/lestrrat-go/file-rotatelogs) - - -# SYNOPSIS - -```go -import ( - "log" - "net/http" - - apachelog "github.com/lestrrat-go/apache-logformat" - rotatelogs "github.com/lestrrat-go/file-rotatelogs" -) - -func main() { - mux := http.NewServeMux() - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { ... }) - - logf, err := rotatelogs.New( - "/path/to/access_log.%Y%m%d%H%M", - rotatelogs.WithLinkName("/path/to/access_log"), - rotatelogs.WithMaxAge(24 * time.Hour), - rotatelogs.WithRotationTime(time.Hour), - ) - if err != nil { - log.Printf("failed to create rotatelogs: %s", err) - return - } - - // Now you must write to logf. apache-logformat library can create - // a http.Handler that only writes the approriate logs for the request - // to the given handle - http.ListenAndServe(":8080", apachelog.CombinedLog.Wrap(mux, logf)) -} -``` - -# DESCRIPTION - -When you integrate this to to you app, it automatically write to logs that -are rotated from within the app: No more disk-full alerts because you forgot -to setup logrotate! - -To install, simply issue a `go get`: - -``` -go get github.com/lestrrat-go/file-rotatelogs -``` - -It's normally expected that this library is used with some other -logging service, such as the built-in `log` library, or loggers -such as `github.com/lestrrat-go/apache-logformat`. - -```go -import( - "log" - "github.com/lestrrat-go/file-rotatelogs" -) - -func main() { - rl, _ := rotatelogs.New("/path/to/access_log.%Y%m%d%H%M") - - log.SetOutput(rl) - - /* elsewhere ... */ - log.Printf("Hello, World!") -} -``` - -OPTIONS -==== - -## Pattern (Required) - -The pattern used to generate actual log file names. You should use patterns -using the strftime (3) format. For example: - -```go - rotatelogs.New("/var/log/myapp/log.%Y%m%d") -``` - -## Clock (default: rotatelogs.Local) - -You may specify an object that implements the roatatelogs.Clock interface. -When this option is supplied, it's used to determine the current time to -base all of the calculations on. For example, if you want to base your -calculations in UTC, you may specify rotatelogs.UTC - -```go - rotatelogs.New( - "/var/log/myapp/log.%Y%m%d", - rotatelogs.WithClock(rotatelogs.UTC), - ) -``` - -## Location - -This is an alternative to the `WithClock` option. Instead of providing an -explicit clock, you can provide a location for you times. We will create -a Clock object that produces times in your specified location, and configure -the rotatelog to respect it. - -## LinkName (default: "") - -Path where a symlink for the actual log file is placed. This allows you to -always check at the same location for log files even if the logs were rotated - -```go - rotatelogs.New( - "/var/log/myapp/log.%Y%m%d", - rotatelogs.WithLinkName("/var/log/myapp/current"), - ) -``` - -``` - // Else where - $ tail -f /var/log/myapp/current -``` - -If not provided, no link will be written. - -## RotationTime (default: 86400 sec) - -Interval between file rotation. By default logs are rotated every 86400 seconds. -Note: Remember to use time.Duration values. - -```go - // Rotate every hour - rotatelogs.New( - "/var/log/myapp/log.%Y%m%d", - rotatelogs.WithRotationTime(time.Hour), - ) -``` - -## MaxAge (default: 7 days) - -Time to wait until old logs are purged. By default no logs are purged, which -certainly isn't what you want. -Note: Remember to use time.Duration values. - -```go - // Purge logs older than 1 hour - rotatelogs.New( - "/var/log/myapp/log.%Y%m%d", - rotatelogs.WithMaxAge(time.Hour), - ) -``` - -## RotationCount (default: -1) - -The number of files should be kept. By default, this option is disabled. - -Note: MaxAge should be disabled by specifing `WithMaxAge(-1)` explicitly. - -```go - // Purge logs except latest 7 files - rotatelogs.New( - "/var/log/myapp/log.%Y%m%d", - rotatelogs.WithMaxAge(-1), - rotatelogs.WithRotationCount(7), - ) -``` - -## Handler (default: nil) - -Sets the event handler to receive event notifications from the RotateLogs -object. Currently only supported event type is FiledRotated - -```go - rotatelogs.New( - "/var/log/myapp/log.%Y%m%d", - rotatelogs.Handler(rotatelogs.HandlerFunc(func(e Event) { - if e.Type() != rotatelogs.FileRotatedEventType { - return - } - - // Do what you want with the data. This is just an idea: - storeLogFileToRemoteStorage(e.(*FileRotatedEvent).PreviousFile()) - })), - ) -``` - -## ForceNewFile - -Ensure a new file is created every time New() is called. If the base file name -already exists, an implicit rotation is performed. - -```go - rotatelogs.New( - "/var/log/myapp/log.%Y%m%d", - rotatelogs.ForceNewFile(), - ) -``` - -## ForceNewFile - -Ensure a new file is created every time New() is called. If the base file name -already exists, an implicit rotation is performed. - -```go - rotatelogs.New( - "/var/log/myapp/log.%Y%m%d", - rotatelogs.ForceNewFile(), - ) -``` - -# Rotating files forcefully - -If you want to rotate files forcefully before the actual rotation time has reached, -you may use the `Rotate()` method. This method forcefully rotates the logs, but -if the generated file name clashes, then a numeric suffix is added so that -the new file will forcefully appear on disk. - -For example, suppose you had a pattern of '%Y.log' with a rotation time of -`86400` so that it only gets rotated every year, but for whatever reason you -wanted to rotate the logs now, you could install a signal handler to -trigger this rotation: - -```go -rl := rotatelogs.New(...) - -signal.Notify(ch, syscall.SIGHUP) - -go func(ch chan os.Signal) { - <-ch - rl.Rotate() -}() -``` - -And you will get a log file name in like `2018.log.1`, `2018.log.2`, etc. diff --git a/vendor/github.com/lestrrat-go/file-rotatelogs/event.go b/vendor/github.com/lestrrat-go/file-rotatelogs/event.go deleted file mode 100644 index 23047c42..00000000 --- a/vendor/github.com/lestrrat-go/file-rotatelogs/event.go +++ /dev/null @@ -1,17 +0,0 @@ -package rotatelogs - -func (h HandlerFunc) Handle(e Event) { - h(e) -} - -func (e *FileRotatedEvent) Type() EventType { - return FileRotatedEventType -} - -func (e *FileRotatedEvent) PreviousFile() string { - return e.prev -} - -func (e *FileRotatedEvent) CurrentFile() string { - return e.current -} diff --git a/vendor/github.com/lestrrat-go/file-rotatelogs/example_test.go b/vendor/github.com/lestrrat-go/file-rotatelogs/example_test.go deleted file mode 100644 index 02fb5f6b..00000000 --- a/vendor/github.com/lestrrat-go/file-rotatelogs/example_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package rotatelogs_test - -import ( - "fmt" - "io/ioutil" - "os" - rotatelogs "github.com/lestrrat-go/file-rotatelogs" -) - -func ExampleForceNewFile () { - logDir, err := ioutil.TempDir("", "rotatelogs_test") - if err != nil { - fmt.Println("could not create log directory ", err) - return - } - logPath := fmt.Sprintf("%s/test.log", logDir) - - for i := 0; i < 2; i++ { - writer, err := rotatelogs.New(logPath, - rotatelogs.ForceNewFile(), - ) - if err != nil { - fmt.Println("Could not open log file ", err) - return - } - - n, err := writer.Write([]byte("test")) - if err != nil || n != 4 { - fmt.Println("Write failed ", err, " number written ", n) - return - } - err = writer.Close() - if err != nil { - fmt.Println("Close failed ", err) - return - } - } - - files, err := ioutil.ReadDir(logDir) - if err != nil { - fmt.Println("ReadDir failed ", err) - return - } - for _, file := range files { - fmt.Println(file.Name(), file.Size()) - } - - err = os.RemoveAll(logDir) - if err != nil { - fmt.Println("RemoveAll failed ", err) - return - } - // OUTPUT: - // test.log 4 - // test.log.1 4 -} diff --git a/vendor/github.com/lestrrat-go/file-rotatelogs/interface.go b/vendor/github.com/lestrrat-go/file-rotatelogs/interface.go deleted file mode 100644 index fcd0f58a..00000000 --- a/vendor/github.com/lestrrat-go/file-rotatelogs/interface.go +++ /dev/null @@ -1,72 +0,0 @@ -package rotatelogs - -import ( - "os" - "sync" - "time" - - strftime "github.com/lestrrat-go/strftime" -) - -type Handler interface { - Handle(Event) -} - -type HandlerFunc func(Event) - -type Event interface { - Type() EventType -} - -type EventType int - -const ( - InvalidEventType EventType = iota - FileRotatedEventType -) - -type FileRotatedEvent struct { - prev string // previous filename - current string // current, new filename -} - -// RotateLogs represents a log file that gets -// automatically rotated as you write to it. -type RotateLogs struct { - clock Clock - curFn string - curBaseFn string - globPattern string - generation int - linkName string - maxAge time.Duration - mutex sync.RWMutex - eventHandler Handler - outFh *os.File - pattern *strftime.Strftime - rotationTime time.Duration - rotationCount uint - forceNewFile bool -} - -// Clock is the interface used by the RotateLogs -// object to determine the current time -type Clock interface { - Now() time.Time -} -type clockFn func() time.Time - -// UTC is an object satisfying the Clock interface, which -// returns the current time in UTC -var UTC = clockFn(func() time.Time { return time.Now().UTC() }) - -// Local is an object satisfying the Clock interface, which -// returns the current time in the local timezone -var Local = clockFn(time.Now) - -// Option is used to pass optional arguments to -// the RotateLogs constructor -type Option interface { - Name() string - Value() interface{} -} diff --git a/vendor/github.com/lestrrat-go/file-rotatelogs/internal/option/option.go b/vendor/github.com/lestrrat-go/file-rotatelogs/internal/option/option.go deleted file mode 100644 index 9259dc51..00000000 --- a/vendor/github.com/lestrrat-go/file-rotatelogs/internal/option/option.go +++ /dev/null @@ -1,25 +0,0 @@ -package option - -type Interface interface { - Name() string - Value() interface{} -} - -type Option struct { - name string - value interface{} -} - -func New(name string, value interface{}) *Option { - return &Option{ - name: name, - value: value, - } -} - -func (o *Option) Name() string { - return o.name -} -func (o *Option) Value() interface{} { - return o.value -} diff --git a/vendor/github.com/lestrrat-go/file-rotatelogs/internal_test.go b/vendor/github.com/lestrrat-go/file-rotatelogs/internal_test.go deleted file mode 100644 index 8ee39317..00000000 --- a/vendor/github.com/lestrrat-go/file-rotatelogs/internal_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package rotatelogs - -import ( - "fmt" - "testing" - "time" - - "github.com/jonboulle/clockwork" - "github.com/stretchr/testify/assert" -) - -func TestGenFilename(t *testing.T) { - // Mock time - ts := []time.Time{ - time.Time{}, - (time.Time{}).Add(24 * time.Hour), - } - - for _, xt := range ts { - rl, err := New( - "/path/to/%Y/%m/%d", - WithClock(clockwork.NewFakeClockAt(xt)), - ) - if !assert.NoError(t, err, "New should succeed") { - return - } - - defer rl.Close() - - fn := rl.genFilename() - expected := fmt.Sprintf("/path/to/%04d/%02d/%02d", - xt.Year(), - xt.Month(), - xt.Day(), - ) - - if !assert.Equal(t, expected, fn) { - return - } - } -} diff --git a/vendor/github.com/lestrrat-go/file-rotatelogs/options.go b/vendor/github.com/lestrrat-go/file-rotatelogs/options.go deleted file mode 100644 index 49cc342b..00000000 --- a/vendor/github.com/lestrrat-go/file-rotatelogs/options.go +++ /dev/null @@ -1,82 +0,0 @@ -package rotatelogs - -import ( - "time" - - "github.com/lestrrat-go/file-rotatelogs/internal/option" -) - -const ( - optkeyClock = "clock" - optkeyHandler = "handler" - optkeyLinkName = "link-name" - optkeyMaxAge = "max-age" - optkeyRotationTime = "rotation-time" - optkeyRotationCount = "rotation-count" - optkeyForceNewFile = "force-new-file" -) - -// WithClock creates a new Option that sets a clock -// that the RotateLogs object will use to determine -// the current time. -// -// By default rotatelogs.Local, which returns the -// current time in the local time zone, is used. If you -// would rather use UTC, use rotatelogs.UTC as the argument -// to this option, and pass it to the constructor. -func WithClock(c Clock) Option { - return option.New(optkeyClock, c) -} - -// WithLocation creates a new Option that sets up a -// "Clock" interface that the RotateLogs object will use -// to determine the current time. -// -// This optin works by always returning the in the given -// location. -func WithLocation(loc *time.Location) Option { - return option.New(optkeyClock, clockFn(func() time.Time { - return time.Now().In(loc) - })) -} - -// WithLinkName creates a new Option that sets the -// symbolic link name that gets linked to the current -// file name being used. -func WithLinkName(s string) Option { - return option.New(optkeyLinkName, s) -} - -// WithMaxAge creates a new Option that sets the -// max age of a log file before it gets purged from -// the file system. -func WithMaxAge(d time.Duration) Option { - return option.New(optkeyMaxAge, d) -} - -// WithRotationTime creates a new Option that sets the -// time between rotation. -func WithRotationTime(d time.Duration) Option { - return option.New(optkeyRotationTime, d) -} - -// WithRotationCount creates a new Option that sets the -// number of files should be kept before it gets -// purged from the file system. -func WithRotationCount(n uint) Option { - return option.New(optkeyRotationCount, n) -} - -// WithHandler creates a new Option that specifies the -// Handler object that gets invoked when an event occurs. -// Currently `FileRotated` event is supported -func WithHandler(h Handler) Option { - return option.New(optkeyHandler, h) -} - -// ForceNewFile ensures a new file is created every time New() -// is called. If the base file name already exists, an implicit -// rotation is performed -func ForceNewFile() Option { - return option.New(optkeyForceNewFile, true) -} diff --git a/vendor/github.com/lestrrat-go/file-rotatelogs/rotatelogs.go b/vendor/github.com/lestrrat-go/file-rotatelogs/rotatelogs.go deleted file mode 100644 index 3059474a..00000000 --- a/vendor/github.com/lestrrat-go/file-rotatelogs/rotatelogs.go +++ /dev/null @@ -1,366 +0,0 @@ -// package rotatelogs is a port of File-RotateLogs from Perl -// (https://metacpan.org/release/File-RotateLogs), and it allows -// you to automatically rotate output files when you write to them -// according to the filename pattern that you can specify. -package rotatelogs - -import ( - "fmt" - "io" - "os" - "path/filepath" - "regexp" - "strings" - "sync" - "time" - - strftime "github.com/lestrrat-go/strftime" - "github.com/pkg/errors" -) - -func (c clockFn) Now() time.Time { - return c() -} - -// New creates a new RotateLogs object. A log filename pattern -// must be passed. Optional `Option` parameters may be passed -func New(p string, options ...Option) (*RotateLogs, error) { - globPattern := p - for _, re := range patternConversionRegexps { - globPattern = re.ReplaceAllString(globPattern, "*") - } - - pattern, err := strftime.New(p) - if err != nil { - return nil, errors.Wrap(err, `invalid strftime pattern`) - } - - var clock Clock = Local - rotationTime := 24 * time.Hour - var rotationCount uint - var linkName string - var maxAge time.Duration - var handler Handler - var forceNewFile bool - - for _, o := range options { - switch o.Name() { - case optkeyClock: - clock = o.Value().(Clock) - case optkeyLinkName: - linkName = o.Value().(string) - case optkeyMaxAge: - maxAge = o.Value().(time.Duration) - if maxAge < 0 { - maxAge = 0 - } - case optkeyRotationTime: - rotationTime = o.Value().(time.Duration) - if rotationTime < 0 { - rotationTime = 0 - } - case optkeyRotationCount: - rotationCount = o.Value().(uint) - case optkeyHandler: - handler = o.Value().(Handler) - case optkeyForceNewFile: - forceNewFile = true - } - } - - if maxAge > 0 && rotationCount > 0 { - return nil, errors.New("options MaxAge and RotationCount cannot be both set") - } - - if maxAge == 0 && rotationCount == 0 { - // if both are 0, give maxAge a sane default - maxAge = 7 * 24 * time.Hour - } - - return &RotateLogs{ - clock: clock, - eventHandler: handler, - globPattern: globPattern, - linkName: linkName, - maxAge: maxAge, - pattern: pattern, - rotationTime: rotationTime, - rotationCount: rotationCount, - forceNewFile: forceNewFile, - }, nil -} - -func (rl *RotateLogs) genFilename() string { - now := rl.clock.Now() - - // XXX HACK: Truncate only happens in UTC semantics, apparently. - // observed values for truncating given time with 86400 secs: - // - // before truncation: 2018/06/01 03:54:54 2018-06-01T03:18:00+09:00 - // after truncation: 2018/06/01 03:54:54 2018-05-31T09:00:00+09:00 - // - // This is really annoying when we want to truncate in local time - // so we hack: we take the apparent local time in the local zone, - // and pretend that it's in UTC. do our math, and put it back to - // the local zone - var base time.Time - if now.Location() != time.UTC { - base = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), now.Nanosecond(), time.UTC) - base = base.Truncate(time.Duration(rl.rotationTime)) - base = time.Date(base.Year(), base.Month(), base.Day(), base.Hour(), base.Minute(), base.Second(), base.Nanosecond(), base.Location()) - } else { - base = now.Truncate(time.Duration(rl.rotationTime)) - } - return rl.pattern.FormatString(base) -} - -// Write satisfies the io.Writer interface. It writes to the -// appropriate file handle that is currently being used. -// If we have reached rotation time, the target file gets -// automatically rotated, and also purged if necessary. -func (rl *RotateLogs) Write(p []byte) (n int, err error) { - // Guard against concurrent writes - rl.mutex.Lock() - defer rl.mutex.Unlock() - - out, err := rl.getWriter_nolock(false, false) - if err != nil { - return 0, errors.Wrap(err, `failed to acquite target io.Writer`) - } - - return out.Write(p) -} - -// must be locked during this operation -func (rl *RotateLogs) getWriter_nolock(bailOnRotateFail, useGenerationalNames bool) (io.Writer, error) { - generation := rl.generation - previousFn := rl.curFn - // This filename contains the name of the "NEW" filename - // to log to, which may be newer than rl.currentFilename - baseFn := rl.genFilename() - filename := baseFn - var forceNewFile bool - if baseFn != rl.curBaseFn { - generation = 0 - // even though this is the first write after calling New(), - // check if a new file needs to be created - if rl.forceNewFile { - forceNewFile = true - } - } else { - if !useGenerationalNames { - // nothing to do - return rl.outFh, nil - } - forceNewFile = true - generation++ - } - if forceNewFile { - // A new file has been requested. Instead of just using the - // regular strftime pattern, we create a new file name using - // generational names such as "foo.1", "foo.2", "foo.3", etc - var name string - for { - if generation == 0 { - name = filename - } else { - name = fmt.Sprintf("%s.%d", filename, generation) - } - if _, err := os.Stat(name); err != nil { - filename = name - break - } - generation++ - } - } - // make sure the dir is existed, eg: - // ./foo/bar/baz/hello.log must make sure ./foo/bar/baz is existed - dirname := filepath.Dir(filename) - if err := os.MkdirAll(dirname, 0755); err != nil { - return nil, errors.Wrapf(err, "failed to create directory %s", dirname) - } - // if we got here, then we need to create a file - fh, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) - if err != nil { - return nil, errors.Errorf("failed to open file %s: %s", rl.pattern, err) - } - - if err := rl.rotate_nolock(filename); err != nil { - err = errors.Wrap(err, "failed to rotate") - if bailOnRotateFail { - // Failure to rotate is a problem, but it's really not a great - // idea to stop your application just because you couldn't rename - // your log. - // - // We only return this error when explicitly needed (as specified by bailOnRotateFail) - // - // However, we *NEED* to close `fh` here - if fh != nil { // probably can't happen, but being paranoid - fh.Close() - } - return nil, err - } - fmt.Fprintf(os.Stderr, "%s\n", err.Error()) - } - - rl.outFh.Close() - rl.outFh = fh - rl.curBaseFn = baseFn - rl.curFn = filename - rl.generation = generation - - if h := rl.eventHandler; h != nil { - go h.Handle(&FileRotatedEvent{ - prev: previousFn, - current: filename, - }) - } - return fh, nil -} - -// CurrentFileName returns the current file name that -// the RotateLogs object is writing to -func (rl *RotateLogs) CurrentFileName() string { - rl.mutex.RLock() - defer rl.mutex.RUnlock() - return rl.curFn -} - -var patternConversionRegexps = []*regexp.Regexp{ - regexp.MustCompile(`%[%+A-Za-z]`), - regexp.MustCompile(`\*+`), -} - -type cleanupGuard struct { - enable bool - fn func() - mutex sync.Mutex -} - -func (g *cleanupGuard) Enable() { - g.mutex.Lock() - defer g.mutex.Unlock() - g.enable = true -} -func (g *cleanupGuard) Run() { - g.fn() -} - -// Rotate forcefully rotates the log files. If the generated file name -// clash because file already exists, a numeric suffix of the form -// ".1", ".2", ".3" and so forth are appended to the end of the log file -// -// Thie method can be used in conjunction with a signal handler so to -// emulate servers that generate new log files when they receive a -// SIGHUP -func (rl *RotateLogs) Rotate() error { - rl.mutex.Lock() - defer rl.mutex.Unlock() - if _, err := rl.getWriter_nolock(true, true); err != nil { - return err - } - return nil -} - -func (rl *RotateLogs) rotate_nolock(filename string) error { - lockfn := filename + `_lock` - fh, err := os.OpenFile(lockfn, os.O_CREATE|os.O_EXCL, 0644) - if err != nil { - // Can't lock, just return - return err - } - - var guard cleanupGuard - guard.fn = func() { - fh.Close() - os.Remove(lockfn) - } - defer guard.Run() - - if rl.linkName != "" { - tmpLinkName := filename + `_symlink` - if err := os.Symlink(filename, tmpLinkName); err != nil { - return errors.Wrap(err, `failed to create new symlink`) - } - - if err := os.Rename(tmpLinkName, rl.linkName); err != nil { - return errors.Wrap(err, `failed to rename new symlink`) - } - } - - if rl.maxAge <= 0 && rl.rotationCount <= 0 { - return errors.New("panic: maxAge and rotationCount are both set") - } - - matches, err := filepath.Glob(rl.globPattern) - if err != nil { - return err - } - - cutoff := rl.clock.Now().Add(-1 * rl.maxAge) - var toUnlink []string - for _, path := range matches { - // Ignore lock files - if strings.HasSuffix(path, "_lock") || strings.HasSuffix(path, "_symlink") { - continue - } - - fi, err := os.Stat(path) - if err != nil { - continue - } - - fl, err := os.Lstat(path) - if err != nil { - continue - } - - if rl.maxAge > 0 && fi.ModTime().After(cutoff) { - continue - } - - if rl.rotationCount > 0 && fl.Mode()&os.ModeSymlink == os.ModeSymlink { - continue - } - toUnlink = append(toUnlink, path) - } - - if rl.rotationCount > 0 { - // Only delete if we have more than rotationCount - if rl.rotationCount >= uint(len(toUnlink)) { - return nil - } - - toUnlink = toUnlink[:len(toUnlink)-int(rl.rotationCount)] - } - - if len(toUnlink) <= 0 { - return nil - } - - guard.Enable() - go func() { - // unlink files on a separate goroutine - for _, path := range toUnlink { - os.Remove(path) - } - }() - - return nil -} - -// Close satisfies the io.Closer interface. You must -// call this method if you performed any writes to -// the object. -func (rl *RotateLogs) Close() error { - rl.mutex.Lock() - defer rl.mutex.Unlock() - - if rl.outFh == nil { - return nil - } - - rl.outFh.Close() - rl.outFh = nil - return nil -} diff --git a/vendor/github.com/lestrrat-go/file-rotatelogs/rotatelogs_test.go b/vendor/github.com/lestrrat-go/file-rotatelogs/rotatelogs_test.go deleted file mode 100644 index 181b2268..00000000 --- a/vendor/github.com/lestrrat-go/file-rotatelogs/rotatelogs_test.go +++ /dev/null @@ -1,531 +0,0 @@ -package rotatelogs_test - -import ( - "fmt" - "io" - "io/ioutil" - "log" - "os" - "path/filepath" - "strings" - "testing" - "time" - - "github.com/jonboulle/clockwork" - rotatelogs "github.com/lestrrat-go/file-rotatelogs" - "github.com/pkg/errors" - "github.com/stretchr/testify/assert" -) - -func TestSatisfiesIOWriter(t *testing.T) { - var w io.Writer - w, _ = rotatelogs.New("/foo/bar") - _ = w -} - -func TestSatisfiesIOCloser(t *testing.T) { - var c io.Closer - c, _ = rotatelogs.New("/foo/bar") - _ = c -} - -func TestLogRotate(t *testing.T) { - dir, err := ioutil.TempDir("", "file-rotatelogs-test") - if !assert.NoError(t, err, "creating temporary directory should succeed") { - return - } - defer os.RemoveAll(dir) - - // Change current time, so we can safely purge old logs - dummyTime := time.Now().Add(-7 * 24 * time.Hour) - dummyTime = dummyTime.Add(time.Duration(-1 * dummyTime.Nanosecond())) - clock := clockwork.NewFakeClockAt(dummyTime) - linkName := filepath.Join(dir, "log") - rl, err := rotatelogs.New( - filepath.Join(dir, "log%Y%m%d%H%M%S"), - rotatelogs.WithClock(clock), - rotatelogs.WithMaxAge(24*time.Hour), - rotatelogs.WithLinkName(linkName), - ) - if !assert.NoError(t, err, `rotatelogs.New should succeed`) { - return - } - defer rl.Close() - - str := "Hello, World" - n, err := rl.Write([]byte(str)) - if !assert.NoError(t, err, "rl.Write should succeed") { - return - } - - if !assert.Len(t, str, n, "rl.Write should succeed") { - return - } - - fn := rl.CurrentFileName() - if fn == "" { - t.Errorf("Could not get filename %s", fn) - } - - content, err := ioutil.ReadFile(fn) - if err != nil { - t.Errorf("Failed to read file %s: %s", fn, err) - } - - if string(content) != str { - t.Errorf(`File content does not match (was "%s")`, content) - } - - err = os.Chtimes(fn, dummyTime, dummyTime) - if err != nil { - t.Errorf("Failed to change access/modification times for %s: %s", fn, err) - } - - fi, err := os.Stat(fn) - if err != nil { - t.Errorf("Failed to stat %s: %s", fn, err) - } - - if !fi.ModTime().Equal(dummyTime) { - t.Errorf("Failed to chtime for %s (expected %s, got %s)", fn, fi.ModTime(), dummyTime) - } - - clock.Advance(time.Duration(7 * 24 * time.Hour)) - - // This next Write() should trigger Rotate() - rl.Write([]byte(str)) - newfn := rl.CurrentFileName() - if newfn == fn { - t.Errorf(`New file name and old file name should not match ("%s" != "%s")`, fn, newfn) - } - - content, err = ioutil.ReadFile(newfn) - if err != nil { - t.Errorf("Failed to read file %s: %s", newfn, err) - } - - if string(content) != str { - t.Errorf(`File content does not match (was "%s")`, content) - } - - time.Sleep(time.Second) - - // fn was declared above, before mocking CurrentTime - // Old files should have been unlinked - _, err = os.Stat(fn) - if !assert.Error(t, err, "os.Stat should have failed") { - return - } - - linkDest, err := os.Readlink(linkName) - if err != nil { - t.Errorf("Failed to readlink %s: %s", linkName, err) - } - - if linkDest != newfn { - t.Errorf(`Symlink destination does not match expected filename ("%s" != "%s")`, newfn, linkDest) - } -} - -func CreateRotationTestFile(dir string, base time.Time, d time.Duration, n int) { - timestamp := base - for i := 0; i < n; i++ { - // %Y%m%d%H%M%S - suffix := timestamp.Format("20060102150405") - path := filepath.Join(dir, "log"+suffix) - ioutil.WriteFile(path, []byte("rotation test file\n"), os.ModePerm) - os.Chtimes(path, timestamp, timestamp) - timestamp = timestamp.Add(d) - } -} - -func TestLogRotationCount(t *testing.T) { - dir, err := ioutil.TempDir("", "file-rotatelogs-rotationcount-test") - if !assert.NoError(t, err, "creating temporary directory should succeed") { - return - } - defer os.RemoveAll(dir) - - dummyTime := time.Now().Add(-7 * 24 * time.Hour) - dummyTime = dummyTime.Add(time.Duration(-1 * dummyTime.Nanosecond())) - clock := clockwork.NewFakeClockAt(dummyTime) - - t.Run("Either maxAge or rotationCount should be set", func(t *testing.T) { - rl, err := rotatelogs.New( - filepath.Join(dir, "log%Y%m%d%H%M%S"), - rotatelogs.WithClock(clock), - rotatelogs.WithMaxAge(time.Duration(0)), - rotatelogs.WithRotationCount(0), - ) - if !assert.NoError(t, err, `Both of maxAge and rotationCount is disabled`) { - return - } - defer rl.Close() - }) - - t.Run("Either maxAge or rotationCount should be set", func(t *testing.T) { - rl, err := rotatelogs.New( - filepath.Join(dir, "log%Y%m%d%H%M%S"), - rotatelogs.WithClock(clock), - rotatelogs.WithMaxAge(1), - rotatelogs.WithRotationCount(1), - ) - if !assert.Error(t, err, `Both of maxAge and rotationCount is enabled`) { - return - } - if rl != nil { - defer rl.Close() - } - }) - - t.Run("Only latest log file is kept", func(t *testing.T) { - rl, err := rotatelogs.New( - filepath.Join(dir, "log%Y%m%d%H%M%S"), - rotatelogs.WithClock(clock), - rotatelogs.WithMaxAge(-1), - rotatelogs.WithRotationCount(1), - ) - if !assert.NoError(t, err, `rotatelogs.New should succeed`) { - return - } - defer rl.Close() - - n, err := rl.Write([]byte("dummy")) - if !assert.NoError(t, err, "rl.Write should succeed") { - return - } - if !assert.Len(t, "dummy", n, "rl.Write should succeed") { - return - } - time.Sleep(time.Second) - files, err := filepath.Glob(filepath.Join(dir, "log*")) - if !assert.Equal(t, 1, len(files), "Only latest log is kept") { - return - } - }) - - t.Run("Old log files are purged except 2 log files", func(t *testing.T) { - CreateRotationTestFile(dir, dummyTime, time.Duration(time.Hour), 5) - rl, err := rotatelogs.New( - filepath.Join(dir, "log%Y%m%d%H%M%S"), - rotatelogs.WithClock(clock), - rotatelogs.WithMaxAge(-1), - rotatelogs.WithRotationCount(2), - ) - if !assert.NoError(t, err, `rotatelogs.New should succeed`) { - return - } - defer rl.Close() - - n, err := rl.Write([]byte("dummy")) - if !assert.NoError(t, err, "rl.Write should succeed") { - return - } - if !assert.Len(t, "dummy", n, "rl.Write should succeed") { - return - } - time.Sleep(time.Second) - files, err := filepath.Glob(filepath.Join(dir, "log*")) - if !assert.Equal(t, 2, len(files), "One file is kept") { - return - } - }) - -} - -func TestLogSetOutput(t *testing.T) { - dir, err := ioutil.TempDir("", "file-rotatelogs-test") - if err != nil { - t.Errorf("Failed to create temporary directory: %s", err) - } - defer os.RemoveAll(dir) - - rl, err := rotatelogs.New(filepath.Join(dir, "log%Y%m%d%H%M%S")) - if !assert.NoError(t, err, `rotatelogs.New should succeed`) { - return - } - defer rl.Close() - - log.SetOutput(rl) - defer log.SetOutput(os.Stderr) - - str := "Hello, World" - log.Print(str) - - fn := rl.CurrentFileName() - if fn == "" { - t.Errorf("Could not get filename %s", fn) - } - - content, err := ioutil.ReadFile(fn) - if err != nil { - t.Errorf("Failed to read file %s: %s", fn, err) - } - - if !strings.Contains(string(content), str) { - t.Errorf(`File content does not contain "%s" (was "%s")`, str, content) - } -} - -func TestGHIssue16(t *testing.T) { - defer func() { - if v := recover(); v != nil { - assert.NoError(t, errors.Errorf("%s", v), "error should be nil") - } - }() - - dir, err := ioutil.TempDir("", "file-rotatelogs-gh16") - if !assert.NoError(t, err, `creating temporary directory should succeed`) { - return - } - defer os.RemoveAll(dir) - - rl, err := rotatelogs.New( - filepath.Join(dir, "log%Y%m%d%H%M%S"), - rotatelogs.WithLinkName("./test.log"), - rotatelogs.WithRotationTime(10*time.Second), - rotatelogs.WithRotationCount(3), - rotatelogs.WithMaxAge(-1), - ) - if !assert.NoError(t, err, `rotatelogs.New should succeed`) { - return - } - - if !assert.NoError(t, rl.Rotate(), "rl.Rotate should succeed") { - return - } - defer rl.Close() -} - -func TestRotationGenerationalNames(t *testing.T) { - dir, err := ioutil.TempDir("", "file-rotatelogs-generational") - if !assert.NoError(t, err, `creating temporary directory should succeed`) { - return - } - defer os.RemoveAll(dir) - - t.Run("Rotate over unchanged pattern", func(t *testing.T) { - rl, err := rotatelogs.New( - filepath.Join(dir, "unchanged-pattern.log"), - ) - if !assert.NoError(t, err, `rotatelogs.New should succeed`) { - return - } - - seen := map[string]struct{}{} - for i := 0; i < 10; i++ { - rl.Write([]byte("Hello, World!")) - if !assert.NoError(t, rl.Rotate(), "rl.Rotate should succeed") { - return - } - - // Because every call to Rotate should yield a new log file, - // and the previous files already exist, the filenames should share - // the same prefix and have a unique suffix - fn := filepath.Base(rl.CurrentFileName()) - if !assert.True(t, strings.HasPrefix(fn, "unchanged-pattern.log"), "prefix for all filenames should match") { - return - } - rl.Write([]byte("Hello, World!")) - suffix := strings.TrimPrefix(fn, "unchanged-pattern.log") - expectedSuffix := fmt.Sprintf(".%d", i+1) - if !assert.True(t, suffix == expectedSuffix, "expected suffix %s found %s", expectedSuffix, suffix) { - return - } - assert.FileExists(t, rl.CurrentFileName(), "file does not exist %s", rl.CurrentFileName()) - stat, err := os.Stat(rl.CurrentFileName()) - if err == nil { - if !assert.True(t, stat.Size() == 13, "file %s size is %d, expected 13", rl.CurrentFileName(), stat.Size()) { - return - } - } else { - assert.Failf(t, "could not stat file %s", rl.CurrentFileName()) - return - } - - if _, ok := seen[suffix]; !assert.False(t, ok, `filename suffix %s should be unique`, suffix) { - return - } - seen[suffix] = struct{}{} - } - defer rl.Close() - }) - t.Run("Rotate over pattern change over every second", func(t *testing.T) { - rl, err := rotatelogs.New( - filepath.Join(dir, "every-second-pattern-%Y%m%d%H%M%S.log"), - rotatelogs.WithRotationTime(time.Nanosecond), - ) - if !assert.NoError(t, err, `rotatelogs.New should succeed`) { - return - } - - for i := 0; i < 10; i++ { - time.Sleep(time.Second) - rl.Write([]byte("Hello, World!")) - if !assert.NoError(t, rl.Rotate(), "rl.Rotate should succeed") { - return - } - - // because every new Write should yield a new logfile, - // every rorate should be create a filename ending with a .1 - if !assert.True(t, strings.HasSuffix(rl.CurrentFileName(), ".1"), "log name should end with .1") { - return - } - } - defer rl.Close() - }) -} - -type ClockFunc func() time.Time - -func (f ClockFunc) Now() time.Time { - return f() -} - -func TestGHIssue23(t *testing.T) { - dir, err := ioutil.TempDir("", "file-rotatelogs-generational") - if !assert.NoError(t, err, `creating temporary directory should succeed`) { - return - } - defer os.RemoveAll(dir) - - for _, locName := range []string{"Asia/Tokyo", "Pacific/Honolulu"} { - loc, _ := time.LoadLocation(locName) - tests := []struct { - Expected string - Clock rotatelogs.Clock - }{ - { - Expected: filepath.Join(dir, strings.ToLower(strings.Replace(locName, "/", "_", -1)) + ".201806010000.log"), - Clock: ClockFunc(func() time.Time { - return time.Date(2018, 6, 1, 3, 18, 0, 0, loc) - }), - }, - { - Expected: filepath.Join(dir, strings.ToLower(strings.Replace(locName, "/", "_", -1)) + ".201712310000.log"), - Clock: ClockFunc(func() time.Time { - return time.Date(2017, 12, 31, 23, 52, 0, 0, loc) - }), - }, - } - for _, test := range tests { - t.Run(fmt.Sprintf("location = %s, time = %s", locName, test.Clock.Now().Format(time.RFC3339)), func(t *testing.T) { - template := strings.ToLower(strings.Replace(locName, "/", "_", -1)) + ".%Y%m%d%H%M.log" - rl, err := rotatelogs.New( - filepath.Join(dir, template), - rotatelogs.WithClock(test.Clock), // we're not using WithLocation, but it's the same thing - ) - if !assert.NoError(t, err, "rotatelogs.New should succeed") { - return - } - - t.Logf("expected %s", test.Expected) - rl.Rotate() - if !assert.Equal(t, test.Expected, rl.CurrentFileName(), "file names should match") { - return - } - }) - } - } -} - -func TestForceNewFile(t *testing.T) { - dir, err := ioutil.TempDir("", "file-rotatelogs-force-new-file") - if !assert.NoError(t, err, `creating temporary directory should succeed`) { - return - } - defer os.RemoveAll(dir) - - t.Run("Force a new file", func(t *testing.T) { - - rl, err := rotatelogs.New( - filepath.Join(dir, "force-new-file.log"), - rotatelogs.ForceNewFile(), - ) - if !assert.NoError(t, err, "rotatelogs.New should succeed") { - return - } - rl.Write([]byte("Hello, World!")) - rl.Close() - - for i := 0; i < 10; i++ { - baseFn := filepath.Join(dir, "force-new-file.log") - rl, err := rotatelogs.New( - baseFn, - rotatelogs.ForceNewFile(), - ) - if !assert.NoError(t, err, "rotatelogs.New should succeed") { - return - } - rl.Write([]byte("Hello, World")) - rl.Write([]byte(fmt.Sprintf("%d", i))) - rl.Close() - - fn := filepath.Base(rl.CurrentFileName()) - suffix := strings.TrimPrefix(fn, "force-new-file.log") - expectedSuffix := fmt.Sprintf(".%d", i+1) - if !assert.True(t, suffix == expectedSuffix, "expected suffix %s found %s", expectedSuffix, suffix) { - return - } - assert.FileExists(t, rl.CurrentFileName(), "file does not exist %s", rl.CurrentFileName()) - content, err := ioutil.ReadFile(rl.CurrentFileName()) - if !assert.NoError(t, err, "ioutil.ReadFile %s should succeed", rl.CurrentFileName()) { - return - } - str := fmt.Sprintf("Hello, World%d", i) - if !assert.Equal(t, str, string(content), "read %s from file %s, not expected %s", string(content), rl.CurrentFileName(), str) { - return - } - - assert.FileExists(t, baseFn, "file does not exist %s", baseFn) - content, err = ioutil.ReadFile(baseFn) - if !assert.NoError(t, err, "ioutil.ReadFile should succeed") { - return - } - if !assert.Equal(t, "Hello, World!", string(content), "read %s from file %s, not expected Hello, World!", string(content), baseFn) { - return - } - } - - }) - - t.Run("Force a new file with Rotate", func(t *testing.T) { - - baseFn := filepath.Join(dir, "force-new-file-rotate.log") - rl, err := rotatelogs.New( - baseFn, - rotatelogs.ForceNewFile(), - ) - if !assert.NoError(t, err, "rotatelogs.New should succeed") { - return - } - rl.Write([]byte("Hello, World!")) - - for i := 0; i < 10; i++ { - if !assert.NoError(t, rl.Rotate(), "rl.Rotate should succeed") { - return - } - rl.Write([]byte("Hello, World")) - rl.Write([]byte(fmt.Sprintf("%d", i))) - assert.FileExists(t, rl.CurrentFileName(), "file does not exist %s", rl.CurrentFileName()) - content, err := ioutil.ReadFile(rl.CurrentFileName()) - if !assert.NoError(t, err, "ioutil.ReadFile %s should succeed", rl.CurrentFileName()) { - return - } - str := fmt.Sprintf("Hello, World%d", i) - if !assert.Equal(t, str, string(content), "read %s from file %s, not expected %s", string(content), rl.CurrentFileName(), str) { - return - } - - assert.FileExists(t, baseFn, "file does not exist %s", baseFn) - content, err = ioutil.ReadFile(baseFn) - if !assert.NoError(t, err, "ioutil.ReadFile should succeed") { - return - } - if !assert.Equal(t, "Hello, World!", string(content), "read %s from file %s, not expected Hello, World!", string(content), baseFn) { - return - } - } - }) -} - diff --git a/vendor/github.com/lestrrat-go/strftime/.gitignore b/vendor/github.com/lestrrat-go/strftime/.gitignore deleted file mode 100644 index daf913b1..00000000 --- a/vendor/github.com/lestrrat-go/strftime/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof diff --git a/vendor/github.com/lestrrat-go/strftime/.travis.yml b/vendor/github.com/lestrrat-go/strftime/.travis.yml deleted file mode 100644 index 1c1b0322..00000000 --- a/vendor/github.com/lestrrat-go/strftime/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: go -sudo: false -go: - - 1.7.x - - tip \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/strftime/LICENSE b/vendor/github.com/lestrrat-go/strftime/LICENSE deleted file mode 100644 index eed69381..00000000 --- a/vendor/github.com/lestrrat-go/strftime/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2016 lestrrat - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/lestrrat-go/strftime/README.md b/vendor/github.com/lestrrat-go/strftime/README.md deleted file mode 100644 index e7ca61f0..00000000 --- a/vendor/github.com/lestrrat-go/strftime/README.md +++ /dev/null @@ -1,151 +0,0 @@ -# strftime - -Fast strftime for Go - -[![Build Status](https://travis-ci.org/lestrrat-go/strftime.png?branch=master)](https://travis-ci.org/lestrrat-go/strftime) - -[![GoDoc](https://godoc.org/github.com/lestrrat-go/strftime?status.svg)](https://godoc.org/github.com/lestrrat-go/strftime) - -# SYNOPSIS - -```go -f := strftime.New(`.... pattern ...`) -if err := f.Format(buf, time.Now()); err != nil { - log.Println(err.Error()) -} -``` - -# DESCRIPTION - -The goals for this library are - -* Optimized for the same pattern being called repeatedly -* Be flexible about destination to write the results out -* Be as complete as possible in terms of conversion specifications - -# API - -## Format(string, time.Time) (string, error) - -Takes the pattern and the time, and formats it. This function is a utility function that recompiles the pattern every time the function is called. If you know beforehand that you will be formatting the same pattern multiple times, consider using `New` to create a `Strftime` object and reuse it. - -## New(string) (\*Strftime, error) - -Takes the pattern and creates a new `Strftime` object. - -## obj.Pattern() string - -Returns the pattern string used to create this `Strftime` object - -## obj.Format(io.Writer, time.Time) error - -Formats the time according to the pre-compiled pattern, and writes the result to the specified `io.Writer` - -## obj.FormatString(time.Time) string - -Formats the time according to the pre-compiled pattern, and returns the result string. - -# SUPPORTED CONVERSION SPECIFICATIONS - -| pattern | description | -|:--------|:------------| -| %A | national representation of the full weekday name | -| %a | national representation of the abbreviated weekday | -| %B | national representation of the full month name | -| %b | national representation of the abbreviated month name | -| %C | (year / 100) as decimal number; single digits are preceded by a zero | -| %c | national representation of time and date | -| %D | equivalent to %m/%d/%y | -| %d | day of the month as a decimal number (01-31) | -| %e | the day of the month as a decimal number (1-31); single digits are preceded by a blank | -| %F | equivalent to %Y-%m-%d | -| %H | the hour (24-hour clock) as a decimal number (00-23) | -| %h | same as %b | -| %I | the hour (12-hour clock) as a decimal number (01-12) | -| %j | the day of the year as a decimal number (001-366) | -| %k | the hour (24-hour clock) as a decimal number (0-23); single digits are preceded by a blank | -| %l | the hour (12-hour clock) as a decimal number (1-12); single digits are preceded by a blank | -| %M | the minute as a decimal number (00-59) | -| %m | the month as a decimal number (01-12) | -| %n | a newline | -| %p | national representation of either "ante meridiem" (a.m.) or "post meridiem" (p.m.) as appropriate. | -| %R | equivalent to %H:%M | -| %r | equivalent to %I:%M:%S %p | -| %S | the second as a decimal number (00-60) | -| %T | equivalent to %H:%M:%S | -| %t | a tab | -| %U | the week number of the year (Sunday as the first day of the week) as a decimal number (00-53) | -| %u | the weekday (Monday as the first day of the week) as a decimal number (1-7) | -| %V | the week number of the year (Monday as the first day of the week) as a decimal number (01-53) | -| %v | equivalent to %e-%b-%Y | -| %W | the week number of the year (Monday as the first day of the week) as a decimal number (00-53) | -| %w | the weekday (Sunday as the first day of the week) as a decimal number (0-6) | -| %X | national representation of the time | -| %x | national representation of the date | -| %Y | the year with century as a decimal number | -| %y | the year without century as a decimal number (00-99) | -| %Z | the time zone name | -| %z | the time zone offset from UTC | -| %% | a '%' | - -# PERFORMANCE / OTHER LIBRARIES - -The following benchmarks were run separately because some libraries were using cgo on specific platforms (notabley, the fastly version) - -``` -// On my OS X 10.11.6, 2.9 GHz Intel Core i5, 16GB memory. -// go version go1.8rc1 darwin/amd64 -hummingbird% go test -tags bench -benchmem -bench . - -BenchmarkTebeka-4 300000 4469 ns/op 288 B/op 21 allocs/op -BenchmarkJehiah-4 1000000 1931 ns/op 256 B/op 17 allocs/op -BenchmarkFastly-4 2000000 724 ns/op 80 B/op 5 allocs/op -BenchmarkLestrrat-4 1000000 1572 ns/op 240 B/op 3 allocs/op -BenchmarkLestrratCachedString-4 3000000 548 ns/op 128 B/op 2 allocs/op -BenchmarkLestrratCachedWriter-4 500000 2519 ns/op 192 B/op 3 allocs/op -PASS -ok github.com/lestrrat-go/strftime 22.900s -``` - -``` -// On a host on Google Cloud Platform, machine-type: n1-standard-4 (vCPU x 4, memory: 15GB) -// Linux 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u2 (2016-10-19) x86_64 GNU/Linux -// go version go1.8rc1 linux/amd64 -hummingbird% go test -tags bench -benchmem -bench . - -BenchmarkTebeka-4 500000 3904 ns/op 288 B/op 21 allocs/op -BenchmarkJehiah-4 1000000 1665 ns/op 256 B/op 17 allocs/op -BenchmarkFastly-4 1000000 2134 ns/op 192 B/op 13 allocs/op -BenchmarkLestrrat-4 1000000 1327 ns/op 240 B/op 3 allocs/op -BenchmarkLestrratCachedString-4 3000000 498 ns/op 128 B/op 2 allocs/op -BenchmarkLestrratCachedWriter-4 1000000 3390 ns/op 192 B/op 3 allocs/op -PASS -ok github.com/lestrrat-go/strftime 44.854s -``` - -This library is much faster than other libraries *IF* you can reuse the format pattern. - -Here's the annotated list from the benchmark results. You can clearly see that (re)using a `Strftime` object -and producing a string is the fastest. Writing to an `io.Writer` seems a bit sluggish, but since -the one producing the string is doing almost exactly the same thing, we believe this is purely the overhead of -writing to an `io.Writer` - -| Import Path | Score | Note | -|:------------------------------------|--------:|:--------------------------------| -| github.com/lestrrat-go/strftime | 3000000 | Using `FormatString()` (cached) | -| github.com/fastly/go-utils/strftime | 2000000 | Pure go version on OS X | -| github.com/lestrrat-go/strftime | 1000000 | Using `Format()` (NOT cached) | -| github.com/jehiah/go-strftime | 1000000 | | -| github.com/fastly/go-utils/strftime | 1000000 | cgo version on Linux | -| github.com/lestrrat-go/strftime | 500000 | Using `Format()` (cached) | -| github.com/tebeka/strftime | 300000 | | - -However, depending on your pattern, this speed may vary. If you find a particular pattern that seems sluggish, -please send in patches or tests. - -Please also note that this benchmark only uses the subset of conversion specifications that are supported by *ALL* of the libraries compared. - -Somethings to consider when making performance comparisons in the future: - -* Can it write to io.Writer? -* Which `%specification` does it handle? diff --git a/vendor/github.com/lestrrat-go/strftime/internal_test.go b/vendor/github.com/lestrrat-go/strftime/internal_test.go deleted file mode 100644 index eaee1d52..00000000 --- a/vendor/github.com/lestrrat-go/strftime/internal_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package strftime - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestCombine(t *testing.T) { - { - s, _ := New(`%A foo`) - if !assert.Equal(t, 1, len(s.compiled), "there are 1 element") { - return - } - } - { - s, _ := New(`%A 100`) - if !assert.Equal(t, 2, len(s.compiled), "there are two elements") { - return - } - } - { - s, _ := New(`%A Mon`) - if !assert.Equal(t, 2, len(s.compiled), "there are two elements") { - return - } - } -} diff --git a/vendor/github.com/lestrrat-go/strftime/strftime.go b/vendor/github.com/lestrrat-go/strftime/strftime.go deleted file mode 100644 index bc34eb49..00000000 --- a/vendor/github.com/lestrrat-go/strftime/strftime.go +++ /dev/null @@ -1,219 +0,0 @@ -package strftime - -import ( - "io" - "strings" - "time" - - "github.com/pkg/errors" -) - -var directives = map[byte]appender{ - 'A': timefmt("Monday"), - 'a': timefmt("Mon"), - 'B': timefmt("January"), - 'b': timefmt("Jan"), - 'C': ¢ury{}, - 'c': timefmt("Mon Jan _2 15:04:05 2006"), - 'D': timefmt("01/02/06"), - 'd': timefmt("02"), - 'e': timefmt("_2"), - 'F': timefmt("2006-01-02"), - 'H': timefmt("15"), - 'h': timefmt("Jan"), // same as 'b' - 'I': timefmt("3"), - 'j': &dayofyear{}, - 'k': hourwblank(false), - 'l': hourwblank(true), - 'M': timefmt("04"), - 'm': timefmt("01"), - 'n': verbatim("\n"), - 'p': timefmt("PM"), - 'R': timefmt("15:04"), - 'r': timefmt("3:04:05 PM"), - 'S': timefmt("05"), - 'T': timefmt("15:04:05"), - 't': verbatim("\t"), - 'U': weeknumberOffset(0), // week number of the year, Sunday first - 'u': weekday(1), - 'V': &weeknumber{}, - 'v': timefmt("_2-Jan-2006"), - 'W': weeknumberOffset(1), // week number of the year, Monday first - 'w': weekday(0), - 'X': timefmt("15:04:05"), // national representation of the time XXX is this correct? - 'x': timefmt("01/02/06"), // national representation of the date XXX is this correct? - 'Y': timefmt("2006"), // year with century - 'y': timefmt("06"), // year w/o century - 'Z': timefmt("MST"), // time zone name - 'z': timefmt("-0700"), // time zone ofset from UTC - '%': verbatim("%"), -} - -type combiningAppend struct { - list appenderList - prev appender - prevCanCombine bool -} - -func (ca *combiningAppend) Append(w appender) { - if ca.prevCanCombine { - if wc, ok := w.(combiner); ok && wc.canCombine() { - ca.prev = ca.prev.(combiner).combine(wc) - ca.list[len(ca.list)-1] = ca.prev - return - } - } - - ca.list = append(ca.list, w) - ca.prev = w - ca.prevCanCombine = false - if comb, ok := w.(combiner); ok { - if comb.canCombine() { - ca.prevCanCombine = true - } - } -} - -func compile(wl *appenderList, p string) error { - var ca combiningAppend - for l := len(p); l > 0; l = len(p) { - i := strings.IndexByte(p, '%') - if i < 0 { - ca.Append(verbatim(p)) - // this is silly, but I don't trust break keywords when there's a - // possibility of this piece of code being rearranged - p = p[l:] - continue - } - if i == l-1 { - return errors.New(`stray % at the end of pattern`) - } - - // we found a '%'. we need the next byte to decide what to do next - // we already know that i < l - 1 - // everything up to the i is verbatim - if i > 0 { - ca.Append(verbatim(p[:i])) - p = p[i:] - } - - directive, ok := directives[p[1]] - if !ok { - return errors.Errorf(`unknown time format specification '%c'`, p[1]) - } - ca.Append(directive) - p = p[2:] - } - - *wl = ca.list - - return nil -} - -// Format takes the format `s` and the time `t` to produce the -// format date/time. Note that this function re-compiles the -// pattern every time it is called. -// -// If you know beforehand that you will be reusing the pattern -// within your application, consider creating a `Strftime` object -// and reusing it. -func Format(p string, t time.Time) (string, error) { - var dst []byte - // TODO: optimize for 64 byte strings - dst = make([]byte, 0, len(p)+10) - // Compile, but execute as we go - for l := len(p); l > 0; l = len(p) { - i := strings.IndexByte(p, '%') - if i < 0 { - dst = append(dst, p...) - // this is silly, but I don't trust break keywords when there's a - // possibility of this piece of code being rearranged - p = p[l:] - continue - } - if i == l-1 { - return "", errors.New(`stray % at the end of pattern`) - } - - // we found a '%'. we need the next byte to decide what to do next - // we already know that i < l - 1 - // everything up to the i is verbatim - if i > 0 { - dst = append(dst, p[:i]...) - p = p[i:] - } - - directive, ok := directives[p[1]] - if !ok { - return "", errors.Errorf(`unknown time format specification '%c'`, p[1]) - } - dst = directive.Append(dst, t) - p = p[2:] - } - - return string(dst), nil -} - -// Strftime is the object that represents a compiled strftime pattern -type Strftime struct { - pattern string - compiled appenderList -} - -// New creates a new Strftime object. If the compilation fails, then -// an error is returned in the second argument. -func New(f string) (*Strftime, error) { - var wl appenderList - if err := compile(&wl, f); err != nil { - return nil, errors.Wrap(err, `failed to compile format`) - } - return &Strftime{ - pattern: f, - compiled: wl, - }, nil -} - -// Pattern returns the original pattern string -func (f *Strftime) Pattern() string { - return f.pattern -} - -// Format takes the destination `dst` and time `t`. It formats the date/time -// using the pre-compiled pattern, and outputs the results to `dst` -func (f *Strftime) Format(dst io.Writer, t time.Time) error { - const bufSize = 64 - var b []byte - max := len(f.pattern) + 10 - if max < bufSize { - var buf [bufSize]byte - b = buf[:0] - } else { - b = make([]byte, 0, max) - } - if _, err := dst.Write(f.format(b, t)); err != nil { - return err - } - return nil -} - -func (f *Strftime) format(b []byte, t time.Time) []byte { - for _, w := range f.compiled { - b = w.Append(b, t) - } - return b -} - -// FormatString takes the time `t` and formats it, returning the -// string containing the formated data. -func (f *Strftime) FormatString(t time.Time) string { - const bufSize = 64 - var b []byte - max := len(f.pattern) + 10 - if max < bufSize { - var buf [bufSize]byte - b = buf[:0] - } else { - b = make([]byte, 0, max) - } - return string(f.format(b, t)) -} diff --git a/vendor/github.com/lestrrat-go/strftime/strftime_bench_test.go b/vendor/github.com/lestrrat-go/strftime/strftime_bench_test.go deleted file mode 100644 index 643f370d..00000000 --- a/vendor/github.com/lestrrat-go/strftime/strftime_bench_test.go +++ /dev/null @@ -1,80 +0,0 @@ -// +build bench - -package strftime_test - -import ( - "bytes" - "log" - "net/http" - _ "net/http/pprof" - "testing" - "time" - - jehiah "github.com/jehiah/go-strftime" - fastly "github.com/fastly/go-utils/strftime" - lestrrat "github.com/lestrrat-go/strftime" - tebeka "github.com/tebeka/strftime" -) - -func init() { - go func() { - log.Println(http.ListenAndServe("localhost:8080", nil)) - }() -} - -const benchfmt = `%A %a %B %b %d %H %I %M %m %p %S %Y %y %Z` - -func BenchmarkTebeka(b *testing.B) { - var t time.Time - for i := 0; i < b.N; i++ { - tebeka.Format(benchfmt, t) - } -} - -func BenchmarkJehiah(b *testing.B) { - // Grr, uses byte slices, and does it faster, but with more allocs - var t time.Time - for i := 0; i < b.N; i++ { - jehiah.Format(benchfmt, t) - } -} - -func BenchmarkFastly(b *testing.B) { - var t time.Time - for i := 0; i < b.N; i++ { - fastly.Strftime(benchfmt, t) - } -} - -func BenchmarkLestrrat(b *testing.B) { - var t time.Time - for i := 0; i < b.N; i++ { - lestrrat.Format(benchfmt, t) - } -} - -func BenchmarkLestrratCachedString(b *testing.B) { - var t time.Time - f, _ := lestrrat.New(benchfmt) - // This benchmark does not take into effect the compilation time - for i := 0; i < b.N; i++ { - f.FormatString(t) - } -} - -func BenchmarkLestrratCachedWriter(b *testing.B) { - var t time.Time - f, _ := lestrrat.New(benchfmt) - var buf bytes.Buffer - b.ResetTimer() - - // This benchmark does not take into effect the compilation time - // nor the buffer reset time - for i := 0; i < b.N; i++ { - b.StopTimer() - buf.Reset() - b.StartTimer() - f.Format(&buf, t) - f.FormatString(t) - } -} diff --git a/vendor/github.com/lestrrat-go/strftime/strftime_test.go b/vendor/github.com/lestrrat-go/strftime/strftime_test.go deleted file mode 100644 index 41f25be0..00000000 --- a/vendor/github.com/lestrrat-go/strftime/strftime_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package strftime_test - -import ( - "os" - "testing" - "time" - - envload "github.com/lestrrat-go/envload" - "github.com/lestrrat-go/strftime" - "github.com/stretchr/testify/assert" -) - -var ref = time.Unix(1136239445, 0).UTC() - -func TestExclusion(t *testing.T) { - s, err := strftime.New("%p PM") - if !assert.NoError(t, err, `strftime.New should succeed`) { - return - } - - var tm time.Time - if !assert.Equal(t, "AM PM", s.FormatString(tm)) { - return - } -} - -func TestInvalid(t *testing.T) { - _, err := strftime.New("%") - if !assert.Error(t, err, `strftime.New should return error`) { - return - } - - _, err = strftime.New(" %") - if !assert.Error(t, err, `strftime.New should return error`) { - return - } - _, err = strftime.New(" % ") - if !assert.Error(t, err, `strftime.New should return error`) { - return - } -} - -func TestFormat(t *testing.T) { - l := envload.New() - defer l.Restore() - - os.Setenv("LC_ALL", "C") - - s, err := strftime.Format(`%A %a %B %b %C %c %D %d %e %F %H %h %I %j %k %l %M %m %n %p %R %r %S %T %t %U %u %V %v %W %w %X %x %Y %y %Z %z`, ref) - if !assert.NoError(t, err, `strftime.Format succeeds`) { - return - } - - if !assert.Equal(t, "Monday Mon January Jan 20 Mon Jan 2 22:04:05 2006 01/02/06 02 2 2006-01-02 22 Jan 10 002 22 10 04 01 \n PM 22:04 10:04:05 PM 05 22:04:05 \t 01 1 01 2-Jan-2006 01 1 22:04:05 01/02/06 2006 06 UTC +0000", s, `formatted result matches`) { - return - } -} - -func TestFormatBlanks(t *testing.T) { - l := envload.New() - defer l.Restore() - - os.Setenv("LC_ALL", "C") - - { - dt := time.Date(1, 1, 1, 18, 0, 0, 0, time.UTC) - s, err := strftime.Format("%l", dt) - if !assert.NoError(t, err, `strftime.Format succeeds`) { - return - } - - if !assert.Equal(t, " 6", s, "leading blank is properly set") { - return - } - } - { - dt := time.Date(1, 1, 1, 6, 0, 0, 0, time.UTC) - s, err := strftime.Format("%k", dt) - if !assert.NoError(t, err, `strftime.Format succeeds`) { - return - } - - if !assert.Equal(t, " 6", s, "leading blank is properly set") { - return - } - } -} - -func TestFormatZeropad(t *testing.T) { - l := envload.New() - defer l.Restore() - - os.Setenv("LC_ALL", "C") - - { - dt := time.Date(1, 1, 1, 1, 0, 0, 0, time.UTC) - s, err := strftime.Format("%j", dt) - if !assert.NoError(t, err, `strftime.Format succeeds`) { - return - } - - if !assert.Equal(t, "001", s, "padding is properly set") { - return - } - } - { - dt := time.Date(1, 1, 10, 6, 0, 0, 0, time.UTC) - s, err := strftime.Format("%j", dt) - if !assert.NoError(t, err, `strftime.Format succeeds`) { - return - } - - if !assert.Equal(t, "010", s, "padding is properly set") { - return - } - } - { - dt := time.Date(1, 6, 1, 6, 0, 0, 0, time.UTC) - s, err := strftime.Format("%j", dt) - if !assert.NoError(t, err, `strftime.Format succeeds`) { - return - } - - if !assert.Equal(t, "152", s, "padding is properly set") { - return - } - } - { - dt := time.Date(100, 1, 1, 1, 0, 0, 0, time.UTC) - s, err := strftime.Format("%C", dt) - if !assert.NoError(t, err, `strftime.Format succeeds`) { - return - } - - if !assert.Equal(t, "01", s, "padding is properly set") { - return - } - } -} - -func TestGHIssue5(t *testing.T) { - const expected = `apm-test/logs/apm.log.01000101` - p, _ := strftime.New("apm-test/logs/apm.log.%Y%m%d") - dt := time.Date(100, 1, 1, 1, 0, 0, 0, time.UTC) - if !assert.Equal(t, expected, p.FormatString(dt), `patterns including 'pm' should be treated as verbatim formatter`) { - return - } -} diff --git a/vendor/github.com/lestrrat-go/strftime/writer.go b/vendor/github.com/lestrrat-go/strftime/writer.go deleted file mode 100644 index b52b29ea..00000000 --- a/vendor/github.com/lestrrat-go/strftime/writer.go +++ /dev/null @@ -1,169 +0,0 @@ -package strftime - -import ( - "strconv" - "strings" - "time" -) - -type appender interface { - Append([]byte, time.Time) []byte -} - -type appenderList []appender - -// does the time.Format thing -type timefmtw struct { - s string -} - -func timefmt(s string) *timefmtw { - return &timefmtw{s: s} -} - -func (v timefmtw) Append(b []byte, t time.Time) []byte { - return t.AppendFormat(b, v.s) -} - -func (v timefmtw) str() string { - return v.s -} - -func (v timefmtw) canCombine() bool { - return true -} - -func (v timefmtw) combine(w combiner) appender { - return timefmt(v.s + w.str()) -} - -type verbatimw struct { - s string -} - -func verbatim(s string) *verbatimw { - return &verbatimw{s: s} -} - -func (v verbatimw) Append(b []byte, _ time.Time) []byte { - return append(b, v.s...) -} - -func (v verbatimw) canCombine() bool { - return canCombine(v.s) -} - -func (v verbatimw) combine(w combiner) appender { - if _, ok := w.(*timefmtw); ok { - return timefmt(v.s + w.str()) - } - return verbatim(v.s + w.str()) -} - -func (v verbatimw) str() string { - return v.s -} - -// These words below, as well as any decimal character -var combineExclusion = []string{ - "Mon", - "Monday", - "Jan", - "January", - "MST", - "PM", - "pm", -} - -func canCombine(s string) bool { - if strings.ContainsAny(s, "0123456789") { - return false - } - for _, word := range combineExclusion { - if strings.Contains(s, word) { - return false - } - } - return true -} - -type combiner interface { - canCombine() bool - combine(combiner) appender - str() string -} - -type century struct{} - -func (v century) Append(b []byte, t time.Time) []byte { - n := t.Year() / 100 - if n < 10 { - b = append(b, '0') - } - return append(b, strconv.Itoa(n)...) -} - -type weekday int - -func (v weekday) Append(b []byte, t time.Time) []byte { - n := int(t.Weekday()) - if n < int(v) { - n += 7 - } - return append(b, byte(n+48)) -} - -type weeknumberOffset int - -func (v weeknumberOffset) Append(b []byte, t time.Time) []byte { - yd := t.YearDay() - offset := int(t.Weekday()) - int(v) - if offset < 0 { - offset += 7 - } - - if yd < offset { - return append(b, '0', '0') - } - - n := ((yd - offset) / 7) + 1 - if n < 10 { - b = append(b, '0') - } - return append(b, strconv.Itoa(n)...) -} - -type weeknumber struct{} - -func (v weeknumber) Append(b []byte, t time.Time) []byte { - _, n := t.ISOWeek() - if n < 10 { - b = append(b, '0') - } - return append(b, strconv.Itoa(n)...) -} - -type dayofyear struct{} - -func (v dayofyear) Append(b []byte, t time.Time) []byte { - n := t.YearDay() - if n < 10 { - b = append(b, '0', '0') - } else if n < 100 { - b = append(b, '0') - } - return append(b, strconv.Itoa(n)...) -} - -type hourwblank bool - -func (v hourwblank) Append(b []byte, t time.Time) []byte { - h := t.Hour() - if bool(v) && h > 12 { - h = h - 12 - } - if h < 10 { - b = append(b, ' ') - } - return append(b, strconv.Itoa(h)...) -} -- 2.11.0