diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..57bebc8 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,11 @@ +# Copyright 2024, Thiago Zilli Sarmento + +All rights reserved. No permission is hereby granted to any person obtaining a copy of this software and associated documentation files. We reserve the rights to deal in the Software, to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software or to permit persons to whom the Software is furnished to do so. + +In case you have our prior or written permission you are subject to the following conditions: + +This copyright notice and permission notice shall be included in all copies or substantial portions of the Software. + +If you begin patent litigation against the Licensor over patents that you think may apply to the software (including a cross-claim or counterclaim in a lawsuit), your license to the software ends automatically. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..40df0f0 --- /dev/null +++ b/README.md @@ -0,0 +1,100 @@ +# logruswr - a Golang Logrus Wrapper + +This wrapper enhances Logrus logging in Go applications, providing structured logging, customizable log levels, output formats, log rotation, and the ability to extend functionality with custom hooks. + +## Features + +- **Structured Logging**: Log messages with contextual information as key-value pairs. +- **Log Levels**: Control log output verbosity from Debug to Fatal. +- **Output Formats**: Choose between JSON and plain text for log output. +- **Log Rotation**: Automatically manage log file size and retention. +- **Custom Hooks**: Extend logging functionality by adding hooks. + +## Installation + +Use `go get` to install the Logrus wrapper: + +```sh +go get github.com/thiagozs/go-logruswr +``` +## Usage + +### Basic Logging + +Initialize the logger and log a simple message: + +```go +package main + +import ( + "github.com/thiagozs/go-logruswr" +) + +func main() { + logger, _ := logruswr.New() + logger.Info("Application started successfully") +} +``` + +### Structured Logging + +Log messages with additional context: + +```go +logger.WithFields(logruswr.Fields{"user_id": 42}).Info("User logged in") +``` + +### Error Logging + +Log errors with contextual information: + +```go +err := errors.New("failed to connect to database") +logger.WithError(err).Error("Database connection error") +``` + +### Log Rotation + +Configure log rotation to manage log files: + +```go +logger, _ := logruswr.New( + logruswr.WithLogFilePath("/var/log/myapp.log"), + logruswr.WithMaxLogSize(5), // in MB + logruswr.WithMaxBackups(3), + logruswr.WithMaxAge(7), // in days + logruswr.WithCompressLogs(true), +) +``` + +### Adding Custom Hooks + +Extend logging functionality by implementing and adding custom hooks: + +```go +type MyCustomHook struct { + // Custom hook implementation +} + +func (hook *MyCustomHook) Levels() []logrus.Level { + return []logrus.Level{logrus.InfoLevel} +} + +func (hook *MyCustomHook) Fire(entry *logrus.Entry) error { + // Hook logic here + return nil +} + +// Usage +logger.AddHook(&MyCustomHook{}) +``` + +With this setup, your application can leverage powerful logging capabilities with minimal effort. Customize the logger according to your needs, and take advantage of structured logging, log rotation, and extensibility with hooks. + +----- + +## Versioning and license + +Our version numbers follow the [semantic versioning specification](http://semver.org/). You can see the available versions by checking the [tags on this repository](https://github.com/thiagozs/go-logruswr/tags). For more details about our license model, please take a look at the [LICENSE](LICENSE.md) file. + +**2024**, thiagozs. diff --git a/consts.go b/consts.go new file mode 100644 index 0000000..c4ea8a7 --- /dev/null +++ b/consts.go @@ -0,0 +1,89 @@ +package logruswr + +import "fmt" + +const ( + Panic Level = iota + Fatal + Error + Warn + Info + Debug + Trace + + Stdout Console = iota + Stderr + File + + FormatterText Formatter = iota + FormatterJSON +) + +func (c Console) String() string { + switch c { + case Stdout: + return "stdout" + case Stderr: + return "stderr" + default: + return "stdout" + } +} + +func (l Level) String() string { + switch l { + case Panic: + return "panic" + case Fatal: + return "fatal" + case Error: + return "error" + case Warn: + return "warn" + case Info: + return "info" + case Debug: + return "debug" + case Trace: + return "trace" + default: + return "info" + } +} + +func (l Level) MarshalText() ([]byte, error) { + return []byte(l.String()), nil +} + +func (l *Level) UnmarshalText(text []byte) error { + switch string(text) { + case "panic": + *l = Panic + case "fatal": + *l = Fatal + case "error": + *l = Error + case "warn": + *l = Warn + case "info": + *l = Info + case "debug": + *l = Debug + case "trace": + *l = Trace + default: + return fmt.Errorf("unknown level: %s", text) + } + return nil +} + +func (f Formatter) String() string { + switch f { + case FormatterText: + return "text" + case FormatterJSON: + return "json" + default: + return "text" + } +} diff --git a/examples/main.go b/examples/main.go new file mode 100644 index 0000000..d3162fc --- /dev/null +++ b/examples/main.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" + + "github.com/thiagozs/go-logruswr" +) + +func main() { + log, _ := logruswr.New() + + log.Debug("Debug test") + log.Info("Info test") + log.Warn("Warning test") + log.Error("Error test") + + log.WithError(fmt.Errorf("teste")).Info("Error with error test") + + log.WithFields(logruswr.Fields{ + "test": "test", + "test2": "test2", + }).Info("WithFields test") + + log.Fatal("Fatal test") +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1e8c015 --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module github.com/thiagozs/go-logruswr + +go 1.21.5 + +require github.com/sirupsen/logrus v1.9.3 + +require ( + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f872dd0 --- /dev/null +++ b/go.sum @@ -0,0 +1,13 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/hooks/testhook.go b/hooks/testhook.go new file mode 100644 index 0000000..3ecf70e --- /dev/null +++ b/hooks/testhook.go @@ -0,0 +1,24 @@ +package hooks + +import "github.com/sirupsen/logrus" + +type TestHook struct { + Fired bool +} + +func (h *TestHook) Levels() []logrus.Level { + return logrus.AllLevels +} + +func (h *TestHook) Fire(entry *logrus.Entry) error { + h.Fired = true + return nil +} + +func (h *TestHook) Reset() { + h.Fired = false +} + +func (h *TestHook) IsFired() bool { + return h.Fired +} diff --git a/logruswr.go b/logruswr.go new file mode 100644 index 0000000..b5be191 --- /dev/null +++ b/logruswr.go @@ -0,0 +1,144 @@ +package logruswr + +import ( + "context" + "os" + "time" + + "github.com/sirupsen/logrus" + "gopkg.in/natefinch/lumberjack.v2" +) + +type LogWrapper struct { + log *logrus.Logger + exitFunc func(int) +} + +func New(opts ...Options) (*LogWrapper, error) { + params, err := newLogWrapperParams(opts...) + if err != nil { + return nil, err + } + + log := logrus.New() + + // Set formatter + switch params.GetFormatter() { + case FormatterText: + log.SetFormatter(&logrus.TextFormatter{ + TimestampFormat: time.RFC3339, + ForceColors: true, + }) + case FormatterJSON: + log.SetFormatter(&logrus.JSONFormatter{ + TimestampFormat: time.RFC3339, + }) + } + + // Set log output + switch params.output { + case Stdout: + log.SetOutput(os.Stdout) + case Stderr: + log.SetOutput(os.Stderr) + case File: + if params.GetLogFilePath() != "" { + log.SetOutput(&lumberjack.Logger{ + Filename: params.GetLogFilePath(), + MaxSize: params.GetMaxLogSize(), // megabytes + MaxBackups: params.GetMaxBackups(), + MaxAge: params.GetMaxAge(), // days + Compress: params.GetCompressLogs(), + }) + } else { + log.SetOutput(os.Stdout) + } + } + + // Set log level + log.SetLevel(logrus.Level(params.GetLevel())) + + // Add hooks + for _, hook := range params.hooks { + log.AddHook(hook) + } + + return &LogWrapper{ + log: log, + exitFunc: os.Exit, + }, nil +} + +func (l *LogWrapper) WithField(key string, value interface{}) *Entry { + return l.log.WithField(key, value) +} + +func (l *LogWrapper) WithFields(fields Fields) *Entry { + return l.log.WithFields(logrus.Fields(fields)) +} + +func (l *LogWrapper) WithError(err error) *Entry { + return l.log.WithError(err) +} + +func (l *LogWrapper) WithContext(ctx context.Context) *Entry { + return l.log.WithContext(ctx) +} + +func (l *LogWrapper) Info(args ...interface{}) { + l.log.Info(args...) +} + +func (l *LogWrapper) Infof(format string, args ...interface{}) { + l.log.Infof(format, args...) +} + +func (l *LogWrapper) Warn(args ...interface{}) { + l.log.Warn(args...) +} + +func (l *LogWrapper) Warnf(format string, args ...interface{}) { + l.log.Warnf(format, args...) +} + +func (l *LogWrapper) Error(args ...interface{}) { + l.log.Error(args...) +} + +func (l *LogWrapper) Errorf(format string, args ...interface{}) { + l.log.Errorf(format, args...) +} + +func (l *LogWrapper) Debug(args ...interface{}) { + l.log.Debug(args...) +} + +func (l *LogWrapper) Fatal(args ...interface{}) { + l.log.Fatal(args...) + l.exitFunc(1) // exit + +} + +func (l *LogWrapper) Panic(args ...interface{}) { + l.log.Panic(args...) +} + +func (l *LogWrapper) Trace(args ...interface{}) { + l.log.Trace(args...) +} + +func (l *LogWrapper) AddHook(hook Hook) { + l.log.AddHook(hook) +} + +func (l *LogWrapper) SetLevel(level Level) { + l.log.SetLevel(logrus.Level(level)) +} + +func (l *LogWrapper) SetReportCaller(b bool) { + l.log.SetReportCaller(b) +} + +func (l *LogWrapper) SetExitFunc(exitFunc func(int)) { + l.exitFunc = exitFunc +} diff --git a/logruswr_test.go b/logruswr_test.go new file mode 100644 index 0000000..c20fbf4 --- /dev/null +++ b/logruswr_test.go @@ -0,0 +1,271 @@ +package logruswr + +import ( + "bytes" + "context" + "errors" + "log" + "os" + "strings" + "testing" + + "github.com/thiagozs/go-logruswr/hooks" +) + +func TestLogWrapper_WithField(t *testing.T) { + logger, err := New() + if err != nil { + t.Fatalf("Failed to create logger: %v", err) + } + + entry := logger.WithField("key", "value") + if entry.Data["key"] != "value" { + t.Errorf("Expected field 'key' to be 'value', got '%v'", entry.Data["key"]) + } +} + +func TestLogWrapper_WithFields(t *testing.T) { + logger, err := New() + if err != nil { + t.Fatalf("Failed to create logger: %v", err) + } + + fields := Fields{"key1": "value1", "key2": "value2"} + entry := logger.WithFields(fields) + for k, v := range fields { + if entry.Data[k] != v { + t.Errorf("Expected field '%s' to be '%v', got '%v'", k, v, entry.Data[k]) + } + } +} + +func TestLogWrapper_WithError(t *testing.T) { + logger, err := New() + if err != nil { + t.Fatalf("Failed to create logger: %v", err) + } + + testError := errors.New("test error") + entry := logger.WithError(testError) + if entry.Data["error"] != testError { + t.Errorf("Expected error to be '%v', got '%v'", testError, entry.Data["error"]) + } +} + +func TestLogWrapper_LogLevels(t *testing.T) { + var buf bytes.Buffer + + logger, err := New(WithOutput(Stdout)) + if err != nil { + t.Fatalf("Failed to create logger: %v", err) + } + + // Redirect log output to buffer + logger.log.SetOutput(&buf) + + // Set log level to Info, should not log Debug + logger.SetLevel(Info) + logger.Debug("This is a debug message that should not appear") + if buf.Len() > 0 { + t.Error("Debug message was logged when log level was set to Info") + } + buf.Reset() // Clear buffer + + // Log at Info level, should appear + logger.Info("Test1 message") + if !strings.Contains(buf.String(), "Test1 message") { + t.Error("The message are not the same on Info") + } + buf.Reset() // Clear buffer + + // Log at Error level, should appear + logger.Error("Test2 message") + if !strings.Contains(buf.String(), "Test2 message") { + t.Error("The message are not the same on Info") + } + buf.Reset() // Clear buffer + + logger.Warn("Test3 message") + if !strings.Contains(buf.String(), "Test3 message") { + t.Error("The message are not the same on Warn") + } + buf.Reset() // Clear buffer + + logger.Trace("Test4 message") + if buf.Len() > 0 { + t.Error("Trace message was logged when log level was set to Info") + } + buf.Reset() // Clear buffer + +} + +func TestLogWrapper_LogLevelsPanic(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("The code did not panic") + } + }() + + logger, err := New(WithOutput(Stdout)) + if err != nil { + t.Fatalf("Failed to create logger: %v", err) + } + + // Set log level to Panic, should panic + logger.SetLevel(Panic) + logger.Panic("This is a panic message") +} + +func TestLogWrapper_AddHooks(t *testing.T) { + logger, err := New(WithOutput(Stdout)) + if err != nil { + t.Fatalf("Failed to create logger: %v", err) + } + + hook := &hooks.TestHook{} + + logger.AddHook(hook) + + logger.Info("Test message") + + if !hook.IsFired() { + t.Error("The hook was not called") + } +} + +func TestLogWrapper_WithContext(t *testing.T) { + logger, err := New(WithOutput(Stdout)) + if err != nil { + t.Fatalf("Failed to create logger: %v", err) + } + + ctx := context.Background() + + logger.WithContext(ctx).Info("Test message") +} + +func TestLogWrapper_WithFormatter(t *testing.T) { + logger, err := New(WithOutput(Stdout), WithFormatter(FormatterJSON)) + if err != nil { + t.Fatalf("Failed to create logger: %v", err) + } + + logger.Info("Test message") +} + +func TestLogWrapper_LogFilePath(t *testing.T) { + defer func() { + if err := os.Remove("/tmp/myapp.log"); err != nil { + log.Fatalf("Failed to remove log file: %v", err) + } + }() + logger, err := New( + WithFormatter(FormatterJSON), + WithOutput(File), + WithLevel(Info), + WithLogFilePath("/tmp/myapp.log"), + WithMaxLogSize(10), // Rotate after 10 MB + WithMaxBackups(3), // Keep only 3 log files + WithMaxAge(28), // 28 days + WithCompressLogs(true), // Compress old log files + ) + if err != nil { + log.Fatalf("Failed to initialize logger: %v", err) + } + + logger.Info("Test1 message") + + // open file and check if the message is there + f, err := os.Open("/tmp/myapp.log") + if err != nil { + log.Fatalf("Failed to open log file: %v", err) + } + + buf := make([]byte, 1024) + n, err := f.Read(buf) + if err != nil { + log.Fatalf("Failed to read log file: %v", err) + } + + if !strings.Contains(string(buf[:n]), "Test1 message") { + log.Fatalf("Log message not found in file") + } + +} + +func TestLogWrapper_LogFilePathNoFile(t *testing.T) { + logger, err := New( + WithFormatter(FormatterJSON), + WithOutput(File), + WithLevel(Info), + WithLogFilePath(""), + ) + if err != nil { + t.Fatalf("Failed to initialize logger: %v", err) + } + + logger.Info("Test1 message") +} + +func TestLogWrapper_Constants(t *testing.T) { + if FormatterText.String() != "text" { + t.Errorf("Expected FormatterText.String() to be 'text', got '%s'", FormatterText.String()) + } + + if FormatterJSON.String() != "json" { + t.Errorf("Expected FormatterJSON.String() to be 'json', got '%s'", FormatterJSON.String()) + } + + if Panic.String() != "panic" { + t.Errorf("Expected LevelPanic.String() to be 'panic', got '%s'", Panic.String()) + } + + if Fatal.String() != "fatal" { + t.Errorf("Expected LevelFatal.String() to be 'fatal', got '%s'", Fatal.String()) + } + + if Error.String() != "error" { + t.Errorf("Expected LevelError.String() to be 'error', got '%s'", Error.String()) + } + + if Warn.String() != "warn" { + t.Errorf("Expected LevelWarn.String() to be 'warn', got '%s'", Warn.String()) + } + + if Info.String() != "info" { + t.Errorf("Expected LevelInfo.String() to be 'info', got '%s'", Info.String()) + } + + if Debug.String() != "debug" { + t.Errorf("Expected LevelDebug.String() to be 'debug', got '%s'", Debug.String()) + } + + if Trace.String() != "trace" { + t.Errorf("Expected LevelTrace.String() to be 'trace', got '%s'", Trace.String()) + } +} + +func TestLogWrapper_MarshalText(t *testing.T) { + l := Info + b, err := l.MarshalText() + if err != nil { + t.Errorf("Expected no error, got %v", err) + } + t.Logf("baaa: %s", b) + + if string(b) != Info.String() { + t.Errorf("Expected 'info', got %s", string(b)) + } +} + +func TestLogWrapper_UnmarshalText(t *testing.T) { + var l Level + err := l.UnmarshalText([]byte("info")) + if err != nil { + t.Errorf("Expected no error, got %v", err) + } + + if l != Info { + t.Errorf("Expected 'info', got %v", l) + } +} diff --git a/options.go b/options.go new file mode 100644 index 0000000..21056fd --- /dev/null +++ b/options.go @@ -0,0 +1,183 @@ +package logruswr + +type LogWrapperParams struct { + formatter Formatter + output Console + level Level + logFilePath string + maxLogSize int // in megabytes + maxBackups int + maxAge int // in days + compressLogs bool + hooks []Hook +} + +func newLogWrapperParams(opts ...Options) (*LogWrapperParams, error) { + params := &LogWrapperParams{ + formatter: FormatterText, + output: Stdout, + level: Info, + } + + for _, opt := range opts { + if err := opt(params); err != nil { + return nil, err + } + } + + return params, nil +} + +func WithFormatter(f Formatter) Options { + return func(p *LogWrapperParams) error { + p.formatter = f + return nil + } +} + +func WithOutput(c Console) Options { + return func(p *LogWrapperParams) error { + p.output = c + return nil + } +} + +func WithLevel(l Level) Options { + return func(p *LogWrapperParams) error { + p.level = l + return nil + } +} + +func WithLogFilePath(path string) Options { + return func(p *LogWrapperParams) error { + p.logFilePath = path + return nil + } +} + +func WithMaxLogSize(size int) Options { + return func(p *LogWrapperParams) error { + p.maxLogSize = size + return nil + } +} + +func WithMaxBackups(backups int) Options { + return func(p *LogWrapperParams) error { + p.maxBackups = backups + return nil + } +} + +func WithMaxAge(age int) Options { + return func(p *LogWrapperParams) error { + p.maxAge = age + return nil + } +} + +func WithCompressLogs(compress bool) Options { + return func(p *LogWrapperParams) error { + p.compressLogs = compress + return nil + } +} + +func WithHooks(hooks ...Hook) Options { + return func(p *LogWrapperParams) error { + p.hooks = hooks + return nil + } +} + +func WithHook(hook Hook) Options { + return func(p *LogWrapperParams) error { + p.hooks = append(p.hooks, hook) + return nil + } +} + +// getters .... +func (p *LogWrapperParams) GetFormatter() Formatter { + return p.formatter +} + +func (p *LogWrapperParams) GetOutput() Console { + return p.output +} + +func (p *LogWrapperParams) GetLevel() Level { + return p.level +} + +func (p *LogWrapperParams) GetLogFilePath() string { + return p.logFilePath +} + +func (p *LogWrapperParams) GetMaxLogSize() int { + return p.maxLogSize +} + +func (p *LogWrapperParams) GetMaxBackups() int { + return p.maxBackups +} + +func (p *LogWrapperParams) GetMaxAge() int { + return p.maxAge +} + +func (p *LogWrapperParams) GetCompressLogs() bool { + return p.compressLogs +} + +func (p *LogWrapperParams) GetHooks() []Hook { + return p.hooks +} + +// setters .... + +func (p *LogWrapperParams) SetFormatter(f Formatter) { + p.formatter = f +} + +func (p *LogWrapperParams) SetOutput(c Console) { + p.output = c +} + +func (p *LogWrapperParams) SetLevel(l Level) { + p.level = l +} + +func (p *LogWrapperParams) SetOptions(opts ...Options) error { + for _, opt := range opts { + if err := opt(p); err != nil { + return err + } + } + return nil +} + +func (p *LogWrapperParams) SetLogFilePath(path string) { + p.logFilePath = path +} + +func (p *LogWrapperParams) SetMaxLogSize(size int) { + p.maxLogSize = size +} + +func (p *LogWrapperParams) SetMaxBackups(backups int) { + p.maxBackups = backups +} + +func (p *LogWrapperParams) SetMaxAge(age int) { + p.maxAge = age +} + +func (p *LogWrapperParams) SetCompressLogs(compress bool) { + p.compressLogs = compress +} + +func (p *LogWrapperParams) SetHooks(hooks ...Hook) { + p.hooks = hooks +} diff --git a/types.go b/types.go new file mode 100644 index 0000000..663a3bb --- /dev/null +++ b/types.go @@ -0,0 +1,17 @@ +package logruswr + +import "github.com/sirupsen/logrus" + +type Options func(*LogWrapperParams) error + +type Level uint32 + +type Console int + +type Formatter int + +type Entry = logrus.Entry + +type Hook = logrus.Hook + +type Fields map[string]interface{}