Skip to content

zitadel/sloggcp

Repository files navigation

sloggcp

Go Reference codecov Go Report Card

sloggcp provides utilities to integrate Go's slog logging with Google Cloud Platform (GCP) structured logging.

Features

ReplaceAttr

It provides a simple implementation of the ReplaceAttr function for JSONHandler from slog.

This implementation adapts the default slog attributes to be compatible with Google Cloud Platform's Structured Logging, by replacing the following attribute keys:

Slog key GCP key
level severity
msg message
source logging.googleapis.com/sourceLocation
time time

Error reporting

sloggcp comes with a error reporting handler, which turns a log line into a formatted error message whenever an error is part of the attributes. This enables GCP Error Reporting through logging.

See the documentation for more details.

Usage

Get module

go get github.com/zitadel/sloggcp@latest

Override default attributes

package main

import (
	"github.com/zitadel/sloggcp"
	"log/slog"
	"os"
)

func main() {

	logger := slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
		ReplaceAttr: sloggcp.ReplaceAttr,
		AddSource:   true,
		Level:       slog.LevelDebug,
	}))
	slog.SetDefault(logger)
}

Use error reporting handler

package main

import (
	"errors"
	"fmt"
	"log/slog"
	"os"
	_ "runtime/debug"
	"time"

	"github.com/zitadel/sloggcp"
)

type AppError struct {
	Parent         error
	Message        string
	reportLocation *sloggcp.ReportLocation
	stackTrace     []byte
}

// Error implements [error].
func (e AppError) Error() string {
	return fmt.Sprintf("%s: %v", e.Message, e.Parent)
}

// ReportLocation implements [sloggcp.ReportLocationError].
func (e AppError) ReportLocation() *sloggcp.ReportLocation {
	return e.reportLocation
}

// StackTrace implements [sloggcp.StackTraceError].
func (e AppError) StackTrace() []byte {
	return e.stackTrace
}

// LogValue implements [slog.LogValuer].
func (e AppError) LogValue() slog.Value {
	var parent slog.Attr
	if v, ok := e.Parent.(slog.LogValuer); ok {
		parent = slog.Any("parent", v)
	} else {
		parent = slog.String("parent", e.Parent.Error())
	}

	return slog.GroupValue(
		slog.String("message", e.Message),
		parent,
	)
}

func main() {
	h := sloggcp.NewErrorReportingHandler(os.Stdout, &slog.HandlerOptions{
		Level: slog.LevelInfo,
		// Replace "err" key with the standard [ErrorKey] for GCP error reporting.
		ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
			if len(groups) != 0 {
				return a
			}
			if a.Key == "err" {
				a.Key = sloggcp.ErrorKey
			}
			return a
		},
	})
	logger := slog.New(h).With(sloggcp.TimeKey, time.Time{}) // for deterministic output

	// Simple string error
	logger.Error("", "err", errors.New("something went wrong"))

	err := AppError{
		Parent:  errors.New("database connection failed"),
		Message: "failed to fetch user data",
		reportLocation: &sloggcp.ReportLocation{
			FilePath:     "user_service.go",
			LineNumber:   42,
			FunctionName: "fetchUserData",
		},
		stackTrace: []byte("[STACK TRACE]"), // normally call [debug.Stack]
	}
	logger.Error("", "err", err)
	// Output:
	// {"@type":"type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent","error":"something went wrong","message":"something went wrong","severity":"ERROR","time":"0001-01-01T00:00:00Z"}
	// {"@type":"type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent","error":{"message":"failed to fetch user data","parent":"database connection failed"},"message":"[STACK TRACE]","reportLocation":{"filePath":"user_service.go","lineNumber":42,"functionName":"fetchUserData"},"severity":"ERROR","time":"0001-01-01T00:00:00Z"}
}

Supported Go Versions

For security reasons, we normally only support and recommend the use of one of the latest two Go versions (:white_check_mark:). Versions that also build are marked with :warning:.

sloggcp depends on functions only implemented in Go 1.25 and later.

Version Supported
<1.25
1.25

License

The full functionality of this library is and stays open source and free to use for everyone. Visit our website and get in touch.

See the exact licensing terms here

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

About

Go slog attribute adaptor and error reporting handler

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages