tflog

package
Version: v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 6, 2022 License: MPL-2.0 Imports: 6 Imported by: 21

Documentation

Overview

Package tflog provides helper functions for writing log output and creating loggers for Terraform plugins.

For most plugin authors, building on an SDK or framework, the SDK or framework will take care of injecting a logger using New.

tflog also allows plugin authors to create subsystem loggers, which are loggers for sufficiently distinct areas of the codebase or concerns. The benefit of using distinct loggers for these concerns is doing so allows plugin authors and practitioners to configure different log levels for each subsystem's log, allowing log output to be turned on or off without recompiling.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Debug

func Debug(ctx context.Context, msg string, additionalFields ...map[string]interface{})

Debug logs `msg` at the debug level to the logger in `ctx`, with optional `additionalFields` structured key-value fields in the log output. Fields are shallow merged with any defined on the logger, e.g. by the `With()` function, and across multiple maps.

Example
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// non-example-setup code begins here
Debug(exampleCtx, "hello, world", map[string]interface{}{
	"foo":    123,
	"colors": []string{"red", "blue", "green"},
})
Output:

{"@level":"debug","@message":"hello, world","@module":"provider","colors":["red","blue","green"],"foo":123}

func Error

func Error(ctx context.Context, msg string, additionalFields ...map[string]interface{})

Error logs `msg` at the error level to the logger in `ctx`, with optional `additionalFields` structured key-value fields in the log output. Fields are shallow merged with any defined on the logger, e.g. by the `With()` function, and across multiple maps.

Example
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// non-example-setup code begins here
Error(exampleCtx, "hello, world", map[string]interface{}{
	"foo":    123,
	"colors": []string{"red", "blue", "green"},
})
Output:

{"@level":"error","@message":"hello, world","@module":"provider","colors":["red","blue","green"],"foo":123}

func Info

func Info(ctx context.Context, msg string, additionalFields ...map[string]interface{})

Info logs `msg` at the info level to the logger in `ctx`, with optional `additionalFields` structured key-value fields in the log output. Fields are shallow merged with any defined on the logger, e.g. by the `With()` function, and across multiple maps.

Example
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// non-example-setup code begins here
Info(exampleCtx, "hello, world", map[string]interface{}{
	"foo":    123,
	"colors": []string{"red", "blue", "green"},
})
Output:

{"@level":"info","@message":"hello, world","@module":"provider","colors":["red","blue","green"],"foo":123}

func NewSubsystem

func NewSubsystem(ctx context.Context, subsystem string, options ...logging.Option) context.Context

NewSubsystem returns a new context.Context that contains a subsystem logger configured with the passed options, named after the subsystem argument.

Subsystem loggers allow different areas of a plugin codebase to use different logging levels, giving developers more fine-grained control over what is logging and with what verbosity. They're best utilized for logical concerns that are sometimes helpful to log, but may generate unwanted noise at other times.

The only Options supported for subsystems are the Options for setting the level and additional location offset of the logger.

Example
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// non-example-setup code begins here

// register a new subsystem before using it
subCtx := NewSubsystem(exampleCtx, "my-subsystem")

// messages logged to the subsystem will carry the subsystem name with
// them
SubsystemTrace(subCtx, "my-subsystem", "hello, world", map[string]interface{}{"foo": 123})
Output:

{"@level":"trace","@message":"hello, world","@module":"provider.my-subsystem","foo":123}
Example (WithLevel)
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// simulate the user setting a logging level for the subsystem
os.Setenv("EXAMPLE_SUBSYSTEM_LEVEL", "WARN")

// non-example-setup code begins here

// create a context with a logger for a new "my-subsystem" subsystem,
// using the WARN level from the "EXAMPLE_SUBSYSTEM_LEVEL" environment
// variable
subCtx := NewSubsystem(exampleCtx, "my-subsystem", WithLevelFromEnv("EXAMPLE_SUBSYSTEM_LEVEL"))

// this won't actually get output, it's not at WARN or higher
SubsystemTrace(subCtx, "my-subsystem", "hello, world", map[string]interface{}{"foo": 123})

// the parent logger will still output at its configured TRACE level,
// though
Trace(subCtx, "hello, world", map[string]interface{}{"foo": 123})

// and the subsystem logger will output at the WARN level
SubsystemWarn(subCtx, "my-subsystem", "hello, world", map[string]interface{}{"foo": 123})
Output:

{"@level":"trace","@message":"hello, world","@module":"provider","foo":123}
{"@level":"warn","@message":"hello, world","@module":"provider.my-subsystem","foo":123}

func SubsystemDebug

func SubsystemDebug(ctx context.Context, subsystem, msg string, additionalFields ...map[string]interface{})

SubsystemDebug logs `msg` at the debug level to the subsystem logger specified in `ctx`, with optional `additionalFields` structured key-value fields in the log output. Fields are shallow merged with any defined on the subsystem logger, e.g. by the `SubsystemWith()` function, and across multiple maps.

Example
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// register a new subsystem before using it
exampleCtx = NewSubsystem(exampleCtx, "my-subsystem")

// non-example-setup code begins here
SubsystemDebug(exampleCtx, "my-subsystem", "hello, world", map[string]interface{}{
	"foo":    123,
	"colors": []string{"red", "blue", "green"},
})
Output:

{"@level":"debug","@message":"hello, world","@module":"provider.my-subsystem","colors":["red","blue","green"],"foo":123}

func SubsystemError

func SubsystemError(ctx context.Context, subsystem, msg string, additionalFields ...map[string]interface{})

SubsystemError logs `msg` at the error level to the subsystem logger specified in `ctx`, with optional `additionalFields` structured key-value fields in the log output. Fields are shallow merged with any defined on the subsystem logger, e.g. by the `SubsystemWith()` function, and across multiple maps.

Example
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// register a new subsystem before using it
exampleCtx = NewSubsystem(exampleCtx, "my-subsystem")

// non-example-setup code begins here
SubsystemError(exampleCtx, "my-subsystem", "hello, world", map[string]interface{}{
	"foo":    123,
	"colors": []string{"red", "blue", "green"},
})
Output:

{"@level":"error","@message":"hello, world","@module":"provider.my-subsystem","colors":["red","blue","green"],"foo":123}

func SubsystemInfo

func SubsystemInfo(ctx context.Context, subsystem, msg string, additionalFields ...map[string]interface{})

SubsystemInfo logs `msg` at the info level to the subsystem logger specified in `ctx`, with optional `additionalFields` structured key-value fields in the log output. Fields are shallow merged with any defined on the subsystem logger, e.g. by the `SubsystemWith()` function, and across multiple maps.

Example
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// register a new subsystem before using it
exampleCtx = NewSubsystem(exampleCtx, "my-subsystem")

// non-example-setup code begins here
SubsystemInfo(exampleCtx, "my-subsystem", "hello, world", map[string]interface{}{
	"foo":    123,
	"colors": []string{"red", "blue", "green"},
})
Output:

{"@level":"info","@message":"hello, world","@module":"provider.my-subsystem","colors":["red","blue","green"],"foo":123}

func SubsystemTrace

func SubsystemTrace(ctx context.Context, subsystem, msg string, additionalFields ...map[string]interface{})

SubsystemTrace logs `msg` at the trace level to the subsystem logger specified in `ctx`, with optional `additionalFields` structured key-value fields in the log output. Fields are shallow merged with any defined on the subsystem logger, e.g. by the `SubsystemWith()` function, and across multiple maps.

Example
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// register a new subsystem before using it
exampleCtx = NewSubsystem(exampleCtx, "my-subsystem")

// non-example-setup code begins here
SubsystemTrace(exampleCtx, "my-subsystem", "hello, world", map[string]interface{}{
	"foo":    123,
	"colors": []string{"red", "blue", "green"},
})
Output:

{"@level":"trace","@message":"hello, world","@module":"provider.my-subsystem","colors":["red","blue","green"],"foo":123}

func SubsystemWarn

func SubsystemWarn(ctx context.Context, subsystem, msg string, additionalFields ...map[string]interface{})

SubsystemWarn logs `msg` at the warn level to the subsystem logger specified in `ctx`, with optional `additionalFields` structured key-value fields in the log output. Fields are shallow merged with any defined on the subsystem logger, e.g. by the `SubsystemWith()` function, and across multiple maps.

Example
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// register a new subsystem before using it
exampleCtx = NewSubsystem(exampleCtx, "my-subsystem")

// non-example-setup code begins here
SubsystemWarn(exampleCtx, "my-subsystem", "hello, world", map[string]interface{}{
	"foo":    123,
	"colors": []string{"red", "blue", "green"},
})
Output:

{"@level":"warn","@message":"hello, world","@module":"provider.my-subsystem","colors":["red","blue","green"],"foo":123}

func SubsystemWith

func SubsystemWith(ctx context.Context, subsystem, key string, value interface{}) context.Context

SubsystemWith returns a new context.Context that has a modified logger for the specified subsystem in it which will include key and value as arguments in all its log output.

Example
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// register a new subsystem before using it
exampleCtx = NewSubsystem(exampleCtx, "my-subsystem")

// non-example-setup code begins here

// associate a key and value with all lines logged by the sub-logger
derivedCtx := SubsystemWith(exampleCtx, "my-subsystem", "foo", 123)

// all messages logged with derivedCtx will now have foo=123
// automatically included
SubsystemTrace(derivedCtx, "my-subsystem", "example log message")
Output:

{"@level":"trace","@message":"example log message","@module":"provider.my-subsystem","foo":123}

func Trace

func Trace(ctx context.Context, msg string, additionalFields ...map[string]interface{})

Trace logs `msg` at the trace level to the logger in `ctx`, with optional `additionalFields` structured key-value fields in the log output. Fields are shallow merged with any defined on the logger, e.g. by the `With()` function, and across multiple maps.

Example
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// non-example-setup code begins here
Trace(exampleCtx, "hello, world", map[string]interface{}{
	"foo":    123,
	"colors": []string{"red", "blue", "green"},
})
Output:

{"@level":"trace","@message":"hello, world","@module":"provider","colors":["red","blue","green"],"foo":123}

func Warn

func Warn(ctx context.Context, msg string, additionalFields ...map[string]interface{})

Warn logs `msg` at the warn level to the logger in `ctx`, with optional `additionalFields` structured key-value fields in the log output. Fields are shallow merged with any defined on the logger, e.g. by the `With()` function, and across multiple maps.

Example
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// non-example-setup code begins here
Warn(exampleCtx, "hello, world", map[string]interface{}{
	"foo":    123,
	"colors": []string{"red", "blue", "green"},
})
Output:

{"@level":"warn","@message":"hello, world","@module":"provider","colors":["red","blue","green"],"foo":123}

func With

func With(ctx context.Context, key string, value interface{}) context.Context

With returns a new context.Context that has a modified logger in it which will include key and value as arguments in all its log output.

Example
// virtually no plugin developers will need to worry about
// instantiating loggers, as the libraries they're using will take care
// of that, but we're not using those libraries in these examples. So
// we need to do the injection ourselves. Plugin developers will
// basically never need to do this, so the next line can safely be
// considered setup for the example and ignored. Instead, use the
// context passed in by the framework or library you're using.
exampleCtx := getExampleContext()

// non-example-setup code begins here
derivedCtx := With(exampleCtx, "foo", 123)

// all messages logged with derivedCtx will now have foo=123
// automatically included
Trace(derivedCtx, "example log message")
Output:

{"@level":"trace","@message":"example log message","@module":"provider","foo":123}

func WithAdditionalLocationOffset added in v0.3.0

func WithAdditionalLocationOffset(additionalLocationOffset int) logging.Option

WithAdditionalLocationOffset returns an option that allowing implementations to fix location information when implementing helper functions. The default offset of 1 is automatically added to the provided value to account for the tflog logging functions.

func WithLevel

func WithLevel(level hclog.Level) logging.Option

WithLevel returns an option that will set the level of the logger.

func WithLevelFromEnv

func WithLevelFromEnv(name string, subsystems ...string) logging.Option

WithLevelFromEnv returns an option that will set the level of the logger based on the string in an environment variable. The environment variable checked will be `name` and `subsystems`, joined by _ and in all caps.

func WithRootFields added in v0.4.0

func WithRootFields() logging.Option

WithRootFields enables the copying of root logger fields to a new subsystem logger during creation.

func WithoutLocation

func WithoutLocation() logging.Option

WithoutLocation returns an option that disables including the location of the log line in the log output, which is on by default. This has no effect when used with NewSubsystem.

Types

type Options

type Options []logging.Option

Options are a collection of logging options, useful for collecting arguments to NewSubsystem prior to calling it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL