package module
Version: v0.0.0-...-8950f45 Latest Latest

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

Go to latest
Published: Sep 3, 2019 License: MIT Imports: 3 Imported by: 10


ulog - Structured and context oriented logging interface for Go

Build Status GoDoc

Package ulog provides a simple way to handle structured and context oriented logging and decouples package from specific log implementation.

Pain in Logging

If you write some module or function in your project, you might want to do logging.

func doSomething() {
   log.Println("start do something")
   // ...
   log.Println("end do something")

But your code may be called from server's request handler or some batch process, so it should be logged with authenticated user's ID or batch process name.

Some libraries like logrus, log15 provides a way to bind the context value to a logger object and output structured log. So now you can write like

func doSomething(logger logrus.FieldLogger) {
   logger.Info("start do something")
   // ...
   logger.Info("end do something")

// from serer
doSomething(logrus.WithField("userID" : "123"))

// from batch process
doSomething(logrus.WithField("processName" : "someBatch"))

This looks pretty good! but there're some problem

  • Everywhere you want to output log should take the logger
  • Your code is strongly coupled with some logger library.
    • One project uses glog but the other new project may use logrus

Use context.Context with ulog

ulog provides a way to carry a context using Go's context package (for 1.6 or older version golang.org/x/net/context).

You can write

func doSomething(ctx context.Context) {
	logger := ulog.Logger(ctx)
    logger.Info("start do something")
    // ...
    logger.Info("end do something")
// from server
import "github.com/wacul/ulog/adapter/glog"
// ...
// set glog adapter and fields to context
ctx = ulog.Logger(ctx).
		WithField("userID" : "123")

// from batch process
import (
    logrusadapter "github.com/wacul/adapter/logrus"
// set logrus adapter and fields to context
ctx = ulog.Logger(ctx).
		WithField("processName" : "someBatch")


ulog.Logger(ctx) returns ulog.LoggerContext interface that also implements context.Context interface.


ulog has no output handler itself. By default, all logs are discarded.

To output logs, ulog provides adapter implementations for popular loggers. (see the adapter directory)

  • stdlog (go's standard library log)
  • logrus
  • log15
  • glog
  • apex/log
  • discard
    • discards all logs
  • tee
    • splits logs to multiple adapters

There're two ways to set an adapter.

// set a global adapter
// used when context has no adapter

// set a adapter used with child context
ctx = ulog.Logger(ctx).WithAdapter(adapter)

You can implement a custom adapter implementing simple ulog.Adapter interface.

Code Example

package main

import (
	stdlog "log"

	stdlog_adapter "github.com/wacul/ulog/adapter/stdlog"

func doSomething(ctx context.Context) {
	logger := ulog.Logger(ctx)
	logger.Info("Start doSomething")

	// log with  key-value
	logger.WithField("key1", 1).Warnf("warning! %s", "message")

	logger.Info("End doSomething")

func main() {
	// ulog discards all logs by default

	ctx := context.Background()
	ctx = ulog.Logger(ctx).WithAdapter(&stdlog_adapter.Adapter{})

	// ulog.Logger returns type ulog.LoggerContext that also implements context.Context
	ctx = ulog.Logger(ctx).
		// set field for children
		WithField("module", "app1").
		// and set log adapter for children
		WithAdapter(&stdlog_adapter.Adapter{Level: ulog.WarnLevel})

	// so you can pass as context to other function


demo.go:13:  info Start doSomething        
demo.go:16:  warn warning! message          key1=1
demo.go:18:  info End doSomething          
demo.go:16:  warn warning! message          module=app1 key1=1




This section is empty.


This section is empty.


func CallDepthFromContext

func CallDepthFromContext(ctx context.Context) int

CallerDepthFromContext return callerDepth int value, this value is used by finding caller position, usually doesn't have to remember it.

func SetDefaultAdapter

func SetDefaultAdapter(a Adapter)

SetDefaultAdapter sets the Adapter for default adapter which will be used when the adapter is not set in context or context is nil.


type Adapter

type Adapter interface {

Adapter is interface

type AdapterFunc

type AdapterFunc func(Entry)

AdapterFunc wraps func to Adapter

func (AdapterFunc) Handle

func (f AdapterFunc) Handle(e Entry)

Handle calls f

type Entry

type Entry struct {
	Level   Level
	Message string

Entry is dataset to log, passed to LoggerAdapter's Handle method

func (*Entry) CallDepth

func (e *Entry) CallDepth() int

CallDepth retruns a numver of caller depth

func (*Entry) Fields

func (e *Entry) Fields() []Field

Fields returns log fields binded with context

type Field

type Field struct {
	Key   string
	Value interface{}

Field is key-value pair to log

type Level

type Level uint8

Level type

const (
	DebugLevel Level = iota

Logging levels numeric order (Debug < Info < Warn < Error) is guaranteed

func MustLevel

func MustLevel(s string) Level

MustLevel parses string to Level. Panics when unknown level given

func ParseLevel

func ParseLevel(s string) (Level, error)

ParseLevel parses string to Level

func (Level) String

func (l Level) String() string

type LoggerContext

type LoggerContext interface {
	WithField(key string, value interface{}) LoggerContext
	WithAdapter(Adapter) LoggerContext
	WithCallDepth(depth int) LoggerContext

	Error(args ...interface{})
	Errorf(format string, args ...interface{})
	Warn(args ...interface{})
	Warnf(format string, args ...interface{})
	Info(args ...interface{})
	Infof(format string, args ...interface{})
	Debug(args ...interface{})
	Debugf(format string, args ...interface{})

LoggerContext is context bounded logger

func Logger

func Logger(ctx context.Context) LoggerContext

Logger returns LoggerContext


Path Synopsis

Jump to

Keyboard shortcuts

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