log

package module
v0.1.4 Latest Latest
Warning

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

Go to latest
Published: Jul 1, 2025 License: Unlicense Imports: 5 Imported by: 2

README

Synopsis

Package log implements a simple structured JSON logger. The goal of this package is to eliminate logging clutter generated by more complex logging packages that encourage useless type conversions, declarations, and other noise. The logger starts with a few pre-initialized log fields that can be extended in the package scope, of which individual log lines can be derived from and operated on.

Variables

To use, first override the package-scoped variables at runtime.

var (
	// Service name
	Service = ""

	// Time is your time function
	Time    = func() interface{} {
		return time.Now().UnixNano() / int64(time.Millisecond)
	}

	// Default is the level used when calling Printf
	Default = Info
)

Install

go get github.com/as/log
go test github.com/as/log -v -bench . 
go test github.com/as/log -race -count 1

This code may also be copied and pasted into your microservice and modified to your liking. Put it in a package called log. A little copying is better than a little dependency.

The only file you need is log.go, there are no external dependencies.

Example 1

main.go

package main

import "github.com/as/log"

func main() {
	log.Service = "ex"
	log.Time = func() interface{} { return "2121.12.04" }

	log.Error.Add(
		"env", "prod",
		"burning", true,
		"pi", 3.14,
	).Printf("error: %v", io.EOF)
}

output

{"svc":"ex", "time":"2121.12.04", "level":"error", "msg":"error: EOF", "env":"prod", "burning":true, "pi":3.14}

Example 2

package main

import (
        "io"
        "github.com/as/log"
)

func main() {
        log.Service = "plumber"
        log.Tags = log.Tags.Add("env", "dev", "host", "scruffy") // package scoped tags attach to all logs
        unclog()
}

func unclog() {
        line := log.Info.Add(
                "op", "unclog",
                "account", "514423351351",
                "toilets", []string{"foo", "bar"}, // easily queried for membership in common log aggregators
        )
        line.Printf("enter")
        defer line.Printf("exit")

        // each operation copies the object and returns its copy with any tags added
        line.Add("action", "plunge").Printf("good god man")
        line.Error().Add("action", "flush", "err", io.ErrClosedPipe).Printf("damn")

        line = line.Warn().Add("action", "bill", "mood", "exhausted")
        line.Printf("you need a bigger toilet")
        line.Printf("it gets clogged to easily")
}
go mod init
go get github.com/as/log
touch main.go # copy the example above to this file
go run main.go
{"svc":"plumber", "ts":1682559034, "level":"info", "env":"dev", "host":"scruffy", "op":"unclog", "account":"514423351351", "toilets":["foo","bar"], "msg":"enter"}
{"svc":"plumber", "ts":1682559034, "level":"info", "env":"dev", "host":"scruffy", "op":"unclog", "account":"514423351351", "toilets":["foo","bar"], "action":"plunge", "msg":"good god man"}
{"svc":"plumber", "ts":1682559034, "level":"error", "env":"dev", "host":"scruffy", "op":"unclog", "account":"514423351351", "toilets":["foo","bar"], "action":"flush", "err":"io: read/write on closed pipe", "msg":"damn"}
{"svc":"plumber", "ts":1682559034, "level":"warn", "env":"dev", "host":"scruffy", "op":"unclog", "account":"514423351351", "toilets":["foo","bar"], "action":"bill", "mood":"exhausted", "msg":"you need a bigger toilet"}
{"svc":"plumber", "ts":1682559034, "level":"warn", "env":"dev", "host":"scruffy", "op":"unclog", "account":"514423351351", "toilets":["foo","bar"], "action":"bill", "mood":"exhausted", "msg":"it gets clogged to easily"}
{"svc":"plumber", "ts":1682559034, "level":"info", "env":"dev", "host":"scruffy", "op":"unclog", "account":"514423351351", "toilets":["foo","bar"], "msg":"exit"}

Example 3: But my caller frames!

You can use AddFunc, which has behavior similar to Add. It returns a copy of the line with the attached function executing before every print operation. Some precautions have been taken to avoid infinite recursion, but use of this feature is still mildly discouraged.

package main

import (
        "fmt"
        "path"
        "runtime"

        "github.com/as/log"
)

func main() {
        log.Service = "plumber"
        unclog()
}

func unclog() {
        fn := func(l log.Line) log.Line {
                return l.Add("func", where())
        }
        line := log.Info.AddFunc(fn)
        line.Printf("enter")
        defer line.Printf("exit")
}

func where() string {
        pc, file, line, ok := runtime.Caller(1)
        if !ok {
                return "/dev/null"
        }
        file = path.Base(file)

        fn := runtime.FuncForPC(pc)
        if fn == nil {
                return fmt.Sprintf("%s:%d", file, line)
        }
        return fmt.Sprintf("%s:/%s/", file, fn.Name())
}

Documentation

Overview

Package log implements a simple structured JSON logger

To use, override the package-scoped variables at runtime.

This code may be copied and pasted into your microservice and modified to your liking. Put it in a package called log. A little copying is better than a little dependency.

Example
package main

import (
	"io"
	"os"

	log "github.com/cbsinteractive/mc-log"
)

func main() {
	log.SetOutput(os.Stdout)
	log.Service = "ex"
	log.Time = func() interface{} { return 1000 }

	log.Error.F("hello, error: %v", io.EOF)
}
Output:

{"svc":"ex", "ts":1000, "level":"error", "msg":"hello, error: EOF"}
Example (Second)
package main

import (
	"io"
	"os"

	log "github.com/cbsinteractive/mc-log"
)

func main() {
	log.SetOutput(os.Stdout)
	log.Service = "ex"
	log.Time = func() interface{} { return 1000 }

	log.Error.Add("severity", "high").Printf("hello, error: %v", io.EOF)
}
Output:

{"svc":"ex", "ts":1000, "level":"error", "severity":"high", "msg":"hello, error: EOF"}
Example (Third)
package main

import (
	"io"
	"os"

	log "github.com/cbsinteractive/mc-log"
)

func main() {
	log.SetOutput(os.Stdout)
	log.Service = "ex"
	log.Time = func() interface{} { return "2121.12.04" }

	log.Error.Add(
		"env", "prod",
		"burning", true,
		"pi", 3.14,
	).Printf("error: %v", io.EOF)
}
Output:

{"svc":"ex", "ts":"2121.12.04", "level":"error", "env":"prod", "burning":true, "pi":3.14, "msg":"error: EOF"}

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// Service name (can be set in main or elsewhere)
	Service = os.Getenv("SVC")

	// Time is your time function. Default is a second timestamp.
	Time = func() interface{} {
		return time.Now().Unix()
	}

	// Tags are global static fields to publish for this process on
	// all log levels and callers
	Tags = fields{}

	// Default is the level used when calling Printf and Fatalf
	Default = Info
)
View Source
var (
	// Info, Warn, and so forth are commonly encountered log "levels".
	Info  = line{Level: "info"}
	Warn  = line{Level: "warn"}
	Error = line{Level: "error"}
	Fatal = line{Level: "fatal"}

	// Debug is a special level, it is only printed if DebugOn is true
	Debug   = line{Level: "debug"}
	DebugOn = false
)

Functions

func Fatalf

func Fatalf(f string, v ...interface{})

func New

func New(fields ...interface{}) line

New returns a log line with an extra field list

func Printf

func Printf(f string, v ...interface{})

Printf and Fatalf exist to make this package somewhat compatible with the go standard log.

Example
package main

import (
	"os"

	log "github.com/cbsinteractive/mc-log"
)

func main() {
	log.SetOutput(os.Stdout)
	log.Service = "ex"
	log.Time = func() interface{} { return 1000 }
	log.Printf("hello, world")
}
Output:

{"svc":"ex", "ts":1000, "level":"info", "msg":"hello, world"}

func SetOutput

func SetOutput(w io.Writer) (old io.Writer)

SetOutput sets the log output to w. It returns the previous writer used.

func Trap

func Trap()

Trap may be used in a defer to suppress stack traces caused by a call to Fatal.F or Fatal.Printf. Panics from other sources are not affected. Trap calls os.Exit(1) if the panic occured from these functions.

func main(){
		defer log.Trap()

}

Types

type Line

type Line = line

Line allows a log line to be embedded somewhere

Jump to

Keyboard shortcuts

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