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

replace github.com/hashicorp/go-hclog with stdlib log/slog #152

Merged
merged 2 commits into from
Mar 18, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [v0.12.1] - UNRELEASED

### Minor breaking change

- `source.log_level`.
- The README was wrongly still mentioning `silent` as a way to silent the logging. Actually `silent` was remapped to `info` since [v0.8.2](#v082---2022-11-18).
- Starting from this version, levels `silent` and `off` will cause an error.
- The only supported log levels are `debug`, `info`, `warn`, `error`. The default level, `info`, is recommended for normal operation.

### Changed

- Update to Go 1.22

### Removed

- Replaced module github.com/hashicorp/go-hclog with stdlib log/slog.

## [v0.12.0] - 2023-11-03

### Added
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ With reference to the [GitHub Commit status API], the `POST` parameters (`state`
See also: the optional `context` in the [put step](#the-put-step).

- `log_level`:\
The log level (one of `debug`, `info`, `warn`, `error`, `silent`).\
Default: `info`.
The log level (one of `debug`, `info`, `warn`, `error`).\
Default: `info`, recommended for normal operation.

- `github_hostname`:\
GitHub hostname. This allows to post commit statuses to repositories hosted by GitHub Enterprise (GHE) instances. For example: github.mycompany.org will be expanded by cogito to https://github.mycompany.org/api/v3 \
Expand Down
26 changes: 18 additions & 8 deletions cmd/cogito/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import (
"encoding/json"
"fmt"
"io"
"log/slog"
"os"
"path"

"github.com/hashicorp/go-hclog"

"github.com/Pix4D/cogito/cogito"
"github.com/Pix4D/cogito/sets"
)
Expand All @@ -37,16 +36,27 @@ func mainErr(in io.Reader, out io.Writer, logOut io.Writer, args []string) error
if err != nil {
return fmt.Errorf("reading stdin: %s", err)
}

logLevel, err := peekLogLevel(input)
if err != nil {
return err
}
log := hclog.New(&hclog.LoggerOptions{
Name: "cogito",
Level: hclog.LevelFromString(logLevel),
Output: logOut,
DisableTime: true,
})
var level slog.Level
if err := level.UnmarshalText([]byte(logLevel)); err != nil {
return fmt.Errorf("%s. (valid: debug, info, warn, error)", err)
}
removeTime := func(groups []string, a slog.Attr) slog.Attr {
marco-m-pix4d marked this conversation as resolved.
Show resolved Hide resolved
if a.Key == slog.TimeKey {
return slog.Attr{}
}
return a
}
log := slog.New(slog.NewTextHandler(
logOut,
&slog.HandlerOptions{
Level: level,
ReplaceAttr: removeTime,
}))
log.Info(cogito.BuildInfo())

switch cmd {
Expand Down
9 changes: 5 additions & 4 deletions cmd/cogito/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ func TestRunPutSuccessIntegration(t *testing.T) {

assert.NilError(t, err, "\nout:\n%s\nlogOut:\n%s", out.String(), logOut.String())
assert.Assert(t, cmp.Contains(logOut.String(),
"cogito.put.ghCommitStatus: commit status posted successfully"))
`level=INFO msg="commit status posted successfully" name=cogito.put name=ghCommitStatus state=error`))
assert.Assert(t, cmp.Contains(logOut.String(),
"cogito.put.gChat: state posted successfully to chat"))
`level=INFO msg="state posted successfully to chat" name=cogito.put name=gChat state=error`))
}

func TestRunFailure(t *testing.T) {
Expand Down Expand Up @@ -199,11 +199,12 @@ func TestRunPrintsBuildInformation(t *testing.T) {
}
}`)
var logBuf bytes.Buffer
wantLog := "cogito: This is the Cogito GitHub status resource. unknown"
wantLog := "This is the Cogito GitHub status resource. unknown"

err := mainErr(in, io.Discard, &logBuf, []string{"check"})
assert.NilError(t, err)
haveLog := logBuf.String()

assert.Assert(t, strings.Contains(haveLog, wantLog), haveLog)
assert.Assert(t, strings.Contains(haveLog, wantLog),
"\nhave: %s\nwant: %s", haveLog, wantLog)
}
9 changes: 3 additions & 6 deletions cogito/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import (
"encoding/json"
"fmt"
"io"

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

// Check implements the "check" step (the "check" executable).
Expand All @@ -17,10 +16,8 @@ import (
// It is given the configured source and current version on stdin, and must print the
// array of new versions, in chronological order (oldest first), to stdout, including
// the requested version if it is still valid.
func Check(log hclog.Logger, input []byte, out io.Writer, args []string) error {
log = log.Named("check")
log.Debug("started")
defer log.Debug("finished")
func Check(log *slog.Logger, input []byte, out io.Writer, args []string) error {
log = log.With("name", "cogito.check")

request, err := NewCheckRequest(input)
if err != nil {
Expand Down
7 changes: 3 additions & 4 deletions cogito/check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"io"
"testing"

"github.com/hashicorp/go-hclog"
"gotest.tools/v3/assert"

"github.com/Pix4D/cogito/cogito"
Expand All @@ -22,7 +21,7 @@ func TestCheckSuccess(t *testing.T) {
test := func(t *testing.T, tc testCase) {
in := testhelp.ToJSON(t, tc.request)
var out bytes.Buffer
log := hclog.NewNullLogger()
log := testhelp.MakeTestLog()

err := cogito.Check(log, in, &out, nil)

Expand Down Expand Up @@ -74,7 +73,7 @@ func TestCheckFailure(t *testing.T) {
test := func(t *testing.T, tc testCase) {
assert.Assert(t, tc.wantErr != "")
in := testhelp.ToJSON(t, cogito.CheckRequest{Source: tc.source})
log := hclog.NewNullLogger()
log := testhelp.MakeTestLog()

err := cogito.Check(log, in, tc.writer, nil)

Expand Down Expand Up @@ -126,7 +125,7 @@ func TestCheckFailure(t *testing.T) {
}

func TestCheckInputFailure(t *testing.T) {
log := hclog.NewNullLogger()
log := testhelp.MakeTestLog()

err := cogito.Check(log, nil, io.Discard, nil)

Expand Down
5 changes: 2 additions & 3 deletions cogito/gchatsink.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@ import (
"context"
"fmt"
"io/fs"
"log/slog"
"strings"
"time"

"github.com/hashicorp/go-hclog"

"github.com/Pix4D/cogito/googlechat"
)

// GoogleChatSink is an implementation of [Sinker] for the Cogito resource.
type GoogleChatSink struct {
Log hclog.Logger
Log *slog.Logger
InputDir fs.FS
GitRef string
Request PutRequest
Expand Down
9 changes: 4 additions & 5 deletions cogito/gchatsink_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"testing"
"testing/fstest"

"github.com/hashicorp/go-hclog"
"gotest.tools/v3/assert"
"gotest.tools/v3/assert/cmp"

Expand Down Expand Up @@ -38,7 +37,7 @@ func TestSinkGoogleChatSendSuccess(t *testing.T) {
tc.setWebHook(&request, ts.URL)
assert.NilError(t, request.Source.Validate())
sink := cogito.GoogleChatSink{
Log: hclog.NewNullLogger(),
Log: testhelp.MakeTestLog(),
GitRef: wantGitRef,
Request: request,
}
Expand Down Expand Up @@ -80,7 +79,7 @@ func TestSinkGoogleChatDecidesNotToSendSuccess(t *testing.T) {

test := func(t *testing.T, tc testCase) {
sink := cogito.GoogleChatSink{
Log: hclog.NewNullLogger(),
Log: testhelp.MakeTestLog(),
Request: tc.request,
}

Expand Down Expand Up @@ -120,7 +119,7 @@ func TestSinkGoogleChatSendBackendFailure(t *testing.T) {
request.Source.GChatWebHook = ts.URL
assert.NilError(t, request.Source.Validate())
sink := cogito.GoogleChatSink{
Log: hclog.NewNullLogger(),
Log: testhelp.MakeTestLog(),
Request: request,
}

Expand All @@ -136,7 +135,7 @@ func TestSinkGoogleChatSendInputFailure(t *testing.T) {
request.Source.GChatWebHook = "dummy-url"
assert.NilError(t, request.Source.Validate())
sink := cogito.GoogleChatSink{
Log: hclog.NewNullLogger(),
Log: testhelp.MakeTestLog(),
InputDir: fstest.MapFS{"bar/msg.txt": {Data: []byte("from-custom-file")}},
Request: request,
}
Expand Down
9 changes: 3 additions & 6 deletions cogito/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import (
"encoding/json"
"fmt"
"io"

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

// Get implements the "get" step (the "in" executable).
Expand All @@ -24,10 +23,8 @@ import (
// The program must emit a JSON object containing the fetched version, and may emit
// metadata as a list of key-value pairs.
// This data is intended for public consumption and will be shown on the build page.
func Get(log hclog.Logger, input []byte, out io.Writer, args []string) error {
log = log.Named("get")
log.Debug("started")
defer log.Debug("finished")
func Get(log *slog.Logger, input []byte, out io.Writer, args []string) error {
log = log.With("name", "cogito.get")

request, err := NewGetRequest(input)
if err != nil {
Expand Down
7 changes: 3 additions & 4 deletions cogito/get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"io"
"testing"

"github.com/hashicorp/go-hclog"
"gotest.tools/v3/assert"

"github.com/Pix4D/cogito/cogito"
Expand All @@ -22,7 +21,7 @@ func TestGetSuccess(t *testing.T) {
test := func(t *testing.T, tc testCase) {
in := testhelp.ToJSON(t, tc.request)
var out bytes.Buffer
log := hclog.NewNullLogger()
log := testhelp.MakeTestLog()

err := cogito.Get(log, in, &out, []string{"dummy-dir"})

Expand Down Expand Up @@ -73,7 +72,7 @@ func TestGetFailure(t *testing.T) {
Source: tc.source,
Version: tc.version,
})
log := hclog.NewNullLogger()
log := testhelp.MakeTestLog()

err := cogito.Get(log, in, tc.writer, tc.args)

Expand Down Expand Up @@ -144,7 +143,7 @@ func TestGetNonEmptyParamsFailure(t *testing.T) {
}`)
wantErr := `get: parsing request: json: unknown field "params"`

err := cogito.Get(hclog.NewNullLogger(), in, io.Discard, []string{})
err := cogito.Get(testhelp.MakeTestLog(), in, io.Discard, []string{})

assert.Error(t, err, wantErr)
}
7 changes: 2 additions & 5 deletions cogito/ghcommitsink.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import (
"log/slog"
"time"

"github.com/hashicorp/go-hclog"

"github.com/Pix4D/cogito/github"
"github.com/Pix4D/cogito/internal/hclogslog"
"github.com/Pix4D/cogito/retry"
)

Expand All @@ -26,7 +23,7 @@ const (

// GitHubCommitStatusSink is an implementation of [Sinker] for the Cogito resource.
type GitHubCommitStatusSink struct {
Log hclog.Logger
Log *slog.Logger
GitRef string
Request PutRequest
}
Expand All @@ -46,7 +43,7 @@ func (sink GitHubCommitStatusSink) Send() error {
FirstDelay: retryFirstDelay,
BackoffLimit: retryBackoffLimit,
UpTo: retryUpTo,
Log: slog.New(hclogslog.Adapt(sink.Log)),
Log: sink.Log,
},
}
commitStatus := github.NewCommitStatus(target, sink.Request.Source.AccessToken,
Expand Down
5 changes: 2 additions & 3 deletions cogito/ghcommitsink_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"path"
"testing"

"github.com/hashicorp/go-hclog"
"gotest.tools/v3/assert"

"github.com/Pix4D/cogito/cogito"
Expand All @@ -26,7 +25,7 @@ func TestSinkGitHubCommitStatusSendSuccess(t *testing.T) {
gitHubSpyURL, err := url.Parse(ts.URL)
assert.NilError(t, err, "error parsing SpyHttpServer URL: %s", err)
sink := cogito.GitHubCommitStatusSink{
Log: hclog.NewNullLogger(),
Log: testhelp.MakeTestLog(),
GitRef: wantGitRef,
Request: cogito.PutRequest{
Source: cogito.Source{GhHostname: gitHubSpyURL.Host},
Expand All @@ -53,7 +52,7 @@ func TestSinkGitHubCommitStatusSendFailure(t *testing.T) {
assert.NilError(t, err, "error parsing SpyHttpServer URL: %s", err)
defer ts.Close()
sink := cogito.GitHubCommitStatusSink{
Log: hclog.NewNullLogger(),
Log: testhelp.MakeTestLog(),
GitRef: "deadbeefdeadbeef",
Request: cogito.PutRequest{
Source: cogito.Source{GhHostname: gitHubSpyURL.Host},
Expand Down
19 changes: 11 additions & 8 deletions cogito/protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import (
"bytes"
"encoding/json"
"fmt"
"log/slog"
"strings"
"testing"

"github.com/hashicorp/go-hclog"
"gotest.tools/v3/assert"
"gotest.tools/v3/assert/cmp"

"github.com/Pix4D/cogito/cogito"
"github.com/Pix4D/cogito/testhelp"
)

func TestSourceValidationSuccess(t *testing.T) {
Expand Down Expand Up @@ -247,15 +248,16 @@ sinks: []`
assert.Equal(t, have, want)
})

t.Run("hclog redacts fields", func(t *testing.T) {
t.Run("slog redacts fields", func(t *testing.T) {
var logBuf bytes.Buffer
log := hclog.New(&hclog.LoggerOptions{Output: &logBuf})
log := slog.New(slog.NewTextHandler(&logBuf,
&slog.HandlerOptions{ReplaceAttr: testhelp.RemoveTime}))

log.Info("log test", "source", source)
have := logBuf.String()

assert.Assert(t, cmp.Contains(have, "| access_token: ***REDACTED***"))
assert.Assert(t, cmp.Contains(have, "| gchat_webhook: ***REDACTED***"))
assert.Assert(t, cmp.Contains(have, "access_token: ***REDACTED***"))
assert.Assert(t, cmp.Contains(have, "gchat_webhook: ***REDACTED***"))
assert.Assert(t, !strings.Contains(have, "sensitive"))
})
}
Expand Down Expand Up @@ -302,14 +304,15 @@ sinks: []`
assert.Equal(t, have, want)
})

t.Run("hclog redacts fields", func(t *testing.T) {
t.Run("slog redacts fields", func(t *testing.T) {
var logBuf bytes.Buffer
log := hclog.New(&hclog.LoggerOptions{Output: &logBuf})
log := slog.New(slog.NewTextHandler(&logBuf,
&slog.HandlerOptions{ReplaceAttr: testhelp.RemoveTime}))

log.Info("log test", "params", params)
have := logBuf.String()

assert.Assert(t, cmp.Contains(have, "| gchat_webhook: ***REDACTED***"))
assert.Assert(t, cmp.Contains(have, "gchat_webhook: ***REDACTED***"))
assert.Assert(t, !strings.Contains(have, "sensitive"))
})
}
Expand Down
Loading
Loading