Skip to content

Commit

Permalink
Introduce tflogtest and tfsdklogtest packages (#62)
Browse files Browse the repository at this point in the history
Reference: #61
  • Loading branch information
bflad committed May 4, 2022
1 parent 1d9ce94 commit f5284c7
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 1 deletion.
7 changes: 7 additions & 0 deletions .changelog/62.txt
@@ -0,0 +1,7 @@
```release-note:feature
Added `tflogtest` package, which provides functionality for unit testing of provider logging
```

```release-note:feature
Added `tfsdklogtest` package, which provides functionality for unit testing of SDK logging
```
3 changes: 2 additions & 1 deletion internal/loggertest/json_decode.go
Expand Up @@ -8,11 +8,12 @@ import (

func MultilineJSONDecode(data io.Reader) ([]map[string]interface{}, error) {
var result []map[string]interface{}
var entry map[string]interface{}

dec := json.NewDecoder(data)

for {
var entry map[string]interface{}

err := dec.Decode(&entry)

if err == io.EOF {
Expand Down
3 changes: 3 additions & 0 deletions tflogtest/doc.go
@@ -0,0 +1,3 @@
// Package tflogtest provides functionality for unit testing of provider
// logging.
package tflogtest
13 changes: 13 additions & 0 deletions tflogtest/json_decode.go
@@ -0,0 +1,13 @@
package tflogtest

import (
"io"

"github.com/hashicorp/terraform-plugin-log/internal/loggertest"
)

// MultilineJSONDecode supports decoding the output of a JSON logger into a
// slice of maps, with each element representing a log entry.
func MultilineJSONDecode(data io.Reader) ([]map[string]interface{}, error) {
return loggertest.MultilineJSONDecode(data)
}
38 changes: 38 additions & 0 deletions tflogtest/json_decode_example_test.go
@@ -0,0 +1,38 @@
package tflogtest

import (
"bytes"
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-log/tflog"
)

func ExampleMultilineJSONDecode() {
var output bytes.Buffer

ctx := RootLogger(context.Background(), &output)

// Root provider logger is now available for usage, such as writing
// entries, calling With(), or calling NewSubsystem().
tflog.Trace(ctx, "entry 1")
tflog.Trace(ctx, "entry 2")

entries, err := MultilineJSONDecode(&output)

if err != nil {
// Typical unit testing would call t.Fatalf() here.
fmt.Printf("unable to read multiple line JSON: %s", err)
}

// Entries can be checked via go-cmp's cmp.Diff() or other testing methods.
// This example outputs them to stdout in an explicitly formatted string,
// which would not be expected in typical unit testing.
for _, entry := range entries {
fmt.Printf("@message: %s\n", entry["@message"])
}

// Output:
// @message: entry 1
// @message: entry 2
}
21 changes: 21 additions & 0 deletions tflogtest/root_logger.go
@@ -0,0 +1,21 @@
package tflogtest

import (
"context"
"io"

"github.com/hashicorp/terraform-plugin-log/internal/loggertest"
)

// RootLogger returns a context containing a provider root logger suitable for
// unit testing that is:
//
// - Written to the given io.Writer, such as a bytes.Buffer.
// - Written with JSON output, that can be decoded with MultilineJSONDecode.
// - Log level set to TRACE.
// - Without location/caller information in log entries.
// - Without timestamps in log entries.
//
func RootLogger(ctx context.Context, output io.Writer) context.Context {
return loggertest.ProviderRoot(ctx, output)
}
27 changes: 27 additions & 0 deletions tflogtest/root_logger_example_test.go
@@ -0,0 +1,27 @@
package tflogtest

import (
"bytes"
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-log/tflog"
)

func ExampleRootLogger() {
var output bytes.Buffer

ctx := RootLogger(context.Background(), &output)

// Root provider logger is now available for usage, such as writing
// entries, calling With(), or calling NewSubsystem().
tflog.Trace(ctx, "hello, world", map[string]interface{}{
"foo": 123,
"colors": []string{"red", "blue", "green"},
})

fmt.Println(output.String())

// Output:
// {"@level":"trace","@message":"hello, world","@module":"provider","colors":["red","blue","green"],"foo":123}
}
3 changes: 3 additions & 0 deletions tfsdklogtest/doc.go
@@ -0,0 +1,3 @@
// Package tfsdklogtest provides functionality for unit testing of SDK
// logging. Provider developers should use the tflogtest package.
package tfsdklogtest
13 changes: 13 additions & 0 deletions tfsdklogtest/json_decode.go
@@ -0,0 +1,13 @@
package tfsdklogtest

import (
"io"

"github.com/hashicorp/terraform-plugin-log/internal/loggertest"
)

// MultilineJSONDecode supports decoding the output of a JSON logger into a
// slice of maps, with each element representing a log entry.
func MultilineJSONDecode(data io.Reader) ([]map[string]interface{}, error) {
return loggertest.MultilineJSONDecode(data)
}
38 changes: 38 additions & 0 deletions tfsdklogtest/json_decode_example_test.go
@@ -0,0 +1,38 @@
package tfsdklogtest

import (
"bytes"
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-log/tfsdklog"
)

func ExampleMultilineJSONDecode() {
var output bytes.Buffer

ctx := RootLogger(context.Background(), &output)

// Root SDK logger is now available for usage, such as writing entries,
// calling With(), or calling NewSubsystem().
tfsdklog.Trace(ctx, "entry 1")
tfsdklog.Trace(ctx, "entry 2")

entries, err := MultilineJSONDecode(&output)

if err != nil {
// Typical unit testing would call t.Fatalf() here.
fmt.Printf("unable to read multiple line JSON: %s", err)
}

// Entries can be checked via go-cmp's cmp.Diff() or other testing methods.
// This example outputs them to stdout in an explicitly formatted string,
// which would not be expected in typical unit testing.
for _, entry := range entries {
fmt.Printf("@message: %s\n", entry["@message"])
}

// Output:
// @message: entry 1
// @message: entry 2
}
21 changes: 21 additions & 0 deletions tfsdklogtest/root_logger.go
@@ -0,0 +1,21 @@
package tfsdklogtest

import (
"context"
"io"

"github.com/hashicorp/terraform-plugin-log/internal/loggertest"
)

// RootLogger returns a context containing a SDK root logger suitable for unit
// testing that is:
//
// - Written to the given io.Writer, such as a bytes.Buffer.
// - Written with JSON output, that can be decoded with MultilineJSONDecode.
// - Log level set to TRACE.
// - Without location/caller information in log entries.
// - Without timestamps in log entries.
//
func RootLogger(ctx context.Context, output io.Writer) context.Context {
return loggertest.SDKRoot(ctx, output)
}
27 changes: 27 additions & 0 deletions tfsdklogtest/root_logger_example_test.go
@@ -0,0 +1,27 @@
package tfsdklogtest

import (
"bytes"
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-log/tfsdklog"
)

func ExampleRootLogger() {
var output bytes.Buffer

ctx := RootLogger(context.Background(), &output)

// Root SDK logger is now available for usage, such as writing entries,
// calling With(), or calling NewSubsystem().
tfsdklog.Trace(ctx, "hello, world", map[string]interface{}{
"foo": 123,
"colors": []string{"red", "blue", "green"},
})

fmt.Println(output.String())

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

0 comments on commit f5284c7

Please sign in to comment.