log

package module
v1.5.1 Latest Latest
Warning

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

Go to latest
Published: Jan 7, 2025 License: MIT Imports: 13 Imported by: 0

README

go-parkhub-logger

This package provides a singular interface to create logs as well as filtering them out based on level. It also provides two types of formatting json, pretty. This logger doesn't ship any logs.

Features

The logger mimics the log package's Println, Printf, Fatalln and Fatalf functions with some extra features. Like the log package, all log functions will end with a new line.

- [X] Log levels
- [X] JSON formatted output
- [X] Tags
- [X] Colorized output
- [X] Exact timestamps
- [X] File and line numbers
- [X] Attach data to logs

Installing

Add this package to your project's mod file.

$ go get github.com/parkhub/go-parkhub-logger

Setup

The package contains a couple of setup convenience methods for local and cloud development.

Local Logging

Call SetupLocalLogger to setup local logging with the desired log level.

log.SetupLocalLogger(LogLevelDebug)

Local logging contains pretty output, colorized output and no tags. The local logger outputs logs like the following:

Local Logs

Cloud Logging

Call SetupCloudLogger to set up cloud logging with the desired log level and tags.

log.SetupCloudLogger(LogLevelInfo, []string{"test", "tags"})

Cloud logging contains JSON output, non-colorized output and tags. The cloud logger outputs logs like the following:

Local Logs

Custom Logging

Call SetupLogger to specify your own properties.

// Setup the logger with
// - Debug log level
// - Pretty output
// - Non-colorized output
// - File and line numbers
// - Use the tags "live" and "analytics"
SetupLogger(LogLevelDebug, LogFormatPretty, false, true, []string{"live", "analytics"})

Printing Data

Along with the usual "ln" and "f" print functions, the logger includes functions for attaching data to a log using the Debugd, Infod, etc. functions.

The following:

type testStruct struct {
	Name string
	Kind string
}

test := &testStruct{
	Name: "Logan",
	Kind: "Log",
}

log.Warnd("Unable to consume object data.", test)

Produces the output:

2021-02-27T18:08:48-74:94 [WARN] Unable to consume object data. &{Name:Logan Kind:Log}

Example

package main

import (
	log "github.com/parkhub/go-parkhub-logger"
)

func main() {
	// Setup the logger
	if os.Getenv("LOGGING") == "local" {
		log.SetupLocalLogger(log.LogLevelDebug)
	} else {
		log.SetupCloudLogger(log.LogLevelInfo, []string{"test", "tags"})
	}

	// Print info statement
	log.Infoln("This is an info statement.")

	// Print info statement with data
	type testStruct struct {
		Name string
		Kind string
	}

	test := &testStruct{
		Name: "Logan",
		Kind: "Log",
	}

	// Print trace text
	log.Traceln("This is a trace statement.")

	// Print trace text with additional data
	log.Traced("This is a trace statement with data.", test)

	// Print a formatted trace statement
	log.Tracef("This is a formatted trace statement (%d).", 10000)

	// Print debug text
	log.Debugln("This is a debug statement.")

	// Print debug text with additional data.
	log.Debugf("This is a debug statement %d.", 10000)

	// Print info text
	log.Infoln("This is an info statement.")

	// Print info text with additional data.
	log.Infof("This is an info statement %d.", 10000)

	// Print warn text
	log.Warnln("This is a warning.")

	// Print warn text with additional data.
	log.Warnf("This is a warning %d.", 10000)

	// Print error text
	log.Errorln("This is an error.")

	// Print error text with additional data.
	log.Errorf("This is an error %d.", 10000)

	// Print fatal text
	log.Fatalln("This is an error.")

	// Print fatal text with additional data.
	log.Fatalf("This is an error %d.", 10000)
}

Sub-Loggers

The tags provided when setting up the logger will be included in every log statement, and so should apply to the entire application instance. For more granular tags that apply only to a package or a function, the Sublogger function returns a Logger that will include additional tags where it is used instead of the default logger. It does not affect the default logger.

The Sublogger function creates a logger from the default Logger, but a sub-logger can be created from any Logger, even a sub-logger, and will inherit all of its tags.

Example
package main

import (
    log "github.com/parkhub/go-parkhub-logger"
)

func main() {
    log.SetupCloudLogger(log.LogLevelInfo, []string{"environment", "platform", "application"})

    sl := log.Sublogger("package", "function")

    log.Debugln("with default logger")
    // tagged ["environment", "platform", "application"]

    sl.Debugln("with sub-logger")
    // tagged ["environment", "platform", "application", "package", "function"]

    sl2 := sl.Sublogger("super-fine")
    sl2.Debugln("with sub-sub-logger")
	// tagged ["environment", "platform", "application", "package", "function", "super-fine"]
}

Sub-Loggers

The tags provided when setting up the logger will be included in every log statement, and so should apply to the entire application instance. For more granular tags that apply only to a package or a function, the Sublogger function returns a Logger that will include additional tags where it is used instead of the default logger. It does not affect the default logger.

The Sublogger function creates a logger from the default Logger, but a sub-logger can be created from any Logger, even a sub-logger, and will inherit all of its tags.

Example
package main

import (
    log "github.com/parkhub/go-parkhub-logger"
)

func main() {
    log.SetupCloudLogger(log.LogLevelInfo, []string{"environment", "platform", "application"})
    
    sl := log.Sublogger("package", "function")
    
    log.Debugln("with default logger")
    // tagged ["environment", "platform", "application"]
    
    sl.Debugln("with sub-logger")
    // tagged ["environment", "platform", "application", "package", "function"]
    
    sl2 := sl.Sublogger("super-fine")
    sl2.Debugln("with sub-sub-logger")
	// tagged ["environment", "platform", "application", "package", "function", "super-fine"]
}

Request Logging

The package also includes a RequestLogger type that provides an http.Handler by its Handle method. The handler logs all incoming HTTP requests, logging the request method, the requested path, the time it took to complete the request, and whether the request was canceled, timed out, or had another context error.

The RequestLogger config accepts boolean properties for whether to include the headers, params, and/or body in the log, allows for specifying a logger other than the default logger, and any additional tags you'd like included on request logs.

Request Status Log Level
Canceled Warn
Deadline exceeded Warn
Other error Error
Success Debug
Example
package main

import (
	"net/http"
	_ "net/http/pprof"

	"github.com/gorilla/mux"
	log "github.com/parkhub/go-parkhub-logger"
)

func main() {
	log.SetupLogger(
		log.LogLevelDebug,
		log.LogFormatPretty,
		false,
		false,
		[]string{"some-api", "develop"},
	)

	rl := log.NewRequestLogger(log.RequestLoggerConfig{
		Headers: false,
		Params:  true,
		Body:    false,
		Tags:    []string{"http-requests"},
	})

	router := mux.NewRouter()

	// log all incoming requests as middleware
	router.Use(rl.Handle)

	// alternately, log all incoming requests on single route
	routeHandler := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		// some route handler
	})
	router.Handle("/some-route", rl.Handle(routeHandler))

	sl := log.Sublogger("debug-routes")
	drl := log.NewRequestLogger(log.RequestLoggerConfig{
			Logger:  sl,
			Headers: true,
			Tags:    []string{"profiling"},
    })
	router.PathPrefix("/debug").Handler(drl.Handle(http.DefaultServeMux))
	// tags ["some-api", "develop", "debug", "profiling"]

	sl := log.Sublogger("debug-routes")
	drl := log.NewRequestLogger(log.RequestLoggerConfig{
			Logger:  sl,
			Headers: true,
			Tags:    []string{"profiling"},
    })
	router.PathPrefix("/debug").Handler(drl.Handle(http.DefaultServeMux))
	// tags ["some-api", "develop", "debug", "profiling"]

	// etc. ...

	srv := &http.Server{
		Handler:      router,
		Addr:         ":8080",
		WriteTimeout: 10 * time.Second,
		ReadTimeout:  5 * time.Second,
	}
	_ = srv.ListenAndServe()
}

Panic Recovery

The Recover function can be deferred in code to recover from a panic and log it as an error instead, and continue. If an error reference is provided, it can be used to capture the panic as an error to return.

Example
// exampleFunction will panic if index is greater than the length of slice - 1
func exampleFunction(index int, slice []interface{}) interface{} {
  return slice[index]
}

// goroutine returns no error, but calls a function that may panic
func goroutine() {
  defer Recover("goroutine", nil)
  _ = exampleFunction(1, nil)
}

// goroutine2 returns an error set if function recovers from a panic
func goroutine2() (err error) {
  defer Recover("goroutine2", &err)
  panic("fatal error!")
}

Documentation

Overview

Package log provides a singular interface to create logs as well as filtering them out based on level. It also provides two types of formatting; json or pretty. The logger doesn't ship any logs.

Index

Constants

This section is empty.

Variables

View Source
var LoggerSingleton *logger

LoggerSingleton is the main logging instance.

Functions

func Debugd

func Debugd(output string, d interface{})

Debugd prints output string and data.

func Debugf

func Debugf(format string, a ...interface{})

Debugf prints the formatted output.

func Debugln

func Debugln(output string)

Debugln prints the output followed by a newline.

func Errord

func Errord(output string, d interface{})

Errord prints output string and data.

func Errorf

func Errorf(format string, a ...interface{})

Errorf prints the formatted output.

func Errorln

func Errorln(output string)

Errorln prints the output followed by a newline.

func Fatald

func Fatald(output string, d interface{})

Fatald prints output string and data.

func Fatalf

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

Fatalf prints the formatted output.

func Fatalln

func Fatalln(output string)

Fatalln prints the output followed by a newline and calls os.Exit(1).

func Infod

func Infod(output string, d interface{})

Infod prints output string and data.

func Infof

func Infof(format string, a ...interface{})

Infof prints the formatted output.

func Infoln

func Infoln(output string)

Infoln prints the output followed by a newline.

func Logd

func Logd(level Level, output string, d interface{})

Logd prints output string and data

func Logf

func Logf(level Level, format string, a ...interface{})

Logf prints the formatted output

func Logln

func Logln(level Level, output string)

Logln prints the output followed by a newline

func Recover added in v1.2.1

func Recover(in string, err *error)

Recover recovers from a panic to keep from crashing the application and logs the problem as an error. The error argument can be used to set an error to be returned by the calling function.

func SetupCloudLogger

func SetupCloudLogger(level Level, tags []string)

SetupCloudLogger is a convenience function for calling SetupLogger with JSON formatted logs, non-colorized output and the given tags.

func SetupLocalLogger

func SetupLocalLogger(level Level)

SetupLocalLogger is a convenience function for calling SetupLogger with pretty formatted logs, colorized output and no tags.

func SetupLogger

func SetupLogger(level Level, format Format, timeFormat TimeFormat, colorizeOutput bool, logCaller bool, tags []string)

SetupLogger creates a new logger.

func Stdd

func Stdd(output string, d interface{})

Stdd prints output string and data.

func Stdf

func Stdf(format string, a ...interface{})

Stdf prints the formatted output.

func Stdln

func Stdln(output string)

Stdln prints the output followed by a newline.

func Traced

func Traced(output string, d interface{})

Traced prints the output string and data

func Tracef

func Tracef(format string, a ...interface{})

Tracef prints the formatted output

func Traceln

func Traceln(output string)

Traceln prints the output followed by a newline

func Warnd

func Warnd(output string, d interface{})

Warnd prints output string and data.

func Warnf

func Warnf(format string, a ...interface{})

Warnf prints the formatted output.

func Warnln

func Warnln(output string)

Warnln prints the output followed by a newline.

Types

type Format

type Format string

Format visual format of the log message.

const (
	// LogFormatPretty is a non json formatted log output.
	LogFormatPretty Format = "pretty"

	// LogFormatJSON is a json formatted log output.
	LogFormatJSON Format = "json"
)

type Level

type Level int

Level defined the type for a log level.

const (

	// LogLevelTrace trace log level
	LogLevelTrace Level

	// LogLevelDebug debug log level.
	LogLevelDebug

	// LogLevelInfo info log level.
	LogLevelInfo

	// LogLevelWarn warn log level.
	LogLevelWarn

	// LogLevelError error log level.
	LogLevelError

	// LogLevelFatal fatal log level.
	LogLevelFatal
)

func (Level) String

func (l Level) String() string

type Logger

type Logger interface {
	// Base log
	Logln(Level, string)
	Logf(Level, string, ...interface{})
	Logd(Level, string, interface{})

	// Trace
	Traceln(string)
	Tracef(string, ...interface{})
	Traced(string, interface{})

	// Debug
	Debugln(string)
	Debugf(string, ...interface{})
	Debugd(string, interface{})

	// Info
	Infoln(string)
	Infof(string, ...interface{})
	Infod(string, interface{})

	// Warn
	Warnln(string)
	Warnf(string, ...interface{})
	Warnd(string, interface{})

	// Error
	Errorln(string)
	Errorf(string, ...interface{})
	Errord(string, interface{})

	// Fatal
	Fatalln(string)
	Fatalf(string, ...interface{})
	Fatald(string, interface{})

	// Create a logger object with additional tags
	Sublogger(tags ...string) Logger
	// contains filtered or unexported methods
}

func Sublogger

func Sublogger(tags ...string) Logger

Sublogger returns a new sublogger with the provided tags

type RequestLogger

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

RequestLogger is a configured struct with an HTTP Handler method for logging HTTP requests

func NewRequestLogger

func NewRequestLogger(config RequestLoggerConfig) *RequestLogger

NewRequestLogger returns a configured RequestLogger

func (*RequestLogger) Handle

func (rl *RequestLogger) Handle(next http.Handler) http.Handler

Handle logs incoming HTTP requests, calls the next handler, and logs uncaught errors in the handler chain

func (*RequestLogger) RoundTrip added in v1.4.0

func (rl *RequestLogger) RoundTrip(req *http.Request) (res *http.Response, err error)

func (*RequestLogger) RoundTripper added in v1.4.0

func (rl *RequestLogger) RoundTripper(client *http.Client) http.RoundTripper

type RequestLoggerConfig

type RequestLoggerConfig struct {
	Logger  Logger
	Client  *http.Client
	Headers bool
	Params  bool
	GraphQL bool
	Body    bool
	Tags    []string

	// NormalLevel is the log level to use for requests without context errors
	NormalLevel Level

	// DeadlineExceededLevel is the log level to use for requests that time out
	DeadlineExceededLevel Level

	// ContextCancelledLevel is the log level to use for requests that are
	// cancelled for reasons other than a timeout
	ContextCancelledLevel Level

	// ContextErrorLevel is the log level to use for requests that have an other
	// context error
	ContextErrorLevel Level
}

RequestLoggerConfig defines options for which details should be logged

type TimeFormat added in v1.3.0

type TimeFormat string
const (
	TimeFormatLoggly TimeFormat = "loggly"
)

Jump to

Keyboard shortcuts

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