-
Notifications
You must be signed in to change notification settings - Fork 438
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
contrib: add log/slog instrumentation (#2765)
- Loading branch information
1 parent
bdc072c
commit 974aea6
Showing
7 changed files
with
193 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016 Datadog, Inc. | ||
|
||
package slog_test | ||
|
||
import ( | ||
"context" | ||
"log/slog" | ||
"os" | ||
|
||
slogtrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/log/slog" | ||
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" | ||
) | ||
|
||
func ExampleNewJSONHandler() { | ||
// start the DataDog tracer | ||
tracer.Start() | ||
defer tracer.Stop() | ||
|
||
// create the application logger | ||
logger := slog.New(slogtrace.NewJSONHandler(os.Stdout, nil)) | ||
|
||
// start a new span | ||
span, ctx := tracer.StartSpanFromContext(context.Background(), "ExampleNewJSONHandler") | ||
defer span.Finish() | ||
|
||
// log a message using the context containing span information | ||
logger.Log(ctx, slog.LevelInfo, "this is a log with tracing information") | ||
} | ||
|
||
func ExampleWrapHandler() { | ||
// start the DataDog tracer | ||
tracer.Start() | ||
defer tracer.Stop() | ||
|
||
// create the application logger | ||
myHandler := slog.NewJSONHandler(os.Stdout, nil) | ||
logger := slog.New(slogtrace.WrapHandler(myHandler)) | ||
|
||
// start a new span | ||
span, ctx := tracer.StartSpanFromContext(context.Background(), "ExampleWrapHandler") | ||
defer span.Finish() | ||
|
||
// log a message using the context containing span information | ||
logger.Log(ctx, slog.LevelInfo, "this is a log with tracing information") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016 Datadog, Inc. | ||
|
||
// Package slog provides functions to correlate logs and traces using log/slog package (https://pkg.go.dev/log/slog). | ||
package slog // import "gopkg.in/DataDog/dd-trace-go.v1/contrib/log/slog" | ||
|
||
import ( | ||
"context" | ||
"io" | ||
"log/slog" | ||
|
||
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext" | ||
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" | ||
"gopkg.in/DataDog/dd-trace-go.v1/internal/telemetry" | ||
) | ||
|
||
const componentName = "log/slog" | ||
|
||
func init() { | ||
telemetry.LoadIntegration(componentName) | ||
tracer.MarkIntegrationImported("log/slog") | ||
} | ||
|
||
// NewJSONHandler is a convenience function that returns a *slog.JSONHandler logger enhanced with | ||
// tracing information. | ||
func NewJSONHandler(w io.Writer, opts *slog.HandlerOptions) slog.Handler { | ||
return WrapHandler(slog.NewJSONHandler(w, opts)) | ||
} | ||
|
||
// WrapHandler enhances the given logger handler attaching tracing information to logs. | ||
func WrapHandler(h slog.Handler) slog.Handler { | ||
return &handler{h} | ||
} | ||
|
||
type handler struct { | ||
slog.Handler | ||
} | ||
|
||
// Handle handles the given Record, attaching tracing information if found. | ||
func (h *handler) Handle(ctx context.Context, rec slog.Record) error { | ||
span, ok := tracer.SpanFromContext(ctx) | ||
if ok { | ||
rec.Add( | ||
slog.Uint64(ext.LogKeyTraceID, span.Context().TraceID()), | ||
slog.Uint64(ext.LogKeySpanID, span.Context().SpanID()), | ||
) | ||
} | ||
return h.Handler.Handle(ctx, rec) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016 Datadog, Inc. | ||
|
||
package slog | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/json" | ||
"log/slog" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext" | ||
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" | ||
internallog "gopkg.in/DataDog/dd-trace-go.v1/internal/log" | ||
) | ||
|
||
func assertLogEntry(t *testing.T, rawEntry, wantMsg, wantLevel string) { | ||
t.Helper() | ||
|
||
var data map[string]interface{} | ||
err := json.Unmarshal([]byte(rawEntry), &data) | ||
require.NoError(t, err) | ||
require.NotEmpty(t, data) | ||
|
||
assert.Equal(t, wantMsg, data["msg"]) | ||
assert.Equal(t, wantLevel, data["level"]) | ||
assert.NotEmpty(t, data["time"]) | ||
assert.NotEmpty(t, data[ext.LogKeyTraceID]) | ||
assert.NotEmpty(t, data[ext.LogKeySpanID]) | ||
} | ||
|
||
func testLogger(t *testing.T, createHandler func(b *bytes.Buffer) slog.Handler) { | ||
tracer.Start(tracer.WithLogger(internallog.DiscardLogger{})) | ||
defer tracer.Stop() | ||
|
||
// create the application logger | ||
var b bytes.Buffer | ||
h := createHandler(&b) | ||
logger := slog.New(h) | ||
|
||
// start a new span | ||
span, ctx := tracer.StartSpanFromContext(context.Background(), "test") | ||
defer span.Finish() | ||
|
||
// log a message using the context containing span information | ||
logger.Log(ctx, slog.LevelInfo, "this is an info log with tracing information") | ||
logger.Log(ctx, slog.LevelError, "this is an error log with tracing information") | ||
|
||
logs := strings.Split( | ||
strings.TrimRight(b.String(), "\n"), | ||
"\n", | ||
) | ||
// assert log entries contain trace information | ||
require.Len(t, logs, 2) | ||
assertLogEntry(t, logs[0], "this is an info log with tracing information", "INFO") | ||
assertLogEntry(t, logs[1], "this is an error log with tracing information", "ERROR") | ||
} | ||
|
||
func TestNewJSONHandler(t *testing.T) { | ||
testLogger(t, func(b *bytes.Buffer) slog.Handler { | ||
return NewJSONHandler(b, nil) | ||
}) | ||
} | ||
|
||
func TestWrapHandler(t *testing.T) { | ||
testLogger(t, func(b *bytes.Buffer) slog.Handler { | ||
return WrapHandler(slog.NewJSONHandler(b, nil)) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016 Datadog, Inc. | ||
|
||
package ext | ||
|
||
const ( | ||
// LogKeyTraceID is used by log integrations to correlate logs with a given trace. | ||
LogKeyTraceID = "dd.trace_id" | ||
// LogKeySpanID is used by log integrations to correlate logs with a given span. | ||
LogKeySpanID = "dd.span_id" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters