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

tfsdklog: Ensure sink logger options are propagated to SDK and provider root loggers #58

Merged
merged 4 commits into from May 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/58.txt
@@ -0,0 +1,3 @@
```release-note:bug
tflog+tfsdklog: Prevented `Unable to create logging subsystem with AdditionalLocationOffset due to missing root logger options` warning logs during acceptance testing
```
6 changes: 6 additions & 0 deletions internal/logging/log.go
Expand Up @@ -41,6 +41,12 @@ const (
// SinkKey is the loggerKey that will hold the logging sink used for
// test frameworks.
SinkKey loggerKey = ""

// SinkOptionsKey is the loggerKey that will hold the sink
// logger options when the SDK provider logger is created. This is to
// assist creating subsystem loggers, as most options cannot be fetched and
// a logger does not provide set methods for these options.
SinkOptionsKey loggerKey = "sink-options"
)

var (
Expand Down
51 changes: 51 additions & 0 deletions internal/logging/sink.go
@@ -0,0 +1,51 @@
package logging

import (
"context"

"github.com/hashicorp/go-hclog"
)

// GetSink returns the sink logger used for writing logs.
// If no sink logger has been created, it will return nil.
func GetSink(ctx context.Context) hclog.Logger {
logger := ctx.Value(SinkKey)
if logger == nil {
return nil
}
return logger.(hclog.Logger)
}

// GetSinkOptions returns the root logger options used for
// creating the root SDK logger. If the root logger has not been created or
// the options are not present, it will return nil.
func GetSinkOptions(ctx context.Context) *hclog.LoggerOptions {
if GetSink(ctx) == nil {
return nil
}

loggerOptionsRaw := ctx.Value(SinkOptionsKey)

if loggerOptionsRaw == nil {
return nil
}

loggerOptions, ok := loggerOptionsRaw.(*hclog.LoggerOptions)

if !ok {
return nil
}

return loggerOptions
}

// SetSink sets `logger` as the sink logger used for writing logs.
func SetSink(ctx context.Context, logger hclog.Logger) context.Context {
return context.WithValue(ctx, SinkKey, logger)
}

// SetSinkOptions sets `loggerOptions` as the root logger options
// used for creating the SDK root logger.
func SetSinkOptions(ctx context.Context, loggerOptions *hclog.LoggerOptions) context.Context {
return context.WithValue(ctx, SinkOptionsKey, loggerOptions)
}
26 changes: 22 additions & 4 deletions tfsdklog/sdk.go
Expand Up @@ -15,12 +15,21 @@ func NewRootSDKLogger(ctx context.Context, options ...logging.Option) context.Co
if opts.Name == "" {
opts.Name = logging.DefaultSDKRootLoggerName
}
if sink := getSink(ctx); sink != nil {
if sink := logging.GetSink(ctx); sink != nil {
logger := sink.Named(opts.Name)
sinkLoggerOptions := logging.GetSinkOptions(ctx)
sdkLoggerOptions := hclogutils.LoggerOptionsCopy(sinkLoggerOptions)
sdkLoggerOptions.Name = opts.Name

if opts.Level != hclog.NoLevel {
logger.SetLevel(opts.Level)
sdkLoggerOptions.Level = opts.Level
}
return logging.SetSDKRootLogger(ctx, logger)

ctx = logging.SetSDKRootLogger(ctx, logger)
ctx = logging.SetSDKRootLoggerOptions(ctx, sdkLoggerOptions)

return ctx
}
if opts.Level == hclog.NoLevel {
opts.Level = hclog.Trace
Expand Down Expand Up @@ -49,12 +58,21 @@ func NewRootProviderLogger(ctx context.Context, options ...logging.Option) conte
if opts.Name == "" {
opts.Name = logging.DefaultProviderRootLoggerName
}
if sink := getSink(ctx); sink != nil {
if sink := logging.GetSink(ctx); sink != nil {
logger := sink.Named(opts.Name)
sinkLoggerOptions := logging.GetSinkOptions(ctx)
providerLoggerOptions := hclogutils.LoggerOptionsCopy(sinkLoggerOptions)
providerLoggerOptions.Name = opts.Name

if opts.Level != hclog.NoLevel {
logger.SetLevel(opts.Level)
providerLoggerOptions.Level = opts.Level
}
return logging.SetProviderRootLogger(ctx, logger)

ctx = logging.SetProviderRootLogger(ctx, logger)
ctx = logging.SetProviderRootLoggerOptions(ctx, providerLoggerOptions)

return ctx
}
if opts.Level == hclog.NoLevel {
opts.Level = hclog.Trace
Expand Down
23 changes: 11 additions & 12 deletions tfsdklog/sink.go
Expand Up @@ -57,14 +57,6 @@ var ValidLevels = []string{"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF"}
// Only show invalid log level message once across any number of level lookups.
var invalidLogLevelMessage sync.Once

func getSink(ctx context.Context) hclog.Logger {
logger := ctx.Value(logging.SinkKey)
if logger == nil {
return nil
}
return logger.(hclog.Logger)
}

// RegisterTestSink sets up a logging sink, for use with test frameworks and
// other cases where plugin logs don't get routed through Terraform. This
// applies the same filtering and file output behaviors that Terraform does.
Expand All @@ -75,10 +67,15 @@ func getSink(ctx context.Context) hclog.Logger {
// RegisterTestSink must be called prior to any loggers being setup or
// instantiated.
func RegisterTestSink(ctx context.Context, t testing.T) context.Context {
return context.WithValue(ctx, logging.SinkKey, newSink(t))
logger, loggerOptions := newSink(t)

ctx = logging.SetSink(ctx, logger)
ctx = logging.SetSinkOptions(ctx, loggerOptions)

return ctx
}

func newSink(t testing.T) hclog.Logger {
func newSink(t testing.T) (hclog.Logger, *hclog.LoggerOptions) {
logOutput := io.Writer(os.Stderr)
var json bool
var logLevel hclog.Level
Expand Down Expand Up @@ -134,12 +131,14 @@ func newSink(t testing.T) hclog.Logger {
})
}

return hclog.New(&hclog.LoggerOptions{
loggerOptions := &hclog.LoggerOptions{
Level: logLevel,
Output: logOutput,
IndependentLevels: true,
JSONFormat: json,
})
}

return hclog.New(loggerOptions), loggerOptions
}

func isValidLogLevel(level string) bool {
Expand Down