-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdecorators.go
159 lines (131 loc) · 3.54 KB
/
decorators.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package trc
import (
"context"
"fmt"
"io"
"log"
"strings"
"github.com/peterbourgon/trc/internal/trcutil"
)
// DecoratorFunc is a function that decorates a trace in some way. It's similar
// to an HTTP middleware. Decorators can be provided to a [Collector] and will
// be applied to every trace created in that collector.
type DecoratorFunc func(Trace) Trace
//
//
//
// LogDecorator logs a simple string to the provided destination when the trace
// is created, on every event, and when the trace is finished. The logged string
// is a reduced form of the full trace, containing only the trace ID and the
// single event that triggered the log.
func LogDecorator(dst io.Writer) DecoratorFunc {
return func(tr Trace) Trace {
ltr := &logTrace{
Trace: tr,
id: tr.ID(),
dst: dst,
}
ltr.logEvent("started, source '%s', category '%s'", tr.Source(), tr.Category())
return ltr
}
}
// LoggerDecorator is like LogDecorator, but uses a log.Logger.
func LoggerDecorator(logger *log.Logger) DecoratorFunc {
return LogDecorator(&loggerWriter{logger})
}
type loggerWriter struct{ logger *log.Logger }
func (lw *loggerWriter) Write(p []byte) (int, error) {
lw.logger.Printf(string(p))
return len(p), nil
}
type logTrace struct {
Trace
id string
dst io.Writer
}
var _ interface{ Free() } = (*logTrace)(nil)
func (ltr *logTrace) Tracef(format string, args ...any) {
ltr.logEvent(format, args...)
ltr.Trace.Tracef(format, args...)
}
func (ltr *logTrace) LazyTracef(format string, args ...any) {
ltr.logEvent(format, args...)
ltr.Trace.LazyTracef(format, args...)
}
func (ltr *logTrace) Errorf(format string, args ...any) {
ltr.logEvent("ERROR: "+format, args...)
ltr.Trace.Errorf(format, args...)
}
func (ltr *logTrace) LazyErrorf(format string, args ...any) {
ltr.logEvent("ERROR: "+format, args...)
ltr.Trace.LazyErrorf(format, args...)
}
func (ltr *logTrace) Finish() {
ltr.Trace.Finish()
var (
outcome = "unknown"
duration = trcutil.HumanizeDuration(ltr.Trace.Duration())
)
switch {
case ltr.Errored():
outcome = "errored"
default:
outcome = "success"
}
ltr.logEvent("done, %s, %s", outcome, duration)
}
func (ltr *logTrace) logEvent(format string, args ...any) {
format = ltr.id + " " + strings.TrimSuffix(format, "\n") + "\n"
fmt.Fprintf(ltr.dst, format, args...)
}
func (ltr *logTrace) Free() {
if f, ok := ltr.Trace.(interface{ Free() }); ok {
f.Free()
}
}
//
//
//
func publishDecorator(p publisher) DecoratorFunc {
return func(tr Trace) Trace {
ptr := &publishTrace{
Trace: tr,
p: p,
}
p.Publish(context.Background(), ptr.Trace)
return ptr
}
}
type publisher interface {
Publish(ctx context.Context, tr Trace)
}
type publishTrace struct {
Trace
p publisher
}
var _ interface{ Free() } = (*publishTrace)(nil)
func (ptr *publishTrace) Tracef(format string, args ...any) {
ptr.Trace.Tracef(format, args...)
ptr.p.Publish(context.Background(), ptr.Trace)
}
func (ptr *publishTrace) LazyTracef(format string, args ...any) {
ptr.Trace.LazyTracef(format, args...)
ptr.p.Publish(context.Background(), ptr.Trace)
}
func (ptr *publishTrace) Errorf(format string, args ...any) {
ptr.Trace.Errorf(format, args...)
ptr.p.Publish(context.Background(), ptr.Trace)
}
func (ptr *publishTrace) LazyErrorf(format string, args ...any) {
ptr.Trace.LazyErrorf(format, args...)
ptr.p.Publish(context.Background(), ptr.Trace)
}
func (ptr *publishTrace) Finish() {
ptr.Trace.Finish()
ptr.p.Publish(context.Background(), ptr.Trace)
}
func (ptr *publishTrace) Free() {
if f, ok := ptr.Trace.(interface{ Free() }); ok {
f.Free()
}
}