Simple, opinionated logger for go
Go to file
Mai Lapyst 3f08c36524 Adding mutex-es to both StreamHandler and RotatingFileHandler so that Write() dosn't mess up 2022-07-30 18:02:10 +02:00
doc Adding documentation about RotatingFileHandler; release v0.2.0 2022-07-30 04:38:46 +02:00
formatters Initial commit 2022-07-25 11:05:49 +02:00
handlers Adding mutex-es to both StreamHandler and RotatingFileHandler so that Write() dosn't mess up 2022-07-30 18:02:10 +02:00
processors Initial commit 2022-07-25 11:05:49 +02:00
.gitignore Changes 2022-07-30 04:29:33 +02:00
LICENSE Initial commit 2022-07-25 11:05:49 +02:00
errors.go Initial commit 2022-07-25 11:05:49 +02:00
formatter.go Initial commit 2022-07-25 11:05:49 +02:00
go.mod Changes / release v0.3.0 2022-07-30 17:38:56 +02:00
go.sum Changes / release v0.3.0 2022-07-30 17:38:56 +02:00
handler.go Changes / release v0.3.0 2022-07-30 17:38:56 +02:00
level.go Initial commit 2022-07-25 11:05:49 +02:00
logger.go Changes / release v0.3.0 2022-07-30 17:38:56 +02:00
logger_test.go Initial commit 2022-07-25 11:05:49 +02:00
processor.go Initial commit 2022-07-25 11:05:49 +02:00
readme.md Initial commit 2022-07-25 11:05:49 +02:00
record.go Initial commit 2022-07-25 11:05:49 +02:00
utils.go Changes / release v0.3.0 2022-07-30 17:38:56 +02:00

readme.md

logfrog for golang

A opinionated logger with great flexibility

License

This project is licensed under AGPL-3.0. See the LICENSE file for more informations.

Usage

Overview of the log-flow:

logger.Log(...)
      |
  processors
      |
  handlers: handle( process -> format -> write )

In logfrog there are three different components: Formatter, Processor and Handler

  • a Processor modifies or mutates any given logrecord. It can either be globally for every record an logger produces or scoped inside an handler.
  • a Formatter used by handlers to transform an log-record into an sequence of bytes
  • a Handler handles what to do with an record; it can apply own mutations (via an seperate process chain), than formats it and finally writes it werever it wants the data to go (like into a file, send an email and so on). It also can decide if the record should be handed to the next handler, or if it was "consumed".

Getting started

Heres an simple example to get you started:

package main

import (
    "os"
    "codeark.it/Bithero-Agency-Go/logfrog-go"
    logfrog_handlers "codeark.it/Bithero-Agency-Go/logfrog-go/handlers"
)

func main() {
    // First we need an logger. We can create one with `NewLogger(name, level)`.
    // The name can be visible in the logs; the level is used to configure which logging calls
    // should actually be handled, and which one should be sorted out.
    logger := logfrog.NewLogger("main", logfrog.DEBUG)
    defer logger.Close()

    // Adds an handler so we actually can see the output... more on that later on
    logger->AddHandler(logfrog_handlers.NewStreamHandler(os.Stdout))

    // The logger supports a easy function for all available log levels (TRACE, DEBUG, INFO, WARN, ERROR, CRITICAL, FATAL).
    // Their signature is: Info(format string, args ...interface{}); as you see, they act a lot like fmt.Printf() .
    logger->Info("2 * 20 is %d", 2 * 20)

    // Since we set the logger in our constructor to debug level, this call will log nothing and not
    // even call the global processors!
    logger->Trace("this will not be processed")

    // If you want it a bit more complex you also could use the Log() method directly.
    // You might notice the zero as first argument; this is the 'skip'; it determines how many function calls
    // the caller-lookup should go up in order to find the function that called the logging function.
    // Zero means this function, one the caller of the current function and so on.
    logger->Log(0, logfrog.INFO, "2 * 20 is %d", 2 * 20)

    // Logfrog also allows for "fields" to be attached to an log entry:
    logger->InfoFields(logfrog.Fields{
        "animal": "cat",
        "color": "red",
    }, "2 * 20 is %d", 2 * 20)

    // Logfrog also has an generic method here as well:
    logger->LogFields(0, logFrog.INFO, logfrog.Fields{
        "animal": "cat",
        "color": "red",
    }, "2 * 20 is %d", 2 * 20)
}

Using & implementing Components

Components are processors, formatters and handlers in logfrog. Implementing them is a bit more work, see Implementing Components.

To use them, just use the AddHandler(), AddProcessor() and SetFormatter() functions:

import (
    logfrog_formatters "codeark.it/Bithero-Agency-Go/logfrog-go/formatters"
    logfrog_handlers "codeark.it/Bithero-Agency-Go/logfrog-go/handlers"
    logfrog_processors "codeark.it/Bithero-Agency-Go/logfrog-go/processors"
)

func main() {
    // ...

    // Adds an handler and lets the logger own it
    logger->AddHandler(logfrog_handlers.NewStreamHandler(os.Stdout))

    // Adds an handler an let both you and the logger own it
    handler := logfrog_handlers.NewStreamHandler(os.Stdout)
    handler.Ref()
    logger->AddHandler(handler)

    handler.Unref()     // give up your ownage share
    logger.Close()      // logger gives up his ownage on close
    // When the last ownage is gone, the component will be Close()-ed

    //-------------------------------------------------------------------

    // Adds an processor-function to the logger
    // The RuntimeVersionProcessor is an example if you can create semi-statefull processors
    logger->AddProcessorFn(logfrog_processors.RuntimeVersionProcessor("goVer"))

    // adds an lambda function as processor
    logger->AddProcessorFn(func (r *logfrog.LogRecord) *logfrog.LogRecord {
        return r
    })

    // ...
}