Documentation ¶
Overview ¶
altnrslog is an alternative library for New Relic Logs in Context with log/slog.
altnrslog can also forward slog.Attr even only APM Agent.
Example ¶
package main import ( "encoding/json" "fmt" "log" "log/slog" "net/http" "os" "github.com/miyamo2/altnrslog" "github.com/newrelic/go-agent/v3/newrelic" ) func main() { type Request struct { Name string `json:"name"` } nr, err := newrelic.NewApplication( newrelic.ConfigAppName(os.Getenv("NEW_RELIC_CONFIG_APP_NAME")), newrelic.ConfigLicense(os.Getenv("NEW_RELIC_CONFIG_LICENSE")), newrelic.ConfigAppLogForwardingEnabled(true), ) if err != nil { panic(err) } httpHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() tx := newrelic.FromContext(ctx) logHandler := altnrslog.NewTransactionalHandler(nr, tx) logger := slog.New(logHandler) var req Request if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } logger.InfoContext(ctx, "START", slog.Group("request", slog.String("name", req.Name))) response := fmt.Sprintf("Hello, %s!", req.Name) defer logger.InfoContext(ctx, "END", slog.String("response", response)) w.Write([]byte(response)) }) http.Handle(newrelic.WrapHandle(nr, "/introduce", httpHandler)) log.Fatal(http.ListenAndServe(":8080", nil)) }
Output:
Example (WithCustomMiddleware) ¶
package main import ( "encoding/json" "fmt" "log" "log/slog" "net/http" "os" "github.com/miyamo2/altnrslog" "github.com/newrelic/go-agent/v3/newrelic" ) func main() { type Request struct { Name string `json:"name"` } nr, err := newrelic.NewApplication( newrelic.ConfigAppName(os.Getenv("NEW_RELIC_CONFIG_APP_NAME")), newrelic.ConfigLicense(os.Getenv("NEW_RELIC_CONFIG_LICENSE")), newrelic.ConfigAppLogForwardingEnabled(true), ) if err != nil { panic(err) } httpHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() tx := newrelic.FromContext(ctx) logHandler := altnrslog.NewTransactionalHandler(nr, tx) logger := slog.New(logHandler) var req Request if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } logger.InfoContext(ctx, "START", slog.Group("request", slog.String("name", req.Name))) response := fmt.Sprintf("Hello, %s!", req.Name) defer logger.InfoContext(ctx, "END", slog.String("response", response)) w.Write([]byte(response)) }) middleware := func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() tx := newrelic.FromContext(ctx) logHandler := altnrslog.NewTransactionalHandler(nr, tx) logger := slog.New(logHandler) ctx, err := altnrslog.StoreToContext(ctx, logger) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } next.ServeHTTP(w, r.WithContext(ctx)) }) } http.Handle(newrelic.WrapHandle(nr, "/introduce", middleware(httpHandler))) log.Fatal(http.ListenAndServe(":8080", nil)) }
Output:
Index ¶
- Variables
- func FromContext(ctx context.Context) (*slog.Logger, error)
- func StoreToContext(ctx context.Context, logger *slog.Logger) (context.Context, error)
- type HandlerOption
- type InnerHandlerProvider
- type Properties
- type TransactionalHandler
- func (h *TransactionalHandler) Enabled(ctx context.Context, level slog.Level) bool
- func (h *TransactionalHandler) Handle(ctx context.Context, r slog.Record) error
- func (h *TransactionalHandler) WithAttrs(attrs []slog.Attr) slog.Handler
- func (h *TransactionalHandler) WithGroup(name string) slog.Handler
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidHandler is returned when the handler is not a TransactionalHandler. ErrInvalidHandler = errors.New("invalid handler") // ErrNotStored is returned when the logger is not stored in context.Context. ErrNotStored = errors.New("logger not stored") )
Functions ¶
func FromContext ¶
FromContext returns *slog.Logger with *TransactionalHandler, stored in the context.Context. If it does not exist, return ErrNotStored.
func StoreToContext ¶
StoreToContext stores the *slog.Logger in context.Context. Logger must be set to *TransactionalHandler in the Handler
Types ¶
type HandlerOption ¶
type HandlerOption func(*Properties)
HandlerOption is a functional option for creating a new TransactionalHandler.
func WithInnerHandlerProvider ¶ added in v0.2.0
func WithInnerHandlerProvider(innerHandlerProvider InnerHandlerProvider) HandlerOption
WithInnerHandlerProvider specifies the function that provides the slog.Handler to be wrapped.
func WithInnerWriter ¶
func WithInnerWriter(w io.Writer) HandlerOption
WithInnerWriter specifies the io.Writer that wraps logWriter.logWriter
func WithLogLevel ¶ added in v0.4.0
func WithLogLevel(level slog.Level) HandlerOption
WithLogLevel specifies the log level. if not specified, the default is slog.LevelInfo. if lower than the inner handler's level, the inner handler's level will be used.
func WithSlogHandlerSpecify ¶
func WithSlogHandlerSpecify(json bool, o *slog.HandlerOptions) HandlerOption
WithSlogHandlerSpecify specifies whether to use JSON format and slog.HandlerOptions.
type Properties ¶
type Properties struct {
// contains filtered or unexported fields
}
Properties is an options for creating a new TransactionalHandler.
type TransactionalHandler ¶
type TransactionalHandler struct {
// contains filtered or unexported fields
}
TransactionalHandler is a slog.Handler that adds New Relic distributed tracing metadata to log records.
func NewTransactionalHandler ¶
func NewTransactionalHandler(app *newrelic.Application, tx *newrelic.Transaction, options ...HandlerOption) *TransactionalHandler
NewTransactionalHandler is constructor for TransactionalHandler.
Example ¶
package main import ( "log/slog" "os" "github.com/miyamo2/altnrslog" "github.com/newrelic/go-agent/v3/newrelic" ) func main() { app, err := newrelic.NewApplication( newrelic.ConfigAppName(os.Getenv("NEW_RELIC_CONFIG_APP_NAME")), newrelic.ConfigLicense(os.Getenv("NEW_RELIC_CONFIG_LICENSE")), newrelic.ConfigAppLogForwardingEnabled(true), ) tx := app.StartTransaction("ExampleNewTransactionalHandler") if err != nil { panic(err) } txHandler := altnrslog.NewTransactionalHandler(app, tx) slog.New(txHandler) }
Output:
Example (WithInnerHandlerProvider) ¶
package main import ( "fmt" "io" "log/slog" "os" "github.com/miyamo2/altnrslog" "github.com/newrelic/go-agent/v3/newrelic" ) func main() { app, err := newrelic.NewApplication( newrelic.ConfigAppName(os.Getenv("NEW_RELIC_CONFIG_APP_NAME")), newrelic.ConfigLicense(os.Getenv("NEW_RELIC_CONFIG_LICENSE")), newrelic.ConfigAppLogForwardingEnabled(true), ) tx := app.StartTransaction("ExampleNewTransactionalHandler_withInnerHandlerProvider") if err != nil { panic(err) } handlerOpt := slog.HandlerOptions{ AddSource: true, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { return slog.Attr{ Key: fmt.Sprintf("replaced.%s.%s", groups[0], a.Key), Value: a.Value, } }, } jsonHandlerProvider := func(w io.Writer) slog.Handler { return slog.NewJSONHandler(w, &handlerOpt) } txHandler := altnrslog.NewTransactionalHandler(app, tx, altnrslog.WithInnerHandlerProvider(jsonHandlerProvider)) slog.New(txHandler) }
Output:
Example (WithInnerWriter) ¶
package main import ( "io" "log/slog" "os" "github.com/miyamo2/altnrslog" "github.com/newrelic/go-agent/v3/newrelic" ) func main() { app, err := newrelic.NewApplication( newrelic.ConfigAppName(os.Getenv("NEW_RELIC_CONFIG_APP_NAME")), newrelic.ConfigLicense(os.Getenv("NEW_RELIC_CONFIG_LICENSE")), newrelic.ConfigAppLogForwardingEnabled(true), ) tx := app.StartTransaction("ExampleNewTransactionalHandler_withInnerWriter") if err != nil { panic(err) } logFile, err := os.OpenFile("log.txt", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666) if err != nil { panic(err) } mw := io.MultiWriter(os.Stdout, logFile) txHandler := altnrslog.NewTransactionalHandler(app, tx, altnrslog.WithInnerWriter(mw)) slog.New(txHandler) }
Output:
Example (WithSlogHandlerSpecify) ¶
package main import ( "fmt" "log/slog" "os" "github.com/miyamo2/altnrslog" "github.com/newrelic/go-agent/v3/newrelic" ) func main() { app, err := newrelic.NewApplication( newrelic.ConfigAppName(os.Getenv("NEW_RELIC_CONFIG_APP_NAME")), newrelic.ConfigLicense(os.Getenv("NEW_RELIC_CONFIG_LICENSE")), newrelic.ConfigAppLogForwardingEnabled(true), ) tx := app.StartTransaction("ExampleNewTransactionalHandler_withSlogHandlerSpecify") if err != nil { panic(err) } txHandler := altnrslog.NewTransactionalHandler(app, tx, altnrslog.WithSlogHandlerSpecify(true, &slog.HandlerOptions{ AddSource: true, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { return slog.Attr{ Key: fmt.Sprintf("replaced.%s.%s", groups[0], a.Key), Value: a.Value, } }, })) slog.New(txHandler) }
Output:
func (*TransactionalHandler) Enabled ¶
Enabled See: slog.Handler.Enabled
func (*TransactionalHandler) Handle ¶
Handle adds New Relic distributed tracing metadata to log records before passing them to the wrapped handler.
func (*TransactionalHandler) WithAttrs ¶
func (h *TransactionalHandler) WithAttrs(attrs []slog.Attr) slog.Handler
WithAttrs See: slog.Handler.WithAttrs
func (*TransactionalHandler) WithGroup ¶
func (h *TransactionalHandler) WithGroup(name string) slog.Handler
WithGroup See: slog.Handler.WithGroup