Git Product home page Git Product logo

jellog's Introduction

Jellog

Go Reference

Custom and simplish Go logging library that supports logging of different types via generics.

Jellog uses an architecture similar to python logs. It provides a Logger type which has methods for logging messages at various pre-configured or custom severity levels. The Logger routes the message to one or more Handler which handles either further routing or writing the message to an output such as files or std streams.

It also includes top-level functions intended for drop-in or near drop-in replacement of use of the default logger in the built-in Go log library.

Installing

go get github.com/dekarrin/jellog

Use

Once imported, you can call package functions to invoke the default logger, which will simply print to stderr with a pre-configured header similar to the default built-in Go logger.

package main

import (
    "os"

    "github.com/dekarrin/jellog"
)

func main() {
    jellog.Printf("The program has started")

    f, err := os.Open("somefile.txt")
    if err != nil {
        jellog.Fatalf("Can't open somefile.txt: %v", err)
    }
    defer f.Close()

    jellog.Printf("The program is done!")
}

Running the above would result in the following being printed to stderr:

2009/11/10 23:00:00 INFO  The program has started
2009/11/10 23:00:00 FATAL ERROR Can't open somefile.txt: open somefile.txt: no such file or directory

If you need custom logging with source component information, create a Logger and use that.

package main

import (
    "fmt"
    "io"
    "os"
    "http"

    "github.com/dekarrin/jellog"
)

var log jellog.Logger[string]

func main() {
    log = jellog.New(jellog.Defaults[string]().
        WithComponent("server").
        WithHandler(
            // only show INFO-level or higher in stderr
            jellog.LvInfo, jellog.NewStderrHandler(nil),
        ).
        WithHandler(
            // show all levels in the file output
            jellog.LvAll, jellog.MustOpenFile("server.log", nil),
        ))
    
    // and then start using it!
    log.Info("Initialize server...")

    log.Debug("Starting config load...")
    conf, err := loadConfig("server.yml")
    if err != nil {
        if !conf.defaultConf {
            log.Fatalf("Problem loading config: %w", err)
        }
    }
    log.Debug("Config load complete")

    server := createHTTPServer(conf)
    log.Debug("Server created")

    log.Infof("Server is now listening for new connections")
    log.Fatalf("%v", server.ListenAndServe())
}

func loadConfig(filename string) (Config, error) {
    log.Tracef("Open file...")
    f, err := os.Open(filename)
    if err != nil {
        log.Warnf("config unreadable; using default config: can't open: %v", err)
        return Config{defaultConf: true}, err
    }
    defer f.Close()

    log.Tracef("About to start reading config...")
    confData, err := io.ReadAll(f)
    if err != nil {
        log.Errorf("%v", err)
        return Config{}, err
    }
    log.Tracef("Finished reading config")

    log.Tracef("About to start parsing config...")
    conf, err := parseConfig(confData)
    if err != nil {
        log.Errorf("%v", err)
        return Config{}, err
    }
    log.Tracef("Finished parsing config")
    return conf, nil
}

func parseConfig(data []byte) (Config, error) {
    // ...
    //
    // do some stuff with config, eventually end up with a:

    return Config{Port: 20, Address: "localhost"}, nil
}

func createHTTPServer(conf Config) *http.Server {
    return &http.Server{
        Addr: fmt.Sprintf("%s:%d", conf.Address, conf.Port),
    }
}

type Config struct {
    defaultConf bool
    Port int
    Address string
}

Assuming all went well, running the above might result in something such as the following being printed to stderr:

2009/11/10 23:00:00 INFO  (server) Initialize server...
2009/11/10 23:00:04 INFO  (server) Server is is now listening for new connections

And even more details would be in server.log:

2009/11/10 23:00:00 INFO  (server) Initialize server...
2009/11/10 23:00:00 DEBUG (server) Starting config load...
2009/11/10 23:00:00 TRACE (server) Open file...
2009/11/10 23:00:01 TRACE (server) About to start reading config...
2009/11/10 23:00:03 TRACE (server) Finished reading config
2009/11/10 23:00:03 TRACE (server) About to start parsing config...
2009/11/10 23:00:03 TRACE (server) Finished parsing config
2009/11/10 23:00:04 DEBUG (server) Config load complete
2009/11/10 23:00:04 DEBUG (server) Server created
2009/11/10 23:00:04 INFO  (server) Server is is now listening for new connections

jellog's People

Contributors

dekarrin avatar

Watchers

 avatar  avatar

jellog's Issues

Logging functions should accept `any`

Right now, logger functions that are not format versions require the logged object to be of type E. This could be changed to any and auto-conversion performed when necessary, just like the f versions.

Ideally this would follow a similar pattern to the current arguments accepted by the package-level Fatal function, where multiple objects are accepted if something can be worked for that. May need to add Combiner to Logger config tho to handle combining multiple elements.

Chaining is broken

Primary method of chaining, using a Logger as a Handler, does not work because it doesn't implement Handler. it would need a different InsertBreak method to do so.

`Panic` functions

When added to loggers, calling Panic or Panicf will log the panic message at level Fatal and the entire stacktrace with frames removed as needed to show original panic outside of logger. see jelly/cmd/jellytest/main.go for an example string-based level remover.

tho logging at level fatal, it should not cause program exit

Chaining Handler add to Logger

Logger should have a way of Chaining calls to AddHandler to allow creation as a global-level var. Could simply change it to return the new Logger.

Further, rename it to Handle.

This might additionally require the addition of Must* funcs for Handler creation that can raise an error

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.