fixed dependencies

This commit is contained in:
nuknal
2024-10-24 15:46:01 +08:00
parent d16a5bd9c0
commit 1161e8d054
2005 changed files with 690883 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
# 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

View File

@@ -0,0 +1,5 @@
language: go
sudo: false
go:
- "1.14"
- tip

View File

@@ -0,0 +1,8 @@
Changes
=======
v2.4.0 - 8 Sep 2020
* Add WithRotationSize option to specify log ration when
a certain file size is reached. (NOTE: this does not guarantee
that the file size is exactly the size specified, but that it
*exceeds* the specified size)

20
vendor/github.com/lestrrat-go/file-rotatelogs/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,20 @@
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.

233
vendor/github.com/lestrrat-go/file-rotatelogs/README.md generated vendored Normal file
View File

@@ -0,0 +1,233 @@
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 into your 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
```
Links that share the same parent directory with the main log path will get a
special treatment: namely, linked paths will be *RELATIVE* to the main log file.
| Main log file name | Link name | Linked path |
|---------------------|---------------------|-----------------------|
| /path/to/log.%Y%m%d | /path/to/log | log.YYYYMMDD |
| /path/to/log.%Y%m%d | /path/to/nested/log | ../log.YYYYMMDD |
| /path/to/log.%Y%m%d | /foo/bar/baz/log | /path/to/log.YYYYMMDD |
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(),
)
```
# 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.

17
vendor/github.com/lestrrat-go/file-rotatelogs/event.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
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
}

View File

@@ -0,0 +1,73 @@
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
rotationSize int64
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{}
}

View File

@@ -0,0 +1,25 @@
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
}

View File

@@ -0,0 +1,89 @@
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"
optkeyRotationSize = "rotation-size"
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)
}
// WithRotationSize creates a new Option that sets the
// log file size between rotation.
func WithRotationSize(s int64) Option {
return option.New(optkeyRotationSize, s)
}
// 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)
}

View File

@@ -0,0 +1,407 @@
// 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 rotationSize int64
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 optkeyRotationSize:
rotationSize = o.Value().(int64)
if rotationSize < 0 {
rotationSize = 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,
rotationSize: rotationSize,
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
fi, err := os.Stat(rl.curFn)
sizeRotation := false
if err == nil && rl.rotationSize > 0 && rl.rotationSize <= fi.Size() {
forceNewFile = true
sizeRotation = true
}
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 && !sizeRotation {
// 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`
// Change how the link name is generated based on where the
// target location is. if the location is directly underneath
// the main filename's parent directory, then we create a
// symlink with a relative path
linkDest := filename
linkDir := filepath.Dir(rl.linkName)
baseDir := filepath.Dir(filename)
if strings.Contains(rl.linkName, baseDir) {
tmp, err := filepath.Rel(linkDir, filename)
if err != nil {
return errors.Wrapf(err, `failed to evaluate relative path from %#v to %#v`, baseDir, rl.linkName)
}
linkDest = tmp
}
if err := os.Symlink(linkDest, tmpLinkName); err != nil {
return errors.Wrap(err, `failed to create new symlink`)
}
// the directory where rl.linkName should be created must exist
_, err := os.Stat(linkDir)
if err != nil { // Assume err != nil means the directory doesn't exist
if err := os.MkdirAll(linkDir, 0755); err != nil {
return errors.Wrapf(err, `failed to create directory %s`, linkDir)
}
}
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
}