Add library and command for human-readable logs (#9809)
* Update logrus to 1.2 and add as a direct dependency * Create an mlog/human package for pretty-printing logs This package can read JSON logs from mattermost.log, and output the data to either logrus or a custom formatter, to make the logs more human readable. * Create a command for outputting human-readable logs This command will read JSON data from mattermost.log or stdin, and output in a human readable format. An optional argument can be used to activate logrus output (which includes color support). * Reorganize code in mlog/human and improve logrus timestamp formatting
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
e67d89b9a8
Коммит
8d56fcf568
7
Gopkg.lock
сгенерированный
7
Gopkg.lock
сгенерированный
@@ -641,12 +641,12 @@
|
|||||||
revision = "204274ad699c0983a70203a566887f17a717fef4"
|
revision = "204274ad699c0983a70203a566887f17a717fef4"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:dc2d85c13ac22c22a1f3170a41a8e1b897fa05134aaf533f16df44f66a25b4a1"
|
digest = "1:69b1cc331fca23d702bd72f860c6a647afd0aa9fcbc1d0659b1365e26546dd70"
|
||||||
name = "github.com/sirupsen/logrus"
|
name = "github.com/sirupsen/logrus"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "a67f783a3814b8729bd2dac5780b5f78f8dbd64d"
|
revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95"
|
||||||
version = "v1.1.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:6a4a11ba764a56d2758899ec6f3848d24698d48442ebce85ee7a3f63284526cd"
|
digest = "1:6a4a11ba764a56d2758899ec6f3848d24698d48442ebce85ee7a3f63284526cd"
|
||||||
@@ -1031,6 +1031,7 @@
|
|||||||
"github.com/rs/cors",
|
"github.com/rs/cors",
|
||||||
"github.com/rwcarlsen/goexif/exif",
|
"github.com/rwcarlsen/goexif/exif",
|
||||||
"github.com/segmentio/analytics-go",
|
"github.com/segmentio/analytics-go",
|
||||||
|
"github.com/sirupsen/logrus",
|
||||||
"github.com/spf13/cobra",
|
"github.com/spf13/cobra",
|
||||||
"github.com/stretchr/testify/assert",
|
"github.com/stretchr/testify/assert",
|
||||||
"github.com/stretchr/testify/mock",
|
"github.com/stretchr/testify/mock",
|
||||||
|
|||||||
@@ -61,3 +61,7 @@
|
|||||||
[prune]
|
[prune]
|
||||||
go-tests = true
|
go-tests = true
|
||||||
unused-packages = true
|
unused-packages = true
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/sirupsen/logrus"
|
||||||
|
version = "1.2.0"
|
||||||
|
|||||||
52
cmd/mattermost/commands/logs.go
Обычный файл
52
cmd/mattermost/commands/logs.go
Обычный файл
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mattermost/mattermost-server/mlog/human"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var LogsCmd = &cobra.Command{
|
||||||
|
Use: "logs",
|
||||||
|
Short: "Display logs in a human-readable format",
|
||||||
|
RunE: logsCmdF,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
LogsCmd.Flags().Bool("logrus", false, "Use logrus for formatting.")
|
||||||
|
RootCmd.AddCommand(LogsCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func logsCmdF(command *cobra.Command, args []string) error {
|
||||||
|
// check stdin to see if we have a pipe
|
||||||
|
fi, err := os.Stdin.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var input io.Reader
|
||||||
|
if fi.Size() == 0 && fi.Mode()&os.ModeNamedPipe == 0 {
|
||||||
|
file, err := os.Open("mattermost.log")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
input = file
|
||||||
|
} else {
|
||||||
|
input = os.Stdin
|
||||||
|
}
|
||||||
|
var writer human.LogWriter
|
||||||
|
|
||||||
|
if flag, _ := command.Flags().GetBool("logrus"); flag {
|
||||||
|
writer = human.NewLogrusWriter(os.Stdout)
|
||||||
|
} else {
|
||||||
|
writer = human.NewSimpleWriter(os.Stdout)
|
||||||
|
}
|
||||||
|
human.ProcessLogs(input, writer)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
51
mlog/human/entry.go
Обычный файл
51
mlog/human/entry.go
Обычный файл
@@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
package human
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/mattermost/mattermost-server/mlog"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogEntry struct {
|
||||||
|
Time time.Time
|
||||||
|
Level string
|
||||||
|
Message string
|
||||||
|
Caller string
|
||||||
|
Fields []mlog.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide default string representation. Used by SimpleWriter
|
||||||
|
func (f LogEntry) String() string {
|
||||||
|
var sb strings.Builder
|
||||||
|
if !f.Time.IsZero() {
|
||||||
|
sb.WriteString(f.Time.Format(time.RFC3339Nano))
|
||||||
|
sb.WriteRune(' ')
|
||||||
|
}
|
||||||
|
if f.Level != "" {
|
||||||
|
sb.WriteString(f.Level)
|
||||||
|
sb.WriteRune(' ')
|
||||||
|
}
|
||||||
|
if f.Caller != "" {
|
||||||
|
sb.WriteString(f.Caller)
|
||||||
|
sb.WriteRune(' ')
|
||||||
|
}
|
||||||
|
for _, field := range f.Fields {
|
||||||
|
sb.WriteString(field.Key)
|
||||||
|
sb.WriteRune('=')
|
||||||
|
sb.WriteString(fmt.Sprint(field.Interface))
|
||||||
|
sb.WriteRune(' ')
|
||||||
|
}
|
||||||
|
if f.Message != "" {
|
||||||
|
// If the message is multiple lines, start the whole message on a new line
|
||||||
|
if strings.ContainsRune(f.Message, '\n') {
|
||||||
|
sb.WriteRune('\n')
|
||||||
|
}
|
||||||
|
sb.WriteString(f.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
76
mlog/human/logrus_writer.go
Обычный файл
76
mlog/human/logrus_writer.go
Обычный файл
@@ -0,0 +1,76 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
package human
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogrusWriter struct {
|
||||||
|
logger *logrus.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *LogrusWriter) Write(e LogEntry) {
|
||||||
|
if e.Level == "" {
|
||||||
|
fmt.Fprintln(w.logger.Out, e.Message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lvl, err := logrus.ParseLevel(e.Level)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w.logger.Out, err)
|
||||||
|
lvl = logrus.TraceLevel + 1 // will invoke Println
|
||||||
|
}
|
||||||
|
|
||||||
|
logger := w.logger.WithTime(e.Time)
|
||||||
|
|
||||||
|
if e.Caller != "" {
|
||||||
|
// logrus has a system of reporting the caller, but there's no easy way to override it
|
||||||
|
logger = logger.WithField("caller", e.Caller)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, field := range e.Fields {
|
||||||
|
logger = logger.WithField(field.Key, field.Interface)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch lvl {
|
||||||
|
case logrus.PanicLevel:
|
||||||
|
// Prevent panic from causing us to exit
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
}()
|
||||||
|
logger.Panic(e.Message)
|
||||||
|
case logrus.FatalLevel:
|
||||||
|
logger.Fatal(e.Message)
|
||||||
|
case logrus.ErrorLevel:
|
||||||
|
logger.Error(e.Message)
|
||||||
|
case logrus.WarnLevel:
|
||||||
|
logger.Warn(e.Message)
|
||||||
|
case logrus.InfoLevel:
|
||||||
|
logger.Info(e.Message)
|
||||||
|
case logrus.DebugLevel:
|
||||||
|
logger.Debug(e.Message)
|
||||||
|
case logrus.TraceLevel:
|
||||||
|
logger.Trace(e.Message)
|
||||||
|
default:
|
||||||
|
logger.Println(e.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogrusWriter(output io.Writer) *LogrusWriter {
|
||||||
|
w := new(LogrusWriter)
|
||||||
|
w.logger = logrus.New()
|
||||||
|
w.logger.SetLevel(logrus.TraceLevel) // don't filter any logs
|
||||||
|
w.logger.ExitFunc = func(int) {} // prevent Fatal from causing us to exit
|
||||||
|
w.logger.SetReportCaller(false)
|
||||||
|
w.logger.SetOutput(output)
|
||||||
|
var tf logrus.TextFormatter
|
||||||
|
tf.FullTimestamp = true
|
||||||
|
tf.TimestampFormat = time.RFC3339Nano
|
||||||
|
w.logger.SetFormatter(&tf)
|
||||||
|
return w
|
||||||
|
}
|
||||||
180
mlog/human/parser.go
Обычный файл
180
mlog/human/parser.go
Обычный файл
@@ -0,0 +1,180 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
package human
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/mattermost/mattermost-server/mlog"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParseLogMessage(msg string) LogEntry {
|
||||||
|
result, err := parseLogMessage(msg)
|
||||||
|
if err != nil {
|
||||||
|
// If failed to parse, just output a LogEntry where all fields are blank, but Message is the original string
|
||||||
|
var result2 LogEntry
|
||||||
|
result2.Message = msg
|
||||||
|
return result2
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLogMessage(msg string) (result LogEntry, err error) {
|
||||||
|
|
||||||
|
// Note: This implementation uses a custom json decoding loop.
|
||||||
|
// The primary advantage of this versus decoding directly into a map is to
|
||||||
|
// preserve the order of the fields. This can be simplified if we end up
|
||||||
|
// having the formatter sort fields alphabetically (logrus does by default)
|
||||||
|
|
||||||
|
dec := json.NewDecoder(strings.NewReader(msg))
|
||||||
|
|
||||||
|
// look for an initial "{"
|
||||||
|
if token, err := dec.Token(); err != nil {
|
||||||
|
return result, err
|
||||||
|
} else {
|
||||||
|
d, ok := token.(json.Delim)
|
||||||
|
if !ok || d != '{' {
|
||||||
|
return result, errors.New(fmt.Sprintf("input is not a JSON object, found: %v", token))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read all key-value pairs
|
||||||
|
for dec.More() {
|
||||||
|
key, err := dec.Token()
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
if skey, ok := key.(string); !ok {
|
||||||
|
return result, errors.New("key is not a value string")
|
||||||
|
} else {
|
||||||
|
if !dec.More() {
|
||||||
|
return result, errors.New("missing value pair")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch skey {
|
||||||
|
case "ts":
|
||||||
|
var ts json.Number
|
||||||
|
if err := dec.Decode(&ts); err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
if time, err := numberToTime(ts); err != nil {
|
||||||
|
return result, err
|
||||||
|
} else {
|
||||||
|
result.Time = time
|
||||||
|
}
|
||||||
|
|
||||||
|
case "level":
|
||||||
|
if s, err := decodeAsString(dec); err != nil {
|
||||||
|
return result, err
|
||||||
|
} else {
|
||||||
|
result.Level = s
|
||||||
|
}
|
||||||
|
|
||||||
|
case "msg":
|
||||||
|
if s, err := decodeAsString(dec); err != nil {
|
||||||
|
return result, err
|
||||||
|
} else {
|
||||||
|
result.Message = s
|
||||||
|
}
|
||||||
|
|
||||||
|
case "caller":
|
||||||
|
if s, err := decodeAsString(dec); err != nil {
|
||||||
|
return result, err
|
||||||
|
} else {
|
||||||
|
result.Caller = s
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
var p interface{}
|
||||||
|
if err := dec.Decode(&p); err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
var f mlog.Field
|
||||||
|
f.Key = skey
|
||||||
|
f.Interface = p
|
||||||
|
result.Fields = append(result.Fields, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the "}"
|
||||||
|
if token, err := dec.Token(); err != nil {
|
||||||
|
return result, err
|
||||||
|
} else {
|
||||||
|
d, ok := token.(json.Delim)
|
||||||
|
if !ok || d != '}' {
|
||||||
|
return result, errors.New(fmt.Sprintf("failed to read '}', read: %v", token))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure nothing else trailing
|
||||||
|
if token, err := dec.Token(); err != io.EOF {
|
||||||
|
return result, err
|
||||||
|
} else if token != nil {
|
||||||
|
return result, errors.New("found trailing data")
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate a number into a time
|
||||||
|
func numberToTime(v json.Number) (time.Time, error) {
|
||||||
|
// Using floating point math to extract the nanoseconds leads to a time that doesn't exactly match the input
|
||||||
|
// Instead, parse out the components from the string representation
|
||||||
|
|
||||||
|
var t time.Time
|
||||||
|
|
||||||
|
// First make sure it is a number...
|
||||||
|
flt, err := v.Float64()
|
||||||
|
if err != nil {
|
||||||
|
return t, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s := v.String()
|
||||||
|
|
||||||
|
if strings.ContainsAny(s, "eE") {
|
||||||
|
// input is in scientific notation. Convert to standard decimal notation
|
||||||
|
s = strconv.FormatFloat(flt, 'f', -1, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract the seconds and nanoseconds separately
|
||||||
|
var nanos, sec int64
|
||||||
|
|
||||||
|
parts := strings.SplitN(s, ".", 2)
|
||||||
|
sec, err = strconv.ParseInt(parts[0], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return t, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(parts) == 2 {
|
||||||
|
nanosText := parts[1] + "000000000"
|
||||||
|
nanosText = nanosText[:9]
|
||||||
|
nanos, err = strconv.ParseInt(nanosText, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return t, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t = time.Unix(sec, nanos)
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decodes a value from JSON, coercing it to a string value as necessary
|
||||||
|
func decodeAsString(dec *json.Decoder) (s string, err error) {
|
||||||
|
var v interface{}
|
||||||
|
if err = dec.Decode(&v); err != nil {
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
var ok bool
|
||||||
|
if s, ok = v.(string); ok {
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
s = fmt.Sprint(v)
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
23
mlog/human/process.go
Обычный файл
23
mlog/human/process.go
Обычный файл
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
package human
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogWriter interface {
|
||||||
|
Write(e LogEntry)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read JSON logs from input and write formatted logs to the output
|
||||||
|
func ProcessLogs(reader io.Reader, writer LogWriter) {
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
for scanner.Scan() {
|
||||||
|
s := scanner.Text()
|
||||||
|
e := ParseLogMessage(s)
|
||||||
|
writer.Write(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
23
mlog/human/simple_writer.go
Обычный файл
23
mlog/human/simple_writer.go
Обычный файл
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
package human
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SimpleWriter struct {
|
||||||
|
out io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *SimpleWriter) Write(e LogEntry) {
|
||||||
|
fmt.Fprintln(w.out, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSimpleWriter(out io.Writer) *SimpleWriter {
|
||||||
|
w := new(SimpleWriter)
|
||||||
|
w.out = out
|
||||||
|
return w
|
||||||
|
}
|
||||||
1
vendor/github.com/sirupsen/logrus/.gitignore
сгенерированный
поставляемый
1
vendor/github.com/sirupsen/logrus/.gitignore
сгенерированный
поставляемый
@@ -1 +1,2 @@
|
|||||||
logrus
|
logrus
|
||||||
|
vendor
|
||||||
|
|||||||
12
vendor/github.com/sirupsen/logrus/CHANGELOG.md
сгенерированный
поставляемый
12
vendor/github.com/sirupsen/logrus/CHANGELOG.md
сгенерированный
поставляемый
@@ -1,3 +1,15 @@
|
|||||||
|
# 1.2.0
|
||||||
|
This new release introduces:
|
||||||
|
* A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued
|
||||||
|
* A new trace level named `Trace` whose level is below `Debug`
|
||||||
|
* A configurable exit function to be called upon a Fatal trace
|
||||||
|
* The `Level` object now implements `encoding.TextUnmarshaler` interface
|
||||||
|
|
||||||
|
# 1.1.1
|
||||||
|
This is a bug fix release.
|
||||||
|
* fix the build break on Solaris
|
||||||
|
* don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized
|
||||||
|
|
||||||
# 1.1.0
|
# 1.1.0
|
||||||
This new release introduces:
|
This new release introduces:
|
||||||
* several fixes:
|
* several fixes:
|
||||||
|
|||||||
36
vendor/github.com/sirupsen/logrus/README.md
сгенерированный
поставляемый
36
vendor/github.com/sirupsen/logrus/README.md
сгенерированный
поставляемый
@@ -56,8 +56,39 @@ time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased
|
|||||||
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
||||||
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
||||||
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
||||||
exit status 1
|
|
||||||
```
|
```
|
||||||
|
To ensure this behaviour even if a TTY is attached, set your formatter as follows:
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.SetFormatter(&log.TextFormatter{
|
||||||
|
DisableColors: true,
|
||||||
|
FullTimestamp: true,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Logging Method Name
|
||||||
|
|
||||||
|
If you wish to add the calling method as a field, instruct the logger via:
|
||||||
|
```go
|
||||||
|
log.SetReportCaller(true)
|
||||||
|
```
|
||||||
|
This adds the caller as 'method' like so:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by",
|
||||||
|
"time":"2014-03-10 19:57:38.562543129 -0400 EDT"}
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin
|
||||||
|
```
|
||||||
|
Note that this does add measurable overhead - the cost will depend on the version of Go, but is
|
||||||
|
between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your
|
||||||
|
environment via benchmarks:
|
||||||
|
```
|
||||||
|
go test -bench=.*CallerTracing
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
#### Case-sensitivity
|
#### Case-sensitivity
|
||||||
|
|
||||||
@@ -246,9 +277,10 @@ A list of currently known of service hook can be found in this wiki [page](https
|
|||||||
|
|
||||||
#### Level logging
|
#### Level logging
|
||||||
|
|
||||||
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
log.Trace("Something very low level.")
|
||||||
log.Debug("Useful debugging information.")
|
log.Debug("Useful debugging information.")
|
||||||
log.Info("Something noteworthy happened!")
|
log.Info("Something noteworthy happened!")
|
||||||
log.Warn("You should probably take a look at this.")
|
log.Warn("You should probably take a look at this.")
|
||||||
|
|||||||
134
vendor/github.com/sirupsen/logrus/entry.go
сгенерированный
поставляемый
134
vendor/github.com/sirupsen/logrus/entry.go
сгенерированный
поставляемый
@@ -4,11 +4,30 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var bufferPool *sync.Pool
|
var (
|
||||||
|
bufferPool *sync.Pool
|
||||||
|
|
||||||
|
// qualified package name, cached at first use
|
||||||
|
logrusPackage string
|
||||||
|
|
||||||
|
// Positions in the call stack when tracing to report the calling method
|
||||||
|
minimumCallerDepth int
|
||||||
|
|
||||||
|
// Used for caller information initialisation
|
||||||
|
callerInitOnce sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
maximumCallerDepth int = 25
|
||||||
|
knownLogrusFrames int = 4
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
bufferPool = &sync.Pool{
|
bufferPool = &sync.Pool{
|
||||||
@@ -16,15 +35,18 @@ func init() {
|
|||||||
return new(bytes.Buffer)
|
return new(bytes.Buffer)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start at the bottom of the stack before the package-name cache is primed
|
||||||
|
minimumCallerDepth = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defines the key when adding errors using WithError.
|
// Defines the key when adding errors using WithError.
|
||||||
var ErrorKey = "error"
|
var ErrorKey = "error"
|
||||||
|
|
||||||
// An entry is the final or intermediate Logrus logging entry. It contains all
|
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||||
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
// the fields passed with WithField{,s}. It's finally logged when Trace, Debug,
|
||||||
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
// Info, Warn, Error, Fatal or Panic is called on it. These objects can be
|
||||||
// passed around as much as you wish to avoid field duplication.
|
// reused and passed around as much as you wish to avoid field duplication.
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
Logger *Logger
|
Logger *Logger
|
||||||
|
|
||||||
@@ -34,22 +56,28 @@ type Entry struct {
|
|||||||
// Time at which the log entry was created
|
// Time at which the log entry was created
|
||||||
Time time.Time
|
Time time.Time
|
||||||
|
|
||||||
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
// Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic
|
||||||
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
|
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
|
||||||
Level Level
|
Level Level
|
||||||
|
|
||||||
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
// Calling method, with package name
|
||||||
|
Caller *runtime.Frame
|
||||||
|
|
||||||
|
// Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
|
||||||
Message string
|
Message string
|
||||||
|
|
||||||
// When formatter is called in entry.log(), a Buffer may be set to entry
|
// When formatter is called in entry.log(), a Buffer may be set to entry
|
||||||
Buffer *bytes.Buffer
|
Buffer *bytes.Buffer
|
||||||
|
|
||||||
|
// err may contain a field formatting error
|
||||||
|
err string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEntry(logger *Logger) *Entry {
|
func NewEntry(logger *Logger) *Entry {
|
||||||
return &Entry{
|
return &Entry{
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
// Default is five fields, give a little extra room
|
// Default is three fields, plus one optional. Give a little extra room.
|
||||||
Data: make(Fields, 5),
|
Data: make(Fields, 6),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,10 +108,18 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
|
|||||||
for k, v := range entry.Data {
|
for k, v := range entry.Data {
|
||||||
data[k] = v
|
data[k] = v
|
||||||
}
|
}
|
||||||
|
var field_err string
|
||||||
for k, v := range fields {
|
for k, v := range fields {
|
||||||
data[k] = v
|
if t := reflect.TypeOf(v); t != nil && t.Kind() == reflect.Func {
|
||||||
|
field_err = fmt.Sprintf("can not add field %q", k)
|
||||||
|
if entry.err != "" {
|
||||||
|
field_err = entry.err + ", " + field_err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time}
|
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: field_err}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overrides the time of the Entry.
|
// Overrides the time of the Entry.
|
||||||
@@ -91,6 +127,57 @@ func (entry *Entry) WithTime(t time.Time) *Entry {
|
|||||||
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t}
|
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getPackageName reduces a fully qualified function name to the package name
|
||||||
|
// There really ought to be to be a better way...
|
||||||
|
func getPackageName(f string) string {
|
||||||
|
for {
|
||||||
|
lastPeriod := strings.LastIndex(f, ".")
|
||||||
|
lastSlash := strings.LastIndex(f, "/")
|
||||||
|
if lastPeriod > lastSlash {
|
||||||
|
f = f[:lastPeriod]
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCaller retrieves the name of the first non-logrus calling function
|
||||||
|
func getCaller() *runtime.Frame {
|
||||||
|
// Restrict the lookback frames to avoid runaway lookups
|
||||||
|
pcs := make([]uintptr, maximumCallerDepth)
|
||||||
|
depth := runtime.Callers(minimumCallerDepth, pcs)
|
||||||
|
frames := runtime.CallersFrames(pcs[:depth])
|
||||||
|
|
||||||
|
// cache this package's fully-qualified name
|
||||||
|
callerInitOnce.Do(func() {
|
||||||
|
logrusPackage = getPackageName(runtime.FuncForPC(pcs[0]).Name())
|
||||||
|
|
||||||
|
// now that we have the cache, we can skip a minimum count of known-logrus functions
|
||||||
|
// XXX this is dubious, the number of frames may vary store an entry in a logger interface
|
||||||
|
minimumCallerDepth = knownLogrusFrames
|
||||||
|
})
|
||||||
|
|
||||||
|
for f, again := frames.Next(); again; f, again = frames.Next() {
|
||||||
|
pkg := getPackageName(f.Function)
|
||||||
|
|
||||||
|
// If the caller isn't part of this package, we're done
|
||||||
|
if pkg != logrusPackage {
|
||||||
|
return &f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we got here, we failed to find the caller's context
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry Entry) HasCaller() (has bool) {
|
||||||
|
return entry.Logger != nil &&
|
||||||
|
entry.Logger.ReportCaller &&
|
||||||
|
entry.Caller != nil
|
||||||
|
}
|
||||||
|
|
||||||
// This function is not declared with a pointer value because otherwise
|
// This function is not declared with a pointer value because otherwise
|
||||||
// race conditions will occur when using multiple goroutines
|
// race conditions will occur when using multiple goroutines
|
||||||
func (entry Entry) log(level Level, msg string) {
|
func (entry Entry) log(level Level, msg string) {
|
||||||
@@ -107,6 +194,9 @@ func (entry Entry) log(level Level, msg string) {
|
|||||||
|
|
||||||
entry.Level = level
|
entry.Level = level
|
||||||
entry.Message = msg
|
entry.Message = msg
|
||||||
|
if entry.Logger.ReportCaller {
|
||||||
|
entry.Caller = getCaller()
|
||||||
|
}
|
||||||
|
|
||||||
entry.fireHooks()
|
entry.fireHooks()
|
||||||
|
|
||||||
@@ -150,6 +240,12 @@ func (entry *Entry) write() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Trace(args ...interface{}) {
|
||||||
|
if entry.Logger.IsLevelEnabled(TraceLevel) {
|
||||||
|
entry.log(TraceLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (entry *Entry) Debug(args ...interface{}) {
|
func (entry *Entry) Debug(args ...interface{}) {
|
||||||
if entry.Logger.IsLevelEnabled(DebugLevel) {
|
if entry.Logger.IsLevelEnabled(DebugLevel) {
|
||||||
entry.log(DebugLevel, fmt.Sprint(args...))
|
entry.log(DebugLevel, fmt.Sprint(args...))
|
||||||
@@ -186,7 +282,7 @@ func (entry *Entry) Fatal(args ...interface{}) {
|
|||||||
if entry.Logger.IsLevelEnabled(FatalLevel) {
|
if entry.Logger.IsLevelEnabled(FatalLevel) {
|
||||||
entry.log(FatalLevel, fmt.Sprint(args...))
|
entry.log(FatalLevel, fmt.Sprint(args...))
|
||||||
}
|
}
|
||||||
Exit(1)
|
entry.Logger.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Panic(args ...interface{}) {
|
func (entry *Entry) Panic(args ...interface{}) {
|
||||||
@@ -198,6 +294,12 @@ func (entry *Entry) Panic(args ...interface{}) {
|
|||||||
|
|
||||||
// Entry Printf family functions
|
// Entry Printf family functions
|
||||||
|
|
||||||
|
func (entry *Entry) Tracef(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.IsLevelEnabled(TraceLevel) {
|
||||||
|
entry.Trace(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||||
if entry.Logger.IsLevelEnabled(DebugLevel) {
|
if entry.Logger.IsLevelEnabled(DebugLevel) {
|
||||||
entry.Debug(fmt.Sprintf(format, args...))
|
entry.Debug(fmt.Sprintf(format, args...))
|
||||||
@@ -234,7 +336,7 @@ func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
|||||||
if entry.Logger.IsLevelEnabled(FatalLevel) {
|
if entry.Logger.IsLevelEnabled(FatalLevel) {
|
||||||
entry.Fatal(fmt.Sprintf(format, args...))
|
entry.Fatal(fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
Exit(1)
|
entry.Logger.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||||
@@ -245,6 +347,12 @@ func (entry *Entry) Panicf(format string, args ...interface{}) {
|
|||||||
|
|
||||||
// Entry Println family functions
|
// Entry Println family functions
|
||||||
|
|
||||||
|
func (entry *Entry) Traceln(args ...interface{}) {
|
||||||
|
if entry.Logger.IsLevelEnabled(TraceLevel) {
|
||||||
|
entry.Trace(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (entry *Entry) Debugln(args ...interface{}) {
|
func (entry *Entry) Debugln(args ...interface{}) {
|
||||||
if entry.Logger.IsLevelEnabled(DebugLevel) {
|
if entry.Logger.IsLevelEnabled(DebugLevel) {
|
||||||
entry.Debug(entry.sprintlnn(args...))
|
entry.Debug(entry.sprintlnn(args...))
|
||||||
@@ -281,7 +389,7 @@ func (entry *Entry) Fatalln(args ...interface{}) {
|
|||||||
if entry.Logger.IsLevelEnabled(FatalLevel) {
|
if entry.Logger.IsLevelEnabled(FatalLevel) {
|
||||||
entry.Fatal(entry.sprintlnn(args...))
|
entry.Fatal(entry.sprintlnn(args...))
|
||||||
}
|
}
|
||||||
Exit(1)
|
entry.Logger.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Panicln(args ...interface{}) {
|
func (entry *Entry) Panicln(args ...interface{}) {
|
||||||
|
|||||||
21
vendor/github.com/sirupsen/logrus/exported.go
сгенерированный
поставляемый
21
vendor/github.com/sirupsen/logrus/exported.go
сгенерированный
поставляемый
@@ -24,6 +24,12 @@ func SetFormatter(formatter Formatter) {
|
|||||||
std.SetFormatter(formatter)
|
std.SetFormatter(formatter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetReportCaller sets whether the standard logger will include the calling
|
||||||
|
// method as a field.
|
||||||
|
func SetReportCaller(include bool) {
|
||||||
|
std.SetReportCaller(include)
|
||||||
|
}
|
||||||
|
|
||||||
// SetLevel sets the standard logger level.
|
// SetLevel sets the standard logger level.
|
||||||
func SetLevel(level Level) {
|
func SetLevel(level Level) {
|
||||||
std.SetLevel(level)
|
std.SetLevel(level)
|
||||||
@@ -77,6 +83,11 @@ func WithTime(t time.Time) *Entry {
|
|||||||
return std.WithTime(t)
|
return std.WithTime(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trace logs a message at level Trace on the standard logger.
|
||||||
|
func Trace(args ...interface{}) {
|
||||||
|
std.Trace(args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Debug logs a message at level Debug on the standard logger.
|
// Debug logs a message at level Debug on the standard logger.
|
||||||
func Debug(args ...interface{}) {
|
func Debug(args ...interface{}) {
|
||||||
std.Debug(args...)
|
std.Debug(args...)
|
||||||
@@ -117,6 +128,11 @@ func Fatal(args ...interface{}) {
|
|||||||
std.Fatal(args...)
|
std.Fatal(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tracef logs a message at level Trace on the standard logger.
|
||||||
|
func Tracef(format string, args ...interface{}) {
|
||||||
|
std.Tracef(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Debugf logs a message at level Debug on the standard logger.
|
// Debugf logs a message at level Debug on the standard logger.
|
||||||
func Debugf(format string, args ...interface{}) {
|
func Debugf(format string, args ...interface{}) {
|
||||||
std.Debugf(format, args...)
|
std.Debugf(format, args...)
|
||||||
@@ -157,6 +173,11 @@ func Fatalf(format string, args ...interface{}) {
|
|||||||
std.Fatalf(format, args...)
|
std.Fatalf(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Traceln logs a message at level Trace on the standard logger.
|
||||||
|
func Traceln(args ...interface{}) {
|
||||||
|
std.Traceln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Debugln logs a message at level Debug on the standard logger.
|
// Debugln logs a message at level Debug on the standard logger.
|
||||||
func Debugln(args ...interface{}) {
|
func Debugln(args ...interface{}) {
|
||||||
std.Debugln(args...)
|
std.Debugln(args...)
|
||||||
|
|||||||
33
vendor/github.com/sirupsen/logrus/formatter.go
сгенерированный
поставляемый
33
vendor/github.com/sirupsen/logrus/formatter.go
сгенерированный
поставляемый
@@ -2,7 +2,16 @@ package logrus
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
const defaultTimestampFormat = time.RFC3339
|
// Default key names for the default fields
|
||||||
|
const (
|
||||||
|
defaultTimestampFormat = time.RFC3339
|
||||||
|
FieldKeyMsg = "msg"
|
||||||
|
FieldKeyLevel = "level"
|
||||||
|
FieldKeyTime = "time"
|
||||||
|
FieldKeyLogrusError = "logrus_error"
|
||||||
|
FieldKeyFunc = "func"
|
||||||
|
FieldKeyFile = "file"
|
||||||
|
)
|
||||||
|
|
||||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||||
// `Entry`. It exposes all the fields, including the default ones:
|
// `Entry`. It exposes all the fields, including the default ones:
|
||||||
@@ -18,7 +27,7 @@ type Formatter interface {
|
|||||||
Format(*Entry) ([]byte, error)
|
Format(*Entry) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when
|
||||||
// dumping it. If this code wasn't there doing:
|
// dumping it. If this code wasn't there doing:
|
||||||
//
|
//
|
||||||
// logrus.WithField("level", 1).Info("hello")
|
// logrus.WithField("level", 1).Info("hello")
|
||||||
@@ -30,7 +39,7 @@ type Formatter interface {
|
|||||||
//
|
//
|
||||||
// It's not exported because it's still using Data in an opinionated way. It's to
|
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||||
// avoid code duplication between the two default formatters.
|
// avoid code duplication between the two default formatters.
|
||||||
func prefixFieldClashes(data Fields, fieldMap FieldMap) {
|
func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) {
|
||||||
timeKey := fieldMap.resolve(FieldKeyTime)
|
timeKey := fieldMap.resolve(FieldKeyTime)
|
||||||
if t, ok := data[timeKey]; ok {
|
if t, ok := data[timeKey]; ok {
|
||||||
data["fields."+timeKey] = t
|
data["fields."+timeKey] = t
|
||||||
@@ -48,4 +57,22 @@ func prefixFieldClashes(data Fields, fieldMap FieldMap) {
|
|||||||
data["fields."+levelKey] = l
|
data["fields."+levelKey] = l
|
||||||
delete(data, levelKey)
|
delete(data, levelKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logrusErrKey := fieldMap.resolve(FieldKeyLogrusError)
|
||||||
|
if l, ok := data[logrusErrKey]; ok {
|
||||||
|
data["fields."+logrusErrKey] = l
|
||||||
|
delete(data, logrusErrKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If reportCaller is not set, 'func' will not conflict.
|
||||||
|
if reportCaller {
|
||||||
|
funcKey := fieldMap.resolve(FieldKeyFunc)
|
||||||
|
if l, ok := data[funcKey]; ok {
|
||||||
|
data["fields."+funcKey] = l
|
||||||
|
}
|
||||||
|
fileKey := fieldMap.resolve(FieldKeyFile)
|
||||||
|
if l, ok := data[fileKey]; ok {
|
||||||
|
data["fields."+fileKey] = l
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
vendor/github.com/sirupsen/logrus/go.mod
сгенерированный
поставляемый
3
vendor/github.com/sirupsen/logrus/go.mod
сгенерированный
поставляемый
@@ -2,8 +2,9 @@ module github.com/sirupsen/logrus
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/stretchr/objx v0.1.1 // indirect
|
||||||
github.com/stretchr/testify v1.2.2
|
github.com/stretchr/testify v1.2.2
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33
|
||||||
|
|||||||
3
vendor/github.com/sirupsen/logrus/go.sum
сгенерированный
поставляемый
3
vendor/github.com/sirupsen/logrus/go.sum
сгенерированный
поставляемый
@@ -2,8 +2,11 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs=
|
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
|
||||||
|
|||||||
23
vendor/github.com/sirupsen/logrus/json_formatter.go
сгенерированный
поставляемый
23
vendor/github.com/sirupsen/logrus/json_formatter.go
сгенерированный
поставляемый
@@ -11,13 +11,6 @@ type fieldKey string
|
|||||||
// FieldMap allows customization of the key names for default fields.
|
// FieldMap allows customization of the key names for default fields.
|
||||||
type FieldMap map[fieldKey]string
|
type FieldMap map[fieldKey]string
|
||||||
|
|
||||||
// Default key names for the default fields
|
|
||||||
const (
|
|
||||||
FieldKeyMsg = "msg"
|
|
||||||
FieldKeyLevel = "level"
|
|
||||||
FieldKeyTime = "time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (f FieldMap) resolve(key fieldKey) string {
|
func (f FieldMap) resolve(key fieldKey) string {
|
||||||
if k, ok := f[key]; ok {
|
if k, ok := f[key]; ok {
|
||||||
return k
|
return k
|
||||||
@@ -41,9 +34,10 @@ type JSONFormatter struct {
|
|||||||
// As an example:
|
// As an example:
|
||||||
// formatter := &JSONFormatter{
|
// formatter := &JSONFormatter{
|
||||||
// FieldMap: FieldMap{
|
// FieldMap: FieldMap{
|
||||||
// FieldKeyTime: "@timestamp",
|
// FieldKeyTime: "@timestamp",
|
||||||
// FieldKeyLevel: "@level",
|
// FieldKeyLevel: "@level",
|
||||||
// FieldKeyMsg: "@message",
|
// FieldKeyMsg: "@message",
|
||||||
|
// FieldKeyFunc: "@caller",
|
||||||
// },
|
// },
|
||||||
// }
|
// }
|
||||||
FieldMap FieldMap
|
FieldMap FieldMap
|
||||||
@@ -54,7 +48,7 @@ type JSONFormatter struct {
|
|||||||
|
|
||||||
// Format renders a single log entry
|
// Format renders a single log entry
|
||||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
data := make(Fields, len(entry.Data)+3)
|
data := make(Fields, len(entry.Data)+4)
|
||||||
for k, v := range entry.Data {
|
for k, v := range entry.Data {
|
||||||
switch v := v.(type) {
|
switch v := v.(type) {
|
||||||
case error:
|
case error:
|
||||||
@@ -72,18 +66,25 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|||||||
data = newData
|
data = newData
|
||||||
}
|
}
|
||||||
|
|
||||||
prefixFieldClashes(data, f.FieldMap)
|
prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
|
||||||
|
|
||||||
timestampFormat := f.TimestampFormat
|
timestampFormat := f.TimestampFormat
|
||||||
if timestampFormat == "" {
|
if timestampFormat == "" {
|
||||||
timestampFormat = defaultTimestampFormat
|
timestampFormat = defaultTimestampFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if entry.err != "" {
|
||||||
|
data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err
|
||||||
|
}
|
||||||
if !f.DisableTimestamp {
|
if !f.DisableTimestamp {
|
||||||
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
|
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
|
||||||
}
|
}
|
||||||
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
|
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
|
||||||
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
|
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
|
||||||
|
if entry.HasCaller() {
|
||||||
|
data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function
|
||||||
|
data[f.FieldMap.resolve(FieldKeyFile)] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||||
|
}
|
||||||
|
|
||||||
var b *bytes.Buffer
|
var b *bytes.Buffer
|
||||||
if entry.Buffer != nil {
|
if entry.Buffer != nil {
|
||||||
|
|||||||
62
vendor/github.com/sirupsen/logrus/logger.go
сгенерированный
поставляемый
62
vendor/github.com/sirupsen/logrus/logger.go
сгенерированный
поставляемый
@@ -24,6 +24,10 @@ type Logger struct {
|
|||||||
// own that implements the `Formatter` interface, see the `README` or included
|
// own that implements the `Formatter` interface, see the `README` or included
|
||||||
// formatters for examples.
|
// formatters for examples.
|
||||||
Formatter Formatter
|
Formatter Formatter
|
||||||
|
|
||||||
|
// Flag for whether to log caller info (off by default)
|
||||||
|
ReportCaller bool
|
||||||
|
|
||||||
// The logging level the logger should log at. This is typically (and defaults
|
// The logging level the logger should log at. This is typically (and defaults
|
||||||
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||||
// logged.
|
// logged.
|
||||||
@@ -32,8 +36,12 @@ type Logger struct {
|
|||||||
mu MutexWrap
|
mu MutexWrap
|
||||||
// Reusable empty entry
|
// Reusable empty entry
|
||||||
entryPool sync.Pool
|
entryPool sync.Pool
|
||||||
|
// Function to exit the application, defaults to `os.Exit()`
|
||||||
|
ExitFunc exitFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type exitFunc func(int)
|
||||||
|
|
||||||
type MutexWrap struct {
|
type MutexWrap struct {
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
disabled bool
|
disabled bool
|
||||||
@@ -69,10 +77,12 @@ func (mw *MutexWrap) Disable() {
|
|||||||
// It's recommended to make this a global instance called `log`.
|
// It's recommended to make this a global instance called `log`.
|
||||||
func New() *Logger {
|
func New() *Logger {
|
||||||
return &Logger{
|
return &Logger{
|
||||||
Out: os.Stderr,
|
Out: os.Stderr,
|
||||||
Formatter: new(TextFormatter),
|
Formatter: new(TextFormatter),
|
||||||
Hooks: make(LevelHooks),
|
Hooks: make(LevelHooks),
|
||||||
Level: InfoLevel,
|
Level: InfoLevel,
|
||||||
|
ExitFunc: os.Exit,
|
||||||
|
ReportCaller: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,6 +131,14 @@ func (logger *Logger) WithTime(t time.Time) *Entry {
|
|||||||
return entry.WithTime(t)
|
return entry.WithTime(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Tracef(format string, args ...interface{}) {
|
||||||
|
if logger.IsLevelEnabled(TraceLevel) {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Tracef(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||||
if logger.IsLevelEnabled(DebugLevel) {
|
if logger.IsLevelEnabled(DebugLevel) {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
@@ -173,7 +191,7 @@ func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
|||||||
entry.Fatalf(format, args...)
|
entry.Fatalf(format, args...)
|
||||||
logger.releaseEntry(entry)
|
logger.releaseEntry(entry)
|
||||||
}
|
}
|
||||||
Exit(1)
|
logger.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||||
@@ -184,6 +202,14 @@ func (logger *Logger) Panicf(format string, args ...interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Trace(args ...interface{}) {
|
||||||
|
if logger.IsLevelEnabled(TraceLevel) {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Trace(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debug(args ...interface{}) {
|
func (logger *Logger) Debug(args ...interface{}) {
|
||||||
if logger.IsLevelEnabled(DebugLevel) {
|
if logger.IsLevelEnabled(DebugLevel) {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
@@ -236,7 +262,7 @@ func (logger *Logger) Fatal(args ...interface{}) {
|
|||||||
entry.Fatal(args...)
|
entry.Fatal(args...)
|
||||||
logger.releaseEntry(entry)
|
logger.releaseEntry(entry)
|
||||||
}
|
}
|
||||||
Exit(1)
|
logger.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panic(args ...interface{}) {
|
func (logger *Logger) Panic(args ...interface{}) {
|
||||||
@@ -247,6 +273,14 @@ func (logger *Logger) Panic(args ...interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Traceln(args ...interface{}) {
|
||||||
|
if logger.IsLevelEnabled(TraceLevel) {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Traceln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debugln(args ...interface{}) {
|
func (logger *Logger) Debugln(args ...interface{}) {
|
||||||
if logger.IsLevelEnabled(DebugLevel) {
|
if logger.IsLevelEnabled(DebugLevel) {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
@@ -299,7 +333,7 @@ func (logger *Logger) Fatalln(args ...interface{}) {
|
|||||||
entry.Fatalln(args...)
|
entry.Fatalln(args...)
|
||||||
logger.releaseEntry(entry)
|
logger.releaseEntry(entry)
|
||||||
}
|
}
|
||||||
Exit(1)
|
logger.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panicln(args ...interface{}) {
|
func (logger *Logger) Panicln(args ...interface{}) {
|
||||||
@@ -310,6 +344,14 @@ func (logger *Logger) Panicln(args ...interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Exit(code int) {
|
||||||
|
runHandlers()
|
||||||
|
if logger.ExitFunc == nil {
|
||||||
|
logger.ExitFunc = os.Exit
|
||||||
|
}
|
||||||
|
logger.ExitFunc(code)
|
||||||
|
}
|
||||||
|
|
||||||
//When file is opened with appending mode, it's safe to
|
//When file is opened with appending mode, it's safe to
|
||||||
//write concurrently to a file (within 4k message on Linux).
|
//write concurrently to a file (within 4k message on Linux).
|
||||||
//In these cases user can choose to disable the lock.
|
//In these cases user can choose to disable the lock.
|
||||||
@@ -357,6 +399,12 @@ func (logger *Logger) SetOutput(output io.Writer) {
|
|||||||
logger.Out = output
|
logger.Out = output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) SetReportCaller(reportCaller bool) {
|
||||||
|
logger.mu.Lock()
|
||||||
|
defer logger.mu.Unlock()
|
||||||
|
logger.ReportCaller = reportCaller
|
||||||
|
}
|
||||||
|
|
||||||
// ReplaceHooks replaces the logger hooks and returns the old ones
|
// ReplaceHooks replaces the logger hooks and returns the old ones
|
||||||
func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
|
func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
|
||||||
logger.mu.Lock()
|
logger.mu.Lock()
|
||||||
|
|||||||
30
vendor/github.com/sirupsen/logrus/logrus.go
сгенерированный
поставляемый
30
vendor/github.com/sirupsen/logrus/logrus.go
сгенерированный
поставляемый
@@ -15,6 +15,8 @@ type Level uint32
|
|||||||
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
||||||
func (level Level) String() string {
|
func (level Level) String() string {
|
||||||
switch level {
|
switch level {
|
||||||
|
case TraceLevel:
|
||||||
|
return "trace"
|
||||||
case DebugLevel:
|
case DebugLevel:
|
||||||
return "debug"
|
return "debug"
|
||||||
case InfoLevel:
|
case InfoLevel:
|
||||||
@@ -47,12 +49,26 @@ func ParseLevel(lvl string) (Level, error) {
|
|||||||
return InfoLevel, nil
|
return InfoLevel, nil
|
||||||
case "debug":
|
case "debug":
|
||||||
return DebugLevel, nil
|
return DebugLevel, nil
|
||||||
|
case "trace":
|
||||||
|
return TraceLevel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var l Level
|
var l Level
|
||||||
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
|
func (level *Level) UnmarshalText(text []byte) error {
|
||||||
|
l, err := ParseLevel(string(text))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*level = Level(l)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// A constant exposing all logging levels
|
// A constant exposing all logging levels
|
||||||
var AllLevels = []Level{
|
var AllLevels = []Level{
|
||||||
PanicLevel,
|
PanicLevel,
|
||||||
@@ -61,6 +77,7 @@ var AllLevels = []Level{
|
|||||||
WarnLevel,
|
WarnLevel,
|
||||||
InfoLevel,
|
InfoLevel,
|
||||||
DebugLevel,
|
DebugLevel,
|
||||||
|
TraceLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are the different logging levels. You can set the logging level to log
|
// These are the different logging levels. You can set the logging level to log
|
||||||
@@ -69,7 +86,7 @@ const (
|
|||||||
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||||
// message passed to Debug, Info, ...
|
// message passed to Debug, Info, ...
|
||||||
PanicLevel Level = iota
|
PanicLevel Level = iota
|
||||||
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
// FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the
|
||||||
// logging level is set to Panic.
|
// logging level is set to Panic.
|
||||||
FatalLevel
|
FatalLevel
|
||||||
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||||
@@ -82,6 +99,8 @@ const (
|
|||||||
InfoLevel
|
InfoLevel
|
||||||
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||||
DebugLevel
|
DebugLevel
|
||||||
|
// TraceLevel level. Designates finer-grained informational events than the Debug.
|
||||||
|
TraceLevel
|
||||||
)
|
)
|
||||||
|
|
||||||
// Won't compile if StdLogger can't be realized by a log.Logger
|
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||||
@@ -148,3 +167,12 @@ type FieldLogger interface {
|
|||||||
// IsFatalEnabled() bool
|
// IsFatalEnabled() bool
|
||||||
// IsPanicEnabled() bool
|
// IsPanicEnabled() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is
|
||||||
|
// here for consistancy. Do not use. Use Logger or Entry instead.
|
||||||
|
type Ext1FieldLogger interface {
|
||||||
|
FieldLogger
|
||||||
|
Tracef(format string, args ...interface{})
|
||||||
|
Trace(args ...interface{})
|
||||||
|
Traceln(args ...interface{})
|
||||||
|
}
|
||||||
|
|||||||
13
vendor/github.com/sirupsen/logrus/terminal_appengine.go
сгенерированный
поставляемый
13
vendor/github.com/sirupsen/logrus/terminal_appengine.go
сгенерированный
поставляемый
@@ -1,13 +0,0 @@
|
|||||||
// Based on ssh/terminal:
|
|
||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func initTerminal(w io.Writer) {
|
|
||||||
}
|
|
||||||
17
vendor/github.com/sirupsen/logrus/terminal_bsd.go
сгенерированный
поставляемый
17
vendor/github.com/sirupsen/logrus/terminal_bsd.go
сгенерированный
поставляемый
@@ -1,17 +0,0 @@
|
|||||||
// +build darwin freebsd openbsd netbsd dragonfly
|
|
||||||
// +build !appengine,!js
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
const ioctlReadTermios = unix.TIOCGETA
|
|
||||||
|
|
||||||
type Termios unix.Termios
|
|
||||||
|
|
||||||
func initTerminal(w io.Writer) {
|
|
||||||
}
|
|
||||||
21
vendor/github.com/sirupsen/logrus/terminal_linux.go
сгенерированный
поставляемый
21
vendor/github.com/sirupsen/logrus/terminal_linux.go
сгенерированный
поставляемый
@@ -1,21 +0,0 @@
|
|||||||
// Based on ssh/terminal:
|
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !appengine,!js
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
const ioctlReadTermios = unix.TCGETS
|
|
||||||
|
|
||||||
type Termios unix.Termios
|
|
||||||
|
|
||||||
func initTerminal(w io.Writer) {
|
|
||||||
}
|
|
||||||
8
vendor/github.com/sirupsen/logrus/terminal_notwindows.go
сгенерированный
поставляемый
Обычный файл
8
vendor/github.com/sirupsen/logrus/terminal_notwindows.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,8 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
func initTerminal(w io.Writer) {
|
||||||
|
}
|
||||||
40
vendor/github.com/sirupsen/logrus/text_formatter.go
сгенерированный
поставляемый
40
vendor/github.com/sirupsen/logrus/text_formatter.go
сгенерированный
поставляемый
@@ -107,14 +107,14 @@ func (f *TextFormatter) isColored() bool {
|
|||||||
|
|
||||||
// Format renders a single log entry
|
// Format renders a single log entry
|
||||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
prefixFieldClashes(entry.Data, f.FieldMap)
|
prefixFieldClashes(entry.Data, f.FieldMap, entry.HasCaller())
|
||||||
|
|
||||||
keys := make([]string, 0, len(entry.Data))
|
keys := make([]string, 0, len(entry.Data))
|
||||||
for k := range entry.Data {
|
for k := range entry.Data {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
fixedKeys := make([]string, 0, 3+len(entry.Data))
|
fixedKeys := make([]string, 0, 4+len(entry.Data))
|
||||||
if !f.DisableTimestamp {
|
if !f.DisableTimestamp {
|
||||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
|
||||||
}
|
}
|
||||||
@@ -122,6 +122,13 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|||||||
if entry.Message != "" {
|
if entry.Message != "" {
|
||||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg))
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg))
|
||||||
}
|
}
|
||||||
|
if entry.err != "" {
|
||||||
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
|
||||||
|
}
|
||||||
|
if entry.HasCaller() {
|
||||||
|
fixedKeys = append(fixedKeys,
|
||||||
|
f.FieldMap.resolve(FieldKeyFunc), f.FieldMap.resolve(FieldKeyFile))
|
||||||
|
}
|
||||||
|
|
||||||
if !f.DisableSorting {
|
if !f.DisableSorting {
|
||||||
if f.SortingFunc == nil {
|
if f.SortingFunc == nil {
|
||||||
@@ -157,13 +164,19 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|||||||
} else {
|
} else {
|
||||||
for _, key := range fixedKeys {
|
for _, key := range fixedKeys {
|
||||||
var value interface{}
|
var value interface{}
|
||||||
switch key {
|
switch {
|
||||||
case f.FieldMap.resolve(FieldKeyTime):
|
case key == f.FieldMap.resolve(FieldKeyTime):
|
||||||
value = entry.Time.Format(timestampFormat)
|
value = entry.Time.Format(timestampFormat)
|
||||||
case f.FieldMap.resolve(FieldKeyLevel):
|
case key == f.FieldMap.resolve(FieldKeyLevel):
|
||||||
value = entry.Level.String()
|
value = entry.Level.String()
|
||||||
case f.FieldMap.resolve(FieldKeyMsg):
|
case key == f.FieldMap.resolve(FieldKeyMsg):
|
||||||
value = entry.Message
|
value = entry.Message
|
||||||
|
case key == f.FieldMap.resolve(FieldKeyLogrusError):
|
||||||
|
value = entry.err
|
||||||
|
case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller():
|
||||||
|
value = entry.Caller.Function
|
||||||
|
case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller():
|
||||||
|
value = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||||
default:
|
default:
|
||||||
value = entry.Data[key]
|
value = entry.Data[key]
|
||||||
}
|
}
|
||||||
@@ -178,7 +191,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|||||||
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
|
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
|
||||||
var levelColor int
|
var levelColor int
|
||||||
switch entry.Level {
|
switch entry.Level {
|
||||||
case DebugLevel:
|
case DebugLevel, TraceLevel:
|
||||||
levelColor = gray
|
levelColor = gray
|
||||||
case WarnLevel:
|
case WarnLevel:
|
||||||
levelColor = yellow
|
levelColor = yellow
|
||||||
@@ -197,12 +210,19 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
|
|||||||
// the behavior of logrus text_formatter the same as the stdlib log package
|
// the behavior of logrus text_formatter the same as the stdlib log package
|
||||||
entry.Message = strings.TrimSuffix(entry.Message, "\n")
|
entry.Message = strings.TrimSuffix(entry.Message, "\n")
|
||||||
|
|
||||||
|
caller := ""
|
||||||
|
|
||||||
|
if entry.HasCaller() {
|
||||||
|
caller = fmt.Sprintf("%s:%d %s()",
|
||||||
|
entry.Caller.File, entry.Caller.Line, entry.Caller.Function)
|
||||||
|
}
|
||||||
|
|
||||||
if f.DisableTimestamp {
|
if f.DisableTimestamp {
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message)
|
||||||
} else if !f.FullTimestamp {
|
} else if !f.FullTimestamp {
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message)
|
||||||
}
|
}
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
v := entry.Data[k]
|
v := entry.Data[k]
|
||||||
|
|||||||
2
vendor/github.com/sirupsen/logrus/writer.go
сгенерированный
поставляемый
2
vendor/github.com/sirupsen/logrus/writer.go
сгенерированный
поставляемый
@@ -24,6 +24,8 @@ func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
|
|||||||
var printFunc func(args ...interface{})
|
var printFunc func(args ...interface{})
|
||||||
|
|
||||||
switch level {
|
switch level {
|
||||||
|
case TraceLevel:
|
||||||
|
printFunc = entry.Trace
|
||||||
case DebugLevel:
|
case DebugLevel:
|
||||||
printFunc = entry.Debug
|
printFunc = entry.Debug
|
||||||
case InfoLevel:
|
case InfoLevel:
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user