Skip to content

Commit 533ecbb

Browse files
authored
feat(logging): Add (*Logger). StandardLoggerFromTemplate() method. (#7261)
1 parent d5ea93c commit 533ecbb

File tree

4 files changed

+144
-11
lines changed

4 files changed

+144
-11
lines changed

β€Žlogging/examples_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,23 @@ func ExampleLogger_StandardLogger() {
203203
slg.Println("an informative message")
204204
}
205205

206+
func ExampleLogger_StandardLoggerFromTemplate() {
207+
ctx := context.Background()
208+
client, err := logging.NewClient(ctx, "my-project")
209+
if err != nil {
210+
// TODO: Handle error.
211+
}
212+
lg := client.Logger("my-log")
213+
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
214+
slg := lg.StandardLoggerFromTemplate(&logging.Entry{
215+
Severity: logging.Info,
216+
HTTPRequest: &logging.HTTPRequest{Request: r},
217+
})
218+
slg.Println("Before hello world")
219+
fmt.Fprintf(w, "Hello world!\n")
220+
})
221+
}
222+
206223
func ExampleParseSeverity() {
207224
sev := logging.ParseSeverity("ALERT")
208225
fmt.Println(sev)

β€Žlogging/logging.go

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ var (
9696
ErrRedirectProtoPayloadNotSupported = errors.New("printEntryToStdout: cannot find valid payload")
9797

9898
// For testing:
99-
now = time.Now
99+
now = time.Now
100+
toLogEntryInternal = toLogEntryInternalImpl
100101

101102
// ErrOverflow signals that the number of buffered entries for a Logger
102103
// exceeds its BufferLimit.
@@ -287,7 +288,8 @@ func (c *Client) Logger(logID string, opts ...LoggerOption) *Logger {
287288
}
288289
l.stdLoggers = map[Severity]*log.Logger{}
289290
for s := range severityName {
290-
l.stdLoggers[s] = log.New(severityWriter{l, s}, "", 0)
291+
e := Entry{Severity: s}
292+
l.stdLoggers[s] = log.New(templateEntryWriter{l, &e}, "", 0)
291293
}
292294

293295
c.loggers.Add(1)
@@ -301,16 +303,15 @@ func (c *Client) Logger(logID string, opts ...LoggerOption) *Logger {
301303
return l
302304
}
303305

304-
type severityWriter struct {
305-
l *Logger
306-
s Severity
306+
type templateEntryWriter struct {
307+
l *Logger
308+
template *Entry
307309
}
308310

309-
func (w severityWriter) Write(p []byte) (n int, err error) {
310-
w.l.Log(Entry{
311-
Severity: w.s,
312-
Payload: string(p),
313-
})
311+
func (w templateEntryWriter) Write(p []byte) (n int, err error) {
312+
e := *w.template
313+
e.Payload = string(p)
314+
w.l.Log(e)
314315
return len(p), nil
315316
}
316317

@@ -721,6 +722,20 @@ func (l *Logger) writeLogEntries(entries []*logpb.LogEntry) {
721722
// (for example by calling SetFlags or SetPrefix).
722723
func (l *Logger) StandardLogger(s Severity) *log.Logger { return l.stdLoggers[s] }
723724

725+
// StandardLoggerFromTemplate returns a Go Standard Logging API *log.Logger.
726+
//
727+
// The returned logger emits logs using logging.(*Logger).Log() with an entry
728+
// constructed from the provided template Entry struct.
729+
//
730+
// The caller is responsible for ensuring that the template Entry struct
731+
// does not change during the the lifetime of the returned *log.Logger.
732+
//
733+
// Prefer (*Logger).StandardLogger() which is more efficient if the template
734+
// only sets Severity.
735+
func (l *Logger) StandardLoggerFromTemplate(template *Entry) *log.Logger {
736+
return log.New(templateEntryWriter{l, template}, "", 0)
737+
}
738+
724739
func populateTraceInfo(e *Entry, req *http.Request) bool {
725740
if req == nil {
726741
if e.HTTPRequest != nil && e.HTTPRequest.Request != nil {
@@ -834,7 +849,7 @@ func (l *Logger) ToLogEntry(e Entry, parent string) (*logpb.LogEntry, error) {
834849
return toLogEntryInternal(e, l, parent, 1)
835850
}
836851

837-
func toLogEntryInternal(e Entry, l *Logger, parent string, skipLevels int) (*logpb.LogEntry, error) {
852+
func toLogEntryInternalImpl(e Entry, l *Logger, parent string, skipLevels int) (*logpb.LogEntry, error) {
838853
if e.LogName != "" {
839854
return nil, errors.New("logging: Entry.LogName should be not be set when writing")
840855
}

β€Žlogging/logging_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"net/http"
2929
"net/url"
3030
"os"
31+
"reflect"
3132
"runtime"
3233
"strings"
3334
"sync"
@@ -717,6 +718,100 @@ func TestStandardLogger(t *testing.T) {
717718
}
718719
}
719720

721+
func TestStandardLoggerFromTemplate(t *testing.T) {
722+
tests := []struct {
723+
name string
724+
template logging.Entry
725+
message string
726+
want logging.Entry
727+
}{
728+
{
729+
name: "severity only",
730+
template: logging.Entry{
731+
Severity: logging.Error,
732+
},
733+
message: "log message",
734+
want: logging.Entry{
735+
Severity: logging.Error,
736+
Payload: "log message\n",
737+
},
738+
},
739+
{
740+
name: "severity and trace",
741+
template: logging.Entry{
742+
Severity: logging.Info,
743+
Trace: "projects/P/traces/105445aa7843bc8bf206b120001000",
744+
},
745+
message: "log message",
746+
want: logging.Entry{
747+
Severity: logging.Info,
748+
Payload: "log message\n",
749+
Trace: "projects/P/traces/105445aa7843bc8bf206b120001000",
750+
},
751+
},
752+
{
753+
name: "severity and http request",
754+
template: logging.Entry{
755+
Severity: logging.Info,
756+
HTTPRequest: &logging.HTTPRequest{
757+
Request: &http.Request{
758+
Method: "GET",
759+
Host: "example.com",
760+
},
761+
Status: 200,
762+
},
763+
},
764+
message: "log message",
765+
want: logging.Entry{
766+
Severity: logging.Info,
767+
Payload: "log message\n",
768+
HTTPRequest: &logging.HTTPRequest{
769+
Request: &http.Request{
770+
Method: "GET",
771+
Host: "example.com",
772+
},
773+
Status: 200,
774+
},
775+
},
776+
},
777+
{
778+
name: "payload in template is ignored",
779+
template: logging.Entry{
780+
Severity: logging.Info,
781+
Payload: "this should not be set in the template",
782+
Trace: "projects/P/traces/105445aa7843bc8bf206b120001000",
783+
},
784+
message: "log message",
785+
want: logging.Entry{
786+
Severity: logging.Info,
787+
Payload: "log message\n",
788+
Trace: "projects/P/traces/105445aa7843bc8bf206b120001000",
789+
},
790+
},
791+
}
792+
lg := client.Logger(testLogID)
793+
for _, tc := range tests {
794+
t.Run(tc.name, func(t *testing.T) {
795+
mock := func(got logging.Entry, l *logging.Logger, parent string, skipLevels int) (*logpb.LogEntry, error) {
796+
if !reflect.DeepEqual(got, tc.want) {
797+
t.Errorf("Emitted Entry incorrect. Expected %v got %v", tc.want, got)
798+
}
799+
// Return value is not interesting
800+
return &logpb.LogEntry{}, nil
801+
}
802+
803+
f := logging.SetToLogEntryInternal(mock)
804+
defer func() { logging.SetToLogEntryInternal(f) }()
805+
806+
slg := lg.StandardLoggerFromTemplate(&tc.template)
807+
slg.Print(tc.message)
808+
if err := lg.Flush(); err != nil {
809+
t.Fatal(err)
810+
}
811+
})
812+
}
813+
}
814+
720815
func TestSeverity(t *testing.T) {
721816
if got, want := logging.Info.String(), "Info"; got != want {
722817
t.Errorf("got %q, want %q", got, want)

β€Žlogging/logging_unexported_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"time"
2525

2626
"cloud.google.com/go/internal/testutil"
27+
logpb "cloud.google.com/go/logging/apiv2/loggingpb"
2728
"github.com/golang/protobuf/proto"
2829
durpb "github.com/golang/protobuf/ptypes/duration"
2930
structpb "github.com/golang/protobuf/ptypes/struct"
@@ -355,3 +356,8 @@ func SetNow(f func() time.Time) func() time.Time {
355356
now, f = f, now
356357
return f
357358
}
359+
360+
func SetToLogEntryInternal(f func(Entry, *Logger, string, int) (*logpb.LogEntry, error)) func(Entry, *Logger, string, int) (*logpb.LogEntry, error) {
361+
toLogEntryInternal, f = f, toLogEntryInternal
362+
return f
363+
}

0 commit comments

Comments
 (0)