logtic

package module
v1.9.4 Latest Latest
Warning

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

Go to latest
Published: Sep 12, 2023 License: MIT Imports: 12 Imported by: 25

README

[!IMPORTANT]
Following Go 1.21 and the introduction of the log/slog package, new projects should prefer to use that over logtic. This package will continue to be supported in terms of bugfixes and security fixes only. No new functionality will be added.

logtic

Go Report Card Godoc Releases LICENSE

Logtic is a yet another logging library for golang projects.

The goal of logtic is to be as transparent and easy to use as possible, allowing applications and libraries to seamlessly log to a single file. Logtic can be used in libraries and won't cause any problems if the parent application isn't using logtic.

Logtic supports multiple sources, which annotate the outputted log lines. It also supports defining a minimum desired log level, which can be changed at any time. Events printed to the terminal output support color-coded severities.

Events can be printed as formatted strings, like with fmt.Printf, or can be parameterized events which can be easily parsed by log analysis tools such as Splunk.

By default, logtic will only print to stdout and stderr, but when configured it can also write to a log file. Log files include the date-time for each event in RFC-3339 format.

Logtic provides a default logging instance but also supports unique instances that can operate in parallel, writing to unique files and having unique settings.

Log files can be rotated using the provided rotate method.

Logtic is optimized for Linux & Unix environments but offers limited support for Windows.

Usage & Examples

For more examples please refer to the official documentation

Basic Log File

var log *logtic.Source

func init() {
    logtic.Log.FilePath = "./app.log"
    logtic.Log.Level = logtic.LevelInfo
}

func main() {
    if err := logtic.Open(); err != nil {
        // There was an error opening the log file for writing
        panic(err)
    }
    log = logtic.Connect("MyApp")
    log.Info("This is an %s message", "informational")
    defer logtic.Close()
}

Console-Only (No Log File)

var log *logtic.Source

func main() {
    // By default, calling logtic.Open without changing anything
    // will open a console-only log file
    logtic.Open()
    log = logtic.Connect("MyApp")
    log.Info("This is an %s message", "informational")
}

Writing Events

Logtic uses "sources", which can be thought of like Classes in traditional OOP. Log entries are annotated with the name.

For example, if you have two unique goroutines that you want to easily identify in logs, you can give each routine a source with a unique name.

log := logtic.Connect("MyCoolApplication")
log.Info("Print something %s", "COOL!")
// Output: [INFO][MyCoolApplication] Print something COOL!

Documentation

Overview

Package logtic is a yet another logging library for golang projects.

Important: Following Go 1.21 and the introduction of the log/slog package, new projects should prefer to use that over logtic. This package will continue to be supported in terms of bugfixes and security fixes only. No new functionality will be added.

The goal of logtic is to be as transparent and easy to use as possible, allowing applications and libraries to seamlessly log to a single file. Logtic can be used in libraries and won't cause any problems if the parent application isn't using logtic.

Logtic supports multiple sources, which annotate the outputted log lines. It also supports defining a minimum desired log level, which can be changed at any time. Events printed to the terminal output support color-coded severities.

Events can be printed as formatted strings, like with `fmt.Printf`, or can be parameterized events which can be easily parsed by log analysis tools such as Splunk.

By default, logtic will only print to stdout and stderr, but when configured it can also write to a log file. Log files include the date-time for each event in RFC-3339 format.

Logtic provides a default logging instance but also supports unique instances that can operate in parallel, writing to unique files and having unique settings.

Log files can be rotated using the provided rotate method.

Logtic is optimized for Linux & Unix environments but offers limited support for Windows.

Example

Common setup for file-based logging

package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	// Set the log file path and default log level (if desired)
	logtic.Log.FilePath = "./file.log"
	logtic.Log.Level = logtic.LevelInfo

	if err := logtic.Log.Open(); err != nil {
		// There was an error opening the log file for writing
		panic(err)
	}

	log := logtic.Log.Connect("MyApp")
	log.Warn("Print something %s", "COOL!")

	// Don't forget to close the log file when your application exits
	logtic.Log.Close()
}
Output:

Index

Examples

Constants

View Source
const (
	// LevelDebug debug messages for troubleshooting application behaviour
	LevelDebug = 3
	// LevelInfo informational messages for normal operation of the application
	LevelInfo = 2
	// LevelWarn warning messages for potential issues
	LevelWarn = 1
	// LevelError error messages for problems
	LevelError = 0
)

Variables

View Source
var Log = New()

Log is the default logging instance.

Functions

func FormatBytesB added in v1.6.0

func FormatBytesB(b uint64) string

FormatBytesB takes in a number of bytes and returns a human readable string with binary units (up-to Exbibyte)

Example
package main

import (
	"fmt"

	"github.com/ecnepsnai/logtic"
)

func main() {
	fmt.Println(logtic.FormatBytesB(10485760))
}
Output:

10.0 MiB

func FormatBytesD added in v1.6.0

func FormatBytesD(b uint64) string

FormatBytesB takes in a number of bytes and returns a human readable string with decimal units (up-to Exabyte)

Example
package main

import (
	"fmt"

	"github.com/ecnepsnai/logtic"
)

func main() {
	fmt.Println(logtic.FormatBytesD(10000000))
}
Output:

10.0 MB

func StringFromParameters added in v1.6.0

func StringFromParameters(parameters map[string]interface{}) string

StringFromParameters return a key=value string for the given parameters. Depending on the type of the parameter value, it may be wrapped in single quotes. Byte slices are represented as hexadecimal strings. Parameters are always alphabetically sorted in the outputted string.

Example
package main

import (
	"fmt"
	"time"

	"github.com/ecnepsnai/logtic"
)

func main() {
	fmt.Println(logtic.StringFromParameters(map[string]interface{}{
		"hello":            "world!",
		"meaning_of_life":  42,
		"pie":              3.12,
		"does_golang_rock": true,
		"secret_sauce":     []byte("mayo ketchup sriracha"),
		"unix_epoch":       time.Unix(0, 0).UTC(),
		"prime_numbers":    []int{2, 3, 5, 7, 11},
	}))
}
Output:

does_golang_rock='true' hello='world!' meaning_of_life=42 pie=3.120000 prime_numbers='[2 3 5 7 11]' secret_sauce=6d61796f206b657463687570207372697261636861 unix_epoch='1970-01-01T00:00:00Z'

Types

type Logger added in v1.7.0

type Logger struct {
	// The path to the log file.
	FilePath string
	// The minimum level of events captured in the log file and printed to console. Inclusive.
	Level int
	// The file mode (permissions) used for the log file and rotated log files.
	FileMode os.FileMode
	// Options various options for this logger
	Options LoggerOptions
	// Stdout the writer to use for standard output. Defaults to the system stdout.
	Stdout io.Writer
	// Stdout the writer to use for standard error. Defaults to the system stderr.
	Stderr io.Writer
	// contains filtered or unexported fields
}

Logger describes a logging instance

func New added in v1.7.0

func New() *Logger

New will create a new logging instance with all default options. You should only use new if you want a separate logging instance from the default instance, which is automatically created for you.

func (*Logger) Close added in v1.7.0

func (l *Logger) Close()

Close will flush and close this logging instance.

func (*Logger) Connect added in v1.7.0

func (l *Logger) Connect(sourceName string) *Source

Connect will prepare a new logtic source with the given name for this logging instance. Sources can be written even if there is no open logtic log instance.

Example

This example shows how to connect a new source to a logtic instance

package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	// You can connect to logtic before a log file has been opened
	// however, any events will not be captured until logtic.Log.Open()
	// has been called
	source1 := logtic.Log.Connect("Source1")
	source2 := logtic.Log.Connect("Source2")

	source1.Warn("Important warning")
	source2.Error("Something went wrong")
}
Output:

func (*Logger) Open added in v1.7.0

func (l *Logger) Open() error

Open will open the file specified by FilePath on this logging instance. The file will be created if it does not already exist, otherwise it will be appended to.

Example

This example shows how to set up a unique logging instance, separate form the default instance

package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	logger := logtic.New()

	// You must tell logtic where the log file is
	// before any events will be captured
	logger.FilePath = "./file.log"
	// The default level is Error, you can change that at any time
	logger.Level = logtic.LevelInfo

	if err := logger.Open(); err != nil {
		// There was an error opening the log file for writing
		panic(err)
	}
}
Output:

Example (WithoutFile)

This example shows how to prepare logtic to only print to the console, without writing to a log file

package main

import (
	"os"

	"github.com/ecnepsnai/logtic"
)

func main() {
	logger := logtic.New()

	// You don't have to specify os.DevNull, however it is good pratice to be explicit that it is
	// not being written to any file
	logger.FilePath = os.DevNull
	// The default level is Error, you can change that at any time
	logger.Level = logtic.LevelInfo

	if err := logger.Open(); err != nil {
		// You probably should panic here, or exit the app
		// as failing to open a file to DevNull is a bad sign
		panic(err)
	}
}
Output:

func (*Logger) Reset added in v1.7.0

func (l *Logger) Reset()

Reset will reset this logging instance to its original state. Open files will be closed.

func (*Logger) Rotate added in v1.7.0

func (l *Logger) Rotate() error

Rotate will rotate the log file of this logging instance. The current log file will be renamed and suffixed with the current date in a YYYY-MM-DD format. A new log file will be opened with the original file path and used for all subsequent writes. Writes will be blocked while the rotation is in progress. If a file matching the name of what would be used for the rotated file, a numerical suffix is added to the end of the name.

If an error is returned during rotation it is highly recommended that you either panic or call logger.Reset() as logtic may be in an undefined state and log calls may cause panics.

Example

This example shows how to trigger a log file rotation

package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	logtic.Log.FilePath = "/path/to/log/file.log"

	if err := logtic.Log.Open(); err != nil {
		panic(err)
	}

	if err := logtic.Log.Rotate(); err != nil {
		// There was an error rotating the log
		// It's recommended that you panic or exit here, as logtic is now in an undefined state
		panic(err)
	}
}
Output:

type LoggerOptions added in v1.8.0

type LoggerOptions struct {
	// Should logtic not use color when printing events to stdout/stderr. Enabled by default.
	Color bool
	// Should logtic escape control characters automatically. For example, replaces actual newlines with a literal \n.
	// Enabled by default.
	EscapeCharacters bool
	// Should logtic automatically gzip log files after rotation. Disabled by default.
	GZipRotatedLogs bool
}

LoggerOptions describe logger options

type Source

type Source struct {
	Name  string
	Level int
	// contains filtered or unexported fields
}

Source describes a source for log events

func (*Source) Debug

func (s *Source) Debug(format string, a ...interface{})

Debug will log a debug formatted message.

Example
package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	log := logtic.Log.Connect("Example")
	log.Debug("This is a %s message", "debug")
	// Terminal output: [DEBUG][Example] This is a debug message
	// File output: 2021-03-15T21:43:34-07:00 [DEBUG][Example] This is a debug message
}
Output:

func (*Source) Error

func (s *Source) Error(format string, a ...interface{})

Error will log an error formatted message. Errors are printed to stderr.

Example
package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	log := logtic.Log.Connect("Example")
	log.Error("This is a %s message", "error")
	// Terminal output: [ERROR][Example] This is a error message
	// File output: 2021-03-15T21:43:34-07:00 [ERROR][Example] This is a error message
}
Output:

func (*Source) Fatal

func (s *Source) Fatal(format string, a ...interface{})

Fatal will log a fatal formatted error message and exit the application with status 1. Fatal messages are printed to stderr.

Example
package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	log := logtic.Log.Connect("Example")
	log.Fatal("This is a %s message", "fatal")
	// Terminal output: [FATAL][Example] This is a fatal message
	// File output: 2021-03-15T21:43:34-07:00 [FATAL][Example] This is a fatal message
}
Output:

func (*Source) GoLogger added in v1.9.2

func (s *Source) GoLogger(level int) *log.Logger

GoLogger returns a logger that acts as a proxy between the go/log package and logtic. Printf events sent to this logger will be forwarded to this source with the given level.

func (*Source) Info

func (s *Source) Info(format string, a ...interface{})

Info will log an informational formatted message.

Example
package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	log := logtic.Log.Connect("Example")
	log.Info("This is a %s message", "info")
	// Terminal output: [INFO][Example] This is a info message
	// File output: 2021-03-15T21:43:34-07:00 [INFO][Example] This is a info message
}
Output:

func (*Source) PDebug added in v1.6.0

func (s *Source) PDebug(event string, parameters map[string]interface{})

PDebug will log a debug parameterized message. Parameterized messages are formatted as key=value strings. Depending on the type of the parameter value, it may be wrapped in single quotes. Byte slices are represented as hexadecimal strings. Parameters are always alphabetically sorted in the outputted string.

Example
package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	log := logtic.Log.Connect("Example")
	log.PDebug("Debug event", map[string]interface{}{
		"param1": "string",
		"param2": 123,
	})
	// Terminal output: [DEBUG][Example] Debug event: param1='string' param2=123
	// File output: 2021-03-15T21:43:34-07:00 [DEBUG][Example] Debug event: param1='string' param2=123
}
Output:

func (*Source) PError added in v1.6.0

func (s *Source) PError(event string, parameters map[string]interface{})

PError will log an error parameterized message. Errors are printed to stderr. Parameterized messages are formatted as key=value strings. Depending on the type of the parameter value, it may be wrapped in single quotes. Byte slices are represented as hexadecimal strings. Parameters are always alphabetically sorted in the outputted string.

Example
package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	log := logtic.Log.Connect("Example")
	log.PError("Error event", map[string]interface{}{
		"param1": "string",
		"param2": 123,
	})
	// Terminal output: [ERROR][Example] Error event: param1='string' param2=123
	// File output: 2021-03-15T21:43:34-07:00 [ERROR][Example] Error event: param1='string' param2=123
}
Output:

func (*Source) PFatal added in v1.6.0

func (s *Source) PFatal(event string, parameters map[string]interface{})

PFatal will log a fatal parameterized error message and exit the application with status 1. Fatal messages are printed to stderr. Parameterized messages are formatted as key=value strings. Depending on the type of the parameter value, it may be wrapped in single quotes. Byte slices are represented as hexadecimal strings. Parameters are always alphabetically sorted in the outputted string.

Example
package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	log := logtic.Log.Connect("Example")
	log.PFatal("Fatal event", map[string]interface{}{
		"param1": "string",
		"param2": 123,
	})
	// Terminal output: [FATAL][Example] Fatal event: param1='string' param2=123
	// File output: 2021-03-15T21:43:34-07:00 [FATAL][Example] Fatal event: param1='string' param2=123
}
Output:

func (*Source) PInfo added in v1.6.0

func (s *Source) PInfo(event string, parameters map[string]interface{})

PInfo will log an informational parameterized message. Parameterized messages are formatted as key=value strings. Depending on the type of the parameter value, it may be wrapped in single quotes. Byte slices are represented as hexadecimal strings. Parameters are always alphabetically sorted in the outputted string.

Example
package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	log := logtic.Log.Connect("Example")
	log.PInfo("Info event", map[string]interface{}{
		"param1": "string",
		"param2": 123,
	})
	// Terminal output: [INFO][Example] Info event: param1='string' param2=123
	// File output: 2021-03-15T21:43:34-07:00 [INFO][Example] Info event: param1='string' param2=123
}
Output:

func (*Source) PPanic added in v1.6.0

func (s *Source) PPanic(event string, parameters map[string]interface{})

PPanic functions like source.PFatal() but panics rather than exits. Parameterized messages are formatted as key=value strings. Depending on the type of the parameter value, it may be wrapped in single quotes. Byte slices are represented as hexadecimal strings. Parameters are always alphabetically sorted in the outputted string.

Example
package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	log := logtic.Log.Connect("Example")
	log.PPanic("Panic event", map[string]interface{}{
		"param1": "string",
		"param2": 123,
	})
	// Terminal output: [FATAL][Example] Panic event: param1='string' param2=123
	// File output: 2021-03-15T21:43:34-07:00 [FATAL][Example] Panic event: param1='string' param2=123
}
Output:

func (*Source) PWarn added in v1.6.0

func (s *Source) PWarn(event string, parameters map[string]interface{})

PWarn will log a warning parameterized message. Parameterized messages are formatted as key=value strings. Depending on the type of the parameter value, it may be wrapped in single quotes. Byte slices are represented as hexadecimal strings. Parameters are always alphabetically sorted in the outputted string.

Example
package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	log := logtic.Log.Connect("Example")
	log.PWarn("Warning event", map[string]interface{}{
		"param1": "string",
		"param2": 123,
	})
	// Terminal output: [WARN][Example] Warning event: param1='string' param2=123
	// File output: 2021-03-15T21:43:34-07:00 [WARN][Example] Warning event: param1='string' param2=123
}
Output:

func (*Source) PWrite added in v1.6.0

func (s *Source) PWrite(level int, event string, parameters map[string]interface{})

PWrite will call the matching write function for the given level, printing the provided message. For example:

source.PWrite(logtic.LevelDebug, "My Event", map[string]interface{}{"key": "value"})

is the same as:

source.PDebug("My Event", map[string]interface{}{"key": "value"})

func (*Source) Panic

func (s *Source) Panic(format string, a ...interface{})

Panic functions like source.Fatal() but panics rather than exits.

Example
package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	log := logtic.Log.Connect("Example")
	log.Panic("This is a %s message", "fatal")
	// Terminal output: [FATAL][Example] This is a fatal message
	// File output: 2021-03-15T21:43:34-07:00 [FATAL][Example] This is a fatal message
}
Output:

func (*Source) Warn

func (s *Source) Warn(format string, a ...interface{})

Warn will log a warning formatted message.

Example
package main

import (
	"github.com/ecnepsnai/logtic"
)

func main() {
	log := logtic.Log.Connect("Example")
	log.Warn("This is a %s message", "warning")
	// Terminal output: [WARN][Example] This is a warning message
	// File output: 2021-03-15T21:43:34-07:00 [WARN][Example] This is a warning message
}
Output:

func (*Source) Write added in v1.4.1

func (s *Source) Write(level int, format string, a ...interface{})

Write will call the matching write function for the given level, printing the provided message. For example:

source.Write(logtic.LevelDebug, "Hello world")

is the same as:

source.Debug("Hello world")

Jump to

Keyboard shortcuts

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