Skip to content

Commit 681aa1e

Browse files
author
Raphaël Simon
committed
Add functions to retrieve native loggers in each adapter package. (goadesign#427)
* Add functions to retrieve native loggers in each adapter package. Also rename files from logger to adapter to better fit semantic. * NewStdLogger => NewLogger. Add Logger function.
1 parent 3f376b2 commit 681aa1e

15 files changed

+302
-186
lines changed

goagen/gen_client/generator.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ func (cmd *{{ $cmdName }}) Run(c *client.Client, args []string) error {
575575
{{ $default := defaultPath .Action }}{{ if $default }} path = "{{ $default }}"
576576
{{ else }} return fmt.Errorf("missing path argument")
577577
{{ end }} }
578-
logger := goa.NewStdLogger(log.New(os.Stderr, "", log.LstdFlags))
578+
logger := goa.NewLogger(log.New(os.Stderr, "", log.LstdFlags))
579579
ctx := goa.WithLogger(context.Background(), logger)
580580
ws, err := c.{{ goify (printf "%s%s" .Action.Name (title .Resource.Name)) true }}(ctx, path{{/*
581581
*/}}{{ $params := joinNames .Action.QueryParams }}{{ if $params }}, {{ $params }}{{ end }}{{/*
@@ -621,7 +621,7 @@ func (cmd *{{ $cmdName }}) Run(c *client.Client, args []string) error {
621621
{{ else }} return fmt.Errorf("failed to deserialize payload: %s", err)
622622
{{ end }} }
623623
}
624-
{{ end }} logger := goa.NewStdLogger(log.New(os.Stderr, "", log.LstdFlags))
624+
{{ end }} logger := goa.NewLogger(log.New(os.Stderr, "", log.LstdFlags))
625625
ctx := goa.WithLogger(context.Background(), logger)
626626
resp, err := c.{{ goify (printf "%s%s" .Action.Name (title .Resource.Name)) true }}(ctx, path{{ if .Action.Payload }}, {{ if or .Action.Payload.Type.IsObject .Action.Payload.IsPrimitive }}&{{ end }}payload{{ else }}{{ end }}{{/*
627627
*/}}{{ $params := joinNames .Action.QueryParams }}{{ if $params }}, {{ $params }}{{ end }}{{/*

goatest/testing.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func (r ResponseSetterFunc) Encode(v interface{}) error {
2222
func Service(logBuf *bytes.Buffer, respSetter ResponseSetterFunc) *goa.Service {
2323
s := goa.New("test")
2424
logger := log.New(logBuf, "", log.Ltime)
25-
s.WithLogger(goa.NewStdLogger(logger))
25+
s.WithLogger(goa.NewLogger(logger))
2626
s.Use(middleware.LogRequest(true))
2727
s.Use(middleware.LogResponse())
2828
newEncoder := func(io.Writer) goa.Encoder {

logging.go

+54-49
Original file line numberDiff line numberDiff line change
@@ -8,101 +8,84 @@ import (
88
"golang.org/x/net/context"
99
)
1010

11+
// ErrMissingLogValue is the value used to log keys with missing values
12+
const ErrMissingLogValue = "MISSING"
13+
1114
type (
1215
// LogAdapter is the logger interface used by goa to log informational and error messages.
13-
// Adapters to different logging backends are provided in the logging package.
16+
// Adapters to different logging backends are provided in the logging sub-packages.
1417
// goa takes care of initializing the logging context with the service, controller and
15-
// action name. Additional logging context values may be set via WithValue.
18+
// action names.
1619
LogAdapter interface {
1720
// Info logs an informational message.
1821
Info(msg string, keyvals ...interface{})
1922
// Error logs an error.
2023
Error(msg string, keyvals ...interface{})
21-
// New appends to the logger context and returns the updated logger adapter.
24+
// New appends to the logger context and returns the updated logger logger.
2225
New(keyvals ...interface{}) LogAdapter
2326
}
2427

25-
// stdLogger uses the stdlib logger.
26-
stdLogger struct {
28+
// adapter is the stdlib logger adapter.
29+
adapter struct {
2730
*log.Logger
2831
keyvals []interface{}
2932
}
3033
)
3134

32-
// ErrMissingLogValue is the value used to log keys with missing values
33-
const ErrMissingLogValue = "MISSING"
34-
35-
// LogInfo extracts the logger from the given context and calls Info on it.
36-
// In general this shouldn't be needed (the client code should already have a handle on the logger)
37-
// This is mainly useful for "out-of-band" code like middleware.
38-
func LogInfo(ctx context.Context, msg string, keyvals ...interface{}) {
39-
logit(ctx, msg, keyvals, false)
35+
// NewLogger returns a goa log adpater backed by a log logger.
36+
func NewLogger(logger *log.Logger) LogAdapter {
37+
return &adapter{Logger: logger}
4038
}
4139

42-
// LogError extracts the logger from the given context and calls Error on it.
43-
// In general this shouldn't be needed (the client code should already have a handle on the logger)
44-
// This is mainly useful for "out-of-band" code like middleware.
45-
func LogError(ctx context.Context, msg string, keyvals ...interface{}) {
46-
logit(ctx, msg, keyvals, true)
47-
}
48-
49-
func logit(ctx context.Context, msg string, keyvals []interface{}, aserror bool) {
50-
if l := ctx.Value(logKey); l != nil {
51-
if logger, ok := l.(LogAdapter); ok {
52-
if aserror {
53-
logger.Error(msg, keyvals...)
54-
} else {
55-
logger.Info(msg, keyvals...)
56-
}
57-
}
40+
// Logger returns the logger stored in the context if any, nil otherwise.
41+
func Logger(ctx context.Context) *log.Logger {
42+
logger := ContextLogger(ctx)
43+
if a, ok := logger.(*adapter); ok {
44+
return a.Logger
5845
}
46+
return nil
5947
}
6048

61-
// NewStdLogger returns an implementation of Logger backed by a stdlib Logger.
62-
func NewStdLogger(logger *log.Logger) LogAdapter {
63-
return &stdLogger{Logger: logger}
64-
}
65-
66-
func (l *stdLogger) Info(msg string, keyvals ...interface{}) {
67-
l.logit(msg, keyvals, false)
49+
func (a *adapter) Info(msg string, keyvals ...interface{}) {
50+
a.logit(msg, keyvals, false)
6851
}
6952

70-
func (l *stdLogger) Error(msg string, keyvals ...interface{}) {
71-
l.logit(msg, keyvals, true)
53+
func (a *adapter) Error(msg string, keyvals ...interface{}) {
54+
a.logit(msg, keyvals, true)
7255
}
7356

74-
func (l *stdLogger) New(keyvals ...interface{}) LogAdapter {
57+
func (a *adapter) New(keyvals ...interface{}) LogAdapter {
7558
if len(keyvals) == 0 {
76-
return l
59+
return a
7760
}
78-
kvs := append(l.keyvals, keyvals...)
61+
kvs := append(a.keyvals, keyvals...)
7962
if len(kvs)%2 != 0 {
8063
kvs = append(kvs, ErrMissingLogValue)
8164
}
82-
return &stdLogger{
83-
Logger: l.Logger,
65+
return &adapter{
66+
Logger: a.Logger,
8467
// Limiting the capacity of the stored keyvals ensures that a new
8568
// backing array is created if the slice must grow.
8669
keyvals: kvs[:len(kvs):len(kvs)],
8770
}
8871
}
8972

90-
func (l *stdLogger) logit(msg string, keyvals []interface{}, iserror bool) {
73+
func (a *adapter) logit(msg string, keyvals []interface{}, iserror bool) {
9174
n := (len(keyvals) + 1) / 2
9275
if len(keyvals)%2 != 0 {
9376
keyvals = append(keyvals, ErrMissingLogValue)
9477
}
9578
var fm bytes.Buffer
9679
lvl := "INFO"
9780
if iserror {
98-
lvl = "ERROR"
81+
lvl = "EROR"
9982
}
10083
fm.WriteString(fmt.Sprintf("[%s] %s", lvl, msg))
10184
vals := make([]interface{}, n)
102-
offset := len(l.keyvals)
85+
offset := len(a.keyvals)
10386
for i := 0; i < offset; i += 2 {
104-
k := l.keyvals[i]
105-
v := l.keyvals[i+1]
87+
k := a.keyvals[i]
88+
v := a.keyvals[i+1]
10689
vals[i/2] = v
10790
fm.WriteString(fmt.Sprintf(" %s=%%+v", k))
10891
}
@@ -112,5 +95,27 @@ func (l *stdLogger) logit(msg string, keyvals []interface{}, iserror bool) {
11295
vals[i/2+offset/2] = v
11396
fm.WriteString(fmt.Sprintf(" %s=%%+v", k))
11497
}
115-
l.Logger.Printf(fm.String(), vals...)
98+
a.Logger.Printf(fm.String(), vals...)
99+
}
100+
101+
// LogInfo extracts the logger from the given context and calls Info on it.
102+
// This is intended for code that needs portable logging such as the internal code of goa and
103+
// middleware. User code should use the log adapters instead.
104+
func LogInfo(ctx context.Context, msg string, keyvals ...interface{}) {
105+
if l := ctx.Value(logKey); l != nil {
106+
if logger, ok := l.(LogAdapter); ok {
107+
logger.Info(msg, keyvals...)
108+
}
109+
}
110+
}
111+
112+
// LogError extracts the logger from the given context and calls Error on it.
113+
// This is intended for code that needs portable logging such as the internal code of goa and
114+
// middleware. User code should use the log adapters instead.
115+
func LogError(ctx context.Context, msg string, keyvals ...interface{}) {
116+
if l := ctx.Value(logKey); l != nil {
117+
if logger, ok := l.(LogAdapter); ok {
118+
logger.Error(msg, keyvals...)
119+
}
120+
}
116121
}

logging/doc.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
Package logging contains logger adapters that make it possible for goa to log messages to various
3-
logger backends. Each adapter exists in its own package named after the corresponding logger package.
3+
logger backends. Each adapter exists in its own sub-package named after the corresponding logger
4+
package.
45
56
Once instantiated adapters can be used by setting the goa service logger with WithLogger:
67
@@ -18,5 +19,7 @@ Once instantiated adapters can be used by setting the goa service logger with Wi
1819
// ...
1920
}
2021
```
22+
23+
See http://goa.design/implement/logging/ for details.
2124
*/
2225
package logging

logging/kit/logger.go logging/kit/adapter.go

+22-9
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,20 @@ Usage:
88
// Initialize goa service logger using adapter
99
service.WithLogger(goakit.New(logger))
1010
// ... Proceed with configuring and starting the goa service
11+
12+
// In handlers:
13+
goakit.Context(ctx).Log("foo", "bar")
1114
*/
1215
package goakit
1316

1417
import (
1518
"github.com/go-kit/kit/log"
1619
"github.com/goadesign/goa"
20+
"golang.org/x/net/context"
1721
)
1822

19-
// Logger is the go-kit log goa adapter logger.
20-
type Logger struct {
23+
// adapter is the go-kit log goa logger adapter.
24+
type adapter struct {
2125
*log.Context
2226
}
2327

@@ -28,24 +32,33 @@ func New(logger log.Logger) goa.LogAdapter {
2832

2933
// FromContext wraps a go-kit log context into a goa logger.
3034
func FromContext(ctx *log.Context) goa.LogAdapter {
31-
return &Logger{Context: ctx}
35+
return &adapter{Context: ctx}
36+
}
37+
38+
// Context returns the go-kit log context stored in the given context if any, nil otherwise.
39+
func Context(ctx context.Context) *log.Context {
40+
logger := goa.ContextLogger(ctx)
41+
if a, ok := logger.(*adapter); ok {
42+
return a.Context
43+
}
44+
return nil
3245
}
3346

3447
// Info logs informational messages using go-kit.
35-
func (l *Logger) Info(msg string, data ...interface{}) {
48+
func (a *adapter) Info(msg string, data ...interface{}) {
3649
ctx := []interface{}{"lvl", "info", "msg", msg}
3750
ctx = append(ctx, data...)
38-
l.Context.Log(ctx...)
51+
a.Context.Log(ctx...)
3952
}
4053

4154
// Error logs error messages using go-kit.
42-
func (l *Logger) Error(msg string, data ...interface{}) {
55+
func (a *adapter) Error(msg string, data ...interface{}) {
4356
ctx := []interface{}{"lvl", "error", "msg", msg}
4457
ctx = append(ctx, data...)
45-
l.Context.Log(ctx...)
58+
a.Context.Log(ctx...)
4659
}
4760

4861
// New instantiates a new logger from the given context.
49-
func (l *Logger) New(data ...interface{}) goa.LogAdapter {
50-
return &Logger{Context: l.Context.With(data...)}
62+
func (a *adapter) New(data ...interface{}) goa.LogAdapter {
63+
return &adapter{Context: a.Context.With(data...)}
5164
}

logging/kit/adapter_test.go

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package goakit_test
2+
3+
import (
4+
"bytes"
5+
6+
"golang.org/x/net/context"
7+
8+
"github.com/go-kit/kit/log"
9+
"github.com/goadesign/goa"
10+
"github.com/goadesign/goa/logging/kit"
11+
. "github.com/onsi/ginkgo"
12+
. "github.com/onsi/gomega"
13+
)
14+
15+
var _ = Describe("New", func() {
16+
var buf bytes.Buffer
17+
var logger log.Logger
18+
var adapter goa.LogAdapter
19+
20+
BeforeEach(func() {
21+
logger = log.NewLogfmtLogger(&buf)
22+
adapter = goakit.New(logger)
23+
})
24+
25+
It("creates an adapter that logs", func() {
26+
msg := "msg"
27+
adapter.Info(msg)
28+
Ω(buf.String()).Should(Equal("lvl=info msg=" + msg + "\n"))
29+
})
30+
})
31+
32+
var _ = Describe("FromContext", func() {
33+
var buf bytes.Buffer
34+
var logctx *log.Context
35+
var adapter goa.LogAdapter
36+
37+
BeforeEach(func() {
38+
logger := log.NewLogfmtLogger(&buf)
39+
logctx = log.NewContext(logger)
40+
adapter = goakit.FromContext(logctx)
41+
})
42+
43+
It("creates an adapter that logs", func() {
44+
msg := "msg"
45+
adapter.Info(msg)
46+
Ω(buf.String()).Should(Equal("lvl=info msg=" + msg + "\n"))
47+
})
48+
49+
Context("Context", func() {
50+
var ctx context.Context
51+
52+
BeforeEach(func() {
53+
ctx = goa.WithLogger(context.Background(), adapter)
54+
})
55+
56+
It("extracts the log context", func() {
57+
Ω(goakit.Context(ctx)).Should(Equal(logctx))
58+
})
59+
})
60+
})

logging/kit/logger_test.go

-31
This file was deleted.

0 commit comments

Comments
 (0)