debug

package module
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Jan 5, 2021 License: MIT Imports: 16 Imported by: 2

README

go-debug build status

Conditional debug logging for Go libraries.

View the docs.

Installation

$ go get github.com/nmccready/go-debug

Example

Show me everthing
$ DEBUG=* go run ./example/readme/index.go
18:18:25.215 4us   app-name:main - sending mail
    key=value
18:18:25.215 986ns app-name:main - sending mail
    key=value
18:18:25.215 516ns app-name:main - send email to tobi@segment.io
    key=value
18:18:25.215 550ns app-name:main - send email to loki@segment.io
    key=value
18:18:25.215 486ns app-name:main - send email to jane@segment.io
    key=value
18:18:25.215 1us   error:app-name:main - oh noes
18:18:25.215 852ns app-name:main:child - hi from child
18:18:25.215 804ns app-name:sibling:a - hi
18:18:25.215 804ns app-name:sibling:b - hi
18:18:25.215 850ns error:app-name:sibling:b - sad
App Domain only
$ DEBUG=app-name* go run ./example/readme/index.go
18:19:00.567 5us   app-name:main - sending mail
    key=value
18:19:00.567 916ns app-name:main - sending mail
    key=value
18:19:00.567 493ns app-name:main - send email to tobi@segment.io
    key=value
18:19:00.567 458ns app-name:main - send email to loki@segment.io
    key=value
18:19:00.567 423ns app-name:main - send email to jane@segment.io
    key=value
18:19:00.567 736ns app-name:main:child - hi from child
18:19:00.567 793ns app-name:sibling:a - hi
18:19:00.567 713ns app-name:sibling:b - hi
Filter out errors
$ DEBUG=*,-error* go run ./example/readme/index.go
18:19:20.595 5us   app-name:main - sending mail
    key=value
18:19:20.595 1us   app-name:main - sending mail
    key=value
18:19:20.595 611ns app-name:main - send email to tobi@segment.io
    key=value
18:19:20.595 584ns app-name:main - send email to loki@segment.io
    key=value
18:19:20.595 505ns app-name:main - send email to jane@segment.io
    key=value
18:19:20.595 801ns app-name:main:child - hi from child
18:19:20.595 779ns app-name:sibling:a - hi
18:19:20.595 794ns app-name:sibling:b - hi
Errors Only
$ DEBUG=error* go run ./example/readme/index.go
17:35:13.401 1us   error:app-name:main - oh noes
17:35:13.401 1us   error:app-name:sibling:b - sad
Everything but omit some

Omitting sibling but report their errors

$ DEBUG=*,-app-name:sibling* go run ./example/readme/index.go
18:19:48.034 5us   app-name:main - sending mail
    key=value
18:19:48.034 1us   app-name:main - sending mail
    key=value
18:19:48.034 730ns app-name:main - send email to tobi@segment.io
    key=value
18:19:48.034 648ns app-name:main - send email to loki@segment.io
    key=value
18:19:48.034 533ns app-name:main - send email to jane@segment.io
    key=value
18:19:48.034 1us   error:app-name:main - oh noes
18:19:48.034 1us   app-name:main:child - hi from child
18:19:48.034 1us   error:app-name:sibling:b - sad

Formatters

By Default the TextFormatter is w/o Fields as seen above. Fields can be added via WithField or WithFields. If TextFormatter{HasFieldsOnly:true} then all fields namespace, time, msg, and delta will be inlined as fields.

Otherwise the message is printed as above but with fields below it.

TextFormatter HasFieldsOnly
$ DEBUG=* go run ./example/readme/index.go -fieldsOnly
delta=6us key=value msg="sending mail" namespace=app-name:main time=18:14:49.462
delta=925ns key=value msg="sending mail" namespace=app-name:main time=18:14:49.462
delta=532ns key=value msg="send email to tobi@segment.io" namespace=app-name:main time=18:14:49.462
delta=528ns key=value msg="send email to loki@segment.io" namespace=app-name:main time=18:14:49.462
delta=466ns key=value msg="send email to jane@segment.io" namespace=app-name:main time=18:14:49.462
delta=1us msg="oh noes" namespace=error:app-name:main time=18:14:49.462
delta=1us msg="hi from child" namespace=app-name:main:child time=18:14:49.462
delta=3us msg=hi namespace=app-name:sibling:a time=18:14:49.462
delta=1us msg=hi namespace=app-name:sibling:b time=18:14:49.462
delta=7us msg=sad namespace=error:app-name:sibling:b time=18:14:49.462
JSONFormatter
$ DEBUG=* go run ./example/readme/index.go -json
{"delta":"6us","key":"value","msg":"sending mail","namespace":"app-name:main","time":"18:15:17.113"}
{"delta":"892ns","key":"value","msg":"sending mail","namespace":"app-name:main","time":"18:15:17.113"}
{"delta":"640ns","key":"value","msg":"send email to tobi@segment.io","namespace":"app-name:main","time":"18:15:17.113"}
{"delta":"604ns","key":"value","msg":"send email to loki@segment.io","namespace":"app-name:main","time":"18:15:17.113"}
{"delta":"505ns","key":"value","msg":"send email to jane@segment.io","namespace":"app-name:main","time":"18:15:17.113"}
{"delta":"1us","msg":"oh noes","namespace":"error:app-name:main","time":"18:15:17.113"}
{"delta":"1us","msg":"hi from child","namespace":"app-name:main:child","time":"18:15:17.113"}
{"delta":"1us","msg":"hi","namespace":"app-name:sibling:a","time":"18:15:17.113"}
{"delta":"1us","msg":"hi","namespace":"app-name:sibling:b","time":"18:15:17.113"}
{"delta":"4us","msg":"sad","namespace":"error:app-name:sibling:b","time":"18:15:17.113"}
W/ PrettyPrint
$ DEBUG=* go run ./example/readme/index.go -json -pretty
{
  "delta": "6us",
  "key": "value",
  "msg": "sending mail",
  "namespace": "app-name:main",
  "time": "18:16:13.351"
}
{
  "delta": "912ns",
  "key": "value",
  "msg": "sending mail",
  "namespace": "app-name:main",
  "time": "18:16:13.351"
}
{
  "delta": "561ns",
  "key": "value",
  "msg": "send email to tobi@segment.io",
  "namespace": "app-name:main",
  "time": "18:16:13.351"
}
{
  "delta": "580ns",
  "key": "value",
  "msg": "send email to loki@segment.io",
  "namespace": "app-name:main",
  "time": "18:16:13.351"
}
{
  "delta": "518ns",
  "key": "value",
  "msg": "send email to jane@segment.io",
  "namespace": "app-name:main",
  "time": "18:16:13.351"
}
{
  "delta": "1us",
  "msg": "oh noes",
  "namespace": "error:app-name:main",
  "time": "18:16:13.351"
}
{
  "delta": "1us",
  "msg": "hi from child",
  "namespace": "app-name:main:child",
  "time": "18:16:13.351"
}
{
  "delta": "1us",
  "msg": "hi",
  "namespace": "app-name:sibling:a",
  "time": "18:16:13.351"
}
{
  "delta": "1us",
  "msg": "hi",
  "namespace": "app-name:sibling:b",
  "time": "18:16:13.351"
}
{
  "delta": "4us",
  "msg": "sad",
  "namespace": "error:app-name:sibling:b",
  "time": "18:16:13.351"
}

Timestamp & Delta

A timestamp and one delta . The timestamp consists of hour, minute, second and microseconds. The delta is relative to the previous debug call of any name.

The environment variables

DEBUG

Executables often support --verbose flags for conditional logging, however libraries typically either require altering your code to enable logging, or simply omit logging all together. go-debug allows conditional logging to be enabled via the DEBUG environment variable, where one or more patterns may be specified.

For example suppose your application has several models and you want to output logs for users only, you might use DEBUG=models:user. In contrast if you wanted to see what all database activity was you might use DEBUG=models:*, or if you're love being swamped with logs: DEBUG=*. You may also specify a list of names delimited by a comma, for example DEBUG=mongo,redis:*. If your swamped you can also start omitting namespaces ie: DEBUG=*,-mongo,-redis.

The name given should be the package name, however you can use whatever you like.

DEBUG_CACHE_MINUTES

Integer in minutes to set the debug caching. By default each debug namespace is cached 60 minutes via Spawn.

DEBUG_COLOR_OFF

Default is false and color is on. Truthy ie anything not an empty string is true. Thus, turning color off.

DEBUG_TIME_OFF

Default is false and timestamp & delta are on. Truthy ie anything not an empty string is true. Thus, turning times off.

License

MIT

Development

Install:

  • yq - brew install yq
  • golines - go get -u github.com/segmentio/golines
  • golangci-lint - brew install golangci/tap/golangci-lint

Documentation

Index

Examples

Constants

View Source
const (
	FieldKeyMsg       = "msg"
	FieldKeyNamespace = "namespace"
	FieldKeyTime      = "time"
	FieldKeyDelta     = "delta"
	FieldKeyError     = "debug_error"
)

Variables

View Source
var (
	HAS_COLORS = true
	HAS_TIME   = true
)
View Source
var SetHasColors = setBoolWithLock(func(isOn bool) {
	HAS_COLORS = isOn
})
View Source
var SetHasTime = setBoolWithLock(func(isOn bool) {
	HAS_TIME = isOn
})

Functions

func BasicFormat added in v0.1.0

func BasicFormat(ts string, delta string, ns string, msg string) string

func BuildNegativeMatches added in v0.1.0

func BuildNegativeMatches(pattern string, orString string) (string, []*regexp.Regexp)

Find all negative namespaces and pull them out of the pattern.

But build a slice of negatives

example: pattern="*,-somenamespace"

Returns: "*", ["somenamespace"]

func BuildPattern added in v0.1.0

func BuildPattern(pattern string) (string, []*regexp.Regexp)

func Disable

func Disable()

Disable all pattern matching. This function is thread-safe.

func Enable

func Enable(pattern string)

Enable the given debug `pattern`. Patterns take a glob-like form, for example if you wanted to enable everything, just use "*", or if you had a library named mongodb you could use "mongodb:connection", or "mongodb:*". Multiple matches can be made with a comma, for example "mongo*,redis*".

This function is thread-safe.

Example
Enable("mongo:connection")
Enable("mongo:*")
Enable("foo,bar,baz")
Enable("*")
Output:

func RegExWildCard added in v0.1.1

func RegExWildCard(pattern string) string

func RegExWrap added in v0.1.0

func RegExWrap(pattern string) string

func RegExWrapCompile added in v0.1.1

func RegExWrapCompile(pattern string) *regexp.Regexp

func SetCache added in v0.0.5

func SetCache(cacheMinStr string) error

Initialize the namespace cache which defaults to 60 min lifespan

func SetFormatter added in v0.1.0

func SetFormatter(f Formatter)

func SetFormatterString added in v0.2.0

func SetFormatterString(s string)

func SetWriter

func SetWriter(w io.Writer)

SetWriter replaces the default of os.Stderr with `w`.

Types

type Debugger

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

func Debug

func Debug(name string) Debugger

Debug creates a debug function for `name` which you call with printf-style arguments in your application or library.

Example
var debug = Debug("single")

for {
	debug.Log("sending mail")
	debug.Log("send email to %s", "tobi@segment.io")
	debug.Log("send email to %s", "loki@segment.io")
	debug.Log("send email to %s", "jane@segment.io")
	time.Sleep(500 * time.Millisecond)
}
Output:

func (Debugger) ApplyRootFields added in v0.4.0

func (dbg Debugger) ApplyRootFields(name string) Debugger

func (Debugger) Error added in v0.1.1

func (dbg Debugger) Error(args ...interface{})

prepend error/warn name as it is easier to filter!

func (Debugger) Log

func (dbg Debugger) Log(args ...interface{})

func (Debugger) Spawn

func (dbg Debugger) Spawn(ns string) *Debugger

func (Debugger) Warn added in v0.1.2

func (dbg Debugger) Warn(args ...interface{})

func (Debugger) WithField added in v0.1.0

func (dbg Debugger) WithField(key string, value interface{}) *Debugger

NOT *Debugger receiver on purpose to be immutable to not deal with locks on fields

func (Debugger) WithFields added in v0.1.0

func (dbg Debugger) WithFields(fields Fields) *Debugger

NOT *Debugger receiver on purpose to be immutable to not deal with locks on fields

type Fields added in v0.1.0

type Fields map[string]interface{}

type Finalized added in v0.1.0

type Finalized struct {
	Fields     Fields
	Namespace  string
	TimeString string
	Delta      string
}

type Formatter added in v0.1.0

type Formatter interface {
	Format(Debugger, interface{}) string
	GetHasFieldsOnly() bool
}

highly inspired by logrus

type IDebugger added in v0.1.0

type IDebugger interface {
	Log(...interface{})
	Error(...interface{})
	Warn(...interface{})
	Spawn(ns string) *Debugger
	WithFields(fields Fields) *Debugger
	WithField(key string, value interface{}) *Debugger
}

type JSONFormatter added in v0.1.0

type JSONFormatter struct {
	// TimestampFormat sets the format used for marshaling timestamps.
	TimestampFormat string

	// HTMLEscape allows disabling html escaping in output
	HTMLEscape bool

	Indent int

	// CallerPrettyfier can be set by the user to modify the content
	// of the function and file keys in the json data when ReportCaller is
	// activated. If any of the returned value is the empty string the
	// corresponding key will be removed from json fields.
	CallerPrettyfier func(*runtime.Frame) (function string, file string)

	// PrettyPrint will indent all json logs
	PrettyPrint bool

	FlattenMsgFields bool
}

JSONFormatter formats logs into parsable json

func (*JSONFormatter) Format added in v0.1.0

func (f *JSONFormatter) Format(dbg Debugger, _msg interface{}) string

func (*JSONFormatter) GetHasFieldsOnly added in v0.1.0

func (f *JSONFormatter) GetHasFieldsOnly() bool

type TextFormatter added in v0.1.0

type TextFormatter struct {
	HasColor         bool
	ForceQuote       bool
	QuoteEmptyFields bool
	DisableQuote     bool
	HasFieldsOnly    bool
	SortingFunc      func(keys []string)
}

func (*TextFormatter) Format added in v0.1.0

func (t *TextFormatter) Format(dbg Debugger, _msg interface{}) string

func (*TextFormatter) GetHasFieldsOnly added in v0.1.0

func (t *TextFormatter) GetHasFieldsOnly() bool

Directories

Path Synopsis
example

Jump to

Keyboard shortcuts

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