timber: github.com/ngmoco/timber Index | Files

package timber

import "github.com/ngmoco/timber"

This is a logger implementation that supports multiple log levels, multiple output destinations with configurable formats and levels for each. It also supports granular output configuration to get more detailed logging for specific files/packages. Timber includes support for standard XML or JSON config files to get you started quickly. It's also easy to configure in code if you want to DIY.

Basic use:

import "timber"
timber.LoadConfiguration("timber.xml")
timber.Debug("Debug message!")

IMPORTANT: timber has not default destination configured so log messages will be dropped until a destination is configured

It can be used as a drop-in replacement for the standard logger by changing the log import statement from:

import "log"

to

import log "timber"

It can also be used as the output of the standard logger with

log.SetFlags(0)
log.SetOutput(timber.Global)

Configuration in code is also simple:

timber.AddLogger(timber.ConfigLogger{
	LogWriter: new(timber.ConsoleWriter),
	Level:     timber.DEBUG,
	Formatter: timber.NewPatFormatter("[%D %T] [%L] %S %M"),
})

XML Config file:

<logging>
  <filter enabled="true">
	<tag>stdout</tag>
	<type>console</type>
	<!-- level is (:?FINEST|FINE|DEBUG|TRACE|INFO|WARNING|ERROR) -->
	<level>DEBUG</level>
  </filter>
  <filter enabled="true">
	<tag>file</tag>
	<type>file</type>
	<level>FINEST</level>
	<granular>
	  <level>INFO</level>
	  <path>path/to/package.FunctionName</path>
	</granular>
	<granular>
	  <level>WARNING</level>
	  <path>path/to/package</path>
	</granular>
	<property name="filename">log/server.log</property>
	<property name="format">server [%D %T] [%L] %M</property>
  </filter>
  <filter enabled="false">
	<tag>syslog</tag>
	<type>socket</type>
	<level>FINEST</level>
	<property name="protocol">unixgram</property>
	<property name="endpoint">/dev/log</property>
    <format name="pattern">%L %M</property>
  </filter>
</logging>

The <tag> is ignored.

To configure the pattern formatter all filters accept:

<format name="pattern">[%D %T] %L %M</format>

Pattern format specifiers (not the same as log4go!):

%T - Time: 17:24:05.333 HH:MM:SS.ms
%t - Time: 17:24:05 HH:MM:SS
%D - Date: 2011-12-25 yyyy-mm-dd
%d - Date: 2011/12/25 yyyy/mm/dd
%L - Level (FNST, FINE, DEBG, TRAC, WARN, EROR, CRIT)
%S - Source: full runtime.Caller line and line number
%s - Short Source: just file and line number
%x - Extra Short Source: just file without .go suffix
%M - Message
%% - Percent sign
%P - Caller Path: packagePath.CallingFunctionName
%p - Caller Path: packagePath

the string number prefixes are allowed e.g.: %10s will pad the source field to 10 spaces pattern defaults to %M Both log4go synatax of <property name="format"> and new <format name=type> are supported the property syntax will only ever support the pattern formatter To configure granulars:

- Create one or many <granular> within a filter
- Define a <level> and <path> within, where path can be path to package or path to
  package.FunctionName. Function name definitions override package paths.

Code Architecture: A MultiLogger <logging> which consists of many ConfigLoggers <filter>. ConfigLoggers have three properties: LogWriter <type>, Level (as a threshold) <level> and LogFormatter <format>.

In practice, this means that you define ConfigLoggers with a LogWriter (where the log prints to eg. socket, file, stdio etc), the Level threshold, and a LogFormatter which formats the message before writing. Because the LogFormatters and LogWriters are simple interfaces, it is easy to write your own custom implementations.

Once configured, you only deal with the "Logger" interface and use the log methods in your code

The motivation for this package grew from a need to make some changes to the functionality of log4go (which had already been integrated into a larger project). I tried to maintain compatiblity with log4go for the interface and configuration. The main issue I had with log4go was that each of logger types had incisistent and incompatible configuration. I looked at contributing changes to log4go, but I would have needed to break existing use cases so I decided to do a rewrite from scratch.

Index

Package Files

buffered_writer.go config.go config_json.go config_xml.go console_writer.go file_writer.go pattern_formatter.go socket_writer.go syslog_formatter.go timber.go

Constants

const DefaultFileDepth int = 3

Default level passed to runtime.Caller by Timber, add to this if you wrap Timber in your own logging code

Variables

var DefaultSeverityMap = map[Level]syslog.Priority{
    NONE:     syslog.LOG_INFO,
    FINEST:   syslog.LOG_DEBUG,
    FINE:     syslog.LOG_DEBUG,
    DEBUG:    syslog.LOG_DEBUG,
    TRACE:    syslog.LOG_INFO,
    INFO:     syslog.LOG_INFO,
    WARNING:  syslog.LOG_WARNING,
    ERROR:    syslog.LOG_ERR,
    CRITICAL: syslog.LOG_CRIT,
}

Mapping from the timber levels to the syslog severity If you override this, make sure all the entries are in the map since the syslog.Priority zero value will cause a message at the Emergency severity

var Global = NewTimber()

Default Timber Instance (used for all the package level function calls)

var LevelStrings = [...]string{"", "FNST", "FINE", "DEBG", "TRAC", "INFO", "WARN", "EROR", "CRIT"}

What gets printed for each Log level

var LongLevelStrings = []string{
    "NONE",
    "FINEST",
    "FINE",
    "DEBUG",
    "TRACE",
    "INFO",
    "WARNING",
    "ERROR",
    "CRITICAL",
}

Full level names

func AddLogger Uses

func AddLogger(logger ConfigLogger) int

func Close Uses

func Close()

func Critical Uses

func Critical(arg0 interface{}, args ...interface{}) error

func Debug Uses

func Debug(arg0 interface{}, args ...interface{})

func Error Uses

func Error(arg0 interface{}, args ...interface{}) error

func Fatal Uses

func Fatal(v ...interface{})

func Fatalf Uses

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

func Fatalln Uses

func Fatalln(v ...interface{})

func Fine Uses

func Fine(arg0 interface{}, args ...interface{})

func Finest Uses

func Finest(arg0 interface{}, args ...interface{})

Simple wrappers for Logger interface

func Info Uses

func Info(arg0 interface{}, args ...interface{})

func LoadConfiguration Uses

func LoadConfiguration(filename string)

func LoadJSONConfiguration Uses

func LoadJSONConfiguration(filename string)

func LoadXMLConfiguration Uses

func LoadXMLConfiguration(filename string)

func Log Uses

func Log(lvl Level, arg0 interface{}, args ...interface{})

func Panic Uses

func Panic(v ...interface{})

func Panicf Uses

func Panicf(format string, v ...interface{})

func Panicln Uses

func Panicln(v ...interface{})

func Print Uses

func Print(v ...interface{})

func Printf Uses

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

func Println Uses

func Println(v ...interface{})

func Trace Uses

func Trace(arg0 interface{}, args ...interface{})

func Warn Uses

func Warn(arg0 interface{}, args ...interface{}) error

type BufferedWriter Uses

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

Use this of you need some buffering, or not

func NewBufferedWriter Uses

func NewBufferedWriter(writer io.WriteCloser) (*BufferedWriter, error)

func (*BufferedWriter) Close Uses

func (bw *BufferedWriter) Close()

func (*BufferedWriter) Flush Uses

func (bw *BufferedWriter) Flush() error

Force flush the buffer

func (*BufferedWriter) LogWrite Uses

func (bw *BufferedWriter) LogWrite(msg string)

type ConfigLogger Uses

type ConfigLogger struct {
    LogWriter LogWriter
    // Messages with level < Level will be ignored.  It's up to the implementor to keep the contract or not
    Level     Level
    Formatter LogFormatter
    Granulars map[string]Level
}

Container a single log format/destination

type ConsoleWriter Uses

type ConsoleWriter func(string)

This uses the standard go logger to write the messages

func (ConsoleWriter) Close Uses

func (c ConsoleWriter) Close()

func (ConsoleWriter) LogWrite Uses

func (c ConsoleWriter) LogWrite(msg string)

type FileWriter Uses

type FileWriter struct {
    BaseFilename string

    RotateChan chan string // defaults to nil.  receives previous filename on rotate
    RotateSize int64       // rotate after RotateSize bytes have been written to the file
    // contains filtered or unexported fields
}

func NewFileWriter Uses

func NewFileWriter(name string) (*FileWriter, error)

This writer has a buffer that I don't ever bother to flush, so it may take a while to see messages. Filenames ending in .gz will automatically be compressed on write. Filename string is proccessed through the template library using the FilenameFields struct.

func (*FileWriter) Close Uses

func (w *FileWriter) Close()

func (*FileWriter) Flush Uses

func (w *FileWriter) Flush() error

func (*FileWriter) LogWrite Uses

func (w *FileWriter) LogWrite(m string)

func (*FileWriter) Rotate Uses

func (w *FileWriter) Rotate() error

Close and re-open the file. You should use the timestamp in the filename if you're going to use rotation

func (*FileWriter) RotateEvery Uses

func (w *FileWriter) RotateEvery(d time.Duration)

Automatically rotate every `d`

type FilenameFields Uses

type FilenameFields struct {
    Hostname string
    Date     time.Time
    Pid      int
    Random   int64
}

func GetFilenameFields Uses

func GetFilenameFields() *FilenameFields

type JSONConfig Uses

type JSONConfig struct {
    Filters []JSONFilter
}

type JSONFilter Uses

type JSONFilter struct {
    Enabled    bool
    Tag        string
    Type       string
    Level      string
    Format     JSONProperty
    Properties []JSONProperty
    Granulars  []JSONGranular
}

type JSONGranular Uses

type JSONGranular struct {
    Level string `xml:"level"`
    Path  string `xml:"path"`
}

Granulars are overriding levels that can be either package paths or package path + function name

type JSONProperty Uses

type JSONProperty struct {
    Name  string `xml:"name"`
    Value string `xml:"value"`
}

type Level Uses

type Level int
const (
    NONE Level = iota // NONE to be used for standard go log impl's
    FINEST
    FINE
    DEBUG
    TRACE
    INFO
    WARNING
    ERROR
    CRITICAL
)

Log levels

type LogFormatter Uses

type LogFormatter interface {
    Format(rec *LogRecord) string
}

Format a log message before writing

type LogRecord Uses

type LogRecord struct {
    Level       Level
    Timestamp   time.Time
    SourceFile  string
    SourceLine  int
    Message     string
    FuncPath    string
    PackagePath string
}

This packs up all the message data and metadata. This structure will be passed to the LogFormatter

type LogWriter Uses

type LogWriter interface {
    LogWrite(msg string)
    Close()
}

Interface required for a log writer endpoint. It's more or less a io.WriteCloser with no errors allowed to be returned and string instead of []byte.

TODO: Maybe this should just be a standard io.WriteCloser?

type Logger Uses

type Logger interface {
    // match log4go interface to drop-in replace
    Finest(arg0 interface{}, args ...interface{})
    Fine(arg0 interface{}, args ...interface{})
    Debug(arg0 interface{}, args ...interface{})
    Trace(arg0 interface{}, args ...interface{})
    Info(arg0 interface{}, args ...interface{})
    Warn(arg0 interface{}, args ...interface{}) error
    Error(arg0 interface{}, args ...interface{}) error
    Critical(arg0 interface{}, args ...interface{}) error
    Log(lvl Level, arg0 interface{}, args ...interface{})

    // support standard log too
    Print(v ...interface{})
    Printf(format string, v ...interface{})
    Println(v ...interface{})
    Panic(v ...interface{})
    Panicf(format string, v ...interface{})
    Panicln(v ...interface{})
    Fatal(v ...interface{})
    Fatalf(format string, v ...interface{})
    Fatalln(v ...interface{})
}

This explicitly defines the contract for a logger Not really useful except for documentation for writing an separate implementation

type LoggerConfig Uses

type LoggerConfig interface {
    // When set, messages with level < lvl will be ignored.  It's up to the implementor to keep the contract or not
    SetLevel(lvl Level)
    // Set the formatter for the log
    SetFormatter(formatter LogFormatter)
}

Not used

type MultiLogger Uses

type MultiLogger interface {
    // returns an int that identifies the logger for future calls to SetLevel and SetFormatter
    AddLogger(logger ConfigLogger) int
    // dynamically change level or format
    SetLevel(index int, lvl Level)
    SetFormatter(index int, formatter LogFormatter)
    Close()
}

Allow logging to multiple places

type PatFormatter Uses

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

func NewPatFormatter Uses

func NewPatFormatter(format string) *PatFormatter

Format codes:

  %T - Time: 17:24:05.333 HH:MM:SS.ms
  %t - Time: 17:24:05 HH:MM:SS
  %D - Date: 2011-12-25 yyyy-mm-dd
  %d - Date: 2011/12/25
  %L - Level (FNST, FINE, DEBG, TRAC, WARN, EROR, CRIT)
  %S - Source: full runtime.Caller line
  %s - Short Source: just file and line number
  %x - Extra Short Source: just file without .go suffix
  %M - Message
  %% - Percent sign
	 %P - Caller Path: package path + calling function name
	 %p - Caller Path: package path

the string number prefixes are allowed e.g.: %10s will pad the source field to 10 spaces

func (*PatFormatter) Format Uses

func (pf *PatFormatter) Format(rec *LogRecord) string

LogFormatter interface

type SocketWriter Uses

type SocketWriter struct {
    Timeout time.Duration
    // contains filtered or unexported fields
}

This should write to anything that you can write to with net.Dial

func NewSocketWriter Uses

func NewSocketWriter(network, addr string) (*SocketWriter, error)

func (*SocketWriter) Close Uses

func (sw *SocketWriter) Close()

func (*SocketWriter) LogWrite Uses

func (sw *SocketWriter) LogWrite(msg string)

type SyslogFormatter Uses

type SyslogFormatter struct {
    Hostname    string
    Tag         string
    Facility    syslog.Priority
    SeverityMap map[Level]syslog.Priority
    // contains filtered or unexported fields
}

Syslog formatter wraps a PatFormatter but adds the syslog protocol format to the message. Defaults: Facility: syslog.LOG_USER (1 << 3 for pre-go1.1 compatibility) Hostname: os.Hostname() Tag: os.Args[0]

func NewSyslogFormatter Uses

func NewSyslogFormatter(format string) *SyslogFormatter

func (*SyslogFormatter) Format Uses

func (sf *SyslogFormatter) Format(rec *LogRecord) string

type Timber Uses

type Timber struct {

    // This value is passed to runtime.Caller to get the file name/line and may require
    // tweaking if you want to wrap the logger
    FileDepth int
    // contains filtered or unexported fields
}

The Timber instance is the concrete implementation of the logger interfaces. New instances may be created, but usually you'll just want to use the default instance in Global

NOTE: I don't supporting the log4go special handling of the first parameter based on type mainly cuz I don't think it's particularly useful (I kept passing a data string as the first param and expecting a Println-like output but that would always break expecting a format string) I also don't support the passing of the closure stuff

func NewTimber Uses

func NewTimber() *Timber

Creates a new Timber logger that is ready to be configured With no subsequent configuration, nothing will be logged

func (*Timber) AddLogger Uses

func (t *Timber) AddLogger(logger ConfigLogger) int

MultiLogger interface

func (*Timber) Close Uses

func (t *Timber) Close()

MultiLogger interface

func (*Timber) Critical Uses

func (t *Timber) Critical(arg0 interface{}, args ...interface{}) error

func (*Timber) Debug Uses

func (t *Timber) Debug(arg0 interface{}, args ...interface{})

func (*Timber) Error Uses

func (t *Timber) Error(arg0 interface{}, args ...interface{}) error

func (*Timber) Fatal Uses

func (t *Timber) Fatal(v ...interface{})

func (*Timber) Fatalf Uses

func (t *Timber) Fatalf(format string, v ...interface{})

func (*Timber) Fatalln Uses

func (t *Timber) Fatalln(v ...interface{})

func (*Timber) Fine Uses

func (t *Timber) Fine(arg0 interface{}, args ...interface{})

func (*Timber) Finest Uses

func (t *Timber) Finest(arg0 interface{}, args ...interface{})

func (*Timber) Info Uses

func (t *Timber) Info(arg0 interface{}, args ...interface{})

func (*Timber) LoadConfig Uses

func (t *Timber) LoadConfig(filename string)

func (*Timber) LoadJSONConfig Uses

func (t *Timber) LoadJSONConfig(filename string) error

Loads the configuration from an JSON file (as you were probably expecting)

func (*Timber) LoadXMLConfig Uses

func (t *Timber) LoadXMLConfig(filename string) error

Loads the configuration from an XML file (as you were probably expecting)

func (*Timber) Log Uses

func (t *Timber) Log(lvl Level, arg0 interface{}, args ...interface{})

func (*Timber) Panic Uses

func (t *Timber) Panic(v ...interface{})

func (*Timber) Panicf Uses

func (t *Timber) Panicf(format string, v ...interface{})

func (*Timber) Panicln Uses

func (t *Timber) Panicln(v ...interface{})

func (*Timber) Print Uses

func (t *Timber) Print(v ...interface{})

Print won't work well with a pattern_logger because it explicitly adds its own \n; so you'd have to write your own formatter to remove it

func (*Timber) Printf Uses

func (t *Timber) Printf(format string, v ...interface{})

func (*Timber) Println Uses

func (t *Timber) Println(v ...interface{})

Println won't work well either with a pattern_logger because it explicitly adds its own \n; so you'd have to write your own formatter to not have 2 \n's

func (*Timber) SetFormatter Uses

func (t *Timber) SetFormatter(index int, formatter LogFormatter)

Not yet implemented

func (*Timber) SetLevel Uses

func (t *Timber) SetLevel(index int, lvl Level)

Not yet implemented

func (*Timber) Trace Uses

func (t *Timber) Trace(arg0 interface{}, args ...interface{})

func (*Timber) Warn Uses

func (t *Timber) Warn(arg0 interface{}, args ...interface{}) error

func (*Timber) Write Uses

func (t *Timber) Write(p []byte) (n int, err error)

This function allows a Timber instance to be used in the standard library log.SetOutput(). It is not a general Writer interface and assumes one message per call to Write. All messages are send at level INFO

type XMLConfig Uses

type XMLConfig struct {
    XMLName xml.Name    `xml:"logging"`
    Filters []XMLFilter `xml:"filter"`
}

type XMLFilter Uses

type XMLFilter struct {
    XMLName    xml.Name      `xml:"filter"`
    Enabled    bool          `xml:"enabled,attr"`
    Tag        string        `xml:"tag"`
    Type       string        `xml:"type"`
    Level      string        `xml:"level"`
    Format     XMLProperty   `xml:"format"`
    Properties []XMLProperty `xml:"property"`
    Granulars  []XMLGranular `xml:"granular"`
}

type XMLGranular Uses

type XMLGranular struct {
    Level string `xml:"level"`
    Path  string `xml:"path"`
}

Granulars are overriding levels that can be either package paths or package path + function name

type XMLProperty Uses

type XMLProperty struct {
    Name  string `xml:"name,attr"`
    Value string `xml:",chardata"`
}

match the log4go structure so i don't have to change my configs

Package timber imports 21 packages (graph) and is imported by 7 packages. Updated 2016-07-23. Refresh now. Tools for package owners.