actionslog

package module
v0.5.1 Latest Latest
Warning

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

Go to latest
Published: Jul 20, 2023 License: MIT Imports: 9 Imported by: 3

README

actionslog

Go Reference

Contributions welcome.

go get github.com/willabides/actionslog

actionslog's creation was blogged here

actionslog provides a wrapper around a Handler for Go's log/slog that outputs logs as GitHub Actions workflow commands that will cause the logs to show up in the GitHub UI -- optionally with links to the source code.

It can wrap any slog.Handler, but it also provides human.Handler which is meant to be a little easier for human's to read. human.Handler's output is roughly <message>\n <vars as yaml>, so output for logger.Info("hello", slog.String("object", "world"), slog.Any("list", []string{"a", "b", "c")) would look like:

hello
  object: world
  list:
    - a
    - b
    - c

actionslog.Wrapper implements slog.Handler from "log/slog" when built with go 1.21 or higher. When built with go earlier versions that predate "log/slog", it implements slog.Handler from "golang.org/x/exp/slog".

Usage

package main

import (
	"log/slog"

	"github.com/willabides/actionslog"
	"github.com/willabides/actionslog/human"
)

func main() {
	logger := slog.New(&actionslog.Wrapper{
		Handler: human.Handler{}.WithOutput
	})
	logger.Info("hello", slog.String("object", "world"))
}

Screenshots

This is what the output of ./internal/example looks like in the GitHub UI.

Run Log

run log

Workflow Summary

workflow summary

Inline Code Annotations

inline code annotations

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultHandler added in v0.2.0

func DefaultHandler(w io.Writer) slog.Handler

DefaultHandler is a slog.TextHandler with time and level output removed because that would be redundant with the actions log.

Types

type ActionsLog added in v0.4.0

type ActionsLog int

ActionsLog is a log level in GitHub Actions.

const (
	LogDebug ActionsLog = iota
	LogNotice
	LogWarn
	LogError
)

func DefaultActionsLog added in v0.4.0

func DefaultActionsLog(level slog.Level) ActionsLog

DefaultActionsLog is the default mapping from slog.Level to ActionsLog.

func (ActionsLog) String added in v0.4.0

func (a ActionsLog) String() string

type Wrapper added in v0.3.0

type Wrapper struct {
	// Handler is a function that returns the handler the Wrapper will wrap. Handler is only called once, so changes
	// after the Wrapper is created will not be reflected. Defaults to DefaultHandler.
	Handler func(w io.Writer) slog.Handler

	// Output is the io.Writer that the Wrapper will write to. Defaults to os.Stdout because that is what GitHub
	// Actions expects. Output should not be changed after the Wrapper is created.
	Output io.Writer

	// AddSource causes the Wrapper to compute the source code position
	// of the log statement so that it can be linked from the GitHub Actions UI.
	AddSource bool

	// Level sets the level for the Wrapper itself. If it is set, the Wrapper will only pass through logs that
	// are at or above this level. Handler may have its own level set as well. It is probably advisable
	// to either set it on the Wrapper or the Handler but not both.
	Level slog.Leveler

	// ActionsLogger maps a slog.Level to an ActionsLog. Defaults to DefaultActionsLog. See ExampleWrapper_writeDebugToNotice for
	// an example of a custom ActionsLogger.
	ActionsLogger func(level slog.Level) ActionsLog
	// contains filtered or unexported fields
}

Wrapper is a slog.Handler that wraps another slog.Handler and formats its output for GitHub Actions.

Example
package main

import (
	"fmt"
	"golang.org/x/exp/slog"

	"github.com/willabides/actionslog"
)

func main() {
	logger := slog.New(&actionslog.Wrapper{})
	logger = logger.With(slog.String("func", "Example"))

	logger.Info("hello", slog.String("object", "world"))
	logger.Warn("This is a stern warning")
	logger.Error("got an error", slog.Any("err", fmt.Errorf("omg")))
	logger.Debug("this is a debug message")
	logger.Info("this is a \n multiline \r\n message")
	logger.Info("multiline value", slog.String("value", "this is a\nmultiline\nvalue"))

}
Output:


::notice ::msg=hello func=Example object=world
::warning ::msg="This is a stern warning" func=Example
::error ::msg="got an error" func=Example err=omg
::debug ::msg="this is a debug message" func=Example
::notice ::msg="this is a \n multiline \r\n message" func=Example
::notice ::msg="multiline value" func=Example value="this is a\nmultiline\nvalue"
Example (WriteDebugToNotice)
package main

import (
	"golang.org/x/exp/slog"

	"github.com/willabides/actionslog"
)

func main() {
	// This gets around GitHub Actions' behavior of hiding debug messages unless you specify
	// "enable debug logging" by outputting debug messages as notice messages.

	logger := slog.New(&actionslog.Wrapper{
		ActionsLogger: func(level slog.Level) actionslog.ActionsLog {
			defaultLog := actionslog.DefaultActionsLog(level)
			if defaultLog == actionslog.LogDebug {
				return actionslog.LogNotice
			}
			return defaultLog
		},
	})
	logger.Debug("this is a debug message")
	logger.Info("this is an info message")

}
Output:


::notice ::msg="this is a debug message"
::notice ::msg="this is an info message"

func (*Wrapper) Enabled added in v0.3.0

func (w *Wrapper) Enabled(ctx context.Context, level slog.Level) bool

func (*Wrapper) Handle added in v0.3.0

func (w *Wrapper) Handle(ctx context.Context, record slog.Record) error

func (*Wrapper) WithAttrs added in v0.3.0

func (w *Wrapper) WithAttrs(attrs []slog.Attr) slog.Handler

func (*Wrapper) WithGroup added in v0.3.0

func (w *Wrapper) WithGroup(name string) slog.Handler

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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