• R/O
  • HTTP
  • SSH
  • HTTPS

vapor: Commit

Golang implemented sidechain for Bytom


Commit MetaInfo

Revisiond037ce0c805eb94230797bab05b45333cfc8e5ae (tree)
Time2019-07-29 11:32:01
AuthorPaladz <yzhu101@uott...>
CommiterGitHub

Log Message

Revert "log into file (#357)"

This reverts commit bc213b29d91743bb9cb23c043f2856f47b34bb3e.

Change Summary

  • modified: config/config.go (diff)
  • delete: log/log.go
  • modified: node/node.go (diff)
  • delete: vendor/github.com/lestrrat-go/file-rotatelogs/.gitignore
  • delete: vendor/github.com/lestrrat-go/file-rotatelogs/.travis.yml
  • delete: vendor/github.com/lestrrat-go/file-rotatelogs/LICENSE
  • delete: vendor/github.com/lestrrat-go/file-rotatelogs/README.md
  • delete: vendor/github.com/lestrrat-go/file-rotatelogs/event.go
  • delete: vendor/github.com/lestrrat-go/file-rotatelogs/example_test.go
  • delete: vendor/github.com/lestrrat-go/file-rotatelogs/interface.go
  • delete: vendor/github.com/lestrrat-go/file-rotatelogs/internal/option/option.go
  • delete: vendor/github.com/lestrrat-go/file-rotatelogs/internal_test.go
  • delete: vendor/github.com/lestrrat-go/file-rotatelogs/options.go
  • delete: vendor/github.com/lestrrat-go/file-rotatelogs/rotatelogs.go
  • delete: vendor/github.com/lestrrat-go/file-rotatelogs/rotatelogs_test.go
  • delete: vendor/github.com/lestrrat-go/strftime/.gitignore
  • delete: vendor/github.com/lestrrat-go/strftime/.travis.yml
  • delete: vendor/github.com/lestrrat-go/strftime/LICENSE
  • delete: vendor/github.com/lestrrat-go/strftime/README.md
  • delete: vendor/github.com/lestrrat-go/strftime/internal_test.go
  • delete: vendor/github.com/lestrrat-go/strftime/strftime.go
  • delete: vendor/github.com/lestrrat-go/strftime/strftime_bench_test.go
  • delete: vendor/github.com/lestrrat-go/strftime/strftime_test.go
  • delete: vendor/github.com/lestrrat-go/strftime/writer.go

Incremental Difference

--- a/config/config.go
+++ b/config/config.go
@@ -134,7 +134,6 @@ func DefaultBaseConfig() BaseConfig {
134134 DBBackend: "leveldb",
135135 DBPath: "data",
136136 KeysPath: "keystore",
137- LogFile: "log",
138137 PrivateKeyFile: "node_key.txt",
139138 FederationFileName: "federation.json",
140139 }
@@ -144,10 +143,6 @@ func (b BaseConfig) DBDir() string {
144143 return rootify(b.DBPath, b.RootDir)
145144 }
146145
147-func (b BaseConfig) LogDir() string {
148- return rootify(b.LogFile, b.RootDir)
149-}
150-
151146 func (b BaseConfig) KeysDir() string {
152147 return rootify(b.KeysPath, b.RootDir)
153148 }
--- a/log/log.go
+++ /dev/null
@@ -1,72 +0,0 @@
1-package log
2-
3-import (
4- "path/filepath"
5- "sync"
6- "time"
7-
8- rotatelogs "github.com/lestrrat-go/file-rotatelogs"
9- "github.com/sirupsen/logrus"
10-
11- "github.com/vapor/config"
12-)
13-
14-const (
15- rotationTime int64 = 86400
16- maxAge int64 = 604800
17-)
18-
19-var defaultFormatter = &logrus.TextFormatter{DisableColors: true}
20-
21-func InitLogFile(config *config.Config) {
22- hook := newBtmHook(config.LogDir())
23- logrus.AddHook(hook)
24-}
25-
26-type BtmHook struct {
27- logPath string
28- lock *sync.Mutex
29-}
30-
31-func newBtmHook(logPath string) *BtmHook {
32- hook := &BtmHook{lock: new(sync.Mutex)}
33- hook.logPath = logPath
34- return hook
35-}
36-
37-// Write a log line to an io.Writer.
38-func (hook *BtmHook) ioWrite(entry *logrus.Entry) error {
39- module := "general"
40- if data, ok := entry.Data["module"]; ok {
41- module = data.(string)
42- }
43-
44- logPath := filepath.Join(hook.logPath, module)
45- writer, err := rotatelogs.New(
46- logPath+".%Y%m%d",
47- rotatelogs.WithMaxAge(time.Duration(maxAge)*time.Second),
48- rotatelogs.WithRotationTime(time.Duration(rotationTime)*time.Second),
49- )
50- if err != nil {
51- return err
52- }
53-
54- msg, err := defaultFormatter.Format(entry)
55- if err != nil {
56- return err
57- }
58-
59- _, err = writer.Write(msg)
60- return err
61-}
62-
63-func (hook *BtmHook) Fire(entry *logrus.Entry) error {
64- hook.lock.Lock()
65- defer hook.lock.Unlock()
66- return hook.ioWrite(entry)
67-}
68-
69-// Levels returns configured log levels.
70-func (hook *BtmHook) Levels() []logrus.Level {
71- return logrus.AllLevels
72-}
--- a/node/node.go
+++ b/node/node.go
@@ -6,6 +6,7 @@ import (
66 "net"
77 "net/http"
88 _ "net/http/pprof"
9+ "os"
910 "path/filepath"
1011 "reflect"
1112
@@ -25,7 +26,6 @@ import (
2526 dbm "github.com/vapor/database/leveldb"
2627 "github.com/vapor/env"
2728 "github.com/vapor/event"
28- vaporLog "github.com/vapor/log"
2929 "github.com/vapor/net/websocket"
3030 "github.com/vapor/netsync"
3131 "github.com/vapor/proposal/blockproposer"
@@ -66,8 +66,6 @@ func NewNode(config *cfg.Config) *Node {
6666 cmn.Exit(cmn.Fmt("Failed to load federated information:[%s]", err.Error()))
6767 }
6868
69- vaporLog.InitLogFile(config)
70-
7169 log.WithFields(log.Fields{
7270 "module": logModule,
7371 "pubkey": config.PrivateKey().XPub(),
@@ -76,10 +74,10 @@ func NewNode(config *cfg.Config) *Node {
7674 "fed_controlprogram": hex.EncodeToString(cfg.FederationWScript(config)),
7775 }).Info()
7876
77+ initLogFile(config)
7978 if err := consensus.InitActiveNetParams(config.ChainID); err != nil {
8079 log.Fatalf("Failed to init ActiveNetParams:[%s]", err.Error())
8180 }
82-
8381 initCommonConfig(config)
8482
8583 // Get store
@@ -190,6 +188,20 @@ func lockDataDirectory(config *cfg.Config) error {
190188 return nil
191189 }
192190
191+func initLogFile(config *cfg.Config) {
192+ if config.LogFile == "" {
193+ return
194+ }
195+ cmn.EnsureDir(filepath.Dir(config.LogFile), 0700)
196+ file, err := os.OpenFile(config.LogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
197+ if err == nil {
198+ log.SetOutput(file)
199+ } else {
200+ log.WithFields(log.Fields{"module": logModule, "err": err}).Info("using default")
201+ }
202+
203+}
204+
193205 func initCommonConfig(config *cfg.Config) {
194206 cfg.CommonConfig = config
195207 }
--- a/vendor/github.com/lestrrat-go/file-rotatelogs/.gitignore
+++ /dev/null
@@ -1,22 +0,0 @@
1-# Compiled Object files, Static and Dynamic libs (Shared Objects)
2-*.o
3-*.a
4-*.so
5-
6-# Folders
7-_obj
8-_test
9-
10-# Architecture specific extensions/prefixes
11-*.[568vq]
12-[568vq].out
13-
14-*.cgo1.go
15-*.cgo2.c
16-_cgo_defun.c
17-_cgo_gotypes.go
18-_cgo_export.*
19-
20-_testmain.go
21-
22-*.exe
--- a/vendor/github.com/lestrrat-go/file-rotatelogs/.travis.yml
+++ /dev/null
@@ -1,5 +0,0 @@
1-language: go
2-sudo: false
3-go:
4- - "1.10"
5- - tip
--- a/vendor/github.com/lestrrat-go/file-rotatelogs/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
1-The MIT License (MIT)
2-
3-Copyright (c) 2014 lestrrat
4-
5-Permission is hereby granted, free of charge, to any person obtaining a copy of
6-this software and associated documentation files (the "Software"), to deal in
7-the Software without restriction, including without limitation the rights to
8-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9-the Software, and to permit persons to whom the Software is furnished to do so,
10-subject to the following conditions:
11-
12-The above copyright notice and this permission notice shall be included in all
13-copies or substantial portions of the Software.
14-
15-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- a/vendor/github.com/lestrrat-go/file-rotatelogs/README.md
+++ /dev/null
@@ -1,236 +0,0 @@
1-file-rotatelogs
2-==================
3-
4-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.
5-
6-[![Build Status](https://travis-ci.org/lestrrat-go/file-rotatelogs.png?branch=master)](https://travis-ci.org/lestrrat-go/file-rotatelogs)
7-
8-[![GoDoc](https://godoc.org/github.com/lestrrat-go/file-rotatelogs?status.svg)](https://godoc.org/github.com/lestrrat-go/file-rotatelogs)
9-
10-
11-# SYNOPSIS
12-
13-```go
14-import (
15- "log"
16- "net/http"
17-
18- apachelog "github.com/lestrrat-go/apache-logformat"
19- rotatelogs "github.com/lestrrat-go/file-rotatelogs"
20-)
21-
22-func main() {
23- mux := http.NewServeMux()
24- mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { ... })
25-
26- logf, err := rotatelogs.New(
27- "/path/to/access_log.%Y%m%d%H%M",
28- rotatelogs.WithLinkName("/path/to/access_log"),
29- rotatelogs.WithMaxAge(24 * time.Hour),
30- rotatelogs.WithRotationTime(time.Hour),
31- )
32- if err != nil {
33- log.Printf("failed to create rotatelogs: %s", err)
34- return
35- }
36-
37- // Now you must write to logf. apache-logformat library can create
38- // a http.Handler that only writes the approriate logs for the request
39- // to the given handle
40- http.ListenAndServe(":8080", apachelog.CombinedLog.Wrap(mux, logf))
41-}
42-```
43-
44-# DESCRIPTION
45-
46-When you integrate this to to you app, it automatically write to logs that
47-are rotated from within the app: No more disk-full alerts because you forgot
48-to setup logrotate!
49-
50-To install, simply issue a `go get`:
51-
52-```
53-go get github.com/lestrrat-go/file-rotatelogs
54-```
55-
56-It's normally expected that this library is used with some other
57-logging service, such as the built-in `log` library, or loggers
58-such as `github.com/lestrrat-go/apache-logformat`.
59-
60-```go
61-import(
62- "log"
63- "github.com/lestrrat-go/file-rotatelogs"
64-)
65-
66-func main() {
67- rl, _ := rotatelogs.New("/path/to/access_log.%Y%m%d%H%M")
68-
69- log.SetOutput(rl)
70-
71- /* elsewhere ... */
72- log.Printf("Hello, World!")
73-}
74-```
75-
76-OPTIONS
77-====
78-
79-## Pattern (Required)
80-
81-The pattern used to generate actual log file names. You should use patterns
82-using the strftime (3) format. For example:
83-
84-```go
85- rotatelogs.New("/var/log/myapp/log.%Y%m%d")
86-```
87-
88-## Clock (default: rotatelogs.Local)
89-
90-You may specify an object that implements the roatatelogs.Clock interface.
91-When this option is supplied, it's used to determine the current time to
92-base all of the calculations on. For example, if you want to base your
93-calculations in UTC, you may specify rotatelogs.UTC
94-
95-```go
96- rotatelogs.New(
97- "/var/log/myapp/log.%Y%m%d",
98- rotatelogs.WithClock(rotatelogs.UTC),
99- )
100-```
101-
102-## Location
103-
104-This is an alternative to the `WithClock` option. Instead of providing an
105-explicit clock, you can provide a location for you times. We will create
106-a Clock object that produces times in your specified location, and configure
107-the rotatelog to respect it.
108-
109-## LinkName (default: "")
110-
111-Path where a symlink for the actual log file is placed. This allows you to
112-always check at the same location for log files even if the logs were rotated
113-
114-```go
115- rotatelogs.New(
116- "/var/log/myapp/log.%Y%m%d",
117- rotatelogs.WithLinkName("/var/log/myapp/current"),
118- )
119-```
120-
121-```
122- // Else where
123- $ tail -f /var/log/myapp/current
124-```
125-
126-If not provided, no link will be written.
127-
128-## RotationTime (default: 86400 sec)
129-
130-Interval between file rotation. By default logs are rotated every 86400 seconds.
131-Note: Remember to use time.Duration values.
132-
133-```go
134- // Rotate every hour
135- rotatelogs.New(
136- "/var/log/myapp/log.%Y%m%d",
137- rotatelogs.WithRotationTime(time.Hour),
138- )
139-```
140-
141-## MaxAge (default: 7 days)
142-
143-Time to wait until old logs are purged. By default no logs are purged, which
144-certainly isn't what you want.
145-Note: Remember to use time.Duration values.
146-
147-```go
148- // Purge logs older than 1 hour
149- rotatelogs.New(
150- "/var/log/myapp/log.%Y%m%d",
151- rotatelogs.WithMaxAge(time.Hour),
152- )
153-```
154-
155-## RotationCount (default: -1)
156-
157-The number of files should be kept. By default, this option is disabled.
158-
159-Note: MaxAge should be disabled by specifing `WithMaxAge(-1)` explicitly.
160-
161-```go
162- // Purge logs except latest 7 files
163- rotatelogs.New(
164- "/var/log/myapp/log.%Y%m%d",
165- rotatelogs.WithMaxAge(-1),
166- rotatelogs.WithRotationCount(7),
167- )
168-```
169-
170-## Handler (default: nil)
171-
172-Sets the event handler to receive event notifications from the RotateLogs
173-object. Currently only supported event type is FiledRotated
174-
175-```go
176- rotatelogs.New(
177- "/var/log/myapp/log.%Y%m%d",
178- rotatelogs.Handler(rotatelogs.HandlerFunc(func(e Event) {
179- if e.Type() != rotatelogs.FileRotatedEventType {
180- return
181- }
182-
183- // Do what you want with the data. This is just an idea:
184- storeLogFileToRemoteStorage(e.(*FileRotatedEvent).PreviousFile())
185- })),
186- )
187-```
188-
189-## ForceNewFile
190-
191-Ensure a new file is created every time New() is called. If the base file name
192-already exists, an implicit rotation is performed.
193-
194-```go
195- rotatelogs.New(
196- "/var/log/myapp/log.%Y%m%d",
197- rotatelogs.ForceNewFile(),
198- )
199-```
200-
201-## ForceNewFile
202-
203-Ensure a new file is created every time New() is called. If the base file name
204-already exists, an implicit rotation is performed.
205-
206-```go
207- rotatelogs.New(
208- "/var/log/myapp/log.%Y%m%d",
209- rotatelogs.ForceNewFile(),
210- )
211-```
212-
213-# Rotating files forcefully
214-
215-If you want to rotate files forcefully before the actual rotation time has reached,
216-you may use the `Rotate()` method. This method forcefully rotates the logs, but
217-if the generated file name clashes, then a numeric suffix is added so that
218-the new file will forcefully appear on disk.
219-
220-For example, suppose you had a pattern of '%Y.log' with a rotation time of
221-`86400` so that it only gets rotated every year, but for whatever reason you
222-wanted to rotate the logs now, you could install a signal handler to
223-trigger this rotation:
224-
225-```go
226-rl := rotatelogs.New(...)
227-
228-signal.Notify(ch, syscall.SIGHUP)
229-
230-go func(ch chan os.Signal) {
231- <-ch
232- rl.Rotate()
233-}()
234-```
235-
236-And you will get a log file name in like `2018.log.1`, `2018.log.2`, etc.
--- a/vendor/github.com/lestrrat-go/file-rotatelogs/event.go
+++ /dev/null
@@ -1,17 +0,0 @@
1-package rotatelogs
2-
3-func (h HandlerFunc) Handle(e Event) {
4- h(e)
5-}
6-
7-func (e *FileRotatedEvent) Type() EventType {
8- return FileRotatedEventType
9-}
10-
11-func (e *FileRotatedEvent) PreviousFile() string {
12- return e.prev
13-}
14-
15-func (e *FileRotatedEvent) CurrentFile() string {
16- return e.current
17-}
--- a/vendor/github.com/lestrrat-go/file-rotatelogs/example_test.go
+++ /dev/null
@@ -1,56 +0,0 @@
1-package rotatelogs_test
2-
3-import (
4- "fmt"
5- "io/ioutil"
6- "os"
7- rotatelogs "github.com/lestrrat-go/file-rotatelogs"
8-)
9-
10-func ExampleForceNewFile () {
11- logDir, err := ioutil.TempDir("", "rotatelogs_test")
12- if err != nil {
13- fmt.Println("could not create log directory ", err)
14- return
15- }
16- logPath := fmt.Sprintf("%s/test.log", logDir)
17-
18- for i := 0; i < 2; i++ {
19- writer, err := rotatelogs.New(logPath,
20- rotatelogs.ForceNewFile(),
21- )
22- if err != nil {
23- fmt.Println("Could not open log file ", err)
24- return
25- }
26-
27- n, err := writer.Write([]byte("test"))
28- if err != nil || n != 4 {
29- fmt.Println("Write failed ", err, " number written ", n)
30- return
31- }
32- err = writer.Close()
33- if err != nil {
34- fmt.Println("Close failed ", err)
35- return
36- }
37- }
38-
39- files, err := ioutil.ReadDir(logDir)
40- if err != nil {
41- fmt.Println("ReadDir failed ", err)
42- return
43- }
44- for _, file := range files {
45- fmt.Println(file.Name(), file.Size())
46- }
47-
48- err = os.RemoveAll(logDir)
49- if err != nil {
50- fmt.Println("RemoveAll failed ", err)
51- return
52- }
53- // OUTPUT:
54- // test.log 4
55- // test.log.1 4
56-}
--- a/vendor/github.com/lestrrat-go/file-rotatelogs/interface.go
+++ /dev/null
@@ -1,72 +0,0 @@
1-package rotatelogs
2-
3-import (
4- "os"
5- "sync"
6- "time"
7-
8- strftime "github.com/lestrrat-go/strftime"
9-)
10-
11-type Handler interface {
12- Handle(Event)
13-}
14-
15-type HandlerFunc func(Event)
16-
17-type Event interface {
18- Type() EventType
19-}
20-
21-type EventType int
22-
23-const (
24- InvalidEventType EventType = iota
25- FileRotatedEventType
26-)
27-
28-type FileRotatedEvent struct {
29- prev string // previous filename
30- current string // current, new filename
31-}
32-
33-// RotateLogs represents a log file that gets
34-// automatically rotated as you write to it.
35-type RotateLogs struct {
36- clock Clock
37- curFn string
38- curBaseFn string
39- globPattern string
40- generation int
41- linkName string
42- maxAge time.Duration
43- mutex sync.RWMutex
44- eventHandler Handler
45- outFh *os.File
46- pattern *strftime.Strftime
47- rotationTime time.Duration
48- rotationCount uint
49- forceNewFile bool
50-}
51-
52-// Clock is the interface used by the RotateLogs
53-// object to determine the current time
54-type Clock interface {
55- Now() time.Time
56-}
57-type clockFn func() time.Time
58-
59-// UTC is an object satisfying the Clock interface, which
60-// returns the current time in UTC
61-var UTC = clockFn(func() time.Time { return time.Now().UTC() })
62-
63-// Local is an object satisfying the Clock interface, which
64-// returns the current time in the local timezone
65-var Local = clockFn(time.Now)
66-
67-// Option is used to pass optional arguments to
68-// the RotateLogs constructor
69-type Option interface {
70- Name() string
71- Value() interface{}
72-}
--- a/vendor/github.com/lestrrat-go/file-rotatelogs/internal/option/option.go
+++ /dev/null
@@ -1,25 +0,0 @@
1-package option
2-
3-type Interface interface {
4- Name() string
5- Value() interface{}
6-}
7-
8-type Option struct {
9- name string
10- value interface{}
11-}
12-
13-func New(name string, value interface{}) *Option {
14- return &Option{
15- name: name,
16- value: value,
17- }
18-}
19-
20-func (o *Option) Name() string {
21- return o.name
22-}
23-func (o *Option) Value() interface{} {
24- return o.value
25-}
--- a/vendor/github.com/lestrrat-go/file-rotatelogs/internal_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
1-package rotatelogs
2-
3-import (
4- "fmt"
5- "testing"
6- "time"
7-
8- "github.com/jonboulle/clockwork"
9- "github.com/stretchr/testify/assert"
10-)
11-
12-func TestGenFilename(t *testing.T) {
13- // Mock time
14- ts := []time.Time{
15- time.Time{},
16- (time.Time{}).Add(24 * time.Hour),
17- }
18-
19- for _, xt := range ts {
20- rl, err := New(
21- "/path/to/%Y/%m/%d",
22- WithClock(clockwork.NewFakeClockAt(xt)),
23- )
24- if !assert.NoError(t, err, "New should succeed") {
25- return
26- }
27-
28- defer rl.Close()
29-
30- fn := rl.genFilename()
31- expected := fmt.Sprintf("/path/to/%04d/%02d/%02d",
32- xt.Year(),
33- xt.Month(),
34- xt.Day(),
35- )
36-
37- if !assert.Equal(t, expected, fn) {
38- return
39- }
40- }
41-}
--- a/vendor/github.com/lestrrat-go/file-rotatelogs/options.go
+++ /dev/null
@@ -1,82 +0,0 @@
1-package rotatelogs
2-
3-import (
4- "time"
5-
6- "github.com/lestrrat-go/file-rotatelogs/internal/option"
7-)
8-
9-const (
10- optkeyClock = "clock"
11- optkeyHandler = "handler"
12- optkeyLinkName = "link-name"
13- optkeyMaxAge = "max-age"
14- optkeyRotationTime = "rotation-time"
15- optkeyRotationCount = "rotation-count"
16- optkeyForceNewFile = "force-new-file"
17-)
18-
19-// WithClock creates a new Option that sets a clock
20-// that the RotateLogs object will use to determine
21-// the current time.
22-//
23-// By default rotatelogs.Local, which returns the
24-// current time in the local time zone, is used. If you
25-// would rather use UTC, use rotatelogs.UTC as the argument
26-// to this option, and pass it to the constructor.
27-func WithClock(c Clock) Option {
28- return option.New(optkeyClock, c)
29-}
30-
31-// WithLocation creates a new Option that sets up a
32-// "Clock" interface that the RotateLogs object will use
33-// to determine the current time.
34-//
35-// This optin works by always returning the in the given
36-// location.
37-func WithLocation(loc *time.Location) Option {
38- return option.New(optkeyClock, clockFn(func() time.Time {
39- return time.Now().In(loc)
40- }))
41-}
42-
43-// WithLinkName creates a new Option that sets the
44-// symbolic link name that gets linked to the current
45-// file name being used.
46-func WithLinkName(s string) Option {
47- return option.New(optkeyLinkName, s)
48-}
49-
50-// WithMaxAge creates a new Option that sets the
51-// max age of a log file before it gets purged from
52-// the file system.
53-func WithMaxAge(d time.Duration) Option {
54- return option.New(optkeyMaxAge, d)
55-}
56-
57-// WithRotationTime creates a new Option that sets the
58-// time between rotation.
59-func WithRotationTime(d time.Duration) Option {
60- return option.New(optkeyRotationTime, d)
61-}
62-
63-// WithRotationCount creates a new Option that sets the
64-// number of files should be kept before it gets
65-// purged from the file system.
66-func WithRotationCount(n uint) Option {
67- return option.New(optkeyRotationCount, n)
68-}
69-
70-// WithHandler creates a new Option that specifies the
71-// Handler object that gets invoked when an event occurs.
72-// Currently `FileRotated` event is supported
73-func WithHandler(h Handler) Option {
74- return option.New(optkeyHandler, h)
75-}
76-
77-// ForceNewFile ensures a new file is created every time New()
78-// is called. If the base file name already exists, an implicit
79-// rotation is performed
80-func ForceNewFile() Option {
81- return option.New(optkeyForceNewFile, true)
82-}
--- a/vendor/github.com/lestrrat-go/file-rotatelogs/rotatelogs.go
+++ /dev/null
@@ -1,366 +0,0 @@
1-// package rotatelogs is a port of File-RotateLogs from Perl
2-// (https://metacpan.org/release/File-RotateLogs), and it allows
3-// you to automatically rotate output files when you write to them
4-// according to the filename pattern that you can specify.
5-package rotatelogs
6-
7-import (
8- "fmt"
9- "io"
10- "os"
11- "path/filepath"
12- "regexp"
13- "strings"
14- "sync"
15- "time"
16-
17- strftime "github.com/lestrrat-go/strftime"
18- "github.com/pkg/errors"
19-)
20-
21-func (c clockFn) Now() time.Time {
22- return c()
23-}
24-
25-// New creates a new RotateLogs object. A log filename pattern
26-// must be passed. Optional `Option` parameters may be passed
27-func New(p string, options ...Option) (*RotateLogs, error) {
28- globPattern := p
29- for _, re := range patternConversionRegexps {
30- globPattern = re.ReplaceAllString(globPattern, "*")
31- }
32-
33- pattern, err := strftime.New(p)
34- if err != nil {
35- return nil, errors.Wrap(err, `invalid strftime pattern`)
36- }
37-
38- var clock Clock = Local
39- rotationTime := 24 * time.Hour
40- var rotationCount uint
41- var linkName string
42- var maxAge time.Duration
43- var handler Handler
44- var forceNewFile bool
45-
46- for _, o := range options {
47- switch o.Name() {
48- case optkeyClock:
49- clock = o.Value().(Clock)
50- case optkeyLinkName:
51- linkName = o.Value().(string)
52- case optkeyMaxAge:
53- maxAge = o.Value().(time.Duration)
54- if maxAge < 0 {
55- maxAge = 0
56- }
57- case optkeyRotationTime:
58- rotationTime = o.Value().(time.Duration)
59- if rotationTime < 0 {
60- rotationTime = 0
61- }
62- case optkeyRotationCount:
63- rotationCount = o.Value().(uint)
64- case optkeyHandler:
65- handler = o.Value().(Handler)
66- case optkeyForceNewFile:
67- forceNewFile = true
68- }
69- }
70-
71- if maxAge > 0 && rotationCount > 0 {
72- return nil, errors.New("options MaxAge and RotationCount cannot be both set")
73- }
74-
75- if maxAge == 0 && rotationCount == 0 {
76- // if both are 0, give maxAge a sane default
77- maxAge = 7 * 24 * time.Hour
78- }
79-
80- return &RotateLogs{
81- clock: clock,
82- eventHandler: handler,
83- globPattern: globPattern,
84- linkName: linkName,
85- maxAge: maxAge,
86- pattern: pattern,
87- rotationTime: rotationTime,
88- rotationCount: rotationCount,
89- forceNewFile: forceNewFile,
90- }, nil
91-}
92-
93-func (rl *RotateLogs) genFilename() string {
94- now := rl.clock.Now()
95-
96- // XXX HACK: Truncate only happens in UTC semantics, apparently.
97- // observed values for truncating given time with 86400 secs:
98- //
99- // before truncation: 2018/06/01 03:54:54 2018-06-01T03:18:00+09:00
100- // after truncation: 2018/06/01 03:54:54 2018-05-31T09:00:00+09:00
101- //
102- // This is really annoying when we want to truncate in local time
103- // so we hack: we take the apparent local time in the local zone,
104- // and pretend that it's in UTC. do our math, and put it back to
105- // the local zone
106- var base time.Time
107- if now.Location() != time.UTC {
108- base = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), now.Nanosecond(), time.UTC)
109- base = base.Truncate(time.Duration(rl.rotationTime))
110- base = time.Date(base.Year(), base.Month(), base.Day(), base.Hour(), base.Minute(), base.Second(), base.Nanosecond(), base.Location())
111- } else {
112- base = now.Truncate(time.Duration(rl.rotationTime))
113- }
114- return rl.pattern.FormatString(base)
115-}
116-
117-// Write satisfies the io.Writer interface. It writes to the
118-// appropriate file handle that is currently being used.
119-// If we have reached rotation time, the target file gets
120-// automatically rotated, and also purged if necessary.
121-func (rl *RotateLogs) Write(p []byte) (n int, err error) {
122- // Guard against concurrent writes
123- rl.mutex.Lock()
124- defer rl.mutex.Unlock()
125-
126- out, err := rl.getWriter_nolock(false, false)
127- if err != nil {
128- return 0, errors.Wrap(err, `failed to acquite target io.Writer`)
129- }
130-
131- return out.Write(p)
132-}
133-
134-// must be locked during this operation
135-func (rl *RotateLogs) getWriter_nolock(bailOnRotateFail, useGenerationalNames bool) (io.Writer, error) {
136- generation := rl.generation
137- previousFn := rl.curFn
138- // This filename contains the name of the "NEW" filename
139- // to log to, which may be newer than rl.currentFilename
140- baseFn := rl.genFilename()
141- filename := baseFn
142- var forceNewFile bool
143- if baseFn != rl.curBaseFn {
144- generation = 0
145- // even though this is the first write after calling New(),
146- // check if a new file needs to be created
147- if rl.forceNewFile {
148- forceNewFile = true
149- }
150- } else {
151- if !useGenerationalNames {
152- // nothing to do
153- return rl.outFh, nil
154- }
155- forceNewFile = true
156- generation++
157- }
158- if forceNewFile {
159- // A new file has been requested. Instead of just using the
160- // regular strftime pattern, we create a new file name using
161- // generational names such as "foo.1", "foo.2", "foo.3", etc
162- var name string
163- for {
164- if generation == 0 {
165- name = filename
166- } else {
167- name = fmt.Sprintf("%s.%d", filename, generation)
168- }
169- if _, err := os.Stat(name); err != nil {
170- filename = name
171- break
172- }
173- generation++
174- }
175- }
176- // make sure the dir is existed, eg:
177- // ./foo/bar/baz/hello.log must make sure ./foo/bar/baz is existed
178- dirname := filepath.Dir(filename)
179- if err := os.MkdirAll(dirname, 0755); err != nil {
180- return nil, errors.Wrapf(err, "failed to create directory %s", dirname)
181- }
182- // if we got here, then we need to create a file
183- fh, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
184- if err != nil {
185- return nil, errors.Errorf("failed to open file %s: %s", rl.pattern, err)
186- }
187-
188- if err := rl.rotate_nolock(filename); err != nil {
189- err = errors.Wrap(err, "failed to rotate")
190- if bailOnRotateFail {
191- // Failure to rotate is a problem, but it's really not a great
192- // idea to stop your application just because you couldn't rename
193- // your log.
194- //
195- // We only return this error when explicitly needed (as specified by bailOnRotateFail)
196- //
197- // However, we *NEED* to close `fh` here
198- if fh != nil { // probably can't happen, but being paranoid
199- fh.Close()
200- }
201- return nil, err
202- }
203- fmt.Fprintf(os.Stderr, "%s\n", err.Error())
204- }
205-
206- rl.outFh.Close()
207- rl.outFh = fh
208- rl.curBaseFn = baseFn
209- rl.curFn = filename
210- rl.generation = generation
211-
212- if h := rl.eventHandler; h != nil {
213- go h.Handle(&FileRotatedEvent{
214- prev: previousFn,
215- current: filename,
216- })
217- }
218- return fh, nil
219-}
220-
221-// CurrentFileName returns the current file name that
222-// the RotateLogs object is writing to
223-func (rl *RotateLogs) CurrentFileName() string {
224- rl.mutex.RLock()
225- defer rl.mutex.RUnlock()
226- return rl.curFn
227-}
228-
229-var patternConversionRegexps = []*regexp.Regexp{
230- regexp.MustCompile(`%[%+A-Za-z]`),
231- regexp.MustCompile(`\*+`),
232-}
233-
234-type cleanupGuard struct {
235- enable bool
236- fn func()
237- mutex sync.Mutex
238-}
239-
240-func (g *cleanupGuard) Enable() {
241- g.mutex.Lock()
242- defer g.mutex.Unlock()
243- g.enable = true
244-}
245-func (g *cleanupGuard) Run() {
246- g.fn()
247-}
248-
249-// Rotate forcefully rotates the log files. If the generated file name
250-// clash because file already exists, a numeric suffix of the form
251-// ".1", ".2", ".3" and so forth are appended to the end of the log file
252-//
253-// Thie method can be used in conjunction with a signal handler so to
254-// emulate servers that generate new log files when they receive a
255-// SIGHUP
256-func (rl *RotateLogs) Rotate() error {
257- rl.mutex.Lock()
258- defer rl.mutex.Unlock()
259- if _, err := rl.getWriter_nolock(true, true); err != nil {
260- return err
261- }
262- return nil
263-}
264-
265-func (rl *RotateLogs) rotate_nolock(filename string) error {
266- lockfn := filename + `_lock`
267- fh, err := os.OpenFile(lockfn, os.O_CREATE|os.O_EXCL, 0644)
268- if err != nil {
269- // Can't lock, just return
270- return err
271- }
272-
273- var guard cleanupGuard
274- guard.fn = func() {
275- fh.Close()
276- os.Remove(lockfn)
277- }
278- defer guard.Run()
279-
280- if rl.linkName != "" {
281- tmpLinkName := filename + `_symlink`
282- if err := os.Symlink(filename, tmpLinkName); err != nil {
283- return errors.Wrap(err, `failed to create new symlink`)
284- }
285-
286- if err := os.Rename(tmpLinkName, rl.linkName); err != nil {
287- return errors.Wrap(err, `failed to rename new symlink`)
288- }
289- }
290-
291- if rl.maxAge <= 0 && rl.rotationCount <= 0 {
292- return errors.New("panic: maxAge and rotationCount are both set")
293- }
294-
295- matches, err := filepath.Glob(rl.globPattern)
296- if err != nil {
297- return err
298- }
299-
300- cutoff := rl.clock.Now().Add(-1 * rl.maxAge)
301- var toUnlink []string
302- for _, path := range matches {
303- // Ignore lock files
304- if strings.HasSuffix(path, "_lock") || strings.HasSuffix(path, "_symlink") {
305- continue
306- }
307-
308- fi, err := os.Stat(path)
309- if err != nil {
310- continue
311- }
312-
313- fl, err := os.Lstat(path)
314- if err != nil {
315- continue
316- }
317-
318- if rl.maxAge > 0 && fi.ModTime().After(cutoff) {
319- continue
320- }
321-
322- if rl.rotationCount > 0 && fl.Mode()&os.ModeSymlink == os.ModeSymlink {
323- continue
324- }
325- toUnlink = append(toUnlink, path)
326- }
327-
328- if rl.rotationCount > 0 {
329- // Only delete if we have more than rotationCount
330- if rl.rotationCount >= uint(len(toUnlink)) {
331- return nil
332- }
333-
334- toUnlink = toUnlink[:len(toUnlink)-int(rl.rotationCount)]
335- }
336-
337- if len(toUnlink) <= 0 {
338- return nil
339- }
340-
341- guard.Enable()
342- go func() {
343- // unlink files on a separate goroutine
344- for _, path := range toUnlink {
345- os.Remove(path)
346- }
347- }()
348-
349- return nil
350-}
351-
352-// Close satisfies the io.Closer interface. You must
353-// call this method if you performed any writes to
354-// the object.
355-func (rl *RotateLogs) Close() error {
356- rl.mutex.Lock()
357- defer rl.mutex.Unlock()
358-
359- if rl.outFh == nil {
360- return nil
361- }
362-
363- rl.outFh.Close()
364- rl.outFh = nil
365- return nil
366-}
--- a/vendor/github.com/lestrrat-go/file-rotatelogs/rotatelogs_test.go
+++ /dev/null
@@ -1,531 +0,0 @@
1-package rotatelogs_test
2-
3-import (
4- "fmt"
5- "io"
6- "io/ioutil"
7- "log"
8- "os"
9- "path/filepath"
10- "strings"
11- "testing"
12- "time"
13-
14- "github.com/jonboulle/clockwork"
15- rotatelogs "github.com/lestrrat-go/file-rotatelogs"
16- "github.com/pkg/errors"
17- "github.com/stretchr/testify/assert"
18-)
19-
20-func TestSatisfiesIOWriter(t *testing.T) {
21- var w io.Writer
22- w, _ = rotatelogs.New("/foo/bar")
23- _ = w
24-}
25-
26-func TestSatisfiesIOCloser(t *testing.T) {
27- var c io.Closer
28- c, _ = rotatelogs.New("/foo/bar")
29- _ = c
30-}
31-
32-func TestLogRotate(t *testing.T) {
33- dir, err := ioutil.TempDir("", "file-rotatelogs-test")
34- if !assert.NoError(t, err, "creating temporary directory should succeed") {
35- return
36- }
37- defer os.RemoveAll(dir)
38-
39- // Change current time, so we can safely purge old logs
40- dummyTime := time.Now().Add(-7 * 24 * time.Hour)
41- dummyTime = dummyTime.Add(time.Duration(-1 * dummyTime.Nanosecond()))
42- clock := clockwork.NewFakeClockAt(dummyTime)
43- linkName := filepath.Join(dir, "log")
44- rl, err := rotatelogs.New(
45- filepath.Join(dir, "log%Y%m%d%H%M%S"),
46- rotatelogs.WithClock(clock),
47- rotatelogs.WithMaxAge(24*time.Hour),
48- rotatelogs.WithLinkName(linkName),
49- )
50- if !assert.NoError(t, err, `rotatelogs.New should succeed`) {
51- return
52- }
53- defer rl.Close()
54-
55- str := "Hello, World"
56- n, err := rl.Write([]byte(str))
57- if !assert.NoError(t, err, "rl.Write should succeed") {
58- return
59- }
60-
61- if !assert.Len(t, str, n, "rl.Write should succeed") {
62- return
63- }
64-
65- fn := rl.CurrentFileName()
66- if fn == "" {
67- t.Errorf("Could not get filename %s", fn)
68- }
69-
70- content, err := ioutil.ReadFile(fn)
71- if err != nil {
72- t.Errorf("Failed to read file %s: %s", fn, err)
73- }
74-
75- if string(content) != str {
76- t.Errorf(`File content does not match (was "%s")`, content)
77- }
78-
79- err = os.Chtimes(fn, dummyTime, dummyTime)
80- if err != nil {
81- t.Errorf("Failed to change access/modification times for %s: %s", fn, err)
82- }
83-
84- fi, err := os.Stat(fn)
85- if err != nil {
86- t.Errorf("Failed to stat %s: %s", fn, err)
87- }
88-
89- if !fi.ModTime().Equal(dummyTime) {
90- t.Errorf("Failed to chtime for %s (expected %s, got %s)", fn, fi.ModTime(), dummyTime)
91- }
92-
93- clock.Advance(time.Duration(7 * 24 * time.Hour))
94-
95- // This next Write() should trigger Rotate()
96- rl.Write([]byte(str))
97- newfn := rl.CurrentFileName()
98- if newfn == fn {
99- t.Errorf(`New file name and old file name should not match ("%s" != "%s")`, fn, newfn)
100- }
101-
102- content, err = ioutil.ReadFile(newfn)
103- if err != nil {
104- t.Errorf("Failed to read file %s: %s", newfn, err)
105- }
106-
107- if string(content) != str {
108- t.Errorf(`File content does not match (was "%s")`, content)
109- }
110-
111- time.Sleep(time.Second)
112-
113- // fn was declared above, before mocking CurrentTime
114- // Old files should have been unlinked
115- _, err = os.Stat(fn)
116- if !assert.Error(t, err, "os.Stat should have failed") {
117- return
118- }
119-
120- linkDest, err := os.Readlink(linkName)
121- if err != nil {
122- t.Errorf("Failed to readlink %s: %s", linkName, err)
123- }
124-
125- if linkDest != newfn {
126- t.Errorf(`Symlink destination does not match expected filename ("%s" != "%s")`, newfn, linkDest)
127- }
128-}
129-
130-func CreateRotationTestFile(dir string, base time.Time, d time.Duration, n int) {
131- timestamp := base
132- for i := 0; i < n; i++ {
133- // %Y%m%d%H%M%S
134- suffix := timestamp.Format("20060102150405")
135- path := filepath.Join(dir, "log"+suffix)
136- ioutil.WriteFile(path, []byte("rotation test file\n"), os.ModePerm)
137- os.Chtimes(path, timestamp, timestamp)
138- timestamp = timestamp.Add(d)
139- }
140-}
141-
142-func TestLogRotationCount(t *testing.T) {
143- dir, err := ioutil.TempDir("", "file-rotatelogs-rotationcount-test")
144- if !assert.NoError(t, err, "creating temporary directory should succeed") {
145- return
146- }
147- defer os.RemoveAll(dir)
148-
149- dummyTime := time.Now().Add(-7 * 24 * time.Hour)
150- dummyTime = dummyTime.Add(time.Duration(-1 * dummyTime.Nanosecond()))
151- clock := clockwork.NewFakeClockAt(dummyTime)
152-
153- t.Run("Either maxAge or rotationCount should be set", func(t *testing.T) {
154- rl, err := rotatelogs.New(
155- filepath.Join(dir, "log%Y%m%d%H%M%S"),
156- rotatelogs.WithClock(clock),
157- rotatelogs.WithMaxAge(time.Duration(0)),
158- rotatelogs.WithRotationCount(0),
159- )
160- if !assert.NoError(t, err, `Both of maxAge and rotationCount is disabled`) {
161- return
162- }
163- defer rl.Close()
164- })
165-
166- t.Run("Either maxAge or rotationCount should be set", func(t *testing.T) {
167- rl, err := rotatelogs.New(
168- filepath.Join(dir, "log%Y%m%d%H%M%S"),
169- rotatelogs.WithClock(clock),
170- rotatelogs.WithMaxAge(1),
171- rotatelogs.WithRotationCount(1),
172- )
173- if !assert.Error(t, err, `Both of maxAge and rotationCount is enabled`) {
174- return
175- }
176- if rl != nil {
177- defer rl.Close()
178- }
179- })
180-
181- t.Run("Only latest log file is kept", func(t *testing.T) {
182- rl, err := rotatelogs.New(
183- filepath.Join(dir, "log%Y%m%d%H%M%S"),
184- rotatelogs.WithClock(clock),
185- rotatelogs.WithMaxAge(-1),
186- rotatelogs.WithRotationCount(1),
187- )
188- if !assert.NoError(t, err, `rotatelogs.New should succeed`) {
189- return
190- }
191- defer rl.Close()
192-
193- n, err := rl.Write([]byte("dummy"))
194- if !assert.NoError(t, err, "rl.Write should succeed") {
195- return
196- }
197- if !assert.Len(t, "dummy", n, "rl.Write should succeed") {
198- return
199- }
200- time.Sleep(time.Second)
201- files, err := filepath.Glob(filepath.Join(dir, "log*"))
202- if !assert.Equal(t, 1, len(files), "Only latest log is kept") {
203- return
204- }
205- })
206-
207- t.Run("Old log files are purged except 2 log files", func(t *testing.T) {
208- CreateRotationTestFile(dir, dummyTime, time.Duration(time.Hour), 5)
209- rl, err := rotatelogs.New(
210- filepath.Join(dir, "log%Y%m%d%H%M%S"),
211- rotatelogs.WithClock(clock),
212- rotatelogs.WithMaxAge(-1),
213- rotatelogs.WithRotationCount(2),
214- )
215- if !assert.NoError(t, err, `rotatelogs.New should succeed`) {
216- return
217- }
218- defer rl.Close()
219-
220- n, err := rl.Write([]byte("dummy"))
221- if !assert.NoError(t, err, "rl.Write should succeed") {
222- return
223- }
224- if !assert.Len(t, "dummy", n, "rl.Write should succeed") {
225- return
226- }
227- time.Sleep(time.Second)
228- files, err := filepath.Glob(filepath.Join(dir, "log*"))
229- if !assert.Equal(t, 2, len(files), "One file is kept") {
230- return
231- }
232- })
233-
234-}
235-
236-func TestLogSetOutput(t *testing.T) {
237- dir, err := ioutil.TempDir("", "file-rotatelogs-test")
238- if err != nil {
239- t.Errorf("Failed to create temporary directory: %s", err)
240- }
241- defer os.RemoveAll(dir)
242-
243- rl, err := rotatelogs.New(filepath.Join(dir, "log%Y%m%d%H%M%S"))
244- if !assert.NoError(t, err, `rotatelogs.New should succeed`) {
245- return
246- }
247- defer rl.Close()
248-
249- log.SetOutput(rl)
250- defer log.SetOutput(os.Stderr)
251-
252- str := "Hello, World"
253- log.Print(str)
254-
255- fn := rl.CurrentFileName()
256- if fn == "" {
257- t.Errorf("Could not get filename %s", fn)
258- }
259-
260- content, err := ioutil.ReadFile(fn)
261- if err != nil {
262- t.Errorf("Failed to read file %s: %s", fn, err)
263- }
264-
265- if !strings.Contains(string(content), str) {
266- t.Errorf(`File content does not contain "%s" (was "%s")`, str, content)
267- }
268-}
269-
270-func TestGHIssue16(t *testing.T) {
271- defer func() {
272- if v := recover(); v != nil {
273- assert.NoError(t, errors.Errorf("%s", v), "error should be nil")
274- }
275- }()
276-
277- dir, err := ioutil.TempDir("", "file-rotatelogs-gh16")
278- if !assert.NoError(t, err, `creating temporary directory should succeed`) {
279- return
280- }
281- defer os.RemoveAll(dir)
282-
283- rl, err := rotatelogs.New(
284- filepath.Join(dir, "log%Y%m%d%H%M%S"),
285- rotatelogs.WithLinkName("./test.log"),
286- rotatelogs.WithRotationTime(10*time.Second),
287- rotatelogs.WithRotationCount(3),
288- rotatelogs.WithMaxAge(-1),
289- )
290- if !assert.NoError(t, err, `rotatelogs.New should succeed`) {
291- return
292- }
293-
294- if !assert.NoError(t, rl.Rotate(), "rl.Rotate should succeed") {
295- return
296- }
297- defer rl.Close()
298-}
299-
300-func TestRotationGenerationalNames(t *testing.T) {
301- dir, err := ioutil.TempDir("", "file-rotatelogs-generational")
302- if !assert.NoError(t, err, `creating temporary directory should succeed`) {
303- return
304- }
305- defer os.RemoveAll(dir)
306-
307- t.Run("Rotate over unchanged pattern", func(t *testing.T) {
308- rl, err := rotatelogs.New(
309- filepath.Join(dir, "unchanged-pattern.log"),
310- )
311- if !assert.NoError(t, err, `rotatelogs.New should succeed`) {
312- return
313- }
314-
315- seen := map[string]struct{}{}
316- for i := 0; i < 10; i++ {
317- rl.Write([]byte("Hello, World!"))
318- if !assert.NoError(t, rl.Rotate(), "rl.Rotate should succeed") {
319- return
320- }
321-
322- // Because every call to Rotate should yield a new log file,
323- // and the previous files already exist, the filenames should share
324- // the same prefix and have a unique suffix
325- fn := filepath.Base(rl.CurrentFileName())
326- if !assert.True(t, strings.HasPrefix(fn, "unchanged-pattern.log"), "prefix for all filenames should match") {
327- return
328- }
329- rl.Write([]byte("Hello, World!"))
330- suffix := strings.TrimPrefix(fn, "unchanged-pattern.log")
331- expectedSuffix := fmt.Sprintf(".%d", i+1)
332- if !assert.True(t, suffix == expectedSuffix, "expected suffix %s found %s", expectedSuffix, suffix) {
333- return
334- }
335- assert.FileExists(t, rl.CurrentFileName(), "file does not exist %s", rl.CurrentFileName())
336- stat, err := os.Stat(rl.CurrentFileName())
337- if err == nil {
338- if !assert.True(t, stat.Size() == 13, "file %s size is %d, expected 13", rl.CurrentFileName(), stat.Size()) {
339- return
340- }
341- } else {
342- assert.Failf(t, "could not stat file %s", rl.CurrentFileName())
343- return
344- }
345-
346- if _, ok := seen[suffix]; !assert.False(t, ok, `filename suffix %s should be unique`, suffix) {
347- return
348- }
349- seen[suffix] = struct{}{}
350- }
351- defer rl.Close()
352- })
353- t.Run("Rotate over pattern change over every second", func(t *testing.T) {
354- rl, err := rotatelogs.New(
355- filepath.Join(dir, "every-second-pattern-%Y%m%d%H%M%S.log"),
356- rotatelogs.WithRotationTime(time.Nanosecond),
357- )
358- if !assert.NoError(t, err, `rotatelogs.New should succeed`) {
359- return
360- }
361-
362- for i := 0; i < 10; i++ {
363- time.Sleep(time.Second)
364- rl.Write([]byte("Hello, World!"))
365- if !assert.NoError(t, rl.Rotate(), "rl.Rotate should succeed") {
366- return
367- }
368-
369- // because every new Write should yield a new logfile,
370- // every rorate should be create a filename ending with a .1
371- if !assert.True(t, strings.HasSuffix(rl.CurrentFileName(), ".1"), "log name should end with .1") {
372- return
373- }
374- }
375- defer rl.Close()
376- })
377-}
378-
379-type ClockFunc func() time.Time
380-
381-func (f ClockFunc) Now() time.Time {
382- return f()
383-}
384-
385-func TestGHIssue23(t *testing.T) {
386- dir, err := ioutil.TempDir("", "file-rotatelogs-generational")
387- if !assert.NoError(t, err, `creating temporary directory should succeed`) {
388- return
389- }
390- defer os.RemoveAll(dir)
391-
392- for _, locName := range []string{"Asia/Tokyo", "Pacific/Honolulu"} {
393- loc, _ := time.LoadLocation(locName)
394- tests := []struct {
395- Expected string
396- Clock rotatelogs.Clock
397- }{
398- {
399- Expected: filepath.Join(dir, strings.ToLower(strings.Replace(locName, "/", "_", -1)) + ".201806010000.log"),
400- Clock: ClockFunc(func() time.Time {
401- return time.Date(2018, 6, 1, 3, 18, 0, 0, loc)
402- }),
403- },
404- {
405- Expected: filepath.Join(dir, strings.ToLower(strings.Replace(locName, "/", "_", -1)) + ".201712310000.log"),
406- Clock: ClockFunc(func() time.Time {
407- return time.Date(2017, 12, 31, 23, 52, 0, 0, loc)
408- }),
409- },
410- }
411- for _, test := range tests {
412- t.Run(fmt.Sprintf("location = %s, time = %s", locName, test.Clock.Now().Format(time.RFC3339)), func(t *testing.T) {
413- template := strings.ToLower(strings.Replace(locName, "/", "_", -1)) + ".%Y%m%d%H%M.log"
414- rl, err := rotatelogs.New(
415- filepath.Join(dir, template),
416- rotatelogs.WithClock(test.Clock), // we're not using WithLocation, but it's the same thing
417- )
418- if !assert.NoError(t, err, "rotatelogs.New should succeed") {
419- return
420- }
421-
422- t.Logf("expected %s", test.Expected)
423- rl.Rotate()
424- if !assert.Equal(t, test.Expected, rl.CurrentFileName(), "file names should match") {
425- return
426- }
427- })
428- }
429- }
430-}
431-
432-func TestForceNewFile(t *testing.T) {
433- dir, err := ioutil.TempDir("", "file-rotatelogs-force-new-file")
434- if !assert.NoError(t, err, `creating temporary directory should succeed`) {
435- return
436- }
437- defer os.RemoveAll(dir)
438-
439- t.Run("Force a new file", func(t *testing.T) {
440-
441- rl, err := rotatelogs.New(
442- filepath.Join(dir, "force-new-file.log"),
443- rotatelogs.ForceNewFile(),
444- )
445- if !assert.NoError(t, err, "rotatelogs.New should succeed") {
446- return
447- }
448- rl.Write([]byte("Hello, World!"))
449- rl.Close()
450-
451- for i := 0; i < 10; i++ {
452- baseFn := filepath.Join(dir, "force-new-file.log")
453- rl, err := rotatelogs.New(
454- baseFn,
455- rotatelogs.ForceNewFile(),
456- )
457- if !assert.NoError(t, err, "rotatelogs.New should succeed") {
458- return
459- }
460- rl.Write([]byte("Hello, World"))
461- rl.Write([]byte(fmt.Sprintf("%d", i)))
462- rl.Close()
463-
464- fn := filepath.Base(rl.CurrentFileName())
465- suffix := strings.TrimPrefix(fn, "force-new-file.log")
466- expectedSuffix := fmt.Sprintf(".%d", i+1)
467- if !assert.True(t, suffix == expectedSuffix, "expected suffix %s found %s", expectedSuffix, suffix) {
468- return
469- }
470- assert.FileExists(t, rl.CurrentFileName(), "file does not exist %s", rl.CurrentFileName())
471- content, err := ioutil.ReadFile(rl.CurrentFileName())
472- if !assert.NoError(t, err, "ioutil.ReadFile %s should succeed", rl.CurrentFileName()) {
473- return
474- }
475- str := fmt.Sprintf("Hello, World%d", i)
476- if !assert.Equal(t, str, string(content), "read %s from file %s, not expected %s", string(content), rl.CurrentFileName(), str) {
477- return
478- }
479-
480- assert.FileExists(t, baseFn, "file does not exist %s", baseFn)
481- content, err = ioutil.ReadFile(baseFn)
482- if !assert.NoError(t, err, "ioutil.ReadFile should succeed") {
483- return
484- }
485- if !assert.Equal(t, "Hello, World!", string(content), "read %s from file %s, not expected Hello, World!", string(content), baseFn) {
486- return
487- }
488- }
489-
490- })
491-
492- t.Run("Force a new file with Rotate", func(t *testing.T) {
493-
494- baseFn := filepath.Join(dir, "force-new-file-rotate.log")
495- rl, err := rotatelogs.New(
496- baseFn,
497- rotatelogs.ForceNewFile(),
498- )
499- if !assert.NoError(t, err, "rotatelogs.New should succeed") {
500- return
501- }
502- rl.Write([]byte("Hello, World!"))
503-
504- for i := 0; i < 10; i++ {
505- if !assert.NoError(t, rl.Rotate(), "rl.Rotate should succeed") {
506- return
507- }
508- rl.Write([]byte("Hello, World"))
509- rl.Write([]byte(fmt.Sprintf("%d", i)))
510- assert.FileExists(t, rl.CurrentFileName(), "file does not exist %s", rl.CurrentFileName())
511- content, err := ioutil.ReadFile(rl.CurrentFileName())
512- if !assert.NoError(t, err, "ioutil.ReadFile %s should succeed", rl.CurrentFileName()) {
513- return
514- }
515- str := fmt.Sprintf("Hello, World%d", i)
516- if !assert.Equal(t, str, string(content), "read %s from file %s, not expected %s", string(content), rl.CurrentFileName(), str) {
517- return
518- }
519-
520- assert.FileExists(t, baseFn, "file does not exist %s", baseFn)
521- content, err = ioutil.ReadFile(baseFn)
522- if !assert.NoError(t, err, "ioutil.ReadFile should succeed") {
523- return
524- }
525- if !assert.Equal(t, "Hello, World!", string(content), "read %s from file %s, not expected Hello, World!", string(content), baseFn) {
526- return
527- }
528- }
529- })
530-}
531-
--- a/vendor/github.com/lestrrat-go/strftime/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
1-# Compiled Object files, Static and Dynamic libs (Shared Objects)
2-*.o
3-*.a
4-*.so
5-
6-# Folders
7-_obj
8-_test
9-
10-# Architecture specific extensions/prefixes
11-*.[568vq]
12-[568vq].out
13-
14-*.cgo1.go
15-*.cgo2.c
16-_cgo_defun.c
17-_cgo_gotypes.go
18-_cgo_export.*
19-
20-_testmain.go
21-
22-*.exe
23-*.test
24-*.prof
--- a/vendor/github.com/lestrrat-go/strftime/.travis.yml
+++ /dev/null
@@ -1,5 +0,0 @@
1-language: go
2-sudo: false
3-go:
4- - 1.7.x
5- - tip
\ No newline at end of file
--- a/vendor/github.com/lestrrat-go/strftime/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
1-MIT License
2-
3-Copyright (c) 2016 lestrrat
4-
5-Permission is hereby granted, free of charge, to any person obtaining a copy
6-of this software and associated documentation files (the "Software"), to deal
7-in the Software without restriction, including without limitation the rights
8-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9-copies of the Software, and to permit persons to whom the Software is
10-furnished to do so, subject to the following conditions:
11-
12-The above copyright notice and this permission notice shall be included in all
13-copies or substantial portions of the Software.
14-
15-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-SOFTWARE.
--- a/vendor/github.com/lestrrat-go/strftime/README.md
+++ /dev/null
@@ -1,151 +0,0 @@
1-# strftime
2-
3-Fast strftime for Go
4-
5-[![Build Status](https://travis-ci.org/lestrrat-go/strftime.png?branch=master)](https://travis-ci.org/lestrrat-go/strftime)
6-
7-[![GoDoc](https://godoc.org/github.com/lestrrat-go/strftime?status.svg)](https://godoc.org/github.com/lestrrat-go/strftime)
8-
9-# SYNOPSIS
10-
11-```go
12-f := strftime.New(`.... pattern ...`)
13-if err := f.Format(buf, time.Now()); err != nil {
14- log.Println(err.Error())
15-}
16-```
17-
18-# DESCRIPTION
19-
20-The goals for this library are
21-
22-* Optimized for the same pattern being called repeatedly
23-* Be flexible about destination to write the results out
24-* Be as complete as possible in terms of conversion specifications
25-
26-# API
27-
28-## Format(string, time.Time) (string, error)
29-
30-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.
31-
32-## New(string) (\*Strftime, error)
33-
34-Takes the pattern and creates a new `Strftime` object.
35-
36-## obj.Pattern() string
37-
38-Returns the pattern string used to create this `Strftime` object
39-
40-## obj.Format(io.Writer, time.Time) error
41-
42-Formats the time according to the pre-compiled pattern, and writes the result to the specified `io.Writer`
43-
44-## obj.FormatString(time.Time) string
45-
46-Formats the time according to the pre-compiled pattern, and returns the result string.
47-
48-# SUPPORTED CONVERSION SPECIFICATIONS
49-
50-| pattern | description |
51-|:--------|:------------|
52-| %A | national representation of the full weekday name |
53-| %a | national representation of the abbreviated weekday |
54-| %B | national representation of the full month name |
55-| %b | national representation of the abbreviated month name |
56-| %C | (year / 100) as decimal number; single digits are preceded by a zero |
57-| %c | national representation of time and date |
58-| %D | equivalent to %m/%d/%y |
59-| %d | day of the month as a decimal number (01-31) |
60-| %e | the day of the month as a decimal number (1-31); single digits are preceded by a blank |
61-| %F | equivalent to %Y-%m-%d |
62-| %H | the hour (24-hour clock) as a decimal number (00-23) |
63-| %h | same as %b |
64-| %I | the hour (12-hour clock) as a decimal number (01-12) |
65-| %j | the day of the year as a decimal number (001-366) |
66-| %k | the hour (24-hour clock) as a decimal number (0-23); single digits are preceded by a blank |
67-| %l | the hour (12-hour clock) as a decimal number (1-12); single digits are preceded by a blank |
68-| %M | the minute as a decimal number (00-59) |
69-| %m | the month as a decimal number (01-12) |
70-| %n | a newline |
71-| %p | national representation of either "ante meridiem" (a.m.) or "post meridiem" (p.m.) as appropriate. |
72-| %R | equivalent to %H:%M |
73-| %r | equivalent to %I:%M:%S %p |
74-| %S | the second as a decimal number (00-60) |
75-| %T | equivalent to %H:%M:%S |
76-| %t | a tab |
77-| %U | the week number of the year (Sunday as the first day of the week) as a decimal number (00-53) |
78-| %u | the weekday (Monday as the first day of the week) as a decimal number (1-7) |
79-| %V | the week number of the year (Monday as the first day of the week) as a decimal number (01-53) |
80-| %v | equivalent to %e-%b-%Y |
81-| %W | the week number of the year (Monday as the first day of the week) as a decimal number (00-53) |
82-| %w | the weekday (Sunday as the first day of the week) as a decimal number (0-6) |
83-| %X | national representation of the time |
84-| %x | national representation of the date |
85-| %Y | the year with century as a decimal number |
86-| %y | the year without century as a decimal number (00-99) |
87-| %Z | the time zone name |
88-| %z | the time zone offset from UTC |
89-| %% | a '%' |
90-
91-# PERFORMANCE / OTHER LIBRARIES
92-
93-The following benchmarks were run separately because some libraries were using cgo on specific platforms (notabley, the fastly version)
94-
95-```
96-// On my OS X 10.11.6, 2.9 GHz Intel Core i5, 16GB memory.
97-// go version go1.8rc1 darwin/amd64
98-hummingbird% go test -tags bench -benchmem -bench .
99-<snip>
100-BenchmarkTebeka-4 300000 4469 ns/op 288 B/op 21 allocs/op
101-BenchmarkJehiah-4 1000000 1931 ns/op 256 B/op 17 allocs/op
102-BenchmarkFastly-4 2000000 724 ns/op 80 B/op 5 allocs/op
103-BenchmarkLestrrat-4 1000000 1572 ns/op 240 B/op 3 allocs/op
104-BenchmarkLestrratCachedString-4 3000000 548 ns/op 128 B/op 2 allocs/op
105-BenchmarkLestrratCachedWriter-4 500000 2519 ns/op 192 B/op 3 allocs/op
106-PASS
107-ok github.com/lestrrat-go/strftime 22.900s
108-```
109-
110-```
111-// On a host on Google Cloud Platform, machine-type: n1-standard-4 (vCPU x 4, memory: 15GB)
112-// Linux <snip> 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u2 (2016-10-19) x86_64 GNU/Linux
113-// go version go1.8rc1 linux/amd64
114-hummingbird% go test -tags bench -benchmem -bench .
115-<snip>
116-BenchmarkTebeka-4 500000 3904 ns/op 288 B/op 21 allocs/op
117-BenchmarkJehiah-4 1000000 1665 ns/op 256 B/op 17 allocs/op
118-BenchmarkFastly-4 1000000 2134 ns/op 192 B/op 13 allocs/op
119-BenchmarkLestrrat-4 1000000 1327 ns/op 240 B/op 3 allocs/op
120-BenchmarkLestrratCachedString-4 3000000 498 ns/op 128 B/op 2 allocs/op
121-BenchmarkLestrratCachedWriter-4 1000000 3390 ns/op 192 B/op 3 allocs/op
122-PASS
123-ok github.com/lestrrat-go/strftime 44.854s
124-```
125-
126-This library is much faster than other libraries *IF* you can reuse the format pattern.
127-
128-Here's the annotated list from the benchmark results. You can clearly see that (re)using a `Strftime` object
129-and producing a string is the fastest. Writing to an `io.Writer` seems a bit sluggish, but since
130-the one producing the string is doing almost exactly the same thing, we believe this is purely the overhead of
131-writing to an `io.Writer`
132-
133-| Import Path | Score | Note |
134-|:------------------------------------|--------:|:--------------------------------|
135-| github.com/lestrrat-go/strftime | 3000000 | Using `FormatString()` (cached) |
136-| github.com/fastly/go-utils/strftime | 2000000 | Pure go version on OS X |
137-| github.com/lestrrat-go/strftime | 1000000 | Using `Format()` (NOT cached) |
138-| github.com/jehiah/go-strftime | 1000000 | |
139-| github.com/fastly/go-utils/strftime | 1000000 | cgo version on Linux |
140-| github.com/lestrrat-go/strftime | 500000 | Using `Format()` (cached) |
141-| github.com/tebeka/strftime | 300000 | |
142-
143-However, depending on your pattern, this speed may vary. If you find a particular pattern that seems sluggish,
144-please send in patches or tests.
145-
146-Please also note that this benchmark only uses the subset of conversion specifications that are supported by *ALL* of the libraries compared.
147-
148-Somethings to consider when making performance comparisons in the future:
149-
150-* Can it write to io.Writer?
151-* Which `%specification` does it handle?
--- a/vendor/github.com/lestrrat-go/strftime/internal_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
1-package strftime
2-
3-import (
4- "testing"
5-
6- "github.com/stretchr/testify/assert"
7-)
8-
9-func TestCombine(t *testing.T) {
10- {
11- s, _ := New(`%A foo`)
12- if !assert.Equal(t, 1, len(s.compiled), "there are 1 element") {
13- return
14- }
15- }
16- {
17- s, _ := New(`%A 100`)
18- if !assert.Equal(t, 2, len(s.compiled), "there are two elements") {
19- return
20- }
21- }
22- {
23- s, _ := New(`%A Mon`)
24- if !assert.Equal(t, 2, len(s.compiled), "there are two elements") {
25- return
26- }
27- }
28-}
--- a/vendor/github.com/lestrrat-go/strftime/strftime.go
+++ /dev/null
@@ -1,219 +0,0 @@
1-package strftime
2-
3-import (
4- "io"
5- "strings"
6- "time"
7-
8- "github.com/pkg/errors"
9-)
10-
11-var directives = map[byte]appender{
12- 'A': timefmt("Monday"),
13- 'a': timefmt("Mon"),
14- 'B': timefmt("January"),
15- 'b': timefmt("Jan"),
16- 'C': &century{},
17- 'c': timefmt("Mon Jan _2 15:04:05 2006"),
18- 'D': timefmt("01/02/06"),
19- 'd': timefmt("02"),
20- 'e': timefmt("_2"),
21- 'F': timefmt("2006-01-02"),
22- 'H': timefmt("15"),
23- 'h': timefmt("Jan"), // same as 'b'
24- 'I': timefmt("3"),
25- 'j': &dayofyear{},
26- 'k': hourwblank(false),
27- 'l': hourwblank(true),
28- 'M': timefmt("04"),
29- 'm': timefmt("01"),
30- 'n': verbatim("\n"),
31- 'p': timefmt("PM"),
32- 'R': timefmt("15:04"),
33- 'r': timefmt("3:04:05 PM"),
34- 'S': timefmt("05"),
35- 'T': timefmt("15:04:05"),
36- 't': verbatim("\t"),
37- 'U': weeknumberOffset(0), // week number of the year, Sunday first
38- 'u': weekday(1),
39- 'V': &weeknumber{},
40- 'v': timefmt("_2-Jan-2006"),
41- 'W': weeknumberOffset(1), // week number of the year, Monday first
42- 'w': weekday(0),
43- 'X': timefmt("15:04:05"), // national representation of the time XXX is this correct?
44- 'x': timefmt("01/02/06"), // national representation of the date XXX is this correct?
45- 'Y': timefmt("2006"), // year with century
46- 'y': timefmt("06"), // year w/o century
47- 'Z': timefmt("MST"), // time zone name
48- 'z': timefmt("-0700"), // time zone ofset from UTC
49- '%': verbatim("%"),
50-}
51-
52-type combiningAppend struct {
53- list appenderList
54- prev appender
55- prevCanCombine bool
56-}
57-
58-func (ca *combiningAppend) Append(w appender) {
59- if ca.prevCanCombine {
60- if wc, ok := w.(combiner); ok && wc.canCombine() {
61- ca.prev = ca.prev.(combiner).combine(wc)
62- ca.list[len(ca.list)-1] = ca.prev
63- return
64- }
65- }
66-
67- ca.list = append(ca.list, w)
68- ca.prev = w
69- ca.prevCanCombine = false
70- if comb, ok := w.(combiner); ok {
71- if comb.canCombine() {
72- ca.prevCanCombine = true
73- }
74- }
75-}
76-
77-func compile(wl *appenderList, p string) error {
78- var ca combiningAppend
79- for l := len(p); l > 0; l = len(p) {
80- i := strings.IndexByte(p, '%')
81- if i < 0 {
82- ca.Append(verbatim(p))
83- // this is silly, but I don't trust break keywords when there's a
84- // possibility of this piece of code being rearranged
85- p = p[l:]
86- continue
87- }
88- if i == l-1 {
89- return errors.New(`stray % at the end of pattern`)
90- }
91-
92- // we found a '%'. we need the next byte to decide what to do next
93- // we already know that i < l - 1
94- // everything up to the i is verbatim
95- if i > 0 {
96- ca.Append(verbatim(p[:i]))
97- p = p[i:]
98- }
99-
100- directive, ok := directives[p[1]]
101- if !ok {
102- return errors.Errorf(`unknown time format specification '%c'`, p[1])
103- }
104- ca.Append(directive)
105- p = p[2:]
106- }
107-
108- *wl = ca.list
109-
110- return nil
111-}
112-
113-// Format takes the format `s` and the time `t` to produce the
114-// format date/time. Note that this function re-compiles the
115-// pattern every time it is called.
116-//
117-// If you know beforehand that you will be reusing the pattern
118-// within your application, consider creating a `Strftime` object
119-// and reusing it.
120-func Format(p string, t time.Time) (string, error) {
121- var dst []byte
122- // TODO: optimize for 64 byte strings
123- dst = make([]byte, 0, len(p)+10)
124- // Compile, but execute as we go
125- for l := len(p); l > 0; l = len(p) {
126- i := strings.IndexByte(p, '%')
127- if i < 0 {
128- dst = append(dst, p...)
129- // this is silly, but I don't trust break keywords when there's a
130- // possibility of this piece of code being rearranged
131- p = p[l:]
132- continue
133- }
134- if i == l-1 {
135- return "", errors.New(`stray % at the end of pattern`)
136- }
137-
138- // we found a '%'. we need the next byte to decide what to do next
139- // we already know that i < l - 1
140- // everything up to the i is verbatim
141- if i > 0 {
142- dst = append(dst, p[:i]...)
143- p = p[i:]
144- }
145-
146- directive, ok := directives[p[1]]
147- if !ok {
148- return "", errors.Errorf(`unknown time format specification '%c'`, p[1])
149- }
150- dst = directive.Append(dst, t)
151- p = p[2:]
152- }
153-
154- return string(dst), nil
155-}
156-
157-// Strftime is the object that represents a compiled strftime pattern
158-type Strftime struct {
159- pattern string
160- compiled appenderList
161-}
162-
163-// New creates a new Strftime object. If the compilation fails, then
164-// an error is returned in the second argument.
165-func New(f string) (*Strftime, error) {
166- var wl appenderList
167- if err := compile(&wl, f); err != nil {
168- return nil, errors.Wrap(err, `failed to compile format`)
169- }
170- return &Strftime{
171- pattern: f,
172- compiled: wl,
173- }, nil
174-}
175-
176-// Pattern returns the original pattern string
177-func (f *Strftime) Pattern() string {
178- return f.pattern
179-}
180-
181-// Format takes the destination `dst` and time `t`. It formats the date/time
182-// using the pre-compiled pattern, and outputs the results to `dst`
183-func (f *Strftime) Format(dst io.Writer, t time.Time) error {
184- const bufSize = 64
185- var b []byte
186- max := len(f.pattern) + 10
187- if max < bufSize {
188- var buf [bufSize]byte
189- b = buf[:0]
190- } else {
191- b = make([]byte, 0, max)
192- }
193- if _, err := dst.Write(f.format(b, t)); err != nil {
194- return err
195- }
196- return nil
197-}
198-
199-func (f *Strftime) format(b []byte, t time.Time) []byte {
200- for _, w := range f.compiled {
201- b = w.Append(b, t)
202- }
203- return b
204-}
205-
206-// FormatString takes the time `t` and formats it, returning the
207-// string containing the formated data.
208-func (f *Strftime) FormatString(t time.Time) string {
209- const bufSize = 64
210- var b []byte
211- max := len(f.pattern) + 10
212- if max < bufSize {
213- var buf [bufSize]byte
214- b = buf[:0]
215- } else {
216- b = make([]byte, 0, max)
217- }
218- return string(f.format(b, t))
219-}
--- a/vendor/github.com/lestrrat-go/strftime/strftime_bench_test.go
+++ /dev/null
@@ -1,80 +0,0 @@
1-// +build bench
2-
3-package strftime_test
4-
5-import (
6- "bytes"
7- "log"
8- "net/http"
9- _ "net/http/pprof"
10- "testing"
11- "time"
12-
13- jehiah "github.com/jehiah/go-strftime"
14- fastly "github.com/fastly/go-utils/strftime"
15- lestrrat "github.com/lestrrat-go/strftime"
16- tebeka "github.com/tebeka/strftime"
17-)
18-
19-func init() {
20- go func() {
21- log.Println(http.ListenAndServe("localhost:8080", nil))
22- }()
23-}
24-
25-const benchfmt = `%A %a %B %b %d %H %I %M %m %p %S %Y %y %Z`
26-
27-func BenchmarkTebeka(b *testing.B) {
28- var t time.Time
29- for i := 0; i < b.N; i++ {
30- tebeka.Format(benchfmt, t)
31- }
32-}
33-
34-func BenchmarkJehiah(b *testing.B) {
35- // Grr, uses byte slices, and does it faster, but with more allocs
36- var t time.Time
37- for i := 0; i < b.N; i++ {
38- jehiah.Format(benchfmt, t)
39- }
40-}
41-
42-func BenchmarkFastly(b *testing.B) {
43- var t time.Time
44- for i := 0; i < b.N; i++ {
45- fastly.Strftime(benchfmt, t)
46- }
47-}
48-
49-func BenchmarkLestrrat(b *testing.B) {
50- var t time.Time
51- for i := 0; i < b.N; i++ {
52- lestrrat.Format(benchfmt, t)
53- }
54-}
55-
56-func BenchmarkLestrratCachedString(b *testing.B) {
57- var t time.Time
58- f, _ := lestrrat.New(benchfmt)
59- // This benchmark does not take into effect the compilation time
60- for i := 0; i < b.N; i++ {
61- f.FormatString(t)
62- }
63-}
64-
65-func BenchmarkLestrratCachedWriter(b *testing.B) {
66- var t time.Time
67- f, _ := lestrrat.New(benchfmt)
68- var buf bytes.Buffer
69- b.ResetTimer()
70-
71- // This benchmark does not take into effect the compilation time
72- // nor the buffer reset time
73- for i := 0; i < b.N; i++ {
74- b.StopTimer()
75- buf.Reset()
76- b.StartTimer()
77- f.Format(&buf, t)
78- f.FormatString(t)
79- }
80-}
--- a/vendor/github.com/lestrrat-go/strftime/strftime_test.go
+++ /dev/null
@@ -1,148 +0,0 @@
1-package strftime_test
2-
3-import (
4- "os"
5- "testing"
6- "time"
7-
8- envload "github.com/lestrrat-go/envload"
9- "github.com/lestrrat-go/strftime"
10- "github.com/stretchr/testify/assert"
11-)
12-
13-var ref = time.Unix(1136239445, 0).UTC()
14-
15-func TestExclusion(t *testing.T) {
16- s, err := strftime.New("%p PM")
17- if !assert.NoError(t, err, `strftime.New should succeed`) {
18- return
19- }
20-
21- var tm time.Time
22- if !assert.Equal(t, "AM PM", s.FormatString(tm)) {
23- return
24- }
25-}
26-
27-func TestInvalid(t *testing.T) {
28- _, err := strftime.New("%")
29- if !assert.Error(t, err, `strftime.New should return error`) {
30- return
31- }
32-
33- _, err = strftime.New(" %")
34- if !assert.Error(t, err, `strftime.New should return error`) {
35- return
36- }
37- _, err = strftime.New(" % ")
38- if !assert.Error(t, err, `strftime.New should return error`) {
39- return
40- }
41-}
42-
43-func TestFormat(t *testing.T) {
44- l := envload.New()
45- defer l.Restore()
46-
47- os.Setenv("LC_ALL", "C")
48-
49- 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)
50- if !assert.NoError(t, err, `strftime.Format succeeds`) {
51- return
52- }
53-
54- 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`) {
55- return
56- }
57-}
58-
59-func TestFormatBlanks(t *testing.T) {
60- l := envload.New()
61- defer l.Restore()
62-
63- os.Setenv("LC_ALL", "C")
64-
65- {
66- dt := time.Date(1, 1, 1, 18, 0, 0, 0, time.UTC)
67- s, err := strftime.Format("%l", dt)
68- if !assert.NoError(t, err, `strftime.Format succeeds`) {
69- return
70- }
71-
72- if !assert.Equal(t, " 6", s, "leading blank is properly set") {
73- return
74- }
75- }
76- {
77- dt := time.Date(1, 1, 1, 6, 0, 0, 0, time.UTC)
78- s, err := strftime.Format("%k", dt)
79- if !assert.NoError(t, err, `strftime.Format succeeds`) {
80- return
81- }
82-
83- if !assert.Equal(t, " 6", s, "leading blank is properly set") {
84- return
85- }
86- }
87-}
88-
89-func TestFormatZeropad(t *testing.T) {
90- l := envload.New()
91- defer l.Restore()
92-
93- os.Setenv("LC_ALL", "C")
94-
95- {
96- dt := time.Date(1, 1, 1, 1, 0, 0, 0, time.UTC)
97- s, err := strftime.Format("%j", dt)
98- if !assert.NoError(t, err, `strftime.Format succeeds`) {
99- return
100- }
101-
102- if !assert.Equal(t, "001", s, "padding is properly set") {
103- return
104- }
105- }
106- {
107- dt := time.Date(1, 1, 10, 6, 0, 0, 0, time.UTC)
108- s, err := strftime.Format("%j", dt)
109- if !assert.NoError(t, err, `strftime.Format succeeds`) {
110- return
111- }
112-
113- if !assert.Equal(t, "010", s, "padding is properly set") {
114- return
115- }
116- }
117- {
118- dt := time.Date(1, 6, 1, 6, 0, 0, 0, time.UTC)
119- s, err := strftime.Format("%j", dt)
120- if !assert.NoError(t, err, `strftime.Format succeeds`) {
121- return
122- }
123-
124- if !assert.Equal(t, "152", s, "padding is properly set") {
125- return
126- }
127- }
128- {
129- dt := time.Date(100, 1, 1, 1, 0, 0, 0, time.UTC)
130- s, err := strftime.Format("%C", dt)
131- if !assert.NoError(t, err, `strftime.Format succeeds`) {
132- return
133- }
134-
135- if !assert.Equal(t, "01", s, "padding is properly set") {
136- return
137- }
138- }
139-}
140-
141-func TestGHIssue5(t *testing.T) {
142- const expected = `apm-test/logs/apm.log.01000101`
143- p, _ := strftime.New("apm-test/logs/apm.log.%Y%m%d")
144- dt := time.Date(100, 1, 1, 1, 0, 0, 0, time.UTC)
145- if !assert.Equal(t, expected, p.FormatString(dt), `patterns including 'pm' should be treated as verbatim formatter`) {
146- return
147- }
148-}
--- a/vendor/github.com/lestrrat-go/strftime/writer.go
+++ /dev/null
@@ -1,169 +0,0 @@
1-package strftime
2-
3-import (
4- "strconv"
5- "strings"
6- "time"
7-)
8-
9-type appender interface {
10- Append([]byte, time.Time) []byte
11-}
12-
13-type appenderList []appender
14-
15-// does the time.Format thing
16-type timefmtw struct {
17- s string
18-}
19-
20-func timefmt(s string) *timefmtw {
21- return &timefmtw{s: s}
22-}
23-
24-func (v timefmtw) Append(b []byte, t time.Time) []byte {
25- return t.AppendFormat(b, v.s)
26-}
27-
28-func (v timefmtw) str() string {
29- return v.s
30-}
31-
32-func (v timefmtw) canCombine() bool {
33- return true
34-}
35-
36-func (v timefmtw) combine(w combiner) appender {
37- return timefmt(v.s + w.str())
38-}
39-
40-type verbatimw struct {
41- s string
42-}
43-
44-func verbatim(s string) *verbatimw {
45- return &verbatimw{s: s}
46-}
47-
48-func (v verbatimw) Append(b []byte, _ time.Time) []byte {
49- return append(b, v.s...)
50-}
51-
52-func (v verbatimw) canCombine() bool {
53- return canCombine(v.s)
54-}
55-
56-func (v verbatimw) combine(w combiner) appender {
57- if _, ok := w.(*timefmtw); ok {
58- return timefmt(v.s + w.str())
59- }
60- return verbatim(v.s + w.str())
61-}
62-
63-func (v verbatimw) str() string {
64- return v.s
65-}
66-
67-// These words below, as well as any decimal character
68-var combineExclusion = []string{
69- "Mon",
70- "Monday",
71- "Jan",
72- "January",
73- "MST",
74- "PM",
75- "pm",
76-}
77-
78-func canCombine(s string) bool {
79- if strings.ContainsAny(s, "0123456789") {
80- return false
81- }
82- for _, word := range combineExclusion {
83- if strings.Contains(s, word) {
84- return false
85- }
86- }
87- return true
88-}
89-
90-type combiner interface {
91- canCombine() bool
92- combine(combiner) appender
93- str() string
94-}
95-
96-type century struct{}
97-
98-func (v century) Append(b []byte, t time.Time) []byte {
99- n := t.Year() / 100
100- if n < 10 {
101- b = append(b, '0')
102- }
103- return append(b, strconv.Itoa(n)...)
104-}
105-
106-type weekday int
107-
108-func (v weekday) Append(b []byte, t time.Time) []byte {
109- n := int(t.Weekday())
110- if n < int(v) {
111- n += 7
112- }
113- return append(b, byte(n+48))
114-}
115-
116-type weeknumberOffset int
117-
118-func (v weeknumberOffset) Append(b []byte, t time.Time) []byte {
119- yd := t.YearDay()
120- offset := int(t.Weekday()) - int(v)
121- if offset < 0 {
122- offset += 7
123- }
124-
125- if yd < offset {
126- return append(b, '0', '0')
127- }
128-
129- n := ((yd - offset) / 7) + 1
130- if n < 10 {
131- b = append(b, '0')
132- }
133- return append(b, strconv.Itoa(n)...)
134-}
135-
136-type weeknumber struct{}
137-
138-func (v weeknumber) Append(b []byte, t time.Time) []byte {
139- _, n := t.ISOWeek()
140- if n < 10 {
141- b = append(b, '0')
142- }
143- return append(b, strconv.Itoa(n)...)
144-}
145-
146-type dayofyear struct{}
147-
148-func (v dayofyear) Append(b []byte, t time.Time) []byte {
149- n := t.YearDay()
150- if n < 10 {
151- b = append(b, '0', '0')
152- } else if n < 100 {
153- b = append(b, '0')
154- }
155- return append(b, strconv.Itoa(n)...)
156-}
157-
158-type hourwblank bool
159-
160-func (v hourwblank) Append(b []byte, t time.Time) []byte {
161- h := t.Hour()
162- if bool(v) && h > 12 {
163- h = h - 12
164- }
165- if h < 10 {
166- b = append(b, ' ')
167- }
168- return append(b, strconv.Itoa(h)...)
169-}
Show on old repository browser