forked from go-logr/logr
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
support a slog.Logger pointer in a context
Conversion is done on demand. A program which uses either slog or logr for logging remains as efficient as before. What is less efficient is storing a logger of one type and then retrieving it as the other. Ideally, reusable packages should avoid using a slog.Logger and prefer logr.Logger instead when retrieving a logger from a context. There is a significant amount of packages which already work that way (Kubernetes and related packages), while storing and retrieving a logr.Logger is new and not done anywhere yet. Emulating existing behavior ensures better performance.
- Loading branch information
Showing
5 changed files
with
196 additions
and
61 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
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,33 @@ | ||
/* | ||
Copyright 2023 The logr Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package logr | ||
|
||
// contextKey is how we find Loggers in a context.Context. With Go < 1.21, | ||
// the value is always a Logger value. With Go >= 1.21, the value can be a | ||
// Logger value or a slog.Logger pointer. | ||
type contextKey struct{} | ||
|
||
// notFoundError exists to carry an IsNotFound method. | ||
type notFoundError struct{} | ||
|
||
func (notFoundError) Error() string { | ||
return "no logr.Logger was present" | ||
} | ||
|
||
func (notFoundError) IsNotFound() bool { | ||
return true | ||
} |
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,49 @@ | ||
//go:build !go1.21 | ||
// +build !go1.21 | ||
|
||
/* | ||
Copyright 2019 The logr Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package logr | ||
|
||
import ( | ||
"context" | ||
) | ||
|
||
// FromContext returns a Logger from ctx or an error if no Logger is found. | ||
func FromContext(ctx context.Context) (Logger, error) { | ||
if v, ok := ctx.Value(contextKey{}).(Logger); ok { | ||
return v, nil | ||
} | ||
|
||
return Logger{}, notFoundError{} | ||
} | ||
|
||
// FromContextOrDiscard returns a Logger from ctx. If no Logger is found, this | ||
// returns a Logger that discards all log messages. | ||
func FromContextOrDiscard(ctx context.Context) Logger { | ||
if v, ok := ctx.Value(contextKey{}).(Logger); ok { | ||
return v | ||
} | ||
|
||
return Discard() | ||
} | ||
|
||
// NewContext returns a new Context, derived from ctx, which carries the | ||
// provided Logger. | ||
func NewContext(ctx context.Context, logger Logger) context.Context { | ||
return context.WithValue(ctx, contextKey{}, logger) | ||
} |
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,83 @@ | ||
//go:build go1.21 | ||
// +build go1.21 | ||
|
||
/* | ||
Copyright 2019 The logr Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package logr | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log/slog" | ||
) | ||
|
||
// FromContext returns a Logger from ctx or an error if no Logger is found. | ||
func FromContext(ctx context.Context) (Logger, error) { | ||
v := ctx.Value(contextKey{}) | ||
if v == nil { | ||
return Logger{}, notFoundError{} | ||
} | ||
|
||
switch v := v.(type) { | ||
case Logger: | ||
return v, nil | ||
case *slog.Logger: | ||
return FromSlogHandler(v.Handler()), nil | ||
default: | ||
// Not reached. | ||
panic(fmt.Sprintf("unexpected value type for logr context key: %T", v)) | ||
} | ||
} | ||
|
||
// FromContextAsSlogLogger returns a slog.Logger from ctx or nil if no such Logger is found. | ||
func FromContextAsSlogLogger(ctx context.Context) *slog.Logger { | ||
v := ctx.Value(contextKey{}) | ||
if v == nil { | ||
return nil | ||
} | ||
|
||
switch v := v.(type) { | ||
case Logger: | ||
return slog.New(ToSlogHandler(v)) | ||
case *slog.Logger: | ||
return v | ||
default: | ||
// Not reached. | ||
panic(fmt.Sprintf("unexpected value type for logr context key: %T", v)) | ||
} | ||
} | ||
|
||
// FromContextOrDiscard returns a Logger from ctx. If no Logger is found, this | ||
// returns a Logger that discards all log messages. | ||
func FromContextOrDiscard(ctx context.Context) Logger { | ||
if logger, err := FromContext(ctx); err == nil { | ||
return logger | ||
} | ||
return Discard() | ||
} | ||
|
||
// NewContext returns a new Context, derived from ctx, which carries the | ||
// provided Logger. | ||
func NewContext(ctx context.Context, logger Logger) context.Context { | ||
return context.WithValue(ctx, contextKey{}, logger) | ||
} | ||
|
||
// NewContextWithSlogLogger returns a new Context, derived from ctx, which carries the | ||
// provided slog.Logger. | ||
func NewContextWithSlogLogger(ctx context.Context, logger *slog.Logger) context.Context { | ||
return context.WithValue(ctx, contextKey{}, logger) | ||
} |
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