Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/gookit/slog
📑 Lightweight, configurable, extensible logging library written in Go. Support multi level, multi outputs and built-in multi file logger, buffers, clean, rotate-file handling.一个易于使用的,轻量级、可配置、可扩展的日志库。支持多个级别,输出到多文件;内置文件日志处理、自动切割、清理、压缩等增强功能
https://github.com/gookit/slog
console-logger file-logging formatter go-logger log log-cleaner log-processor log-rotation logger logging logging-library monolog rotate-file slog
Last synced: 1 day ago
JSON representation
📑 Lightweight, configurable, extensible logging library written in Go. Support multi level, multi outputs and built-in multi file logger, buffers, clean, rotate-file handling.一个易于使用的,轻量级、可配置、可扩展的日志库。支持多个级别,输出到多文件;内置文件日志处理、自动切割、清理、压缩等增强功能
- Host: GitHub
- URL: https://github.com/gookit/slog
- Owner: gookit
- License: mit
- Created: 2020-07-06T02:26:45.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2024-09-14T11:20:48.000Z (3 months ago)
- Last Synced: 2024-09-15T21:02:56.108Z (3 months ago)
- Topics: console-logger, file-logging, formatter, go-logger, log, log-cleaner, log-processor, log-rotation, logger, logging, logging-library, monolog, rotate-file, slog
- Language: Go
- Homepage: https://pkg.go.dev/github.com/gookit/slog
- Size: 1.47 MB
- Stars: 386
- Watchers: 6
- Forks: 25
- Open Issues: 8
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-go - slog - Lightweight, configurable, extensible logger for Go. (Logging / Search and Analytic Databases)
- awesome-go-extra - slog - 07-06T02:26:45Z|2022-08-20T06:55:04Z| (Logging / Advanced Console UIs)
README
# slog
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/gookit/slog?style=flat-square)
[![GoDoc](https://godoc.org/github.com/gookit/slog?status.svg)](https://pkg.go.dev/github.com/gookit/slog)
[![Go Report Card](https://goreportcard.com/badge/github.com/gookit/slog)](https://goreportcard.com/report/github.com/gookit/slog)
[![Unit-Tests](https://github.com/gookit/slog/workflows/Unit-Tests/badge.svg)](https://github.com/gookit/slog/actions)
[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/gookit/slog)](https://github.com/gookit/slog)
[![Coverage Status](https://coveralls.io/repos/github/gookit/slog/badge.svg?branch=master)](https://coveralls.io/github/gookit/slog?branch=master)📑 Lightweight, extensible, configurable logging library written in Golang.
**Output in console:**
![console-log-all-level](_example/images/console-log-all-level.png)
## Features
- Simple, directly available without configuration
- Support common log level processing.
- eg: `trace` `debug` `info` `notice` `warn` `error` `fatal` `panic`
- Support any extension of `Handler` `Formatter` as needed
- Supports adding multiple `Handler` log processing at the same time, outputting logs to different places
- Support to custom log message `Formatter`
- Built-in `json` `text` two log record formatting `Formatter`
- Support to custom build log messages `Handler`
- The built-in `handler.Config` `handler.Builder` can easily and quickly build the desired log handler
- Has built-in common log write handler program
- `console` output logs to the console, supports color output
- `writer` output logs to the specified `io.Writer`
- `file` output log to the specified file, optionally enable `buffer` to buffer writes
- `simple` output log to the specified file, write directly to the file without buffering
- `rotate_file` outputs logs to the specified file, and supports splitting files by time and size, and `buffer` buffered writing is enabled by default
- See ./handler folder for more built-in implementations
- Benchmark performance test please see [Benchmarks](#benchmarks)### Output logs to file
- Support enabling `buffer` for log writing
- Support splitting log files by `time` and `size`
- Support configuration to compress log files via `gzip`
- Support clean old log files by `BackupNum` `BackupTime`### `rotatefile` subpackage
- The `rotatefile` subpackage is a stand-alone tool library with file splitting, cleaning, and compressing backups
- `rotatefile.Writer` can also be directly wrapped and used in other logging libraries. For example: `log`, `glog`, `zap`, etc.
- `rotatefile.FilesClear` is an independent file cleaning backup tool, which can be used in other places (such as other program log cleaning such as PHP)
- For more usage, please see [rotatefile](rotatefile/README.md)## [中文说明](README.zh-CN.md)
中文说明请阅读 [README.zh-CN](README.zh-CN.md)
## GoDoc
- [Godoc for github](https://pkg.go.dev/github.com/gookit/slog?tab=doc)
## Install
```bash
go get github.com/gookit/slog
```## Quick Start
`slog` is very simple to use and can be used without any configuration
```go
package mainimport (
"github.com/gookit/slog"
)func main() {
slog.Info("info log message")
slog.Warn("warning log message")
slog.Infof("info log %s", "message")
slog.Debugf("debug %s", "message")
}
```**Output:**
```text
[2020/07/16 12:19:33] [application] [INFO] [main.go:7] info log message
[2020/07/16 12:19:33] [application] [WARNING] [main.go:8] warning log message
[2020/07/16 12:19:33] [application] [INFO] [main.go:9] info log message
[2020/07/16 12:19:33] [application] [DEBUG] [main.go:10] debug message
```### Console Color
You can enable color on output logs to console. _This is default_
```go
package mainimport (
"github.com/gookit/slog"
)func main() {
slog.Configure(func(logger *slog.SugaredLogger) {
f := logger.Formatter.(*slog.TextFormatter)
f.EnableColor = true
})slog.Trace("this is a simple log message")
slog.Debug("this is a simple log message")
slog.Info("this is a simple log message")
slog.Notice("this is a simple log message")
slog.Warn("this is a simple log message")
slog.Error("this is a simple log message")
slog.Fatal("this is a simple log message")
}
```**Output:**
![](_example/images/console-color-log.png)
### Change log output style
Above is the `Formatter` setting that changed the default logger.
> You can also create your own logger and append `ConsoleHandler` to support printing logs to the console:
```go
h := handler.NewConsoleHandler(slog.AllLevels)
l := slog.NewWithHandlers(h)l.Trace("this is a simple log message")
l.Debug("this is a simple log message")
```Change the default logger log output style:
```go
h.Formatter().(*slog.TextFormatter).SetTemplate(slog.NamedTemplate)
```**Output:**
![](_example/images/console-color-log1.png)
> Note: `slog.TextFormatter` uses a template string to format the output log, so the new field output needs to adjust the template at the same time.
### Use JSON Format
`slog` also has a built-in `Formatter` for JSON format. If not specified, the default is to use `TextFormatter` to format log records.
```go
package mainimport (
"github.com/gookit/slog"
)func main() {
// use JSON formatter
slog.SetFormatter(slog.NewJSONFormatter())slog.Info("info log message")
slog.Warn("warning log message")
slog.WithData(slog.M{
"key0": 134,
"key1": "abc",
}).Infof("info log %s", "message")r := slog.WithFields(slog.M{
"category": "service",
"IP": "127.0.0.1",
})
r.Infof("info %s", "message")
r.Debugf("debug %s", "message")
}
```**Output:**
```text
{"channel":"application","data":{},"datetime":"2020/07/16 13:23:33","extra":{},"level":"INFO","message":"info log message"}
{"channel":"application","data":{},"datetime":"2020/07/16 13:23:33","extra":{},"level":"WARNING","message":"warning log message"}
{"channel":"application","data":{"key0":134,"key1":"abc"},"datetime":"2020/07/16 13:23:33","extra":{},"level":"INFO","message":"info log message"}
{"IP":"127.0.0.1","category":"service","channel":"application","datetime":"2020/07/16 13:23:33","extra":{},"level":"INFO","message":"info message"}
{"IP":"127.0.0.1","category":"service","channel":"application","datetime":"2020/07/16 13:23:33","extra":{},"level":"DEBUG","message":"debug message"}
```## Introduction
- `Logger` - log dispatcher. One logger can register multiple `Handler`, `Processor`
- `Record` - log records, each log is a `Record` instance.
- `Processor` - enables extended processing of log records. It is called before the log `Record` is processed by the `Handler`.
- You can use it to perform additional operations on `Record`, such as: adding fields, adding extended information, etc.
- `Handler` - log handler, each log will be processed by `Handler.Handle()`.
- Here you can send logs to console, file, remote server, etc.
- `Formatter` - logging data formatting process.
- Usually set in `Handler`, it can be used to format log records, convert records into text, JSON, etc., `Handler` then writes the formatted data to the specified place.
- `Formatter` is not required. You can do without it and handle logging directly in `Handler.Handle()`.**Simple structure of log scheduler**:
```text
Processors
Logger --{
Handlers --|- Handler0 With Formatter0
|- Handler1 With Formatter1
|- Handler2 (can also without Formatter)
|- ... more
```> Note: Be sure to remember to add `Handler`, `Processor` to the logger instance and log records will be processed by `Handler`.
### Processor
`Processor` interface:
```go
// Processor interface definition
type Processor interface {
// Process record
Process(record *Record)
}// ProcessorFunc definition
type ProcessorFunc func(record *Record)// Process record
func (fn ProcessorFunc) Process(record *Record) {
fn(record)
}
```> You can use it to perform additional operations on the Record before the log `Record` reaches the `Handler` for processing, such as: adding fields, adding extended information, etc.
Add processor to logger:
```go
slog.AddProcessor(slog.AddHostname())// or
l := slog.New()
l.AddProcessor(slog.AddHostname())
```The built-in processor `slog.AddHostname` is used here as an example, which can add a new field `hostname` on each log record.
```go
slog.AddProcessor(slog.AddHostname())
slog.Info("message")
```Output, including new fields `"hostname":"InhereMac"`:
```json
{"channel":"application","level":"INFO","datetime":"2020/07/17 12:01:35","hostname":"InhereMac","data":{},"extra":{},"message":"message"}
```### Handler
`Handler` interface:
> You can customize any `Handler` you want, just implement the `slog.Handler` interface.
```go
// Handler interface definition
type Handler interface {
io.Closer
Flush() error
// IsHandling Checks whether the given record will be handled by this handler.
IsHandling(level Level) bool
// Handle a log record.
// all records may be passed to this method, and the handler should discard
// those that it does not want to handle.
Handle(*Record) error
}
```### Formatter
`Formatter` interface:
```go
// Formatter interface
type Formatter interface {
Format(record *Record) ([]byte, error)
}
```Function wrapper type:
```go
// FormatterFunc wrapper definition
type FormatterFunc func(r *Record) ([]byte, error)// Format a log record
func (fn FormatterFunc) Format(r *Record) ([]byte, error) {
return fn(r)
}
```**JSON formatter**
```go
type JSONFormatter struct {
// Fields exported log fields.
Fields []string
// Aliases for output fields. you can change export field name.
// item: `"field" : "output name"`
// eg: {"message": "msg"} export field will display "msg"
Aliases StringMap
// PrettyPrint will indent all json logs
PrettyPrint bool
// TimeFormat the time format layout. default is time.RFC3339
TimeFormat string
}
```**Text formatter**
Default templates:
```go
const DefaultTemplate = "[{{datetime}}] [{{channel}}] [{{level}}] [{{caller}}] {{message}} {{data}} {{extra}}\n"
const NamedTemplate = "{{datetime}} channel={{channel}} level={{level}} [file={{caller}}] message={{message}} data={{data}}\n"
```Change template:
```go
myTemplate := "[{{datetime}}] [{{level}}] {{message}}"f := slog.NewTextFormatter()
f.SetTemplate(myTemplate)
```## Custom logger
Custom `Processor` and `Formatter` are relatively simple, just implement a corresponding method.
### Create new logger
`slog.Info, slog.Warn` and other methods use the default logger and output logs to the console by default.
You can create a brand-new instance of `slog.Logger`:
**Method 1**:
```go
l := slog.New()
// add handlers ...
h1 := handler.NewConsoleHandler(slog.AllLevels)
l.AddHandlers(h1)
```**Method 2**:
```go
l := slog.NewWithName("myLogger")
// add handlers ...
h1 := handler.NewConsoleHandler(slog.AllLevels)
l.AddHandlers(h1)
```**Method 3**:
```go
package mainimport (
"github.com/gookit/slog"
"github.com/gookit/slog/handler"
)func main() {
l := slog.NewWithHandlers(handler.NewConsoleHandler(slog.AllLevels))
l.Info("message")
}
```### Create custom Handler
You only need to implement the `slog.Handler` interface to create a custom `Handler`.
You can quickly assemble your own Handler through the built-in `handler.LevelsWithFormatter` `handler.LevelWithFormatter` and other fragments of slog.
Examples:
> Use `handler.LevelsWithFormatter`, only need to implement `Close, Flush, Handle` methods
```go
type MyHandler struct {
handler.LevelsWithFormatter
Output io.Writer
}func (h *MyHandler) Handle(r *slog.Record) error {
// you can write log message to file or send to remote.
}func (h *MyHandler) Flush() error {}
func (h *MyHandler) Close() error {}
```Add `Handler` to the logger to use:
```go
// add to default logger
slog.AddHander(&MyHandler{})// or, add to custom logger:
l := slog.New()
l.AddHander(&MyHandler{})
```## Use the built-in handlers
[./handler](handler) package has built-in common log handlers, which can basically meet most scenarios.
```go
// Output logs to console, allow render color.
func NewConsoleHandler(levels []slog.Level) *ConsoleHandler
// Send logs to email
func NewEmailHandler(from EmailOption, toAddresses []string) *EmailHandler
// Send logs to syslog
func NewSysLogHandler(priority syslog.Priority, tag string) (*SysLogHandler, error)
// A simple handler implementation that outputs logs to a given io.Writer
func NewSimpleHandler(out io.Writer, level slog.Level) *SimpleHandler
```**Output log to file**:
```go
// Output log to the specified file, without buffering by default
func NewFileHandler(logfile string, fns ...ConfigFn) (h *SyncCloseHandler, err error)
// Output logs to the specified file in JSON format, without buffering by default
func JSONFileHandler(logfile string, fns ...ConfigFn) (*SyncCloseHandler, error)
// Buffered output log to specified file
func NewBuffFileHandler(logfile string, buffSize int, fns ...ConfigFn) (*SyncCloseHandler, error)
```> TIP: `NewFileHandler` `JSONFileHandler` can also enable write buffering by passing in fns `handler.WithBuffSize(buffSize)`
**Output log to file and rotate automatically**:
```go
// Automatic rotating according to file size
func NewSizeRotateFile(logfile string, maxSize int, fns ...ConfigFn) (*SyncCloseHandler, error)
// Automatic rotating according to time
func NewTimeRotateFile(logfile string, rt rotatefile.RotateTime, fns ...ConfigFn) (*SyncCloseHandler, error)
// It supports configuration to rotate according to size and time.
// The default setting file size is 20M, and the default automatic splitting time is 1 hour (EveryHour).
func NewRotateFileHandler(logfile string, rt rotatefile.RotateTime, fns ...ConfigFn) (*SyncCloseHandler, error)
```> TIP: By passing in `fns ...ConfigFn`, more options can be set, such as log file retention time, log write buffer size, etc. For detailed settings, see the `handler.Config` structure
### Logs to file
Output log to the specified file, `buffer` buffered writing is not enabled by default. Buffering can also be enabled by passing in a parameter.
```go
package mypkgimport (
"github.com/gookit/slog"
"github.com/gookit/slog/handler"
)func main() {
defer slog.MustClose()// DangerLevels contains: slog.PanicLevel, slog.ErrorLevel, slog.WarnLevel
h1 := handler.MustFileHandler("/tmp/error.log", handler.WithLogLevels(slog.DangerLevels))
// custom log format
// f := h1.Formatter().(*slog.TextFormatter)
f := slog.AsTextFormatter(h1.Formatter())
f.SetTemplate("your template format\n")// NormalLevels contains: slog.InfoLevel, slog.NoticeLevel, slog.DebugLevel, slog.TraceLevel
h2 := handler.MustFileHandler("/tmp/info.log", handler.WithLogLevels(slog.NormalLevels))// register handlers
slog.PushHandler(h1)
slog.PushHandler(h2)// add logs
slog.Info("info message text")
slog.Error("error message text")
}
```> **Note**: If write buffering `buffer` is enabled, be sure to call `logger.Close()` at the end of the program to flush the contents of the buffer to the file.
### Log to file with automatic rotating
`slog/handler` also has a built-in output log to a specified file, and supports splitting files by time and size at the same time.
By default, `buffer` buffered writing is enabled```go
func Example_rotateFileHandler() {
h1 := handler.MustRotateFile("/tmp/error.log", handler.EveryHour, handler.WithLogLevels(slog.DangerLevels))
h2 := handler.MustRotateFile("/tmp/info.log", handler.EveryHour, handler.WithLogLevels(slog.NormalLevels))slog.PushHandler(h1)
slog.PushHandler(h2)// add logs
slog.Info("info message")
slog.Error("error message")
}
```Example of file name sliced by time:
```text
time-rotate-file.log
time-rotate-file.log.20201229_155753
time-rotate-file.log.20201229_155754
```Example of a filename cut by size, in the format `filename.log.HIS_000N`. For example:
```text
size-rotate-file.log
size-rotate-file.log.122915_0001
size-rotate-file.log.122915_0002
```### Use rotatefile on another logger
`rotatefile.Writer` can also be used with other logging packages, such as: `log`, `glog`, etc.
For example, using `rotatefile` on golang `log`:
```go
package mainimport (
"log""github.com/gookit/slog/rotatefile"
)func main() {
logFile := "testdata/go_logger.log"
writer, err := rotatefile.NewConfig(logFile).Create()
if err != nil {
panic(err)
}log.SetOutput(writer)
log.Println("log message")
}
```### Quickly create a Handler based on config
This is config struct for create a Handler:
```go
// Config struct
type Config struct {
// Logfile for write logs
Logfile string `json:"logfile" yaml:"logfile"`
// LevelMode for filter log record. default LevelModeList
LevelMode uint8 `json:"level_mode" yaml:"level_mode"`
// Level value. use on LevelMode = LevelModeValue
Level slog.Level `json:"level" yaml:"level"`
// Levels for log record
Levels []slog.Level `json:"levels" yaml:"levels"`
// UseJSON for format logs
UseJSON bool `json:"use_json" yaml:"use_json"`
// BuffMode type name. allow: line, bite
BuffMode string `json:"buff_mode" yaml:"buff_mode"`
// BuffSize for enable buffer, unit is bytes. set 0 to disable buffer
BuffSize int `json:"buff_size" yaml:"buff_size"`
// RotateTime for rotate file, unit is seconds.
RotateTime rotatefile.RotateTime `json:"rotate_time" yaml:"rotate_time"`
// MaxSize on rotate file by size, unit is bytes.
MaxSize uint64 `json:"max_size" yaml:"max_size"`
// Compress determines if the rotated log files should be compressed using gzip.
// The default is not to perform compression.
Compress bool `json:"compress" yaml:"compress"`
// BackupNum max number for keep old files.
// 0 is not limit, default is 20.
BackupNum uint `json:"backup_num" yaml:"backup_num"`
// BackupTime max time for keep old files. unit is hours
// 0 is not limit, default is a week.
BackupTime uint `json:"backup_time" yaml:"backup_time"`
// RenameFunc build filename for rotate file
RenameFunc func(filepath string, rotateNum uint) string
}
```**Examples**:
```go
testFile := "testdata/error.log"h := handler.NewEmptyConfig(
handler.WithLogfile(testFile),
handler.WithBuffSize(1024*8),
handler.WithLogLevels(slog.DangerLevels),
handler.WithBuffMode(handler.BuffModeBite),
).
CreateHandler()l := slog.NewWithHandlers(h)
```**About BuffMode**
`Config.BuffMode` The name of the BuffMode type to use. Allow: line, bite
- `BuffModeBite`: Buffer by bytes, when the number of bytes in the buffer reaches the specified size, write the contents of the buffer to the file
- `BuffModeLine`: Buffer by line, when the buffer size is reached, always ensure that a complete line of log content is written to the file (to avoid log content being truncated)### Use Builder to quickly create Handler
Use `handler.Builder` to easily and quickly create Handler instances.
```go
testFile := "testdata/info.log"h := handler.NewBuilder().
WithLogfile(testFile).
WithLogLevels(slog.NormalLevels).
WithBuffSize(1024*8).
WithBuffMode(handler.BuffModeBite).
WithRotateTime(rotatefile.Every30Min).
WithCompress(true).
Build()l := slog.NewWithHandlers(h)
```## Extension packages
Package `bufwrite`:
- `bufwrite.BufIOWriter` additionally implements `Sync(), Close()` methods by wrapping go's `bufio.Writer`, which is convenient to use
- `bufwrite.LineWriter` refer to the implementation of `bufio.Writer` in go, which can support flushing the buffer by line, which is more useful for writing log filesPackage `rotatefile`:
- `rotatefile.Writer` implements automatic cutting of log files according to size and specified time, and also supports automatic cleaning of log files
- `handler/rotate_file` is to use it to cut the log file### Use rotatefile on other log package
Of course, the rotatefile.Writer can be use on other log package, such as: `log`, `glog` and more.
Examples, use rotatefile on golang `log`:
```go
package mainimport (
"log""github.com/gookit/slog/rotatefile"
)func main() {
logFile := "testdata/another_logger.log"
writer, err := rotatefile.NewConfig(logFile).Create()
if err != nil {
panic(err)
}log.SetOutput(writer)
log.Println("log message")
}
```## Testing and benchmark
### Unit tests
run unit tests:
```bash
go test ./...
```### Benchmarks
Benchmark code at [_example/bench_loglibs_test.go](_example/bench_loglibs_test.go)
```bash
make test-bench
```Benchmarks for `slog` and other log packages:
> **Note**: test and record ad 2023.04.13
```shell
goos: darwin
goarch: amd64
cpu: Intel(R) Core(TM) i7-3740QM CPU @ 2.70GHz
BenchmarkZapNegative
BenchmarkZapNegative-4 8381674 1429 ns/op 216 B/op 3 allocs/op
BenchmarkZapSugarNegative
BenchmarkZapSugarNegative-4 8655980 1383 ns/op 104 B/op 4 allocs/op
BenchmarkZeroLogNegative
BenchmarkZeroLogNegative-4 14173719 849.8 ns/op 0 B/op 0 allocs/op
BenchmarkPhusLogNegative
BenchmarkPhusLogNegative-4 27456256 451.2 ns/op 0 B/op 0 allocs/op
BenchmarkLogrusNegative
BenchmarkLogrusNegative-4 2550771 4784 ns/op 608 B/op 17 allocs/op
BenchmarkGookitSlogNegative
>>>> BenchmarkGookitSlogNegative-4 8798220 1375 ns/op 120 B/op 3 allocs/op
BenchmarkZapPositive
BenchmarkZapPositive-4 10302483 1167 ns/op 192 B/op 1 allocs/op
BenchmarkZapSugarPositive
BenchmarkZapSugarPositive-4 3833311 3154 ns/op 344 B/op 7 allocs/op
BenchmarkZeroLogPositive
BenchmarkZeroLogPositive-4 14120524 846.7 ns/op 0 B/op 0 allocs/op
BenchmarkPhusLogPositive
BenchmarkPhusLogPositive-4 27152686 434.9 ns/op 0 B/op 0 allocs/op
BenchmarkLogrusPositive
BenchmarkLogrusPositive-4 2601892 4691 ns/op 608 B/op 17 allocs/op
BenchmarkGookitSlogPositive
>>>> BenchmarkGookitSlogPositive-4 8997104 1340 ns/op 120 B/op 3 allocs/op
PASS
ok command-line-arguments 167.095s
```## Gookit packages
- [gookit/ini](https://github.com/gookit/ini) Go config management, use INI files
- [gookit/rux](https://github.com/gookit/rux) Simple and fast request router for golang HTTP
- [gookit/gcli](https://github.com/gookit/gcli) Build CLI application, tool library, running CLI commands
- [gookit/slog](https://github.com/gookit/slog) Lightweight, extensible, configurable logging library written in Go
- [gookit/color](https://github.com/gookit/color) A command-line color library with true color support, universal API methods and Windows support
- [gookit/event](https://github.com/gookit/event) Lightweight event manager and dispatcher implements by Go
- [gookit/cache](https://github.com/gookit/cache) Generic cache use and cache manager for golang. support File, Memory, Redis, Memcached.
- [gookit/config](https://github.com/gookit/config) Go config management. support JSON, YAML, TOML, INI, HCL, ENV and Flags
- [gookit/filter](https://github.com/gookit/filter) Provide filtering, sanitizing, and conversion of golang data
- [gookit/validate](https://github.com/gookit/validate) Use for data validation and filtering. support Map, Struct, Form data
- [gookit/goutil](https://github.com/gookit/goutil) Some utils for the Go: string, array/slice, map, format, cli, env, filesystem, test and more
- More, please see https://github.com/gookit## Acknowledgment
The projects is heavily inspired by follow packages:
- https://github.com/phuslu/log
- https://github.com/golang/glog
- https://github.com/sirupsen/logrus
- https://github.com/Seldaek/monolog
- https://github.com/syyongx/llog
- https://github.com/uber-go/zap
- https://github.com/rs/zerolog
- https://github.com/natefinch/lumberjack
## LICENSE[MIT](LICENSE)