Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/go-clog/clog
Package clog is a channel-based logging package for Go
https://github.com/go-clog/clog
console discord file go logging lsif-enabled slack
Last synced: 7 days ago
JSON representation
Package clog is a channel-based logging package for Go
- Host: GitHub
- URL: https://github.com/go-clog/clog
- Owner: go-clog
- License: mit
- Created: 2017-02-03T17:26:02.000Z (almost 8 years ago)
- Default Branch: main
- Last Pushed: 2023-12-18T02:11:18.000Z (11 months ago)
- Last Synced: 2024-10-22T02:36:08.886Z (14 days ago)
- Topics: console, discord, file, go, logging, lsif-enabled, slack
- Language: Go
- Homepage:
- Size: 104 KB
- Stars: 168
- Watchers: 9
- Forks: 18
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Clog
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/go-clog/clog/Go?logo=github&style=for-the-badge)](https://github.com/go-clog/clog/actions?query=workflow%3AGo)
[![codecov](https://img.shields.io/codecov/c/github/go-clog/clog/master?logo=codecov&style=for-the-badge)](https://codecov.io/gh/go-clog/clog)
[![GoDoc](https://img.shields.io/badge/GoDoc-Reference-blue?style=for-the-badge&logo=go)](https://pkg.go.dev/unknwon.dev/clog/v2?tab=doc)
[![Sourcegraph](https://img.shields.io/badge/view%20on-Sourcegraph-brightgreen.svg?style=for-the-badge&logo=sourcegraph)](https://sourcegraph.com/github.com/go-clog/clog)![](https://avatars1.githubusercontent.com/u/25576866?v=3&s=200)
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:
```go
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:
```go
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:
```go
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:
```go
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.
```go
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.
```go
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.
```go
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:
```go
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`.
```go
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:
```go
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](https://discordapp.com/developers/docs/resources/webhook#execute-slackcompatible-webhook) endpoint.
### Discord Logger
Discord logger is supported in rich format via [Embed Object](https://discordapp.com/developers/docs/resources/channel#embed-object):
```go
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:
```go
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
- Avatar is a modified version based on [egonelbre/gophers' scientist](https://github.com/egonelbre/gophers/blob/master/vector/science/scientist.svg).
## License
This project is under MIT License. See the [LICENSE](LICENSE) file for the full license text.