unlog

package module
v0.0.6 Latest Latest
Warning

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

Go to latest
Published: Apr 26, 2024 License: MIT Imports: 17 Imported by: 2

README

Unlog - Unstructured Logging for Go log/slog

This package provides support for removing the structure from structured go logs. It uses Go templates to expand structured logs into text, and applies colorization using github.com/liamg/tml and line wrapping using github.com/manifoldco/ansiwrap.

It supports both short and long unstructuring templates present as comments in the code, and the tool cmd/unlog can be used to extract those templates, do linting across a source based, and manually unstructure input logs.

Installing the tool

go install bitbucket.org/fufoo/unlog/cmd/unlog@latest

Collecting a message catalog

For example, to collect messages across an entire repo

unlog collect -l -c messages.unl $(find . -name '*.go')

Using unstructurable errors

import (
    "bitbucket.org/fufoo/unlog/errors"
)

func DoIt(x int) error {
    if x < 0 {
        // FOO-1234 the value {{.x}} is negative, which
        // is not a supported configuration.
        //
        // Calling DoIt({{.x}}) is not supported; this functionality
        // only applies to non-negative values
        return errors.New("it doesn't work",
            slog.String("msgid", "FOO-1234"),
            slog.Int("x", x))
    }
}

Using a message catalog

From the command line

Using the command line tool:

unlog format -c messages.unl somelogs.json
Programatically

To programmatically make use of a message catalog, the most convenient approach is to use the new "embed" feature of Go to embed the message catalog into the executable, and then load it into an in-memory message catalog something like this:

import (
    _ "embed"
    "os"
  
    "bitbucket.org/fufoo/unlog"
)

//go:embed messages.unl
var ourCatalog []byte

func explain(err error) {
    cat := unlog.New()
    cat.Load(ourCatalog)
    wr := unlog.NewWriter(os.Stdout, unlog.WithCatalog(cat))
    wr.Explain(err)
}
Working with git

If you are committing your message catalog to the source repository using git, then add a .gitattributes file to mark it as binary:

*.unl binary

Usage with bazel

Since this is a bazel repo as well as a golang module, when consuming this functionality in bazel, instead of using gazelle (TBH I don't know how to use gazelle to load this module; if you figure it out, let me know; it seems that since this is also a golang module, either approach should work but I get an error about not being able to resolve @rules_go when using gazelle 🤷), add this to your MODULE.bazel:

bazel_dep( name = "fufoo_unlog", version = "0.0.1" )

git_override(
    module_name = "fufoo_unlog",
    remote = "[email protected]:fufoo/unlog.git",
    commit = "c7278db5c7b403f630d2873b7eb7f3d0c6f55f75",
)

then you can express a dependency in a BUILD file like so:

    deps = [
        "@fufoo_unlog//:unlog",
    ],

For embedded message catalogs, don't forget to include the embedsrcs in your build, e.g.:

load("@rules_go//go:def.bzl", "go_binary")

go_binary(
    name = "app",
    srcs = ["app.go"],
    visibility = ["//visibility:public"],
    deps = [
        "//:unlog",
    ],
    embedsrcs = ["messages.unl"],
)

Usage outside of bazel

For non-bazel users - i.e., basically everybody - we include the generated protobuf files.

Documentation

Index

Constants

Variables

This section is empty.

Functions

func FlattenAttrs

func FlattenAttrs(list []slog.Attr) map[string]any

FlattenAttrs takes a list of slog Attrs and turns it into a JSON-able map. Time and duration values are included as-is, because they are JSON marshallable.

func FlattenValue

func FlattenValue(v slog.Value) any

Types

type Catalog

type Catalog struct {
	// contains filtered or unexported fields
}

func New

func New() *Catalog

func (*Catalog) Get

func (c *Catalog) Get(msgid string) *Entry

func (*Catalog) Load

func (c *Catalog) Load(src []byte) error

type Entry

type Entry struct {
	// contains filtered or unexported fields
}

type Flag

type Flag uint
const (
	FlagIncludeMsgID Flag = 1 << iota
	FlagIncludeTime
	FlagIncludeLevel
	FlagIncludeSource
	FlagIncludeSourceFirst
	FlagIncludeExtras
	FlagWrap
	FlagIndent
	FlagHangIndent
	FlagLong // use the long message form
)

type Record

type Record struct {
	Catalog *Catalog
	Level   string
	Time    time.Time
	Msg     string
	MsgID   string
	Source  *Source
	Data    map[string]any
}

type Source

type Source struct {
	Function string
	File     string
	Line     int
}

func (*Source) String

func (s *Source) String() string

type Writer

type Writer struct {
	Output  io.Writer
	Width   int
	Catalog *Catalog
	Flags   Flag
}

func NewWriter

func NewWriter(dest io.Writer, opts ...WriterOption) *Writer

func (*Writer) Explain

func (w *Writer) Explain(err error)

Explain produces a longer explanation for an error produced by the unlog/errors package, or just the plain error message otherwise.

func (*Writer) Format

func (w *Writer) Format(rec *Record)

func (*Writer) RenderLong

func (w *Writer) RenderLong(e *Entry, data map[string]any) (int, error)

func (*Writer) RenderShort

func (w *Writer) RenderShort(e *Entry, data map[string]any) (int, error)

type WriterOption

type WriterOption func(*Writer)

func WithCatalog

func WithCatalog(cat *Catalog) WriterOption

func WithWidth

func WithWidth(width int) WriterOption

func WithoutSource

func WithoutSource() WriterOption

func WithoutTime

func WithoutTime() WriterOption

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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