Skip to content

Commit

Permalink
Merge pull request #19 from veqryn/with-error
Browse files Browse the repository at this point in the history
Error slog attribute
  • Loading branch information
veqryn authored Mar 26, 2024
2 parents 47ec50a + d4bc074 commit c6b21ed
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 31 deletions.
26 changes: 9 additions & 17 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
#schedule:
#- cron: '18 16 * * 2'
#- cron: '28 21 * * 1'
push:
branches: [ "main" ]

Expand All @@ -26,47 +26,39 @@ jobs:
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
# Uncomment the permissions below if installing in a private repository.
# contents: read
# actions: read

steps:
- name: "Checkout code"
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false

- name: "Run analysis"
uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecard on a *private* repository
# you want to enable the Branch-Protection check on a *public* repository, or
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}

# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
publish_results: true

# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: SARIF file
path: results.sarif
retention-days: 5

# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
uses: github/codeql-action/upload-sarif@8a470fddafa5cbb6266ee11b37ef4d8aae19c571 # v3.24.6
with:
sarif_file: results.sarif
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ down the stack and with any libraries that use either slog-context or logr.
### Other Great SLOG Utilities
- [slogctx](https://github.com/veqryn/slog-context): Add attributes to context and have them automatically added to all log lines. Work with a logger stored in context.
- [slogotel](https://github.com/veqryn/slog-context/tree/main/otel): Automatically extract and add [OpenTelemetry](https://opentelemetry.io/) TraceID's to all log lines.
- [slogdedup](https://github.com/veqryn/slog-dedup): Middleware that deduplicates and sorts attributes. Particularly useful for JSON logging.
- [slogdedup](https://github.com/veqryn/slog-dedup): Middleware that deduplicates and sorts attributes. Particularly useful for JSON logging. Format logs for aggregators (Graylog, GCP/Stackdriver, etc).
- [slogbugsnag](https://github.com/veqryn/slog-bugsnag): Middleware that pipes Errors to [Bugsnag](https://www.bugsnag.com/).
- [slogjson](https://github.com/veqryn/slog-json): Formatter that uses the [JSON v2](https://github.com/golang/go/discussions/63397) [library](https://github.com/go-json-experiment/json), with optional single-line pretty-printing.

## Install

Expand All @@ -73,6 +74,7 @@ package main

import (
"context"
"errors"
"log/slog"
"os"

Expand All @@ -96,7 +98,7 @@ import (
// logger and its attributes will propagate with it, adding these to any log
// lines using that context.
func main() {
h := slog.NewJSONHandler(os.Stdout, nil)
h := slogctx.NewHandler(slog.NewJSONHandler(os.Stdout, nil), nil)
slog.SetDefault(slog.New(h))

// Store the logger inside the context:
Expand All @@ -123,17 +125,22 @@ func main() {
// and can take a mix of slog.Attr and key-value pairs.
ctx = slogctx.With(ctx, slog.String("subKey", "subValue"), slog.Bool("someBool", true))

err := errors.New("an error")

// Access the logger in the context directly with handy wrappers for Debug/Info/Warn/Error/Log/LogAttrs:
slogctx.Info(ctx, "main message", "mainKey", "mainValue")
slogctx.Error(ctx, "main message",
slogctx.Err(err),
slog.String("mainKey", "mainValue"))
/*
{
"time":"2023-11-14T00:53:46.363072-07:00",
"level":"INFO",
"level":"ERROR",
"msg":"main message",
"rootKey":"rootValue",
"someGroup":{
"subKey":"subValue",
"someBool":true,
"err":"an error",
"mainKey":"mainValue"
}
}
Expand Down
5 changes: 3 additions & 2 deletions ctx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package slogctx
import (
"bytes"
"context"
"errors"
"log/slog"
"testing"
)
Expand Down Expand Up @@ -80,8 +81,8 @@ func TestCtx(t *testing.T) {
}

buf.Reset()
Error(ctx, "main message", "main1", "arg1", "main1", "arg2")
expectedError := `{"time":"2023-09-29T13:00:59Z","level":"ERROR","msg":"main message","with1":"arg1","with1":"arg2","with2":"arg1","with2":"arg2","group1":{"with4":"arg1","with4":"arg2","with5":"arg1","with5":"arg2","main1":"arg1","main1":"arg2"}}
Error(ctx, "main message", "main1", "arg1", "main1", "arg2", Err(errors.New("an error")))
expectedError := `{"time":"2023-09-29T13:00:59Z","level":"ERROR","msg":"main message","with1":"arg1","with1":"arg2","with2":"arg1","with2":"arg2","group1":{"with4":"arg1","with4":"arg2","with5":"arg1","with5":"arg2","main1":"arg1","main1":"arg2","err":"an error"}}
`
if buf.String() != expectedError {
t.Errorf("Expected:\n%s\nGot:\n%s\n", expectedError, buf.String())
Expand Down
12 changes: 9 additions & 3 deletions examples/logger-in-ctx/logger-in-ctx-main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"context"
"errors"
"log/slog"
"os"

Expand All @@ -25,7 +26,7 @@ import (
// logger and its attributes will propagate with it, adding these to any log
// lines using that context.
func main() {
h := slog.NewJSONHandler(os.Stdout, nil)
h := slogctx.NewHandler(slog.NewJSONHandler(os.Stdout, nil), nil)
slog.SetDefault(slog.New(h))

// Store the logger inside the context:
Expand All @@ -52,17 +53,22 @@ func main() {
// and can take a mix of slog.Attr and key-value pairs.
ctx = slogctx.With(ctx, slog.String("subKey", "subValue"), slog.Bool("someBool", true))

err := errors.New("an error")

// Access the logger in the context directly with handy wrappers for Debug/Info/Warn/Error/Log/LogAttrs:
slogctx.Info(ctx, "main message", "mainKey", "mainValue")
slogctx.Error(ctx, "main message",
slogctx.Err(err),
slog.String("mainKey", "mainValue"))
/*
{
"time":"2023-11-14T00:53:46.363072-07:00",
"level":"INFO",
"level":"ERROR",
"msg":"main message",
"rootKey":"rootValue",
"someGroup":{
"subKey":"subValue",
"someBool":true,
"err":"an error",
"mainKey":"mainValue"
}
}
Expand Down
24 changes: 19 additions & 5 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package slogctx_test

import (
"context"
"errors"
"log/slog"
"os"

Expand Down Expand Up @@ -56,7 +57,7 @@ func ExampleNewHandler() {
// Use the logger like normal; add attributes, create groups, pass it around:
log := slog.With("rootKey", "rootValue")
log = log.WithGroup("someGroup")
log = log.With("subKey", "subValue8")
log = log.With("subKey", "subValue")

// The prepended/appended attributes end up in all log lines that use that context
log.InfoContext(ctx, "main message", "mainKey", "mainValue")
Expand Down Expand Up @@ -94,7 +95,7 @@ func ExampleNewCtx() {
// logger and its attributes will propagate with it, adding these to any log
// lines using that context.

h := slog.NewJSONHandler(os.Stdout, nil)
h := slogctx.NewHandler(slog.NewJSONHandler(os.Stdout, nil), nil)
slog.SetDefault(slog.New(h))

// Store the logger inside the context:
Expand All @@ -103,6 +104,13 @@ func ExampleNewCtx() {
// Get the logger back out again at any time, for manual usage:
log := slogctx.FromCtx(ctx)
log.Warn("warning")
/*
{
"time":"2023-11-14T00:53:46.361201-07:00",
"level":"INFO",
"msg":"warning"
}
*/

// Add attributes directly to the logger in the context:
ctx = slogctx.With(ctx, "rootKey", "rootValue")
Expand All @@ -112,18 +120,24 @@ func ExampleNewCtx() {

// With and wrapper methods have the same args signature as slog methods,
// and can take a mix of slog.Attr and key-value pairs.
ctx = slogctx.With(ctx, slog.String("subKey", "subValue"))
ctx = slogctx.With(ctx, slog.String("subKey", "subValue"), slog.Bool("someBool", true))

err := errors.New("an error")

// Access the logger in the context directly with handy wrappers for Debug/Info/Warn/Error/Log/LogAttrs:
slogctx.Info(ctx, "main message", "mainKey", "mainValue")
slogctx.Error(ctx, "main message",
slogctx.Err(err),
slog.String("mainKey", "mainValue"))
/*
{
"time":"2023-11-14T00:53:46.363072-07:00",
"level":"INFO",
"level":"ERROR",
"msg":"main message",
"rootKey":"rootValue",
"someGroup":{
"subKey":"subValue",
"someBool":true,
"err":"an error",
"mainKey":"mainValue"
}
}
Expand Down
10 changes: 10 additions & 0 deletions wrappers.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ import (
"time"
)

// ErrKey is the key used by handlers for an error
// when the log method is called. The associated Value is an error.
const ErrKey = "err" // TODO: consider making a var to allow changes before.

// Err is a convenience method that creates a [slog.Attr] out of an error.
// It uses a consistent key: [ErrKey]
func Err(err error) slog.Attr {
return slog.Any(ErrKey, err)
}

// With calls With on the logger stored in the context,
// or if there isn't any, on the default logger.
// This new logger is stored in a child context and the new context is returned.
Expand Down

0 comments on commit c6b21ed

Please sign in to comment.