diff --git a/cmd/cloud.go b/cmd/cloud.go
index 502ff72e410..de279baa5bf 100644
--- a/cmd/cloud.go
+++ b/cmd/cloud.go
@@ -22,11 +22,14 @@ package cmd
import (
"bytes"
+ "context"
"encoding/json"
"fmt"
"os"
"os/signal"
"path/filepath"
+ "strconv"
+ "sync"
"syscall"
"time"
@@ -51,7 +54,10 @@ const (
)
//nolint:gochecknoglobals
-var exitOnRunning = os.Getenv("K6_EXIT_ON_RUNNING") != ""
+var (
+ exitOnRunning = os.Getenv("K6_EXIT_ON_RUNNING") != ""
+ showCloudLogs = true
+)
//nolint:gochecknoglobals
var cloudCmd = &cobra.Command{
@@ -59,11 +65,26 @@ var cloudCmd = &cobra.Command{
Short: "Run a test on the cloud",
Long: `Run a test on the cloud.
-This will execute the test on the Load Impact cloud service. Use "k6 login cloud" to authenticate.`,
+This will execute the test on the k6 cloud service. Use "k6 login cloud" to authenticate.`,
Example: `
k6 cloud script.js`[1:],
Args: exactArgsWithMsg(1, "arg should either be \"-\", if reading script from stdin, or a path to a script file"),
RunE: func(cmd *cobra.Command, args []string) error {
+ // TODO: don't use the Global logger
+ logger := logrus.StandardLogger()
+ // we specifically first parse it and return an error if it has bad value and then check if
+ // we are going to set it ... so we always parse it instead of it breaking the command if
+ // the cli flag is removed
+ if showCloudLogsEnv, ok := os.LookupEnv("K6_SHOW_CLOUD_LOGS"); ok {
+ showCloudLogsValue, err := strconv.ParseBool(showCloudLogsEnv)
+ if err != nil {
+ return fmt.Errorf("parsing K6_SHOW_CLOUD_LOGS returned an error: %w", err)
+ }
+ if !cmd.Flags().Changed("show-logs") {
+ showCloudLogs = showCloudLogsValue
+ }
+
+ }
// TODO: disable in quiet mode?
_, _ = BannerColor.Fprintf(stdout, "\n%s\n\n", consts.Banner())
@@ -81,8 +102,6 @@ This will execute the test on the Load Impact cloud service. Use "k6 login cloud
filename := args[0]
filesystems := loader.CreateFilesystems()
- // TODO: don't use the Global logger
- logger := logrus.StandardLogger()
src, err := loader.ReadSource(logger, filename, pwd, filesystems, os.Stdin)
if err != nil {
return err
@@ -207,6 +226,16 @@ This will execute the test on the Load Impact cloud service. Use "k6 login cloud
pb.WithConstProgress(0, "Initializing the cloud test"),
)
+ progressCtx, progressCancel := context.WithCancel(context.Background())
+ progressBarWG := &sync.WaitGroup{}
+ progressBarWG.Add(1)
+ defer progressBarWG.Wait()
+ defer progressCancel()
+ go func() {
+ showProgress(progressCtx, conf, []*pb.ProgressBar{progressBar}, logger)
+ progressBarWG.Done()
+ }()
+
// The quiet option hides the progress bar and disallow aborting the test
if quiet {
return nil
@@ -247,6 +276,15 @@ This will execute the test on the Load Impact cloud service. Use "k6 login cloud
var progressErr error
ticker := time.NewTicker(time.Millisecond * 2000)
shouldExitLoop := false
+ if showCloudLogs {
+ go func() {
+ logger.Debug("Connecting to cloud logs server...")
+ // TODO replace with another context
+ if err := cloudConfig.StreamLogsToLogger(context.Background(), logger, refID, 0); err != nil {
+ logger.WithError(err).Error("error while tailing cloud logs")
+ }
+ }()
+ }
runningLoop:
for {
@@ -257,7 +295,6 @@ This will execute the test on the Load Impact cloud service. Use "k6 login cloud
if (testProgress.RunStatus > lib.RunStatusRunning) || (exitOnRunning && testProgress.RunStatus == lib.RunStatusRunning) {
shouldExitLoop = true
}
- printBar(progressBar)
} else {
logger.WithError(progressErr).Error("Test progress error")
}
@@ -305,6 +342,10 @@ func cloudCmdFlagSet() *pflag.FlagSet {
// K6_EXIT_ON_RUNNING=true won't affect the usage message
flags.Lookup("exit-on-running").DefValue = "false"
+ // read the comments above for explanation why this is done this way and what are the problems
+ flags.BoolVar(&showCloudLogs, "show-logs", showCloudLogs,
+ "enable showing of logs when a test is executed in the cloud")
+
return flags
}
diff --git a/cmd/run.go b/cmd/run.go
index 0c0f46cb42f..f81a0d06950 100644
--- a/cmd/run.go
+++ b/cmd/run.go
@@ -187,7 +187,11 @@ a commandline interface for interacting with it.`,
progressBarWG := &sync.WaitGroup{}
progressBarWG.Add(1)
go func() {
- showProgress(progressCtx, conf, execScheduler, logger)
+ pbs := []*pb.ProgressBar{execScheduler.GetInitProgressBar()}
+ for _, s := range execScheduler.GetExecutors() {
+ pbs = append(pbs, s.GetProgress())
+ }
+ showProgress(progressCtx, conf, pbs, logger)
progressBarWG.Done()
}()
diff --git a/cmd/ui.go b/cmd/ui.go
index e0042cf51ce..424844e015b 100644
--- a/cmd/ui.go
+++ b/cmd/ui.go
@@ -35,7 +35,6 @@ import (
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh/terminal"
- "github.com/loadimpact/k6/core/local"
"github.com/loadimpact/k6/lib"
"github.com/loadimpact/k6/ui"
"github.com/loadimpact/k6/ui/pb"
@@ -242,17 +241,12 @@ func renderMultipleBars(
// nolint:funlen
func showProgress(
ctx context.Context, conf Config,
- execScheduler *local.ExecutionScheduler, logger *logrus.Logger,
+ pbs []*pb.ProgressBar, logger *logrus.Logger,
) {
- if quiet || conf.HTTPDebug.Valid && conf.HTTPDebug.String != "" {
+ if quiet {
return
}
- pbs := []*pb.ProgressBar{execScheduler.GetInitProgressBar()}
- for _, s := range execScheduler.GetExecutors() {
- pbs = append(pbs, s.GetProgress())
- }
-
var errTermGetSize bool
termWidth := defaultTermWidth
if stdoutTTY {
diff --git a/go.mod b/go.mod
index c388ccc950b..fbbd62b80af 100644
--- a/go.mod
+++ b/go.mod
@@ -55,7 +55,7 @@ require (
github.com/pmezard/go-difflib v1.0.0
github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 // indirect
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516
- github.com/sirupsen/logrus v1.1.2-0.20181101075517-7eeb7b7cbdeb
+ github.com/sirupsen/logrus v1.6.0
github.com/spf13/afero v1.1.1
github.com/spf13/cobra v0.0.4-0.20180629152535-a114f312e075
github.com/spf13/pflag v1.0.1
diff --git a/go.sum b/go.sum
index db3c94cfe1a..fd7b88abaf0 100644
--- a/go.sum
+++ b/go.sum
@@ -78,8 +78,8 @@ github.com/klauspost/compress v1.7.2 h1:liMOoeIvFpr9kEvalrZ7VVBA4wGf7zfOgwBjzz/5
github.com/klauspost/compress v1.7.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kubernetes/helm v2.9.0+incompatible h1:X6Tl40RMiqT0GD8hT3+jFPgkZV1EB6vYsoJDX8YkY+c=
github.com/kubernetes/helm v2.9.0+incompatible/go.mod h1:3Nb8I82ptmDi7OvvBQK25X1bwxg+WMAkusUQXHxu8ag=
github.com/labstack/echo v3.2.6+incompatible h1:28U/uXFFKBIP+VQIqq641LuYhMS7Br9ZlwEXERaohCc=
@@ -123,15 +123,14 @@ github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFE
github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516 h1:ofR1ZdrNSkiWcMsRrubK9tb2/SlZVWttAfqUjJi6QYc=
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
-github.com/sirupsen/logrus v1.1.2-0.20181101075517-7eeb7b7cbdeb h1:Zs7k4rxIvfXFjav0ia3QqnauqGfG2hr8+y6NZYwq8iA=
-github.com/sirupsen/logrus v1.1.2-0.20181101075517-7eeb7b7cbdeb/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/spf13/afero v1.1.1 h1:Lt3ihYMlE+lreX1GS4Qw4ZsNpYQLxIXKBTEOXm3nt6I=
github.com/spf13/afero v1.1.1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cobra v0.0.4-0.20180629152535-a114f312e075 h1:bfSj+hHTrZKbMJHEldrx659CxsvTHbAznKTfb42l2M4=
github.com/spf13/cobra v0.0.4-0.20180629152535-a114f312e075/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/tidwall/gjson v1.1.3 h1:u4mspaByxY+Qk4U1QYYVzGFI8qxN/3jtEV0ZDb2vRic=
diff --git a/stats/cloud/cloud_easyjson.go b/stats/cloud/cloud_easyjson.go
index 41b733fce78..d0d5a75d476 100644
--- a/stats/cloud/cloud_easyjson.go
+++ b/stats/cloud/cloud_easyjson.go
@@ -82,7 +82,362 @@ func (v samples) MarshalEasyJSON(w *jwriter.Writer) {
func (v *samples) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud(l, v)
}
-func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud1(in *jlexer.Lexer, out *SampleDataSingle) {
+func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud1(in *jlexer.Lexer, out *msgStreams) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "stream":
+ if in.IsNull() {
+ in.Skip()
+ } else {
+ in.Delim('{')
+ out.Stream = make(map[string]string)
+ for !in.IsDelim('}') {
+ key := string(in.String())
+ in.WantColon()
+ var v4 string
+ v4 = string(in.String())
+ (out.Stream)[key] = v4
+ in.WantComma()
+ }
+ in.Delim('}')
+ }
+ case "values":
+ if in.IsNull() {
+ in.Skip()
+ out.Values = nil
+ } else {
+ in.Delim('[')
+ if out.Values == nil {
+ if !in.IsDelim(']') {
+ out.Values = make([][2]string, 0, 2)
+ } else {
+ out.Values = [][2]string{}
+ }
+ } else {
+ out.Values = (out.Values)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v5 [2]string
+ if in.IsNull() {
+ in.Skip()
+ } else {
+ in.Delim('[')
+ v6 := 0
+ for !in.IsDelim(']') {
+ if v6 < 2 {
+ (v5)[v6] = string(in.String())
+ v6++
+ } else {
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ out.Values = append(out.Values, v5)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud1(out *jwriter.Writer, in msgStreams) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ {
+ const prefix string = ",\"stream\":"
+ out.RawString(prefix[1:])
+ if in.Stream == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 {
+ out.RawString(`null`)
+ } else {
+ out.RawByte('{')
+ v7First := true
+ for v7Name, v7Value := range in.Stream {
+ if v7First {
+ v7First = false
+ } else {
+ out.RawByte(',')
+ }
+ out.String(string(v7Name))
+ out.RawByte(':')
+ out.String(string(v7Value))
+ }
+ out.RawByte('}')
+ }
+ }
+ {
+ const prefix string = ",\"values\":"
+ out.RawString(prefix)
+ if in.Values == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
+ out.RawString("null")
+ } else {
+ out.RawByte('[')
+ for v8, v9 := range in.Values {
+ if v8 > 0 {
+ out.RawByte(',')
+ }
+ out.RawByte('[')
+ for v10 := range v9 {
+ if v10 > 0 {
+ out.RawByte(',')
+ }
+ out.String(string((v9)[v10]))
+ }
+ out.RawByte(']')
+ }
+ out.RawByte(']')
+ }
+ }
+ out.RawByte('}')
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v msgStreams) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud1(w, v)
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *msgStreams) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud1(l, v)
+}
+func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud2(in *jlexer.Lexer, out *msgDroppedEntries) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "labels":
+ if in.IsNull() {
+ in.Skip()
+ } else {
+ in.Delim('{')
+ out.Labels = make(map[string]string)
+ for !in.IsDelim('}') {
+ key := string(in.String())
+ in.WantColon()
+ var v11 string
+ v11 = string(in.String())
+ (out.Labels)[key] = v11
+ in.WantComma()
+ }
+ in.Delim('}')
+ }
+ case "timestamp":
+ out.Timestamp = string(in.String())
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud2(out *jwriter.Writer, in msgDroppedEntries) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ {
+ const prefix string = ",\"labels\":"
+ out.RawString(prefix[1:])
+ if in.Labels == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 {
+ out.RawString(`null`)
+ } else {
+ out.RawByte('{')
+ v12First := true
+ for v12Name, v12Value := range in.Labels {
+ if v12First {
+ v12First = false
+ } else {
+ out.RawByte(',')
+ }
+ out.String(string(v12Name))
+ out.RawByte(':')
+ out.String(string(v12Value))
+ }
+ out.RawByte('}')
+ }
+ }
+ {
+ const prefix string = ",\"timestamp\":"
+ out.RawString(prefix)
+ out.String(string(in.Timestamp))
+ }
+ out.RawByte('}')
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v msgDroppedEntries) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud2(w, v)
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *msgDroppedEntries) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud2(l, v)
+}
+func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud3(in *jlexer.Lexer, out *msg) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "streams":
+ if in.IsNull() {
+ in.Skip()
+ out.Streams = nil
+ } else {
+ in.Delim('[')
+ if out.Streams == nil {
+ if !in.IsDelim(']') {
+ out.Streams = make([]msgStreams, 0, 2)
+ } else {
+ out.Streams = []msgStreams{}
+ }
+ } else {
+ out.Streams = (out.Streams)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v13 msgStreams
+ (v13).UnmarshalEasyJSON(in)
+ out.Streams = append(out.Streams, v13)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ case "dropped_entries":
+ if in.IsNull() {
+ in.Skip()
+ out.DroppedEntries = nil
+ } else {
+ in.Delim('[')
+ if out.DroppedEntries == nil {
+ if !in.IsDelim(']') {
+ out.DroppedEntries = make([]msgDroppedEntries, 0, 2)
+ } else {
+ out.DroppedEntries = []msgDroppedEntries{}
+ }
+ } else {
+ out.DroppedEntries = (out.DroppedEntries)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v14 msgDroppedEntries
+ (v14).UnmarshalEasyJSON(in)
+ out.DroppedEntries = append(out.DroppedEntries, v14)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud3(out *jwriter.Writer, in msg) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ {
+ const prefix string = ",\"streams\":"
+ out.RawString(prefix[1:])
+ if in.Streams == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
+ out.RawString("null")
+ } else {
+ out.RawByte('[')
+ for v15, v16 := range in.Streams {
+ if v15 > 0 {
+ out.RawByte(',')
+ }
+ (v16).MarshalEasyJSON(out)
+ }
+ out.RawByte(']')
+ }
+ }
+ {
+ const prefix string = ",\"dropped_entries\":"
+ out.RawString(prefix)
+ if in.DroppedEntries == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
+ out.RawString("null")
+ } else {
+ out.RawByte('[')
+ for v17, v18 := range in.DroppedEntries {
+ if v17 > 0 {
+ out.RawByte(',')
+ }
+ (v18).MarshalEasyJSON(out)
+ }
+ out.RawByte(']')
+ }
+ }
+ out.RawByte('}')
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v msg) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud3(w, v)
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *msg) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud3(l, v)
+}
+func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud4(in *jlexer.Lexer, out *SampleDataSingle) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
@@ -131,7 +486,7 @@ func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud1(in *jlexer.Lexer, ou
in.Consumed()
}
}
-func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud1(out *jwriter.Writer, in SampleDataSingle) {
+func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud4(out *jwriter.Writer, in SampleDataSingle) {
out.RawByte('{')
first := true
_ = first
@@ -160,14 +515,14 @@ func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud1(out *jwriter.Writer,
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v SampleDataSingle) MarshalEasyJSON(w *jwriter.Writer) {
- easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud1(w, v)
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud4(w, v)
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *SampleDataSingle) UnmarshalEasyJSON(l *jlexer.Lexer) {
- easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud1(l, v)
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud4(l, v)
}
-func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud2(in *jlexer.Lexer, out *SampleDataMap) {
+func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud5(in *jlexer.Lexer, out *SampleDataMap) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
@@ -217,9 +572,9 @@ func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud2(in *jlexer.Lexer, ou
for !in.IsDelim('}') {
key := string(in.String())
in.WantColon()
- var v4 float64
- v4 = float64(in.Float64())
- (out.Values)[key] = v4
+ var v19 float64
+ v19 = float64(in.Float64())
+ (out.Values)[key] = v19
in.WantComma()
}
in.Delim('}')
@@ -234,7 +589,7 @@ func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud2(in *jlexer.Lexer, ou
in.Consumed()
}
}
-func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud2(out *jwriter.Writer, in SampleDataMap) {
+func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud5(out *jwriter.Writer, in SampleDataMap) {
out.RawByte('{')
first := true
_ = first
@@ -258,16 +613,16 @@ func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud2(out *jwriter.Writer,
out.RawString(prefix)
{
out.RawByte('{')
- v5First := true
- for v5Name, v5Value := range in.Values {
- if v5First {
- v5First = false
+ v20First := true
+ for v20Name, v20Value := range in.Values {
+ if v20First {
+ v20First = false
} else {
out.RawByte(',')
}
- out.String(string(v5Name))
+ out.String(string(v20Name))
out.RawByte(':')
- out.Float64(float64(v5Value))
+ out.Float64(float64(v20Value))
}
out.RawByte('}')
}
@@ -277,14 +632,14 @@ func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud2(out *jwriter.Writer,
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v SampleDataMap) MarshalEasyJSON(w *jwriter.Writer) {
- easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud2(w, v)
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud5(w, v)
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *SampleDataMap) UnmarshalEasyJSON(l *jlexer.Lexer) {
- easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud2(l, v)
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud5(l, v)
}
-func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud3(in *jlexer.Lexer, out *SampleDataAggregatedHTTPReqs) {
+func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud6(in *jlexer.Lexer, out *SampleDataAggregatedHTTPReqs) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
@@ -333,7 +688,7 @@ func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud3(in *jlexer.Lexer, ou
in.Consumed()
}
}
-func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud3(out *jwriter.Writer, in SampleDataAggregatedHTTPReqs) {
+func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud6(out *jwriter.Writer, in SampleDataAggregatedHTTPReqs) {
out.RawByte('{')
first := true
_ = first
@@ -367,12 +722,12 @@ func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud3(out *jwriter.Writer,
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v SampleDataAggregatedHTTPReqs) MarshalEasyJSON(w *jwriter.Writer) {
- easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud3(w, v)
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud6(w, v)
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *SampleDataAggregatedHTTPReqs) UnmarshalEasyJSON(l *jlexer.Lexer) {
- easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud3(l, v)
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud6(l, v)
}
func easyjson9def2ecdDecode(in *jlexer.Lexer, out *struct {
Duration AggregatedMetric `json:"http_req_duration"`
@@ -402,19 +757,19 @@ func easyjson9def2ecdDecode(in *jlexer.Lexer, out *struct {
}
switch key {
case "http_req_duration":
- easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud4(in, &out.Duration)
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud7(in, &out.Duration)
case "http_req_blocked":
- easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud4(in, &out.Blocked)
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud7(in, &out.Blocked)
case "http_req_connecting":
- easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud4(in, &out.Connecting)
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud7(in, &out.Connecting)
case "http_req_tls_handshaking":
- easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud4(in, &out.TLSHandshaking)
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud7(in, &out.TLSHandshaking)
case "http_req_sending":
- easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud4(in, &out.Sending)
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud7(in, &out.Sending)
case "http_req_waiting":
- easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud4(in, &out.Waiting)
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud7(in, &out.Waiting)
case "http_req_receiving":
- easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud4(in, &out.Receiving)
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud7(in, &out.Receiving)
default:
in.SkipRecursive()
}
@@ -440,41 +795,41 @@ func easyjson9def2ecdEncode(out *jwriter.Writer, in struct {
{
const prefix string = ",\"http_req_duration\":"
out.RawString(prefix[1:])
- easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud4(out, in.Duration)
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud7(out, in.Duration)
}
{
const prefix string = ",\"http_req_blocked\":"
out.RawString(prefix)
- easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud4(out, in.Blocked)
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud7(out, in.Blocked)
}
{
const prefix string = ",\"http_req_connecting\":"
out.RawString(prefix)
- easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud4(out, in.Connecting)
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud7(out, in.Connecting)
}
{
const prefix string = ",\"http_req_tls_handshaking\":"
out.RawString(prefix)
- easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud4(out, in.TLSHandshaking)
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud7(out, in.TLSHandshaking)
}
{
const prefix string = ",\"http_req_sending\":"
out.RawString(prefix)
- easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud4(out, in.Sending)
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud7(out, in.Sending)
}
{
const prefix string = ",\"http_req_waiting\":"
out.RawString(prefix)
- easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud4(out, in.Waiting)
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud7(out, in.Waiting)
}
{
const prefix string = ",\"http_req_receiving\":"
out.RawString(prefix)
- easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud4(out, in.Receiving)
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud7(out, in.Receiving)
}
out.RawByte('}')
}
-func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud4(in *jlexer.Lexer, out *AggregatedMetric) {
+func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud7(in *jlexer.Lexer, out *AggregatedMetric) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
@@ -509,7 +864,7 @@ func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud4(in *jlexer.Lexer, ou
in.Consumed()
}
}
-func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud4(out *jwriter.Writer, in AggregatedMetric) {
+func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud7(out *jwriter.Writer, in AggregatedMetric) {
out.RawByte('{')
first := true
_ = first
@@ -530,7 +885,7 @@ func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud4(out *jwriter.Writer,
}
out.RawByte('}')
}
-func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud5(in *jlexer.Lexer, out *Sample) {
+func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud8(in *jlexer.Lexer, out *Sample) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
@@ -571,7 +926,7 @@ func easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud5(in *jlexer.Lexer, ou
in.Consumed()
}
}
-func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud5(out *jwriter.Writer, in Sample) {
+func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud8(out *jwriter.Writer, in Sample) {
out.RawByte('{')
first := true
_ = first
@@ -601,10 +956,10 @@ func easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud5(out *jwriter.Writer,
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v Sample) MarshalEasyJSON(w *jwriter.Writer) {
- easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud5(w, v)
+ easyjson9def2ecdEncodeGithubComLoadimpactK6StatsCloud8(w, v)
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *Sample) UnmarshalEasyJSON(l *jlexer.Lexer) {
- easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud5(l, v)
+ easyjson9def2ecdDecodeGithubComLoadimpactK6StatsCloud8(l, v)
}
diff --git a/stats/cloud/config.go b/stats/cloud/config.go
index f74367b7af6..1c13f168f4f 100644
--- a/stats/cloud/config.go
+++ b/stats/cloud/config.go
@@ -38,6 +38,7 @@ type Config struct {
Name null.String `json:"name" envconfig:"K6_CLOUD_NAME"`
Host null.String `json:"host" envconfig:"K6_CLOUD_HOST"`
+ LogsHost null.String `json:"-" envconfig:"K6_CLOUD_LOGS_HOST"`
PushRefID null.String `json:"pushRefID" envconfig:"K6_CLOUD_PUSH_REF_ID"`
WebAppURL null.String `json:"webAppURL" envconfig:"K6_CLOUD_WEB_APP_URL"`
NoCompress null.Bool `json:"noCompress" envconfig:"K6_CLOUD_NO_COMPRESS"`
@@ -156,6 +157,7 @@ type Config struct {
func NewConfig() Config {
return Config{
Host: null.NewString("https://ingest.k6.io", false),
+ LogsHost: null.NewString("wss://cloudlogs.k6.io/api/v1/tail", false),
WebAppURL: null.NewString("https://app.k6.io", false),
MetricPushInterval: types.NewNullDuration(1*time.Second, false),
MetricPushConcurrency: null.NewInt(1, false),
@@ -190,6 +192,9 @@ func (c Config) Apply(cfg Config) Config {
if cfg.Host.Valid && cfg.Host.String != "" {
c.Host = cfg.Host
}
+ if cfg.LogsHost.Valid && cfg.LogsHost.String != "" {
+ c.LogsHost = cfg.LogsHost
+ }
if cfg.WebAppURL.Valid {
c.WebAppURL = cfg.WebAppURL
}
diff --git a/stats/cloud/logs.go b/stats/cloud/logs.go
new file mode 100644
index 00000000000..ffd17de7970
--- /dev/null
+++ b/stats/cloud/logs.go
@@ -0,0 +1,176 @@
+/*
+ *
+ * k6 - a next-generation load testing tool
+ * Copyright (C) 2020 Load Impact
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package cloud
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "net/url"
+ "strconv"
+ "time"
+
+ "github.com/gorilla/websocket"
+ "github.com/mailru/easyjson"
+ "github.com/sirupsen/logrus"
+)
+
+//easyjson:json
+type msg struct {
+ Streams []msgStreams `json:"streams"`
+ DroppedEntries []msgDroppedEntries `json:"dropped_entries"`
+}
+
+//easyjson:json
+type msgStreams struct {
+ Stream map[string]string `json:"stream"`
+ Values [][2]string `json:"values"` // this can be optimized
+}
+
+//easyjson:json
+type msgDroppedEntries struct {
+ Labels map[string]string `json:"labels"`
+ Timestamp string `json:"timestamp"`
+}
+
+func (m *msg) Log(logger logrus.FieldLogger) {
+ var level string
+
+ for _, stream := range m.Streams {
+ fields := labelsToLogrusFields(stream.Stream)
+ var ok bool
+ if level, ok = stream.Stream["level"]; ok {
+ delete(fields, "level")
+ }
+
+ for _, value := range stream.Values {
+ nsec, _ := strconv.Atoi(value[0])
+ e := logger.WithFields(fields).WithTime(time.Unix(0, int64(nsec)))
+ lvl, err := logrus.ParseLevel(level)
+ if err != nil {
+ e.Info(value[1])
+ e.Warn("last message had unknown level " + level)
+ } else {
+ e.Log(lvl, value[1])
+ }
+ }
+ }
+
+ for _, dropped := range m.DroppedEntries {
+ nsec, _ := strconv.Atoi(dropped.Timestamp)
+ logger.WithFields(labelsToLogrusFields(dropped.Labels)).WithTime(time.Unix(0, int64(nsec))).Warn("dropped")
+ }
+}
+
+func labelsToLogrusFields(labels map[string]string) logrus.Fields {
+ fields := make(logrus.Fields, len(labels))
+
+ for key, val := range labels {
+ fields[key] = val
+ }
+
+ return fields
+}
+
+func (c *Config) getRequest(referenceID string, start time.Duration) (*url.URL, error) {
+ u, err := url.Parse(c.LogsHost.String)
+ if err != nil {
+ return nil, fmt.Errorf("couldn't parse cloud logs host %w", err)
+ }
+
+ u.RawQuery = fmt.Sprintf(`query={test_run_id="%s"}&start=%d`,
+ referenceID,
+ time.Now().Add(-start).UnixNano(),
+ )
+
+ return u, nil
+}
+
+// StreamLogsToLogger streams the logs for the configured test to the provided logger until ctx is
+// Done or an error occurs.
+func (c *Config) StreamLogsToLogger(
+ ctx context.Context, logger logrus.FieldLogger, referenceID string, start time.Duration,
+) error {
+ u, err := c.getRequest(referenceID, start)
+ if err != nil {
+ return err
+ }
+
+ headers := make(http.Header)
+ headers.Add("Sec-WebSocket-Protocol", "token="+c.Token.String)
+
+ // We don't need to close the http body or use it for anything until we want to actually log
+ // what the server returned as body when it errors out
+ conn, _, err := websocket.DefaultDialer.DialContext(ctx, u.String(), headers) //nolint:bodyclose
+ if err != nil {
+ return err
+ }
+
+ go func() {
+ <-ctx.Done()
+
+ _ = conn.WriteControl(
+ websocket.CloseMessage,
+ websocket.FormatCloseMessage(websocket.CloseGoingAway, "closing"),
+ time.Now().Add(time.Second))
+
+ _ = conn.Close()
+ }()
+
+ msgBuffer := make(chan []byte, 10)
+
+ defer close(msgBuffer)
+
+ go func() {
+ for message := range msgBuffer {
+ var m msg
+ err := easyjson.Unmarshal(message, &m)
+ if err != nil {
+ logger.WithError(err).Errorf("couldn't unmarshal a message from the cloud: %s", string(message))
+
+ continue
+ }
+
+ m.Log(logger)
+ }
+ }()
+
+ for {
+ _, message, err := conn.ReadMessage()
+ select { // check if we should stop before continuing
+ case <-ctx.Done():
+ return nil
+ default:
+ }
+
+ if err != nil {
+ logger.WithError(err).Warn("error reading a message from the cloud")
+
+ return err
+ }
+
+ select {
+ case <-ctx.Done():
+ return nil
+ case msgBuffer <- message:
+ }
+ }
+}
diff --git a/stats/cloud/logs_test.go b/stats/cloud/logs_test.go
new file mode 100644
index 00000000000..840829ed71d
--- /dev/null
+++ b/stats/cloud/logs_test.go
@@ -0,0 +1,124 @@
+/*
+ *
+ * k6 - a next-generation load testing tool
+ * Copyright (C) 2020 Load Impact
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package cloud
+
+import (
+ "io/ioutil"
+ "testing"
+ "time"
+
+ "github.com/loadimpact/k6/lib/testutils"
+ "github.com/mailru/easyjson"
+ "github.com/sirupsen/logrus"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestMsgParsing(t *testing.T) {
+ m := `{
+ "streams": [
+ {
+ "stream": {
+ "key1": "value1",
+ "key2": "value2"
+ },
+ "values": [
+ [
+ "1598282752000000000",
+ "something to log"
+ ]
+ ]
+ }
+ ],
+ "dropped_entries": [
+ {
+ "labels": {
+ "key3": "value1",
+ "key4": "value2"
+ },
+ "timestamp": "1598282752000000000"
+ }
+ ]
+}
+`
+ expectMsg := msg{
+ Streams: []msgStreams{
+ {
+ Stream: map[string]string{"key1": "value1", "key2": "value2"},
+ Values: [][2]string{{"1598282752000000000", "something to log"}},
+ },
+ },
+ DroppedEntries: []msgDroppedEntries{
+ {
+ Labels: map[string]string{"key3": "value1", "key4": "value2"},
+ Timestamp: "1598282752000000000",
+ },
+ },
+ }
+ var message msg
+ require.NoError(t, easyjson.Unmarshal([]byte(m), &message))
+ require.Equal(t, expectMsg, message)
+}
+
+func TestMSGLog(t *testing.T) {
+ expectMsg := msg{
+ Streams: []msgStreams{
+ {
+ Stream: map[string]string{"key1": "value1", "key2": "value2"},
+ Values: [][2]string{{"1598282752000000000", "something to log"}},
+ },
+ {
+ Stream: map[string]string{"key1": "value1", "key2": "value2", "level": "warn"},
+ Values: [][2]string{{"1598282752000000000", "something else log"}},
+ },
+ },
+ DroppedEntries: []msgDroppedEntries{
+ {
+ Labels: map[string]string{"key3": "value1", "key4": "value2", "level": "panic"},
+ Timestamp: "1598282752000000000",
+ },
+ },
+ }
+
+ logger := logrus.New()
+ logger.Out = ioutil.Discard
+ hook := &testutils.SimpleLogrusHook{HookedLevels: logrus.AllLevels}
+ logger.AddHook(hook)
+ expectMsg.Log(logger)
+ logLines := hook.Drain()
+ assert.Equal(t, 4, len(logLines))
+ expectTime := time.Unix(0, 1598282752000000000)
+ for i, entry := range logLines {
+ var expectedMsg string
+ switch i {
+ case 0:
+ expectedMsg = "something to log"
+ case 1:
+ expectedMsg = "last message had unknown level "
+ case 2:
+ expectedMsg = "something else log"
+ case 3:
+ expectedMsg = "dropped"
+ }
+ require.Equal(t, expectedMsg, entry.Message)
+ require.Equal(t, expectTime, entry.Time)
+ }
+}
diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md b/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
index 949b77e304e..09a4a35c9bb 100644
--- a/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
+++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
@@ -26,6 +26,8 @@ The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de).
We thank all the authors who provided code to this library:
* Felix Kollmann
+* Nicolas Perraut
+* @dirty49374
## License
diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
index ef18d8f9787..57f530ae83f 100644
--- a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
+++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
@@ -4,7 +4,6 @@ package sequences
import (
"syscall"
- "unsafe"
)
var (
@@ -27,7 +26,7 @@ func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error {
mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING
}
- ret, _, err := setConsoleMode.Call(uintptr(unsafe.Pointer(stream)), uintptr(mode))
+ ret, _, err := setConsoleMode.Call(uintptr(stream), uintptr(mode))
if ret == 0 {
return err
}
diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go
new file mode 100644
index 00000000000..df61a6f2f6f
--- /dev/null
+++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go
@@ -0,0 +1,11 @@
+// +build linux darwin
+
+package sequences
+
+import (
+ "fmt"
+)
+
+func EnableVirtualTerminalProcessing(stream uintptr, enable bool) error {
+ return fmt.Errorf("windows only package")
+}
diff --git a/vendor/github.com/sirupsen/logrus/CHANGELOG.md b/vendor/github.com/sirupsen/logrus/CHANGELOG.md
index ff047186909..584026d67ca 100644
--- a/vendor/github.com/sirupsen/logrus/CHANGELOG.md
+++ b/vendor/github.com/sirupsen/logrus/CHANGELOG.md
@@ -1,3 +1,68 @@
+# 1.6.0
+Fixes:
+ * end of line cleanup
+ * revert the entry concurrency bug fix whic leads to deadlock under some circumstances
+ * update dependency on go-windows-terminal-sequences to fix a crash with go 1.14
+
+Features:
+ * add an option to the `TextFormatter` to completely disable fields quoting
+
+# 1.5.0
+Code quality:
+ * add golangci linter run on travis
+
+Fixes:
+ * add mutex for hooks concurrent access on `Entry` data
+ * caller function field for go1.14
+ * fix build issue for gopherjs target
+
+Feature:
+ * add an hooks/writer sub-package whose goal is to split output on different stream depending on the trace level
+ * add a `DisableHTMLEscape` option in the `JSONFormatter`
+ * add `ForceQuote` and `PadLevelText` options in the `TextFormatter`
+
+# 1.4.2
+ * Fixes build break for plan9, nacl, solaris
+# 1.4.1
+This new release introduces:
+ * Enhance TextFormatter to not print caller information when they are empty (#944)
+ * Remove dependency on golang.org/x/crypto (#932, #943)
+
+Fixes:
+ * Fix Entry.WithContext method to return a copy of the initial entry (#941)
+
+# 1.4.0
+This new release introduces:
+ * Add `DeferExitHandler`, similar to `RegisterExitHandler` but prepending the handler to the list of handlers (semantically like `defer`) (#848).
+ * Add `CallerPrettyfier` to `JSONFormatter` and `TextFormatter` (#909, #911)
+ * Add `Entry.WithContext()` and `Entry.Context`, to set a context on entries to be used e.g. in hooks (#919).
+
+Fixes:
+ * Fix wrong method calls `Logger.Print` and `Logger.Warningln` (#893).
+ * Update `Entry.Logf` to not do string formatting unless the log level is enabled (#903)
+ * Fix infinite recursion on unknown `Level.String()` (#907)
+ * Fix race condition in `getCaller` (#916).
+
+
+# 1.3.0
+This new release introduces:
+ * Log, Logf, Logln functions for Logger and Entry that take a Level
+
+Fixes:
+ * Building prometheus node_exporter on AIX (#840)
+ * Race condition in TextFormatter (#468)
+ * Travis CI import path (#868)
+ * Remove coloured output on Windows (#862)
+ * Pointer to func as field in JSONFormatter (#870)
+ * Properly marshal Levels (#873)
+
+# 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
diff --git a/vendor/github.com/sirupsen/logrus/README.md b/vendor/github.com/sirupsen/logrus/README.md
index 39873105514..5796706dbfa 100644
--- a/vendor/github.com/sirupsen/logrus/README.md
+++ b/vendor/github.com/sirupsen/logrus/README.md
@@ -1,8 +1,28 @@
-# Logrus [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus)
+# Logrus [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![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.
+**Logrus is in maintenance-mode.** We will not be introducing new features. It's
+simply too hard to do in a way that won't break many people's projects, which is
+the last thing you want from your Logging library (again...).
+
+This does not mean Logrus is dead. Logrus will continue to be maintained for
+security, (backwards compatible) bug fixes, and performance (where we are
+limited by the interface).
+
+I believe Logrus' biggest contribution is to have played a part in today's
+widespread use of structured logging in Golang. There doesn't seem to be a
+reason to do a major, breaking iteration into Logrus V2, since the fantastic Go
+community has built those independently. Many fantastic alternatives have sprung
+up. Logrus would look like those, had it been re-designed with what we know
+about structured logging in Go today. Check out, for example,
+[Zerolog][zerolog], [Zap][zap], and [Apex][apex].
+
+[zerolog]: https://github.com/rs/zerolog
+[zap]: https://github.com/uber-go/zap
+[apex]: https://github.com/apex/log
+
**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
@@ -15,11 +35,6 @@ 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):
@@ -187,7 +202,7 @@ func main() {
log.Out = os.Stdout
// You could set this to any `io.Writer` such as a file
- // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
+ // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
// if err == nil {
// log.Out = file
// } else {
@@ -272,7 +287,7 @@ func init() {
```
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
-A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)
+A list of currently known service hooks can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)
#### Level logging
@@ -354,6 +369,7 @@ The built-in logging formatters are:
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
* When colors are enabled, levels are truncated to 4 characters by default. To disable
truncation set the `DisableLevelTruncation` field to `true`.
+ * When outputting to a TTY, it's often helpful to visually scan down a column where all the levels are the same width. Setting the `PadLevelText` field to `true` enables this behavior, by adding padding to the level text.
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
* `logrus.JSONFormatter`. Logs fields as JSON.
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
@@ -364,7 +380,10 @@ Third party logging formatters:
* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html).
* [`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̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
+* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the Power of Zalgo.
+* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure.
+* [`powerful-logrus-formatter`](https://github.com/zput/zxcTool). get fileName, log's line number and the latest function's name when print log; Sava log to files.
+* [`caption-json-formatter`](https://github.com/nolleh/caption_json_formatter). logrus's message json formatter with human-readable caption added.
You can define your formatter by implementing the `Formatter` interface,
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
@@ -429,14 +448,14 @@ entries. It should not be a feature of the application-level logger.
| Tool | Description |
| ---- | ----------- |
-|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
+|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will be generated with different configs in different environments.|
|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) |
#### Testing
Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
-* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook
+* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just adds the `test` hook
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
```go
@@ -464,7 +483,7 @@ func TestSomething(t*testing.T){
Logrus can register one or more functions that will be called when any `fatal`
level message is logged. The registered handlers will be executed before
-logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need
+logrus performs an `os.Exit(1)`. This behavior may be helpful if callers need
to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted.
```
@@ -489,6 +508,6 @@ Situation when locking is not needed includes:
1) logger.Out is protected by locks.
- 2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing)
+ 2) logger.Out is an os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allows multi-thread/multi-process writing)
(Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/)
diff --git a/vendor/github.com/sirupsen/logrus/alt_exit.go b/vendor/github.com/sirupsen/logrus/alt_exit.go
index 8af90637a99..8fd189e1cca 100644
--- a/vendor/github.com/sirupsen/logrus/alt_exit.go
+++ b/vendor/github.com/sirupsen/logrus/alt_exit.go
@@ -51,9 +51,9 @@ func Exit(code int) {
os.Exit(code)
}
-// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
-// all handlers. The handlers will also be invoked when any Fatal log entry is
-// made.
+// RegisterExitHandler appends a Logrus Exit handler to the list of handlers,
+// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
+// any Fatal log entry is made.
//
// This method is useful when a caller wishes to use logrus to log a fatal
// message but also needs to gracefully shutdown. An example usecase could be
@@ -62,3 +62,15 @@ func Exit(code int) {
func RegisterExitHandler(handler func()) {
handlers = append(handlers, handler)
}
+
+// DeferExitHandler prepends a Logrus Exit handler to the list of handlers,
+// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
+// any Fatal log entry is made.
+//
+// This method is useful when a caller wishes to use logrus to log a fatal
+// message but also needs to gracefully shutdown. An example usecase could be
+// closing database connections, or sending a alert that the application is
+// closing.
+func DeferExitHandler(handler func()) {
+ handlers = append([]func(){handler}, handlers...)
+}
diff --git a/vendor/github.com/sirupsen/logrus/entry.go b/vendor/github.com/sirupsen/logrus/entry.go
index cc85d3aab49..f6e062a3466 100644
--- a/vendor/github.com/sirupsen/logrus/entry.go
+++ b/vendor/github.com/sirupsen/logrus/entry.go
@@ -2,6 +2,7 @@ package logrus
import (
"bytes"
+ "context"
"fmt"
"os"
"reflect"
@@ -69,6 +70,9 @@ type Entry struct {
// When formatter is called in entry.log(), a Buffer may be set to entry
Buffer *bytes.Buffer
+ // Contains the context set by the user. Useful for hook processing etc.
+ Context context.Context
+
// err may contain a field formatting error
err string
}
@@ -81,10 +85,15 @@ func NewEntry(logger *Logger) *Entry {
}
}
+// Returns the bytes representation of this entry from the formatter.
+func (entry *Entry) Bytes() ([]byte, error) {
+ return entry.Logger.Formatter.Format(entry)
+}
+
// Returns the string representation from the reader and ultimately the
// formatter.
func (entry *Entry) String() (string, error) {
- serialized, err := entry.Logger.Formatter.Format(entry)
+ serialized, err := entry.Bytes()
if err != nil {
return "", err
}
@@ -97,6 +106,15 @@ func (entry *Entry) WithError(err error) *Entry {
return entry.WithField(ErrorKey, err)
}
+// Add a context to the Entry.
+func (entry *Entry) WithContext(ctx context.Context) *Entry {
+ dataCopy := make(Fields, len(entry.Data))
+ for k, v := range entry.Data {
+ dataCopy[k] = v
+ }
+ return &Entry{Logger: entry.Logger, Data: dataCopy, Time: entry.Time, err: entry.err, Context: ctx}
+}
+
// Add a single field to the Entry.
func (entry *Entry) WithField(key string, value interface{}) *Entry {
return entry.WithFields(Fields{key: value})
@@ -108,23 +126,38 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
for k, v := range entry.Data {
data[k] = v
}
- var field_err string
+ fieldErr := entry.err
for k, v := range fields {
- 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
+ isErrField := false
+ if t := reflect.TypeOf(v); t != nil {
+ switch t.Kind() {
+ case reflect.Func:
+ isErrField = true
+ case reflect.Ptr:
+ isErrField = t.Elem().Kind() == reflect.Func
+ }
+ }
+ if isErrField {
+ tmp := fmt.Sprintf("can not add field %q", k)
+ if fieldErr != "" {
+ fieldErr = entry.err + ", " + tmp
+ } else {
+ fieldErr = tmp
}
} else {
data[k] = v
}
}
- return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: field_err}
+ return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context}
}
// Overrides the time of the Entry.
func (entry *Entry) WithTime(t time.Time) *Entry {
- return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t}
+ dataCopy := make(Fields, len(entry.Data))
+ for k, v := range entry.Data {
+ dataCopy[k] = v
+ }
+ return &Entry{Logger: entry.Logger, Data: dataCopy, Time: t, err: entry.err, Context: entry.Context}
}
// getPackageName reduces a fully qualified function name to the package name
@@ -145,26 +178,34 @@ func getPackageName(f string) string {
// 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())
+ pcs := make([]uintptr, maximumCallerDepth)
+ _ = runtime.Callers(0, pcs)
+
+ // dynamic get the package name and the minimum caller depth
+ for i := 0; i < maximumCallerDepth; i++ {
+ funcName := runtime.FuncForPC(pcs[i]).Name()
+ if strings.Contains(funcName, "getCaller") {
+ logrusPackage = getPackageName(funcName)
+ break
+ }
+ }
- // 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
})
+ // Restrict the lookback frames to avoid runaway lookups
+ pcs := make([]uintptr, maximumCallerDepth)
+ depth := runtime.Callers(minimumCallerDepth, pcs)
+ frames := runtime.CallersFrames(pcs[:depth])
+
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
+ return &f //nolint:scopelint
}
}
@@ -194,9 +235,11 @@ func (entry Entry) log(level Level, msg string) {
entry.Level = level
entry.Message = msg
+ entry.Logger.mu.Lock()
if entry.Logger.ReportCaller {
entry.Caller = getCaller()
}
+ entry.Logger.mu.Unlock()
entry.fireHooks()
@@ -232,24 +275,25 @@ func (entry *Entry) write() {
serialized, err := entry.Logger.Formatter.Format(entry)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
- } else {
- _, err = entry.Logger.Out.Write(serialized)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
- }
+ return
+ }
+ if _, err = entry.Logger.Out.Write(serialized); err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
}
}
-func (entry *Entry) Trace(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(TraceLevel) {
- entry.log(TraceLevel, fmt.Sprint(args...))
+func (entry *Entry) Log(level Level, args ...interface{}) {
+ if entry.Logger.IsLevelEnabled(level) {
+ entry.log(level, fmt.Sprint(args...))
}
}
+func (entry *Entry) Trace(args ...interface{}) {
+ entry.Log(TraceLevel, args...)
+}
+
func (entry *Entry) Debug(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(DebugLevel) {
- entry.log(DebugLevel, fmt.Sprint(args...))
- }
+ entry.Log(DebugLevel, args...)
}
func (entry *Entry) Print(args ...interface{}) {
@@ -257,15 +301,11 @@ func (entry *Entry) Print(args ...interface{}) {
}
func (entry *Entry) Info(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(InfoLevel) {
- entry.log(InfoLevel, fmt.Sprint(args...))
- }
+ entry.Log(InfoLevel, args...)
}
func (entry *Entry) Warn(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(WarnLevel) {
- entry.log(WarnLevel, fmt.Sprint(args...))
- }
+ entry.Log(WarnLevel, args...)
}
func (entry *Entry) Warning(args ...interface{}) {
@@ -273,43 +313,37 @@ func (entry *Entry) Warning(args ...interface{}) {
}
func (entry *Entry) Error(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(ErrorLevel) {
- entry.log(ErrorLevel, fmt.Sprint(args...))
- }
+ entry.Log(ErrorLevel, args...)
}
func (entry *Entry) Fatal(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(FatalLevel) {
- entry.log(FatalLevel, fmt.Sprint(args...))
- }
+ entry.Log(FatalLevel, args...)
entry.Logger.Exit(1)
}
func (entry *Entry) Panic(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(PanicLevel) {
- entry.log(PanicLevel, fmt.Sprint(args...))
- }
+ entry.Log(PanicLevel, args...)
panic(fmt.Sprint(args...))
}
// 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) Logf(level Level, format string, args ...interface{}) {
+ if entry.Logger.IsLevelEnabled(level) {
+ entry.Log(level, fmt.Sprintf(format, args...))
}
}
+func (entry *Entry) Tracef(format string, args ...interface{}) {
+ entry.Logf(TraceLevel, format, args...)
+}
+
func (entry *Entry) Debugf(format string, args ...interface{}) {
- if entry.Logger.IsLevelEnabled(DebugLevel) {
- entry.Debug(fmt.Sprintf(format, args...))
- }
+ entry.Logf(DebugLevel, format, args...)
}
func (entry *Entry) Infof(format string, args ...interface{}) {
- if entry.Logger.IsLevelEnabled(InfoLevel) {
- entry.Info(fmt.Sprintf(format, args...))
- }
+ entry.Logf(InfoLevel, format, args...)
}
func (entry *Entry) Printf(format string, args ...interface{}) {
@@ -317,9 +351,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) {
}
func (entry *Entry) Warnf(format string, args ...interface{}) {
- if entry.Logger.IsLevelEnabled(WarnLevel) {
- entry.Warn(fmt.Sprintf(format, args...))
- }
+ entry.Logf(WarnLevel, format, args...)
}
func (entry *Entry) Warningf(format string, args ...interface{}) {
@@ -327,42 +359,36 @@ func (entry *Entry) Warningf(format string, args ...interface{}) {
}
func (entry *Entry) Errorf(format string, args ...interface{}) {
- if entry.Logger.IsLevelEnabled(ErrorLevel) {
- entry.Error(fmt.Sprintf(format, args...))
- }
+ entry.Logf(ErrorLevel, format, args...)
}
func (entry *Entry) Fatalf(format string, args ...interface{}) {
- if entry.Logger.IsLevelEnabled(FatalLevel) {
- entry.Fatal(fmt.Sprintf(format, args...))
- }
+ entry.Logf(FatalLevel, format, args...)
entry.Logger.Exit(1)
}
func (entry *Entry) Panicf(format string, args ...interface{}) {
- if entry.Logger.IsLevelEnabled(PanicLevel) {
- entry.Panic(fmt.Sprintf(format, args...))
- }
+ entry.Logf(PanicLevel, format, args...)
}
// Entry Println family functions
-func (entry *Entry) Traceln(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(TraceLevel) {
- entry.Trace(entry.sprintlnn(args...))
+func (entry *Entry) Logln(level Level, args ...interface{}) {
+ if entry.Logger.IsLevelEnabled(level) {
+ entry.Log(level, entry.sprintlnn(args...))
}
}
+func (entry *Entry) Traceln(args ...interface{}) {
+ entry.Logln(TraceLevel, args...)
+}
+
func (entry *Entry) Debugln(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(DebugLevel) {
- entry.Debug(entry.sprintlnn(args...))
- }
+ entry.Logln(DebugLevel, args...)
}
func (entry *Entry) Infoln(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(InfoLevel) {
- entry.Info(entry.sprintlnn(args...))
- }
+ entry.Logln(InfoLevel, args...)
}
func (entry *Entry) Println(args ...interface{}) {
@@ -370,9 +396,7 @@ func (entry *Entry) Println(args ...interface{}) {
}
func (entry *Entry) Warnln(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(WarnLevel) {
- entry.Warn(entry.sprintlnn(args...))
- }
+ entry.Logln(WarnLevel, args...)
}
func (entry *Entry) Warningln(args ...interface{}) {
@@ -380,22 +404,16 @@ func (entry *Entry) Warningln(args ...interface{}) {
}
func (entry *Entry) Errorln(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(ErrorLevel) {
- entry.Error(entry.sprintlnn(args...))
- }
+ entry.Logln(ErrorLevel, args...)
}
func (entry *Entry) Fatalln(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(FatalLevel) {
- entry.Fatal(entry.sprintlnn(args...))
- }
+ entry.Logln(FatalLevel, args...)
entry.Logger.Exit(1)
}
func (entry *Entry) Panicln(args ...interface{}) {
- if entry.Logger.IsLevelEnabled(PanicLevel) {
- entry.Panic(entry.sprintlnn(args...))
- }
+ entry.Logln(PanicLevel, args...)
}
// Sprintlnn => Sprint no newline. This is to get the behavior of how
diff --git a/vendor/github.com/sirupsen/logrus/exported.go b/vendor/github.com/sirupsen/logrus/exported.go
index 7342613c372..42b04f6c809 100644
--- a/vendor/github.com/sirupsen/logrus/exported.go
+++ b/vendor/github.com/sirupsen/logrus/exported.go
@@ -1,6 +1,7 @@
package logrus
import (
+ "context"
"io"
"time"
)
@@ -55,6 +56,11 @@ func WithError(err error) *Entry {
return std.WithField(ErrorKey, err)
}
+// WithContext creates an entry from the standard logger and adds a context to it.
+func WithContext(ctx context.Context) *Entry {
+ return std.WithContext(ctx)
+}
+
// WithField creates an entry from the standard logger and adds a field to
// it. If you want multiple fields, use `WithFields`.
//
@@ -74,7 +80,7 @@ func WithFields(fields Fields) *Entry {
return std.WithFields(fields)
}
-// WithTime creats an entry from the standard logger and overrides the time of
+// WithTime creates an entry from the standard logger and overrides the time of
// logs generated with it.
//
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
diff --git a/vendor/github.com/sirupsen/logrus/go.mod b/vendor/github.com/sirupsen/logrus/go.mod
index 94574cc635c..d41329679f8 100644
--- a/vendor/github.com/sirupsen/logrus/go.mod
+++ b/vendor/github.com/sirupsen/logrus/go.mod
@@ -2,10 +2,10 @@ module github.com/sirupsen/logrus
require (
github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/konsorten/go-windows-terminal-sequences v1.0.1
+ github.com/konsorten/go-windows-terminal-sequences v1.0.3
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/stretchr/objx v0.1.1 // indirect
github.com/stretchr/testify v1.2.2
- 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-20190422165155-953cdadca894
)
+
+go 1.13
diff --git a/vendor/github.com/sirupsen/logrus/go.sum b/vendor/github.com/sirupsen/logrus/go.sum
index 133d34ae116..49c690f2383 100644
--- a/vendor/github.com/sirupsen/logrus/go.sum
+++ b/vendor/github.com/sirupsen/logrus/go.sum
@@ -1,15 +1,12 @@
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/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 v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/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/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/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/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/vendor/github.com/sirupsen/logrus/hooks/test/test.go b/vendor/github.com/sirupsen/logrus/hooks/test/test.go
index 234a17dfa88..b16d06654ae 100644
--- a/vendor/github.com/sirupsen/logrus/hooks/test/test.go
+++ b/vendor/github.com/sirupsen/logrus/hooks/test/test.go
@@ -1,6 +1,5 @@
-// The Test package is used for testing logrus. It is here for backwards
-// compatibility from when logrus' organization was upper-case. Please use
-// lower-case logrus and the `null` package instead of this one.
+// The Test package is used for testing logrus.
+// It provides a simple hooks which register logged messages.
package test
import (
diff --git a/vendor/github.com/sirupsen/logrus/json_formatter.go b/vendor/github.com/sirupsen/logrus/json_formatter.go
index 2605753599f..ba7f237112b 100644
--- a/vendor/github.com/sirupsen/logrus/json_formatter.go
+++ b/vendor/github.com/sirupsen/logrus/json_formatter.go
@@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"fmt"
+ "runtime"
)
type fieldKey string
@@ -27,6 +28,9 @@ type JSONFormatter struct {
// DisableTimestamp allows disabling automatic timestamps in output
DisableTimestamp bool
+ // DisableHTMLEscape allows disabling html escaping in output
+ DisableHTMLEscape bool
+
// DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
DataKey string
@@ -42,6 +46,12 @@ type JSONFormatter struct {
// }
FieldMap FieldMap
+ // CallerPrettyfier can be set by the user to modify the content
+ // of the function and file keys in the json data when ReportCaller is
+ // activated. If any of the returned value is the empty string the
+ // corresponding key will be removed from json fields.
+ CallerPrettyfier func(*runtime.Frame) (function string, file string)
+
// PrettyPrint will indent all json logs
PrettyPrint bool
}
@@ -82,8 +92,17 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
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)
+ funcVal := entry.Caller.Function
+ fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
+ if f.CallerPrettyfier != nil {
+ funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
+ }
+ if funcVal != "" {
+ data[f.FieldMap.resolve(FieldKeyFunc)] = funcVal
+ }
+ if fileVal != "" {
+ data[f.FieldMap.resolve(FieldKeyFile)] = fileVal
+ }
}
var b *bytes.Buffer
@@ -94,11 +113,12 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
}
encoder := json.NewEncoder(b)
+ encoder.SetEscapeHTML(!f.DisableHTMLEscape)
if f.PrettyPrint {
encoder.SetIndent("", " ")
}
if err := encoder.Encode(data); err != nil {
- return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
+ return nil, fmt.Errorf("failed to marshal fields to JSON, %v", err)
}
return b.Bytes(), nil
diff --git a/vendor/github.com/sirupsen/logrus/logger.go b/vendor/github.com/sirupsen/logrus/logger.go
index 5ceca0eab42..6fdda748e4d 100644
--- a/vendor/github.com/sirupsen/logrus/logger.go
+++ b/vendor/github.com/sirupsen/logrus/logger.go
@@ -1,6 +1,7 @@
package logrus
import (
+ "context"
"io"
"os"
"sync"
@@ -67,10 +68,10 @@ func (mw *MutexWrap) Disable() {
// `Out` and `Hooks` directly on the default logger instance. You can also just
// instantiate your own:
//
-// var log = &Logger{
+// var log = &logrus.Logger{
// Out: os.Stderr,
-// Formatter: new(JSONFormatter),
-// Hooks: make(LevelHooks),
+// Formatter: new(logrus.JSONFormatter),
+// Hooks: make(logrus.LevelHooks),
// Level: logrus.DebugLevel,
// }
//
@@ -99,8 +100,9 @@ func (logger *Logger) releaseEntry(entry *Entry) {
logger.entryPool.Put(entry)
}
-// Adds a field to the log entry, note that it doesn't log until you call
-// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry.
+// WithField allocates a new entry and adds a field to it.
+// Debug, Print, Info, Warn, Error, Fatal or Panic must be then applied to
+// this new returned entry.
// If you want multiple fields, use `WithFields`.
func (logger *Logger) WithField(key string, value interface{}) *Entry {
entry := logger.newEntry()
@@ -124,6 +126,13 @@ func (logger *Logger) WithError(err error) *Entry {
return entry.WithError(err)
}
+// Add a context to the log entry.
+func (logger *Logger) WithContext(ctx context.Context) *Entry {
+ entry := logger.newEntry()
+ defer logger.releaseEntry(entry)
+ return entry.WithContext(ctx)
+}
+
// Overrides the time of the log entry.
func (logger *Logger) WithTime(t time.Time) *Entry {
entry := logger.newEntry()
@@ -131,28 +140,24 @@ func (logger *Logger) WithTime(t time.Time) *Entry {
return entry.WithTime(t)
}
-func (logger *Logger) Tracef(format string, args ...interface{}) {
- if logger.IsLevelEnabled(TraceLevel) {
+func (logger *Logger) Logf(level Level, format string, args ...interface{}) {
+ if logger.IsLevelEnabled(level) {
entry := logger.newEntry()
- entry.Tracef(format, args...)
+ entry.Logf(level, format, args...)
logger.releaseEntry(entry)
}
}
+func (logger *Logger) Tracef(format string, args ...interface{}) {
+ logger.Logf(TraceLevel, format, args...)
+}
+
func (logger *Logger) Debugf(format string, args ...interface{}) {
- if logger.IsLevelEnabled(DebugLevel) {
- entry := logger.newEntry()
- entry.Debugf(format, args...)
- logger.releaseEntry(entry)
- }
+ logger.Logf(DebugLevel, format, args...)
}
func (logger *Logger) Infof(format string, args ...interface{}) {
- if logger.IsLevelEnabled(InfoLevel) {
- entry := logger.newEntry()
- entry.Infof(format, args...)
- logger.releaseEntry(entry)
- }
+ logger.Logf(InfoLevel, format, args...)
}
func (logger *Logger) Printf(format string, args ...interface{}) {
@@ -162,139 +167,91 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
}
func (logger *Logger) Warnf(format string, args ...interface{}) {
- if logger.IsLevelEnabled(WarnLevel) {
- entry := logger.newEntry()
- entry.Warnf(format, args...)
- logger.releaseEntry(entry)
- }
+ logger.Logf(WarnLevel, format, args...)
}
func (logger *Logger) Warningf(format string, args ...interface{}) {
- if logger.IsLevelEnabled(WarnLevel) {
- entry := logger.newEntry()
- entry.Warnf(format, args...)
- logger.releaseEntry(entry)
- }
+ logger.Warnf(format, args...)
}
func (logger *Logger) Errorf(format string, args ...interface{}) {
- if logger.IsLevelEnabled(ErrorLevel) {
- entry := logger.newEntry()
- entry.Errorf(format, args...)
- logger.releaseEntry(entry)
- }
+ logger.Logf(ErrorLevel, format, args...)
}
func (logger *Logger) Fatalf(format string, args ...interface{}) {
- if logger.IsLevelEnabled(FatalLevel) {
- entry := logger.newEntry()
- entry.Fatalf(format, args...)
- logger.releaseEntry(entry)
- }
+ logger.Logf(FatalLevel, format, args...)
logger.Exit(1)
}
func (logger *Logger) Panicf(format string, args ...interface{}) {
- if logger.IsLevelEnabled(PanicLevel) {
+ logger.Logf(PanicLevel, format, args...)
+}
+
+func (logger *Logger) Log(level Level, args ...interface{}) {
+ if logger.IsLevelEnabled(level) {
entry := logger.newEntry()
- entry.Panicf(format, args...)
+ entry.Log(level, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Trace(args ...interface{}) {
- if logger.IsLevelEnabled(TraceLevel) {
- entry := logger.newEntry()
- entry.Trace(args...)
- logger.releaseEntry(entry)
- }
+ logger.Log(TraceLevel, args...)
}
func (logger *Logger) Debug(args ...interface{}) {
- if logger.IsLevelEnabled(DebugLevel) {
- entry := logger.newEntry()
- entry.Debug(args...)
- logger.releaseEntry(entry)
- }
+ logger.Log(DebugLevel, args...)
}
func (logger *Logger) Info(args ...interface{}) {
- if logger.IsLevelEnabled(InfoLevel) {
- entry := logger.newEntry()
- entry.Info(args...)
- logger.releaseEntry(entry)
- }
+ logger.Log(InfoLevel, args...)
}
func (logger *Logger) Print(args ...interface{}) {
entry := logger.newEntry()
- entry.Info(args...)
+ entry.Print(args...)
logger.releaseEntry(entry)
}
func (logger *Logger) Warn(args ...interface{}) {
- if logger.IsLevelEnabled(WarnLevel) {
- entry := logger.newEntry()
- entry.Warn(args...)
- logger.releaseEntry(entry)
- }
+ logger.Log(WarnLevel, args...)
}
func (logger *Logger) Warning(args ...interface{}) {
- if logger.IsLevelEnabled(WarnLevel) {
- entry := logger.newEntry()
- entry.Warn(args...)
- logger.releaseEntry(entry)
- }
+ logger.Warn(args...)
}
func (logger *Logger) Error(args ...interface{}) {
- if logger.IsLevelEnabled(ErrorLevel) {
- entry := logger.newEntry()
- entry.Error(args...)
- logger.releaseEntry(entry)
- }
+ logger.Log(ErrorLevel, args...)
}
func (logger *Logger) Fatal(args ...interface{}) {
- if logger.IsLevelEnabled(FatalLevel) {
- entry := logger.newEntry()
- entry.Fatal(args...)
- logger.releaseEntry(entry)
- }
+ logger.Log(FatalLevel, args...)
logger.Exit(1)
}
func (logger *Logger) Panic(args ...interface{}) {
- if logger.IsLevelEnabled(PanicLevel) {
+ logger.Log(PanicLevel, args...)
+}
+
+func (logger *Logger) Logln(level Level, args ...interface{}) {
+ if logger.IsLevelEnabled(level) {
entry := logger.newEntry()
- entry.Panic(args...)
+ entry.Logln(level, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Traceln(args ...interface{}) {
- if logger.IsLevelEnabled(TraceLevel) {
- entry := logger.newEntry()
- entry.Traceln(args...)
- logger.releaseEntry(entry)
- }
+ logger.Logln(TraceLevel, args...)
}
func (logger *Logger) Debugln(args ...interface{}) {
- if logger.IsLevelEnabled(DebugLevel) {
- entry := logger.newEntry()
- entry.Debugln(args...)
- logger.releaseEntry(entry)
- }
+ logger.Logln(DebugLevel, args...)
}
func (logger *Logger) Infoln(args ...interface{}) {
- if logger.IsLevelEnabled(InfoLevel) {
- entry := logger.newEntry()
- entry.Infoln(args...)
- logger.releaseEntry(entry)
- }
+ logger.Logln(InfoLevel, args...)
}
func (logger *Logger) Println(args ...interface{}) {
@@ -304,44 +261,24 @@ func (logger *Logger) Println(args ...interface{}) {
}
func (logger *Logger) Warnln(args ...interface{}) {
- if logger.IsLevelEnabled(WarnLevel) {
- entry := logger.newEntry()
- entry.Warnln(args...)
- logger.releaseEntry(entry)
- }
+ logger.Logln(WarnLevel, args...)
}
func (logger *Logger) Warningln(args ...interface{}) {
- if logger.IsLevelEnabled(WarnLevel) {
- entry := logger.newEntry()
- entry.Warnln(args...)
- logger.releaseEntry(entry)
- }
+ logger.Warnln(args...)
}
func (logger *Logger) Errorln(args ...interface{}) {
- if logger.IsLevelEnabled(ErrorLevel) {
- entry := logger.newEntry()
- entry.Errorln(args...)
- logger.releaseEntry(entry)
- }
+ logger.Logln(ErrorLevel, args...)
}
func (logger *Logger) Fatalln(args ...interface{}) {
- if logger.IsLevelEnabled(FatalLevel) {
- entry := logger.newEntry()
- entry.Fatalln(args...)
- logger.releaseEntry(entry)
- }
+ logger.Logln(FatalLevel, args...)
logger.Exit(1)
}
func (logger *Logger) Panicln(args ...interface{}) {
- if logger.IsLevelEnabled(PanicLevel) {
- entry := logger.newEntry()
- entry.Panicln(args...)
- logger.releaseEntry(entry)
- }
+ logger.Logln(PanicLevel, args...)
}
func (logger *Logger) Exit(code int) {
diff --git a/vendor/github.com/sirupsen/logrus/logrus.go b/vendor/github.com/sirupsen/logrus/logrus.go
index 4ef45186620..2f16224cb9f 100644
--- a/vendor/github.com/sirupsen/logrus/logrus.go
+++ b/vendor/github.com/sirupsen/logrus/logrus.go
@@ -14,24 +14,11 @@ type Level uint32
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
func (level Level) String() string {
- switch level {
- case TraceLevel:
- return "trace"
- case DebugLevel:
- return "debug"
- case InfoLevel:
- return "info"
- case WarnLevel:
- return "warning"
- case ErrorLevel:
- return "error"
- case FatalLevel:
- return "fatal"
- case PanicLevel:
- return "panic"
+ if b, err := level.MarshalText(); err == nil {
+ return string(b)
+ } else {
+ return "unknown"
}
-
- return "unknown"
}
// ParseLevel takes a string level and returns the Logrus log level constant.
@@ -64,11 +51,32 @@ func (level *Level) UnmarshalText(text []byte) error {
return err
}
- *level = Level(l)
+ *level = l
return nil
}
+func (level Level) MarshalText() ([]byte, error) {
+ switch level {
+ case TraceLevel:
+ return []byte("trace"), nil
+ case DebugLevel:
+ return []byte("debug"), nil
+ case InfoLevel:
+ return []byte("info"), nil
+ case WarnLevel:
+ return []byte("warning"), nil
+ case ErrorLevel:
+ return []byte("error"), nil
+ case FatalLevel:
+ return []byte("fatal"), nil
+ case PanicLevel:
+ return []byte("panic"), nil
+ }
+
+ return nil, fmt.Errorf("not a valid logrus level %d", level)
+}
+
// A constant exposing all logging levels
var AllLevels = []Level{
PanicLevel,
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
new file mode 100644
index 00000000000..499789984d2
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
@@ -0,0 +1,13 @@
+// +build darwin dragonfly freebsd netbsd openbsd
+// +build !js
+
+package logrus
+
+import "golang.org/x/sys/unix"
+
+const ioctlReadTermios = unix.TIOCGETA
+
+func isTerminal(fd int) bool {
+ _, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
+ return err == nil
+}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_js.go b/vendor/github.com/sirupsen/logrus/terminal_check_js.go
index 0c209750a33..ebdae3ec626 100644
--- a/vendor/github.com/sirupsen/logrus/terminal_check_js.go
+++ b/vendor/github.com/sirupsen/logrus/terminal_check_js.go
@@ -2,10 +2,6 @@
package logrus
-import (
- "io"
-)
-
-func checkIfTerminal(w io.Writer) bool {
+func isTerminal(fd int) bool {
return false
}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go b/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go
new file mode 100644
index 00000000000..97af92c68ea
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go
@@ -0,0 +1,11 @@
+// +build js nacl plan9
+
+package logrus
+
+import (
+ "io"
+)
+
+func checkIfTerminal(w io.Writer) bool {
+ return false
+}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
index cf309d6fb6e..3293fb3caad 100644
--- a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
+++ b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
@@ -1,18 +1,16 @@
-// +build !appengine,!js,!windows
+// +build !appengine,!js,!windows,!nacl,!plan9
package logrus
import (
"io"
"os"
-
- "golang.org/x/crypto/ssh/terminal"
)
func checkIfTerminal(w io.Writer) bool {
switch v := w.(type) {
case *os.File:
- return terminal.IsTerminal(int(v.Fd()))
+ return isTerminal(int(v.Fd()))
default:
return false
}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go b/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go
new file mode 100644
index 00000000000..f6710b3bd0b
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go
@@ -0,0 +1,11 @@
+package logrus
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func isTerminal(fd int) bool {
+ _, err := unix.IoctlGetTermio(fd, unix.TCGETA)
+ return err == nil
+}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go
new file mode 100644
index 00000000000..cc4fe6e3177
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go
@@ -0,0 +1,13 @@
+// +build linux aix
+// +build !js
+
+package logrus
+
+import "golang.org/x/sys/unix"
+
+const ioctlReadTermios = unix.TCGETS
+
+func isTerminal(fd int) bool {
+ _, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
+ return err == nil
+}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go
index 3b9d2864ca3..572889db216 100644
--- a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go
+++ b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go
@@ -6,15 +6,29 @@ import (
"io"
"os"
"syscall"
+
+ sequences "github.com/konsorten/go-windows-terminal-sequences"
)
+func initTerminal(w io.Writer) {
+ switch v := w.(type) {
+ case *os.File:
+ sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true)
+ }
+}
+
func checkIfTerminal(w io.Writer) bool {
+ var ret bool
switch v := w.(type) {
case *os.File:
var mode uint32
err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode)
- return err == nil
+ ret = (err == nil)
default:
- return false
+ ret = false
+ }
+ if ret {
+ initTerminal(w)
}
+ return ret
}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_notwindows.go b/vendor/github.com/sirupsen/logrus/terminal_notwindows.go
deleted file mode 100644
index 3dbd2372030..00000000000
--- a/vendor/github.com/sirupsen/logrus/terminal_notwindows.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// +build !windows
-
-package logrus
-
-import "io"
-
-func initTerminal(w io.Writer) {
-}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_windows.go b/vendor/github.com/sirupsen/logrus/terminal_windows.go
deleted file mode 100644
index b4ef5286cd4..00000000000
--- a/vendor/github.com/sirupsen/logrus/terminal_windows.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// +build !appengine,!js,windows
-
-package logrus
-
-import (
- "io"
- "os"
- "syscall"
-
- sequences "github.com/konsorten/go-windows-terminal-sequences"
-)
-
-func initTerminal(w io.Writer) {
- switch v := w.(type) {
- case *os.File:
- sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true)
- }
-}
diff --git a/vendor/github.com/sirupsen/logrus/text_formatter.go b/vendor/github.com/sirupsen/logrus/text_formatter.go
index 49ec92f172c..3c28b54caba 100644
--- a/vendor/github.com/sirupsen/logrus/text_formatter.go
+++ b/vendor/github.com/sirupsen/logrus/text_formatter.go
@@ -4,25 +4,23 @@ import (
"bytes"
"fmt"
"os"
+ "runtime"
"sort"
+ "strconv"
"strings"
"sync"
"time"
+ "unicode/utf8"
)
const (
- nocolor = 0
- red = 31
- green = 32
- yellow = 33
- blue = 36
- gray = 37
+ red = 31
+ yellow = 33
+ blue = 36
+ gray = 37
)
-var (
- baseTimestamp time.Time
- emptyFieldMap FieldMap
-)
+var baseTimestamp time.Time
func init() {
baseTimestamp = time.Now()
@@ -36,6 +34,14 @@ type TextFormatter struct {
// Force disabling colors.
DisableColors bool
+ // Force quoting of all values
+ ForceQuote bool
+
+ // DisableQuote disables quoting for all values.
+ // DisableQuote will have a lower priority than ForceQuote.
+ // If both of them are set to true, quote will be forced on all values.
+ DisableQuote bool
+
// Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/
EnvironmentOverrideColors bool
@@ -61,6 +67,10 @@ type TextFormatter struct {
// Disables the truncation of the level text to 4 characters.
DisableLevelTruncation bool
+ // PadLevelText Adds padding the level text so that all the levels output at the same length
+ // PadLevelText is a superset of the DisableLevelTruncation option
+ PadLevelText bool
+
// QuoteEmptyFields will wrap empty fields in quotes if true
QuoteEmptyFields bool
@@ -76,28 +86,39 @@ type TextFormatter struct {
// FieldKeyMsg: "@message"}}
FieldMap FieldMap
+ // CallerPrettyfier can be set by the user to modify the content
+ // of the function and file keys in the data when ReportCaller is
+ // activated. If any of the returned value is the empty string the
+ // corresponding key will be removed from fields.
+ CallerPrettyfier func(*runtime.Frame) (function string, file string)
+
terminalInitOnce sync.Once
+
+ // The max length of the level text, generated dynamically on init
+ levelTextMaxLength int
}
func (f *TextFormatter) init(entry *Entry) {
if entry.Logger != nil {
f.isTerminal = checkIfTerminal(entry.Logger.Out)
-
- if f.isTerminal {
- initTerminal(entry.Logger.Out)
+ }
+ // Get the max length of the level text
+ for _, level := range AllLevels {
+ levelTextLength := utf8.RuneCount([]byte(level.String()))
+ if levelTextLength > f.levelTextMaxLength {
+ f.levelTextMaxLength = levelTextLength
}
}
}
func (f *TextFormatter) isColored() bool {
- isColored := f.ForceColors || f.isTerminal
+ isColored := f.ForceColors || (f.isTerminal && (runtime.GOOS != "windows"))
if f.EnvironmentOverrideColors {
- if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" {
+ switch force, ok := os.LookupEnv("CLICOLOR_FORCE"); {
+ case ok && force != "0":
isColored = true
- } else if ok && force == "0" {
- isColored = false
- } else if os.Getenv("CLICOLOR") == "0" {
+ case ok && force == "0", os.Getenv("CLICOLOR") == "0":
isColored = false
}
}
@@ -107,14 +128,19 @@ func (f *TextFormatter) isColored() bool {
// Format renders a single log entry
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
- prefixFieldClashes(entry.Data, f.FieldMap, entry.HasCaller())
-
- keys := make([]string, 0, len(entry.Data))
- for k := range entry.Data {
+ data := make(Fields)
+ for k, v := range entry.Data {
+ data[k] = v
+ }
+ prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
+ keys := make([]string, 0, len(data))
+ for k := range data {
keys = append(keys, k)
}
- fixedKeys := make([]string, 0, 4+len(entry.Data))
+ var funcVal, fileVal string
+
+ fixedKeys := make([]string, 0, 4+len(data))
if !f.DisableTimestamp {
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
}
@@ -126,8 +152,19 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
}
if entry.HasCaller() {
- fixedKeys = append(fixedKeys,
- f.FieldMap.resolve(FieldKeyFunc), f.FieldMap.resolve(FieldKeyFile))
+ if f.CallerPrettyfier != nil {
+ funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
+ } else {
+ funcVal = entry.Caller.Function
+ fileVal = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
+ }
+
+ if funcVal != "" {
+ fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFunc))
+ }
+ if fileVal != "" {
+ fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFile))
+ }
}
if !f.DisableSorting {
@@ -160,8 +197,9 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
timestampFormat = defaultTimestampFormat
}
if f.isColored() {
- f.printColored(b, entry, keys, timestampFormat)
+ f.printColored(b, entry, keys, data, timestampFormat)
} else {
+
for _, key := range fixedKeys {
var value interface{}
switch {
@@ -174,11 +212,11 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
case key == f.FieldMap.resolve(FieldKeyLogrusError):
value = entry.err
case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller():
- value = entry.Caller.Function
+ value = funcVal
case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller():
- value = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
+ value = fileVal
default:
- value = entry.Data[key]
+ value = data[key]
}
f.appendKeyValue(b, key, value)
}
@@ -188,7 +226,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
return b.Bytes(), nil
}
-func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
+func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, data Fields, timestampFormat string) {
var levelColor int
switch entry.Level {
case DebugLevel, TraceLevel:
@@ -202,39 +240,66 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
}
levelText := strings.ToUpper(entry.Level.String())
- if !f.DisableLevelTruncation {
+ if !f.DisableLevelTruncation && !f.PadLevelText {
levelText = levelText[0:4]
}
+ if f.PadLevelText {
+ // Generates the format string used in the next line, for example "%-6s" or "%-7s".
+ // Based on the max level text length.
+ formatString := "%-" + strconv.Itoa(f.levelTextMaxLength) + "s"
+ // Formats the level text by appending spaces up to the max length, for example:
+ // - "INFO "
+ // - "WARNING"
+ levelText = fmt.Sprintf(formatString, levelText)
+ }
// Remove a single newline if it already exists in the message to keep
// the behavior of logrus text_formatter the same as the stdlib log package
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)
+ funcVal := fmt.Sprintf("%s()", entry.Caller.Function)
+ fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
+
+ if f.CallerPrettyfier != nil {
+ funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
+ }
+
+ if fileVal == "" {
+ caller = funcVal
+ } else if funcVal == "" {
+ caller = fileVal
+ } else {
+ caller = fileVal + " " + funcVal
+ }
}
- if f.DisableTimestamp {
+ switch {
+ case f.DisableTimestamp:
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message)
- } else if !f.FullTimestamp {
+ case !f.FullTimestamp:
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message)
- } else {
+ default:
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message)
}
for _, k := range keys {
- v := entry.Data[k]
+ v := data[k]
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
f.appendValue(b, v)
}
}
func (f *TextFormatter) needsQuoting(text string) bool {
+ if f.ForceQuote {
+ return true
+ }
if f.QuoteEmptyFields && len(text) == 0 {
return true
}
+ if f.DisableQuote {
+ return false
+ }
for _, ch := range text {
if !((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
diff --git a/vendor/github.com/sirupsen/logrus/writer.go b/vendor/github.com/sirupsen/logrus/writer.go
index 9e1f7513597..72e8e3a1b65 100644
--- a/vendor/github.com/sirupsen/logrus/writer.go
+++ b/vendor/github.com/sirupsen/logrus/writer.go
@@ -6,10 +6,16 @@ import (
"runtime"
)
+// Writer at INFO level. See WriterLevel for details.
func (logger *Logger) Writer() *io.PipeWriter {
return logger.WriterLevel(InfoLevel)
}
+// WriterLevel returns an io.Writer that can be used to write arbitrary text to
+// the logger at the given log level. Each line written to the writer will be
+// printed in the usual way using formatters and hooks. The writer is part of an
+// io.Pipe and it is the callers responsibility to close the writer when done.
+// This can be used to override the standard library logger easily.
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
return NewEntry(logger).WriterLevel(level)
}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 2dcea9c4ffb..5f011f813d6 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -124,7 +124,7 @@ github.com/klauspost/compress/zstd
github.com/klauspost/compress/zstd/internal/xxhash
# github.com/klauspost/cpuid v1.3.1
## explicit
-# github.com/konsorten/go-windows-terminal-sequences v1.0.1
+# github.com/konsorten/go-windows-terminal-sequences v1.0.3
github.com/konsorten/go-windows-terminal-sequences
# github.com/kubernetes/helm v2.9.0+incompatible
## explicit
@@ -187,7 +187,7 @@ github.com/rcrowley/go-metrics
# github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516
## explicit
github.com/serenize/snaker
-# github.com/sirupsen/logrus v1.1.2-0.20181101075517-7eeb7b7cbdeb
+# github.com/sirupsen/logrus v1.6.0
## explicit
github.com/sirupsen/logrus
github.com/sirupsen/logrus/hooks/test