1
0
Fork 0
mirror of https://github.com/vbatts/go-mtree.git synced 2025-07-02 05:48:30 +00:00

vendor: explicitly vendor golang.org/x/sys

Vendor golang.org/x/sys to get the UtimesNanoAt function defined for all
unix-like OSes. The function will be used in a successive commit.

This also re-vendors the other dependencies from glide.yaml.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
This commit is contained in:
Tobias Klauser 2017-10-20 11:38:03 +02:00
parent 8bcd48e401
commit 7742183cd4
398 changed files with 23547 additions and 37694 deletions

View file

@ -8,6 +8,8 @@ env:
- GOMAXPROCS=4 GORACE=halt_on_error=1
install:
- go get github.com/stretchr/testify/assert
- go get gopkg.in/gemnasium/logrus-airbrake-hook.v2
- go get golang.org/x/sys/unix
- go get golang.org/x/sys/windows
script:
- go test -race -v .
- cd hooks/null && go test -race -v .
- go test -race -v ./...

View file

@ -1,3 +1,16 @@
# 1.0.3
* Replace example files with testable examples
# 1.0.2
* bug: quote non-string values in text formatter (#583)
* Make (*Logger) SetLevel a public method
# 1.0.1
* bug: fix escaping in text formatter (#575)
# 1.0.0
* Officially changed name to lower-case

View file

@ -1,22 +1,24 @@
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus)&nbsp;[![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus)
Logrus is a structured logger for Go (golang), completely API compatible with
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
yet stable (pre 1.0). Logrus itself is completely stable and has been used in
many large deployments. The core API is unlikely to change much but please
version control your Logrus to make sure you aren't fetching latest `master` on
every build.**
the standard library logger.
**Seeing weird case-sensitive problems?** Unfortunately, the author failed to
realize the consequences of renaming to lower-case. Due to the Go package
environment, this caused issues. Regretfully, there's no turning back now.
**Seeing weird case-sensitive problems?** It's in the past been possible to
import Logrus as both upper- and lower-case. Due to the Go package environment,
this caused issues in the community and we needed a standard. Some environments
experienced problems with the upper-case variant, so the lower-case was decided.
Everything using `logrus` will need to use the lower-case:
`github.com/sirupsen/logrus`. Any package that isn't, should be changed.
I am terribly sorry for this inconvenience. Logrus strives hard for backwards
compatibility, and the author failed to realize the cascading consequences of
such a name-change. To fix Glide, see [these
To fix Glide, see [these
comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437).
For an in-depth explanation of the casing issue, see [this
comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276).
**Are you interested in assisting in maintaining Logrus?** Currently I have a
lot of obligations, and I am unable to provide Logrus with the maintainership it
needs. If you'd like to help, please reach out to me at `simon at author's
username dot com`.
Nicely color-coded in development (when a TTY is attached, otherwise just
plain text):
@ -266,6 +268,7 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
| [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) |
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
@ -280,7 +283,7 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
| [Syslog](https://github.com/sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. |
| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
@ -369,6 +372,7 @@ The built-in logging formatters are:
Third party logging formatters:
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can by parsed by Kubernetes and Google Container Engine.
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
@ -449,13 +453,13 @@ Logrus has a built in facility for asserting the presence of log messages. This
```go
import(
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/null"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"testing"
)
func TestSomething(t*testing.T){
logger, hook := null.NewNullLogger()
logger, hook := test.NewNullLogger()
logger.Error("Helloerror")
assert.Equal(t, 1, len(hook.Entries))

View file

@ -2,7 +2,10 @@ package logrus
import (
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"testing"
"time"
)
@ -11,30 +14,36 @@ func TestRegister(t *testing.T) {
current := len(handlers)
RegisterExitHandler(func() {})
if len(handlers) != current+1 {
t.Fatalf("can't add handler")
t.Fatalf("expected %d handlers, got %d", current+1, len(handlers))
}
}
func TestHandler(t *testing.T) {
gofile := "/tmp/testprog.go"
tempDir, err := ioutil.TempDir("", "test_handler")
if err != nil {
log.Fatalf("can't create temp dir. %q", err)
}
defer os.RemoveAll(tempDir)
gofile := filepath.Join(tempDir, "gofile.go")
if err := ioutil.WriteFile(gofile, testprog, 0666); err != nil {
t.Fatalf("can't create go file")
t.Fatalf("can't create go file. %q", err)
}
outfile := "/tmp/testprog.out"
outfile := filepath.Join(tempDir, "outfile.out")
arg := time.Now().UTC().String()
err := exec.Command("go", "run", gofile, outfile, arg).Run()
err = exec.Command("go", "run", gofile, outfile, arg).Run()
if err == nil {
t.Fatalf("completed normally, should have failed")
}
data, err := ioutil.ReadFile(outfile)
if err != nil {
t.Fatalf("can't read output file %s", outfile)
t.Fatalf("can't read output file %s. %q", outfile, err)
}
if string(data) != arg {
t.Fatalf("bad data")
t.Fatalf("bad data. Expected %q, got %q", data, arg)
}
}

14
vendor/github.com/Sirupsen/logrus/appveyor.yml generated vendored Normal file
View file

@ -0,0 +1,14 @@
version: "{build}"
platform: x64
clone_folder: c:\gopath\src\github.com\sirupsen\logrus
environment:
GOPATH: c:\gopath
branches:
only:
- master
install:
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
- go version
build_script:
- go get -t
- go test

View file

@ -35,6 +35,7 @@ type Entry struct {
Time time.Time
// Level the log entry was logged at: 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.
Level Level
// Message passed to Debug, Info, Warn, Error, Fatal or Panic

View file

@ -0,0 +1,69 @@
package logrus_test
import (
"github.com/sirupsen/logrus"
"os"
)
func Example_basic() {
var log = logrus.New()
log.Formatter = new(logrus.JSONFormatter)
log.Formatter = new(logrus.TextFormatter) //default
log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output
log.Level = logrus.DebugLevel
log.Out = os.Stdout
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
// if err == nil {
// log.Out = file
// } else {
// log.Info("Failed to log to file, using default stderr")
// }
defer func() {
err := recover()
if err != nil {
entry := err.(*logrus.Entry)
log.WithFields(logrus.Fields{
"omg": true,
"err_animal": entry.Data["animal"],
"err_size": entry.Data["size"],
"err_level": entry.Level,
"err_message": entry.Message,
"number": 100,
}).Error("The ice breaks!") // or use Fatal() to force the process to exit with a nonzero code
}
}()
log.WithFields(logrus.Fields{
"animal": "walrus",
"number": 8,
}).Debug("Started observing beach")
log.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
log.WithFields(logrus.Fields{
"omg": true,
"number": 122,
}).Warn("The group's number increased tremendously!")
log.WithFields(logrus.Fields{
"temperature": -4,
}).Debug("Temperature changes")
log.WithFields(logrus.Fields{
"animal": "orca",
"size": 9009,
}).Panic("It's over 9000!")
// Output:
// level=debug msg="Started observing beach" animal=walrus number=8
// level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
// level=warning msg="The group's number increased tremendously!" number=122 omg=true
// level=debug msg="Temperature changes" temperature=-4
// level=panic msg="It's over 9000!" animal=orca size=9009
// level=error msg="The ice breaks!" err_animal=orca err_level=panic err_message="It's over 9000!" err_size=9009 number=100 omg=true
}

35
vendor/github.com/Sirupsen/logrus/example_hook_test.go generated vendored Normal file
View file

@ -0,0 +1,35 @@
package logrus_test
import (
"github.com/sirupsen/logrus"
"gopkg.in/gemnasium/logrus-airbrake-hook.v2"
"os"
)
func Example_hook() {
var log = logrus.New()
log.Formatter = new(logrus.TextFormatter) // default
log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output
log.Hooks.Add(airbrake.NewHook(123, "xyz", "development"))
log.Out = os.Stdout
log.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
log.WithFields(logrus.Fields{
"omg": true,
"number": 122,
}).Warn("The group's number increased tremendously!")
log.WithFields(logrus.Fields{
"omg": true,
"number": 100,
}).Error("The ice breaks!")
// Output:
// level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
// level=warning msg="The group's number increased tremendously!" number=122 omg=true
// level=error msg="The ice breaks!" number=100 omg=true
}

View file

@ -1,59 +0,0 @@
package main
import (
"github.com/sirupsen/logrus"
// "os"
)
var log = logrus.New()
func init() {
log.Formatter = new(logrus.JSONFormatter)
log.Formatter = new(logrus.TextFormatter) // default
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
// if err == nil {
// log.Out = file
// } else {
// log.Info("Failed to log to file, using default stderr")
// }
log.Level = logrus.DebugLevel
}
func main() {
defer func() {
err := recover()
if err != nil {
log.WithFields(logrus.Fields{
"omg": true,
"err": err,
"number": 100,
}).Fatal("The ice breaks!")
}
}()
log.WithFields(logrus.Fields{
"animal": "walrus",
"number": 8,
}).Debug("Started observing beach")
log.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
log.WithFields(logrus.Fields{
"omg": true,
"number": 122,
}).Warn("The group's number increased tremendously!")
log.WithFields(logrus.Fields{
"temperature": -4,
}).Debug("Temperature changes")
log.WithFields(logrus.Fields{
"animal": "orca",
"size": 9009,
}).Panic("It's over 9000!")
}

View file

@ -1,30 +0,0 @@
package main
import (
"github.com/sirupsen/logrus"
"gopkg.in/gemnasium/logrus-airbrake-hook.v2"
)
var log = logrus.New()
func init() {
log.Formatter = new(logrus.TextFormatter) // default
log.Hooks.Add(airbrake.NewHook(123, "xyz", "development"))
}
func main() {
log.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
log.WithFields(logrus.Fields{
"omg": true,
"number": 122,
}).Warn("The group's number increased tremendously!")
log.WithFields(logrus.Fields{
"omg": true,
"number": 100,
}).Fatal("The ice breaks!")
}

View file

@ -31,7 +31,7 @@ func SetFormatter(formatter Formatter) {
func SetLevel(level Level) {
std.mu.Lock()
defer std.mu.Unlock()
std.setLevel(level)
std.SetLevel(level)
}
// GetLevel returns the standard logger level.

View file

@ -2,7 +2,7 @@ package logrus
import "time"
const DefaultTimestampFormat = time.RFC3339
const defaultTimestampFormat = time.RFC3339
// The Formatter interface is used to implement a custom Formatter. It takes an
// `Entry`. It exposes all the fields, including the default ones:

View file

@ -6,12 +6,12 @@
import (
"log/syslog"
"github.com/sirupsen/logrus"
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
lSyslog "github.com/sirupsen/logrus/hooks/syslog"
)
func main() {
log := logrus.New()
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
hook, err := lSyslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
if err == nil {
log.Hooks.Add(hook)
@ -25,12 +25,12 @@ If you want to connect to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "
import (
"log/syslog"
"github.com/sirupsen/logrus"
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
lSyslog "github.com/sirupsen/logrus/hooks/syslog"
)
func main() {
log := logrus.New()
hook, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
hook, err := lSyslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
if err == nil {
log.Hooks.Add(hook)

View file

@ -1,12 +1,13 @@
// +build !windows,!nacl,!plan9
package logrus_syslog
package syslog
import (
"fmt"
"github.com/sirupsen/logrus"
"log/syslog"
"os"
"github.com/sirupsen/logrus"
)
// SyslogHook to send logs via syslog.

View file

@ -1,9 +1,10 @@
package logrus_syslog
package syslog
import (
"github.com/sirupsen/logrus"
"log/syslog"
"testing"
"github.com/sirupsen/logrus"
)
func TestLocalhostAddAndPrint(t *testing.T) {

View file

@ -6,8 +6,11 @@ import (
)
type fieldKey string
// FieldMap allows customization of the key names for default fields.
type FieldMap map[fieldKey]string
// Default key names for the default fields
const (
FieldKeyMsg = "msg"
FieldKeyLevel = "level"
@ -22,6 +25,7 @@ func (f FieldMap) resolve(key fieldKey) string {
return string(key)
}
// JSONFormatter formats logs into parsable json
type JSONFormatter struct {
// TimestampFormat sets the format used for marshaling timestamps.
TimestampFormat string
@ -29,7 +33,7 @@ type JSONFormatter struct {
// DisableTimestamp allows disabling automatic timestamps in output
DisableTimestamp bool
// FieldMap allows users to customize the names of keys for various fields.
// FieldMap allows users to customize the names of keys for default fields.
// As an example:
// formatter := &JSONFormatter{
// FieldMap: FieldMap{
@ -41,6 +45,7 @@ type JSONFormatter struct {
FieldMap FieldMap
}
// Format renders a single log entry
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data := make(Fields, len(entry.Data)+3)
for k, v := range entry.Data {
@ -57,7 +62,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = DefaultTimestampFormat
timestampFormat = defaultTimestampFormat
}
if !f.DisableTimestamp {

View file

@ -25,7 +25,7 @@ type Logger struct {
Formatter Formatter
// 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
// logged. `logrus.Debug` is useful in
// logged.
Level Level
// Used to sync writing to the log. Locking is enabled by Default
mu MutexWrap
@ -312,6 +312,6 @@ func (logger *Logger) level() Level {
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
}
func (logger *Logger) setLevel(level Level) {
func (logger *Logger) SetLevel(level Level) {
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
}

View file

@ -1,10 +0,0 @@
// +build appengine
package logrus
import "io"
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
return true
}

View file

@ -3,8 +3,8 @@
package logrus
import "syscall"
import "golang.org/x/sys/unix"
const ioctlReadTermios = syscall.TIOCGETA
const ioctlReadTermios = unix.TIOCGETA
type Termios syscall.Termios
type Termios unix.Termios

View file

@ -7,8 +7,8 @@
package logrus
import "syscall"
import "golang.org/x/sys/unix"
const ioctlReadTermios = syscall.TCGETS
const ioctlReadTermios = unix.TCGETS
type Termios syscall.Termios
type Termios unix.Termios

View file

@ -1,28 +0,0 @@
// Based on ssh/terminal:
// Copyright 2011 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 linux darwin freebsd openbsd netbsd dragonfly
// +build !appengine
package logrus
import (
"io"
"os"
"syscall"
"unsafe"
)
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
var termios Termios
switch v := f.(type) {
case *os.File:
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
default:
return false
}
}

View file

@ -1,21 +0,0 @@
// +build solaris,!appengine
package logrus
import (
"io"
"os"
"golang.org/x/sys/unix"
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
switch v := f.(type) {
case *os.File:
_, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA)
return err == nil
default:
return false
}
}

View file

@ -1,82 +0,0 @@
// Based on ssh/terminal:
// Copyright 2011 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 windows,!appengine
package logrus
import (
"bytes"
"errors"
"io"
"os"
"os/exec"
"strconv"
"strings"
"syscall"
"unsafe"
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var (
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
)
const (
enableProcessedOutput = 0x0001
enableWrapAtEolOutput = 0x0002
enableVirtualTerminalProcessing = 0x0004
)
func getVersion() (float64, error) {
stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}
cmd := exec.Command("cmd", "ver")
cmd.Stdout = stdout
cmd.Stderr = stderr
err := cmd.Run()
if err != nil {
return -1, err
}
// The output should be like "Microsoft Windows [Version XX.X.XXXXXX]"
version := strings.Replace(stdout.String(), "\n", "", -1)
version = strings.Replace(version, "\r\n", "", -1)
x1 := strings.Index(version, "[Version")
if x1 == -1 || strings.Index(version, "]") == -1 {
return -1, errors.New("Can't determine Windows version")
}
return strconv.ParseFloat(version[x1+9:x1+13], 64)
}
func init() {
ver, err := getVersion()
if err != nil {
return
}
// Activate Virtual Processing for Windows CMD
// Info: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
if ver >= 10 {
handle := syscall.Handle(os.Stderr.Fd())
procSetConsoleMode.Call(uintptr(handle), enableProcessedOutput|enableWrapAtEolOutput|enableVirtualTerminalProcessing)
}
}
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
switch v := f.(type) {
case *os.File:
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
default:
return false
}
}

View file

@ -3,10 +3,14 @@ package logrus
import (
"bytes"
"fmt"
"io"
"os"
"sort"
"strings"
"sync"
"time"
"golang.org/x/crypto/ssh/terminal"
)
const (
@ -14,7 +18,7 @@ const (
red = 31
green = 32
yellow = 33
blue = 34
blue = 36
gray = 37
)
@ -26,6 +30,7 @@ func init() {
baseTimestamp = time.Now()
}
// TextFormatter formats logs into text
type TextFormatter struct {
// Set to true to bypass checking for a TTY before outputting colors.
ForceColors bool
@ -52,10 +57,6 @@ type TextFormatter struct {
// QuoteEmptyFields will wrap empty fields in quotes if true
QuoteEmptyFields bool
// QuoteCharacter can be set to the override the default quoting character "
// with something else. For example: ', or `.
QuoteCharacter string
// Whether the logger's out is to a terminal
isTerminal bool
@ -63,14 +64,21 @@ type TextFormatter struct {
}
func (f *TextFormatter) init(entry *Entry) {
if len(f.QuoteCharacter) == 0 {
f.QuoteCharacter = "\""
}
if entry.Logger != nil {
f.isTerminal = IsTerminal(entry.Logger.Out)
f.isTerminal = f.checkIfTerminal(entry.Logger.Out)
}
}
func (f *TextFormatter) checkIfTerminal(w io.Writer) bool {
switch v := w.(type) {
case *os.File:
return terminal.IsTerminal(int(v.Fd()))
default:
return false
}
}
// Format renders a single log entry
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
var b *bytes.Buffer
keys := make([]string, 0, len(entry.Data))
@ -95,7 +103,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = DefaultTimestampFormat
timestampFormat = defaultTimestampFormat
}
if isColored {
f.printColored(b, entry, keys, timestampFormat)
@ -153,7 +161,7 @@ func (f *TextFormatter) needsQuoting(text string) bool {
if !((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') ||
ch == '-' || ch == '.') {
ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') {
return true
}
}
@ -161,29 +169,23 @@ func (f *TextFormatter) needsQuoting(text string) bool {
}
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
if b.Len() > 0 {
b.WriteByte(' ')
}
b.WriteString(key)
b.WriteByte('=')
f.appendValue(b, value)
b.WriteByte(' ')
}
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
switch value := value.(type) {
case string:
if !f.needsQuoting(value) {
b.WriteString(value)
} else {
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter)
}
case error:
errmsg := value.Error()
if !f.needsQuoting(errmsg) {
b.WriteString(errmsg)
} else {
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
}
default:
fmt.Fprint(b, value)
stringVal, ok := value.(string)
if !ok {
stringVal = fmt.Sprint(value)
}
if !f.needsQuoting(stringVal) {
b.WriteString(stringVal)
} else {
b.WriteString(fmt.Sprintf("%q", stringVal))
}
}

View file

@ -3,18 +3,38 @@ package logrus
import (
"bytes"
"errors"
"fmt"
"strings"
"testing"
"time"
)
func TestFormatting(t *testing.T) {
tf := &TextFormatter{DisableColors: true}
testCases := []struct {
value string
expected string
}{
{`foo`, "time=\"0001-01-01T00:00:00Z\" level=panic test=foo\n"},
}
for _, tc := range testCases {
b, _ := tf.Format(WithField("test", tc.value))
if string(b) != tc.expected {
t.Errorf("formatting expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected)
}
}
}
func TestQuoting(t *testing.T) {
tf := &TextFormatter{DisableColors: true}
checkQuoting := func(q bool, value interface{}) {
b, _ := tf.Format(WithField("test", value))
idx := bytes.Index(b, ([]byte)("test="))
cont := bytes.Contains(b[idx+5:], []byte(tf.QuoteCharacter))
cont := bytes.Contains(b[idx+5:], []byte("\""))
if cont != q {
if q {
t.Errorf("quoting expected for: %#v", value)
@ -28,24 +48,18 @@ func TestQuoting(t *testing.T) {
checkQuoting(false, "abcd")
checkQuoting(false, "v1.0")
checkQuoting(false, "1234567890")
checkQuoting(true, "/foobar")
checkQuoting(false, "/foobar")
checkQuoting(false, "foo_bar")
checkQuoting(false, "foo@bar")
checkQuoting(false, "foobar^")
checkQuoting(false, "+/-_^@f.oobar")
checkQuoting(true, "foobar$")
checkQuoting(true, "&foobar")
checkQuoting(true, "x y")
checkQuoting(true, "x,y")
checkQuoting(false, errors.New("invalid"))
checkQuoting(true, errors.New("invalid argument"))
// Test for custom quote character.
tf.QuoteCharacter = "`"
checkQuoting(false, "")
checkQuoting(false, "abcd")
checkQuoting(true, "/foobar")
checkQuoting(true, errors.New("invalid argument"))
// Test for multi-character quotes.
tf.QuoteCharacter = "§~±"
checkQuoting(false, "abcd")
checkQuoting(true, errors.New("invalid argument"))
// Test for quoting empty fields.
tf.QuoteEmptyFields = true
checkQuoting(true, "")
@ -53,13 +67,53 @@ func TestQuoting(t *testing.T) {
checkQuoting(true, errors.New("invalid argument"))
}
func TestEscaping(t *testing.T) {
tf := &TextFormatter{DisableColors: true}
testCases := []struct {
value string
expected string
}{
{`ba"r`, `ba\"r`},
{`ba'r`, `ba'r`},
}
for _, tc := range testCases {
b, _ := tf.Format(WithField("test", tc.value))
if !bytes.Contains(b, []byte(tc.expected)) {
t.Errorf("escaping expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected)
}
}
}
func TestEscaping_Interface(t *testing.T) {
tf := &TextFormatter{DisableColors: true}
ts := time.Now()
testCases := []struct {
value interface{}
expected string
}{
{ts, fmt.Sprintf("\"%s\"", ts.String())},
{errors.New("error: something went wrong"), "\"error: something went wrong\""},
}
for _, tc := range testCases {
b, _ := tf.Format(WithField("test", tc.value))
if !bytes.Contains(b, []byte(tc.expected)) {
t.Errorf("escaping expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected)
}
}
}
func TestTimestampFormat(t *testing.T) {
checkTimeStr := func(format string) {
customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format}
customStr, _ := customFormatter.Format(WithField("test", "test"))
timeStart := bytes.Index(customStr, ([]byte)("time="))
timeEnd := bytes.Index(customStr, ([]byte)("level="))
timeStr := customStr[timeStart+5+len(customFormatter.QuoteCharacter) : timeEnd-1-len(customFormatter.QuoteCharacter)]
timeStr := customStr[timeStart+5+len("\"") : timeEnd-1-len("\"")]
if format == "" {
format = time.RFC3339
}