Update logrus dependency
This dependency added a method to access the current standard logger. This is required to properly configure the logger for context awareness. The plan is to have all loggers descend from the standard logger. Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
parent
29135602ec
commit
13382e45ba
13 changed files with 133 additions and 33 deletions
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
|
@ -24,8 +24,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/Sirupsen/logrus",
|
"ImportPath": "github.com/Sirupsen/logrus",
|
||||||
"Comment": "v0.6.1-8-gcc09837",
|
"Comment": "v0.6.4-12-g467d9d5",
|
||||||
"Rev": "cc09837bcd512ffe6bb2e3f635bed138c4cd6bc8"
|
"Rev": "467d9d55c2d2c17248441a8fc661561161f40d5e"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/bugsnag/bugsnag-go",
|
"ImportPath": "github.com/bugsnag/bugsnag-go",
|
||||||
|
|
6
Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
6
Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
|
@ -2,9 +2,7 @@ language: go
|
||||||
go:
|
go:
|
||||||
- 1.2
|
- 1.2
|
||||||
- 1.3
|
- 1.3
|
||||||
|
- 1.4
|
||||||
- tip
|
- tip
|
||||||
install:
|
install:
|
||||||
- go get github.com/stretchr/testify
|
- go get -t ./...
|
||||||
- go get github.com/stvp/go-udp-testing
|
|
||||||
- go get github.com/tobi/airbrake-go
|
|
||||||
- go get github.com/getsentry/raven-go
|
|
||||||
|
|
32
Godeps/_workspace/src/github.com/Sirupsen/logrus/README.md
generated
vendored
32
Godeps/_workspace/src/github.com/Sirupsen/logrus/README.md
generated
vendored
|
@ -1,8 +1,8 @@
|
||||||
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)
|
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus) [![godoc reference](https://godoc.org/github.com/Sirupsen/logrus?status.png)][godoc]
|
||||||
|
|
||||||
Logrus is a structured logger for Go (golang), completely API compatible with
|
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
|
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
|
||||||
yet stable (pre 1.0), the core API is unlikely change much but please version
|
yet stable (pre 1.0), 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
|
control your Logrus to make sure you aren't fetching latest `master` on every
|
||||||
build.**
|
build.**
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
||||||
|
|
||||||
With the default `log.Formatter = new(logrus.TextFormatter)` when a TTY is not
|
With the default `log.Formatter = new(logrus.TextFormatter)` when a TTY is not
|
||||||
attached, the output is compatible with the
|
attached, the output is compatible with the
|
||||||
[l2met](http://r.32k.io/l2met-introduction) format:
|
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
time="2014-04-20 15:36:23.830442383 -0400 EDT" level="info" msg="A group of walrus emerges from the ocean" animal="walrus" size=10
|
time="2014-04-20 15:36:23.830442383 -0400 EDT" level="info" msg="A group of walrus emerges from the ocean" animal="walrus" size=10
|
||||||
|
@ -235,6 +235,12 @@ func init() {
|
||||||
* [`github.com/nubo/hiprus`](https://github.com/nubo/hiprus)
|
* [`github.com/nubo/hiprus`](https://github.com/nubo/hiprus)
|
||||||
Send errors to a channel in hipchat.
|
Send errors to a channel in hipchat.
|
||||||
|
|
||||||
|
* [`github.com/sebest/logrusly`](https://github.com/sebest/logrusly)
|
||||||
|
Send logs to Loggly (https://www.loggly.com/)
|
||||||
|
|
||||||
|
* [`github.com/johntdyer/slackrus`](https://github.com/johntdyer/slackrus)
|
||||||
|
Hook for Slack chat.
|
||||||
|
|
||||||
#### Level logging
|
#### Level logging
|
||||||
|
|
||||||
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
||||||
|
@ -314,7 +320,7 @@ The built-in logging formatters are:
|
||||||
|
|
||||||
Third party logging formatters:
|
Third party logging formatters:
|
||||||
|
|
||||||
* [`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 P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||||
|
|
||||||
You can define your formatter by implementing the `Formatter` interface,
|
You can define your formatter by implementing the `Formatter` interface,
|
||||||
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
||||||
|
@ -339,6 +345,24 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Logger as an `io.Writer`
|
||||||
|
|
||||||
|
Logrus can be transormed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsability to close it.
|
||||||
|
|
||||||
|
```go
|
||||||
|
w := logger.Writer()
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
|
srv := http.Server{
|
||||||
|
// create a stdlib log.Logger that writes to
|
||||||
|
// logrus.Logger.
|
||||||
|
ErrorLog: log.New(w, "", 0),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Each line written to that writer will be printed the usual way, using formatters
|
||||||
|
and hooks. The level for those entries is `info`.
|
||||||
|
|
||||||
#### Rotation
|
#### Rotation
|
||||||
|
|
||||||
Log rotation is not provided with Logrus. Log rotation should be done by an
|
Log rotation is not provided with Logrus. Log rotation should be done by an
|
||||||
|
|
4
Godeps/_workspace/src/github.com/Sirupsen/logrus/entry.go
generated
vendored
4
Godeps/_workspace/src/github.com/Sirupsen/logrus/entry.go
generated
vendored
|
@ -126,6 +126,10 @@ func (entry *Entry) Warn(args ...interface{}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warning(args ...interface{}) {
|
||||||
|
entry.Warn(args...)
|
||||||
|
}
|
||||||
|
|
||||||
func (entry *Entry) Error(args ...interface{}) {
|
func (entry *Entry) Error(args ...interface{}) {
|
||||||
if entry.Logger.Level >= ErrorLevel {
|
if entry.Logger.Level >= ErrorLevel {
|
||||||
entry.log(ErrorLevel, fmt.Sprint(args...))
|
entry.log(ErrorLevel, fmt.Sprint(args...))
|
||||||
|
|
4
Godeps/_workspace/src/github.com/Sirupsen/logrus/exported.go
generated
vendored
4
Godeps/_workspace/src/github.com/Sirupsen/logrus/exported.go
generated
vendored
|
@ -9,6 +9,10 @@ var (
|
||||||
std = New()
|
std = New()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func StandardLogger() *Logger {
|
||||||
|
return std
|
||||||
|
}
|
||||||
|
|
||||||
// SetOutput sets the standard logger output.
|
// SetOutput sets the standard logger output.
|
||||||
func SetOutput(out io.Writer) {
|
func SetOutput(out io.Writer) {
|
||||||
std.mu.Lock()
|
std.mu.Lock()
|
||||||
|
|
14
Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go
generated
vendored
14
Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go
generated
vendored
|
@ -26,19 +26,19 @@ type Formatter interface {
|
||||||
//
|
//
|
||||||
// It's not exported because it's still using Data in an opinionated way. It's to
|
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||||
// avoid code duplication between the two default formatters.
|
// avoid code duplication between the two default formatters.
|
||||||
func prefixFieldClashes(entry *Entry) {
|
func prefixFieldClashes(data Fields) {
|
||||||
_, ok := entry.Data["time"]
|
_, ok := data["time"]
|
||||||
if ok {
|
if ok {
|
||||||
entry.Data["fields.time"] = entry.Data["time"]
|
data["fields.time"] = data["time"]
|
||||||
}
|
}
|
||||||
|
|
||||||
_, ok = entry.Data["msg"]
|
_, ok = data["msg"]
|
||||||
if ok {
|
if ok {
|
||||||
entry.Data["fields.msg"] = entry.Data["msg"]
|
data["fields.msg"] = data["msg"]
|
||||||
}
|
}
|
||||||
|
|
||||||
_, ok = entry.Data["level"]
|
_, ok = data["level"]
|
||||||
if ok {
|
if ok {
|
||||||
entry.Data["fields.level"] = entry.Data["level"]
|
data["fields.level"] = data["level"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
3
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
generated
vendored
3
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
generated
vendored
|
@ -30,7 +30,8 @@ func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook,
|
||||||
// Fire is called when a log event is fired.
|
// Fire is called when a log event is fired.
|
||||||
func (hook *PapertrailHook) Fire(entry *logrus.Entry) error {
|
func (hook *PapertrailHook) Fire(entry *logrus.Entry) error {
|
||||||
date := time.Now().Format(format)
|
date := time.Now().Format(format)
|
||||||
payload := fmt.Sprintf("<22> %s %s: [%s] %s", date, hook.AppName, entry.Level, entry.Message)
|
msg, _ := entry.String()
|
||||||
|
payload := fmt.Sprintf("<22> %s %s: %s", date, hook.AppName, msg)
|
||||||
|
|
||||||
bytesWritten, err := hook.UDPConn.Write([]byte(payload))
|
bytesWritten, err := hook.UDPConn.Write([]byte(payload))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
4
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
4
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
|
@ -6,7 +6,7 @@
|
||||||
import (
|
import (
|
||||||
"log/syslog"
|
"log/syslog"
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/Sirupsen/logrus/hooks/syslog"
|
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -17,4 +17,4 @@ func main() {
|
||||||
log.Hooks.Add(hook)
|
log.Hooks.Add(hook)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
14
Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
14
Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
|
@ -9,12 +9,16 @@ import (
|
||||||
type JSONFormatter struct{}
|
type JSONFormatter struct{}
|
||||||
|
|
||||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
prefixFieldClashes(entry)
|
data := make(Fields, len(entry.Data)+3)
|
||||||
entry.Data["time"] = entry.Time.Format(time.RFC3339)
|
for k, v := range entry.Data {
|
||||||
entry.Data["msg"] = entry.Message
|
data[k] = v
|
||||||
entry.Data["level"] = entry.Level.String()
|
}
|
||||||
|
prefixFieldClashes(data)
|
||||||
|
data["time"] = entry.Time.Format(time.RFC3339)
|
||||||
|
data["msg"] = entry.Message
|
||||||
|
data["level"] = entry.Level.String()
|
||||||
|
|
||||||
serialized, err := json.Marshal(entry.Data)
|
serialized, err := json.Marshal(data)
|
||||||
if err != nil {
|
if 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)
|
||||||
}
|
}
|
||||||
|
|
2
Godeps/_workspace/src/github.com/Sirupsen/logrus/logger.go
generated
vendored
2
Godeps/_workspace/src/github.com/Sirupsen/logrus/logger.go
generated
vendored
|
@ -38,7 +38,7 @@ type Logger struct {
|
||||||
// Out: os.Stderr,
|
// Out: os.Stderr,
|
||||||
// Formatter: new(JSONFormatter),
|
// Formatter: new(JSONFormatter),
|
||||||
// Hooks: make(levelHooks),
|
// Hooks: make(levelHooks),
|
||||||
// Level: logrus.Debug,
|
// Level: logrus.DebugLevel,
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// It's recommended to make this a global instance called `log`.
|
// It's recommended to make this a global instance called `log`.
|
||||||
|
|
40
Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus_test.go
generated
vendored
40
Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus_test.go
generated
vendored
|
@ -44,8 +44,12 @@ func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields ma
|
||||||
}
|
}
|
||||||
kvArr := strings.Split(kv, "=")
|
kvArr := strings.Split(kv, "=")
|
||||||
key := strings.TrimSpace(kvArr[0])
|
key := strings.TrimSpace(kvArr[0])
|
||||||
val, err := strconv.Unquote(kvArr[1])
|
val := kvArr[1]
|
||||||
assert.NoError(t, err)
|
if kvArr[1][0] == '"' {
|
||||||
|
var err error
|
||||||
|
val, err = strconv.Unquote(val)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
fields[key] = val
|
fields[key] = val
|
||||||
}
|
}
|
||||||
assertions(fields)
|
assertions(fields)
|
||||||
|
@ -204,6 +208,38 @@ func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
var fields Fields
|
||||||
|
|
||||||
|
logger := New()
|
||||||
|
logger.Out = &buffer
|
||||||
|
logger.Formatter = new(JSONFormatter)
|
||||||
|
|
||||||
|
llog := logger.WithField("context", "eating raw fish")
|
||||||
|
|
||||||
|
llog.Info("looks delicious")
|
||||||
|
|
||||||
|
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||||
|
assert.NoError(t, err, "should have decoded first message")
|
||||||
|
assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
|
||||||
|
assert.Equal(t, fields["msg"], "looks delicious")
|
||||||
|
assert.Equal(t, fields["context"], "eating raw fish")
|
||||||
|
|
||||||
|
buffer.Reset()
|
||||||
|
|
||||||
|
llog.Warn("omg it is!")
|
||||||
|
|
||||||
|
err = json.Unmarshal(buffer.Bytes(), &fields)
|
||||||
|
assert.NoError(t, err, "should have decoded second message")
|
||||||
|
assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
|
||||||
|
assert.Equal(t, fields["msg"], "omg it is!")
|
||||||
|
assert.Equal(t, fields["context"], "eating raw fish")
|
||||||
|
assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestConvertLevelToString(t *testing.T) {
|
func TestConvertLevelToString(t *testing.T) {
|
||||||
assert.Equal(t, "debug", DebugLevel.String())
|
assert.Equal(t, "debug", DebugLevel.String())
|
||||||
assert.Equal(t, "info", InfoLevel.String())
|
assert.Equal(t, "info", InfoLevel.String())
|
||||||
|
|
2
Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
2
Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
|
@ -3,7 +3,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build linux,!appengine darwin freebsd
|
// +build linux,!appengine darwin freebsd openbsd
|
||||||
|
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
|
|
37
Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
37
Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
|
@ -3,6 +3,7 @@ package logrus
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -19,6 +20,7 @@ const (
|
||||||
var (
|
var (
|
||||||
baseTimestamp time.Time
|
baseTimestamp time.Time
|
||||||
isTerminal bool
|
isTerminal bool
|
||||||
|
noQuoteNeeded *regexp.Regexp
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -34,6 +36,9 @@ type TextFormatter struct {
|
||||||
// Set to true to bypass checking for a TTY before outputting colors.
|
// Set to true to bypass checking for a TTY before outputting colors.
|
||||||
ForceColors bool
|
ForceColors bool
|
||||||
DisableColors bool
|
DisableColors bool
|
||||||
|
// Set to true to disable timestamp logging (useful when the output
|
||||||
|
// is redirected to a logging system already adding a timestamp)
|
||||||
|
DisableTimestamp bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
@ -46,14 +51,16 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
|
||||||
b := &bytes.Buffer{}
|
b := &bytes.Buffer{}
|
||||||
|
|
||||||
prefixFieldClashes(entry)
|
prefixFieldClashes(entry.Data)
|
||||||
|
|
||||||
isColored := (f.ForceColors || isTerminal) && !f.DisableColors
|
isColored := (f.ForceColors || isTerminal) && !f.DisableColors
|
||||||
|
|
||||||
if isColored {
|
if isColored {
|
||||||
printColored(b, entry, keys)
|
printColored(b, entry, keys)
|
||||||
} else {
|
} else {
|
||||||
f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
|
if !f.DisableTimestamp {
|
||||||
|
f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
|
||||||
|
}
|
||||||
f.appendKeyValue(b, "level", entry.Level.String())
|
f.appendKeyValue(b, "level", entry.Level.String())
|
||||||
f.appendKeyValue(b, "msg", entry.Message)
|
f.appendKeyValue(b, "msg", entry.Message)
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
|
@ -85,10 +92,32 @@ func printColored(b *bytes.Buffer, entry *Entry, keys []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func needsQuoting(text string) bool {
|
||||||
|
for _, ch := range text {
|
||||||
|
if !((ch >= 'a' && ch <= 'z') ||
|
||||||
|
(ch >= 'A' && ch <= 'Z') ||
|
||||||
|
(ch >= '0' && ch < '9') ||
|
||||||
|
ch == '-' || ch == '.') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key, value interface{}) {
|
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key, value interface{}) {
|
||||||
switch value.(type) {
|
switch value.(type) {
|
||||||
case string, error:
|
case string:
|
||||||
fmt.Fprintf(b, "%v=%q ", key, value)
|
if needsQuoting(value.(string)) {
|
||||||
|
fmt.Fprintf(b, "%v=%s ", key, value)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "%v=%q ", key, value)
|
||||||
|
}
|
||||||
|
case error:
|
||||||
|
if needsQuoting(value.(error).Error()) {
|
||||||
|
fmt.Fprintf(b, "%v=%s ", key, value)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "%v=%q ", key, value)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
fmt.Fprintf(b, "%v=%v ", key, value)
|
fmt.Fprintf(b, "%v=%v ", key, value)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue