All Projects → go-clog → Clog

go-clog / Clog

Licence: mit
Package clog is a channel-based logging package for Go

Programming Languages

go
31211 projects - #10 most used programming language

Projects that are alternatives of or similar to Clog

Quicklogger
Library for logging on files, console, memory, email, rest, eventlog, syslog, slack, telegram, redis, logstash, elasticsearch, influxdb, graylog, Sentry, Twilio, ide debug messages and throw events for Delphi/Firemonkey/freepascal/.NET (Windows/Linux/OSX/IOS/Android).
Stars: ✭ 137 (-9.27%)
Mutual labels:  console, slack, logging
Node Draftlog
📜 Create updatable log lines into the terminal, and give life to your logs!
Stars: ✭ 1,117 (+639.74%)
Mutual labels:  console, logging
Octoslack
OctoPrint plugin for Slack, Mattermost, Pushbullet, Pushover, Rocket.Chat, Discord, Riot/Matrix, & Microsoft Teams
Stars: ✭ 50 (-66.89%)
Mutual labels:  discord, slack
Go Logger
一个简单而强大的 golang 日志工具包,支持同步和异步输出到 命令行,文件, api 接口,文件支持按文件大小,文件行数,日期切分;A simple and powerful golang logging toolkit that supports synchronous and asynchronous output to the console, file, API interfaces, file support by file size, file line number, date sharding.
Stars: ✭ 152 (+0.66%)
Mutual labels:  console, file
Yii2 Slack Log
Pretty Slack log target for Yii 2
Stars: ✭ 24 (-84.11%)
Mutual labels:  slack, logging
Discord Scripts
A collection of scripts to enhance your Discord experience.
Stars: ✭ 26 (-82.78%)
Mutual labels:  discord, logging
Logback Slack Appender
Logback appender for Slack messenger
Stars: ✭ 73 (-51.66%)
Mutual labels:  slack, logging
Notify
A dead simple Go library for sending notifications to various messaging services.
Stars: ✭ 727 (+381.46%)
Mutual labels:  discord, slack
Yurnalist
An elegant console reporter, borrowed from Yarn
Stars: ✭ 88 (-41.72%)
Mutual labels:  console, logging
Chromephp
class for logging PHP variables to Google Chrome console
Stars: ✭ 1,339 (+786.75%)
Mutual labels:  console, logging
Console Logging
Better, prettier commandline logging for Python--with colors! 👻
Stars: ✭ 111 (-26.49%)
Mutual labels:  console, logging
Logging Helpers
Basic template helpers for printing messages out to the console. Useful for debugging context in templates. Should work with any template engine.
Stars: ✭ 5 (-96.69%)
Mutual labels:  console, logging
Inventory Hunter
⚡️ Get notified as soon as your next CPU, GPU, or game console is in stock
Stars: ✭ 778 (+415.23%)
Mutual labels:  discord, slack
Loglevelnext
A modern logging library for Node.js that provides log level mapping to the console
Stars: ✭ 33 (-78.15%)
Mutual labels:  console, logging
Electron Log
Just a simple logging module for your Electron application
Stars: ✭ 765 (+406.62%)
Mutual labels:  console, logging
Android Filelogger
A general-purpose logging library with built-in support to save logs to file efficiently.
Stars: ✭ 70 (-53.64%)
Mutual labels:  logging, file
Diun
Receive notifications when an image is updated on a Docker registry
Stars: ✭ 704 (+366.23%)
Mutual labels:  discord, slack
Integrations
Connect your App to Multiple Messaging Channels with the W3C Open standard.
Stars: ✭ 721 (+377.48%)
Mutual labels:  discord, slack
React Native Logs
Performance-aware simple logger for React-Native with namespaces, custom levels and custom transports (colored console, file writing, etc.)
Stars: ✭ 84 (-44.37%)
Mutual labels:  logging, file
Assent
Multi-provider framework in Elixir
Stars: ✭ 126 (-16.56%)
Mutual labels:  discord, slack

Clog

GitHub Workflow Status codecov GoDoc Sourcegraph

Package clog is a channel-based logging package for Go.

This package supports multiple loggers across different levels of logging. It uses Go's native channel feature to provide goroutine-safe mechanism on large concurrency.

Installation

The minimum requirement of Go is 1.11.

go get unknwon.dev/clog/v2

Please apply -u flag to update in the future.

Getting Started

It is extremely easy to create one with all default settings. Generally, you would want to create new logger inside init or main function.

Let's create a logger that prints logs to the console:

import (
	log "unknwon.dev/clog/v2"
)

func init() {
	err := log.NewConsole()
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}

func main() {
	log.Trace("Hello %s!", "World") // YYYY/MM/DD 12:34:56 [TRACE] Hello World!
	log.Info("Hello %s!", "World")  // YYYY/MM/DD 12:34:56 [ INFO] Hello World!
	log.Warn("Hello %s!", "World")  // YYYY/MM/DD 12:34:56 [ WARN] Hello World!

	// Graceful stopping all loggers before exiting the program.
	log.Stop()
}

The code inside init function is equivalent to the following:

func init() {
	err := log.NewConsole(0, 
        log.ConsoleConfig{
		    Level: log.LevelTrace,
	    },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}

Or expand further:

func init() {
	err := log.NewConsoleWithName(log.DefaultConsoleName, 0, 
        log.ConsoleConfig{
		    Level: log.LevelTrace,
	    },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}
  • The 0 is an integer type so it is used as underlying buffer size. In this case, 0 creates synchronized logger (call hangs until write is finished).
  • Any non-integer type is used as the config object, in this case ConsoleConfig is the respective config object for the console logger.
  • The LevelTrace used here is the lowest logging level, meaning prints every log to the console. All levels from lowest to highest are: LevelTrace, LevelInfo, LevelWarn, LevelError, LevelFatal, each of them has at least one respective function, e.g. log.Trace, log.Info, log.Warn, log.Error and log.Fatal.

In production, you may want to make log less verbose and be asynchronous:

func init() {
	// The buffer size mainly depends on number of logs could be produced at the same time, 
	// 100 is a good default.
	err := log.NewConsole(100,
        log.ConsoleConfig{
		    Level:      log.LevelInfo,
	    },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}
  • When you set level to be LevelInfo, calls to the log.Trace will be simply noop.
  • The console logger comes with color output, but for non-colorable destination, the color output will be disabled automatically.

Other builtin loggers are file (log.NewFile), Slack (log.NewSlack) and Discord (log.NewDiscord), see later sections in the documentation for usage details.

Multiple Loggers

You can have multiple loggers in different modes across levels.

func init() {
	err := log.NewConsole()
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
	err := log.NewFile(
        log.FileConfig{
		    Level:    log.LevelInfo,
		    Filename: "clog.log",
	    },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}

In this example, all logs will be printed to console, and only logs with level Info or higher (i.e. Warn, Error and Fatal) will be written into file.

Write to a specific logger

When multiple loggers are registered, it is also possible to write logs to a special logger by giving its name.

func main() {
	log.TraceTo(log.DefaultConsoleName, "Hello %s!", "World")
	log.InfoTo(log.DefaultConsoleName, "Hello %s!", "World")
	log.WarnTo(log.DefaultConsoleName, "Hello %s!", "World")
	log.ErrorTo(log.DefaultConsoleName, "So bad... %v", err)
	log.FatalTo(log.DefaultConsoleName, "Boom! %v", err)

	// ...
}

Caller Location

When using log.Error and log.Fatal functions, the caller location is written along with logs.

func main() {
	log.Error("So bad... %v", err) // YYYY/MM/DD 12:34:56 [ERROR] [...er/main.go:64 main()] ...
	log.Fatal("Boom! %v", err)     // YYYY/MM/DD 12:34:56 [FATAL] [...er/main.go:64 main()] ...

	// ...
}
  • Calling log.Fatal will exit the program.
  • If you want to have different skip depth than the default, use log.ErrorDepth or log.FatalDepth.

Clean Exit

You should always call log.Stop() to wait until all logs are processed before program exits.

Builtin Loggers

File Logger

File logger is the single most powerful builtin logger, it has the ability to rotate based on file size, line, and date:

func init() {
	err := log.NewFile(100, 
        log.FileConfig{
            Level:              log.LevelInfo,
            Filename:           "clog.log",  
            FileRotationConfig: log.FileRotationConfig {
                Rotate: true,
                Daily:  true,
            },
        },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}

In case you have some other packages that write to a file, and you want to take advatange of this file rotation feature. You can do so by using the log.NewFileWriter function. It acts like a standard io.Writer.

func init() {
	w, err := log.NewFileWriter("filename",
        log.FileRotationConfig{
            Rotate: true,
            Daily:  true,
        },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}

Slack Logger

Slack logger is also supported in a simple way:

func init() {
	err := log.NewSlack(100,
        log.SlackConfig{
            Level: log.LevelInfo,
            URL:   "https://url-to-slack-webhook",
        },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}

This logger also works for Discord Slack endpoint.

Discord Logger

Discord logger is supported in rich format via Embed Object:

func init() {
	err := log.NewDiscord(100,
        log.DiscordConfig{
            Level: log.LevelInfo,
            URL:   "https://url-to-discord-webhook",
        },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}

This logger automatically retries up to 3 times if hits rate limit with respect to retry_after.

Build Your Own Logger

You can implement your own logger and all the concurrency stuff are handled automatically!

Here is an example which sends all logs to a channel, we call it chanLogger here:

import log "unknwon.dev/clog/v2"

type chanConfig struct {
	c chan string
}

var _ log.Logger = (*chanLogger)(nil)

type chanLogger struct {
	name  string
	level log.Level
	c     chan string
}

func (l *chanLogger) Name() string     { return l.name }
func (l *chanLogger) Level() log.Level { return l.level }

func (l *chanLogger) Write(m log.Messager) error {
	l.c <- m.String()
	return nil
}

func main() {
	log.New("channel", func(name string, vs ...interface{}) (log.Logger, error) {
		var cfg *chanConfig
		for i := range vs {
			switch v := vs[i].(type) {
			case chanConfig:
				cfg = &v
			}
		}

		if cfg == nil {
			return nil, fmt.Errorf("config object with the type '%T' not found", chanConfig{})
		} else if cfg.c == nil {
			return nil, errors.New("channel is nil")
		}

		return &chanLogger{
			name: name,
			c:    cfg.c,
		}, nil
	})
}

Have fun!

Credits

License

This project is under MIT License. See the LICENSE file for the full license text.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].