Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(logging): Add (*Logger). StandardLoggerFromTemplate() method. #7261

Merged
merged 11 commits into from
Jan 26, 2023
17 changes: 17 additions & 0 deletions logging/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,23 @@ func ExampleLogger_StandardLogger() {
slg.Println("an informative message")
}

func ExampleLogger_StandardLoggerFromEntry() {
ctx := context.Background()
client, err := logging.NewClient(ctx, "my-project")
if err != nil {
// TODO: Handle error.
}
lg := client.Logger("my-log")
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
slg := lg.StandardLoggerFromEntry(&logging.Entry{
Severity: logging.Info,
HTTPRequest: &logging.HTTPRequest{Request: r},
})
slg.Println("Before hello world")
fmt.Fprintf(w, "Hello world!\n")
})
}

func ExampleParseSeverity() {
sev := logging.ParseSeverity("ALERT")
fmt.Println(sev)
Expand Down
30 changes: 22 additions & 8 deletions logging/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ func (c *Client) Logger(logID string, opts ...LoggerOption) *Logger {
}
l.stdLoggers = map[Severity]*log.Logger{}
for s := range severityName {
l.stdLoggers[s] = log.New(severityWriter{l, s}, "", 0)
e := Entry{Severity: s}
l.stdLoggers[s] = log.New(protoEntryWriter{l, &e}, "", 0)
}

c.loggers.Add(1)
Expand All @@ -301,16 +302,15 @@ func (c *Client) Logger(logID string, opts ...LoggerOption) *Logger {
return l
}

type severityWriter struct {
type protoEntryWriter struct {
l *Logger
s Severity
e *Entry // A prototype Entry object
}

func (w severityWriter) Write(p []byte) (n int, err error) {
w.l.Log(Entry{
Severity: w.s,
Payload: string(p),
})
func (w protoEntryWriter) Write(p []byte) (n int, err error) {
tang-fh marked this conversation as resolved.
Show resolved Hide resolved
e := *w.e
e.Payload = string(p)
w.l.Log(e)
return len(p), nil
}

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

// StandardLoggerFromEntry returns a Go Standard Logging API *log.Logger.
//
// The returned logger emits logs using the provided *Logger. It takes a
// *Entry which is used as a prototype Entry struct.
//
// The caller is responsible for ensuring that the prototype Entry struct
// does not change during the the lifetime of the returned *log.Logger.
//
// Prefer (*Logger).StandardLogger() which is more efficient if the prototype
// only sets Severity.
func (l *Logger) StandardLoggerFromEntry(e *Entry) *log.Logger {
return log.New(protoEntryWriter{l, e}, "", 0)
}

func populateTraceInfo(e *Entry, req *http.Request) bool {
if req == nil {
if e.HTTPRequest != nil && e.HTTPRequest.Request != nil {
Expand Down
41 changes: 41 additions & 0 deletions logging/logging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,47 @@ func TestStandardLogger(t *testing.T) {
}
}

func TestStandardLoggerFromEntry(t *testing.T) {
initLogs() // Generate new testLogID
ctx := context.Background()
lg := client.Logger(testLogID)

slg := lg.StandardLoggerFromEntry(&logging.Entry{
Severity: logging.Info,
Trace: "projects/P/traces/105445aa7843bc8bf206b120001000",
tang-fh marked this conversation as resolved.
Show resolved Hide resolved
})

slg.Print("info")
if err := lg.Flush(); err != nil {
t.Fatal(err)
}
var got []*logging.Entry
ok := waitFor(func() bool {
var err error
got, err = allTestLogEntries(ctx)
if err != nil {
t.Log("fetching log entries: ", err)
return false
}
return len(got) == 1
})
if !ok {
t.Fatalf("timed out; got: %d, want: %d\n", len(got), 1)
}
if len(got) != 1 {
t.Fatalf("expected non-nil request with one entry; got:\n%+v", got)
}
if got, want := got[0].Payload.(string), "info\n"; got != want {
t.Errorf("payload: got %q, want %q", got, want)
}
if got, want := logging.Severity(got[0].Severity), logging.Info; got != want {
t.Errorf("severity: got %s, want %s", got, want)
}
if got, want := got[0].Trace, "projects/P/traces/105445aa7843bc8bf206b120001000"; got != want {
t.Errorf("trace: got %s, want %s", got, want)
}
}

func TestSeverity(t *testing.T) {
if got, want := logging.Info.String(), "Info"; got != want {
t.Errorf("got %q, want %q", got, want)
Expand Down