diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4681936 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +; https://editorconfig.org/ + +root = true + +[*] +insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[{Makefile,go.mod,go.sum,*.go,.gitmodules}] +indent_style = tab +indent_size = 4 + +[*.md] +indent_size = 4 +trim_trailing_whitespace = false + +eclint_indent_style = unset + +[Dockerfile] +indent_size = 4 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f403141 --- /dev/null +++ b/.gitignore @@ -0,0 +1,59 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +.DS_Store + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +# Log files +*.log + +# Temporary files +/tmp + +# Configuration files +*.env + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..6b12d93 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,26 @@ +run: + timeout: 5m + modules-download-mode: readonly + +linters: + enable: + # enabled by default + - errcheck + - gosimple + - govet + - ineffassign + - staticcheck + - typecheck + - unused + # enabled by takt + - errorlint + - goimports + - revive + - gosec + - exportloopref + - misspell + +issues: + exclude-use-default: false + max-issues-per-linter: 0 + max-same-issues: 0 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d9620d8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "makefile.extensionOutputFolder": "./.vscode", + "go.lintTool":"golangci-lint", + "go.lintFlags": [ + "--fast" + ] +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cfb4148 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Takt, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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..3c03938 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# Logrus Logger for FX + +fxlogrus provides a logger for [uber-go/fx](https://github.com/uber-go/fx) based on [sirupsen/logrus](https://github.com/sirupsen/logrus). All non-errors are logged as debug to keep the logs quiet, errors are still logged as errors. + +```go + +fx.New( + // configure logger + fx.WithLogger(func() fxevent.Logger { + return &fxlogrus.LogrusLogger{Logger: logrus.StandardLogger()} + }), +).Run() + +``` diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9749905 --- /dev/null +++ b/go.mod @@ -0,0 +1,15 @@ +module github.com/takt-corp/fx-logrus + +go 1.19 + +require ( + github.com/sirupsen/logrus v1.9.0 + go.uber.org/fx v1.18.2 +) + +require ( + go.uber.org/atomic v1.6.0 // indirect + go.uber.org/multierr v1.5.0 // indirect + go.uber.org/zap v1.16.0 // indirect + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2844d2a --- /dev/null +++ b/go.sum @@ -0,0 +1,62 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/fx v1.18.2 h1:bUNI6oShr+OVFQeU8cDNbnN7VFsu+SsjHzUF51V/GAU= +go.uber.org/fx v1.18.2/go.mod h1:g0V1KMQ66zIRk8bLu3Ea5Jt2w/cHlOIp4wdRsgh0JaY= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/logrus.go b/logrus.go new file mode 100644 index 0000000..72d9681 --- /dev/null +++ b/logrus.go @@ -0,0 +1,140 @@ +// Package fxlogrus provides a logger for [uber-go/fx](https://github.com/uber-go/fx) based +// on [sirupsen/logrus](https://github.com/sirupsen/logrus). All non-errors are logged as debug to keep +// the logs quiet, errors are still logged as errors. +package fxlogrus + +import ( + "strings" + + "github.com/sirupsen/logrus" + "go.uber.org/fx/fxevent" +) + +// LogrusLogger log formatter for the fx application container +type LogrusLogger struct { + Logger *logrus.Logger +} + +// LogEvent handles a log event for fx application container +func (l *LogrusLogger) LogEvent(event fxevent.Event) { + switch e := event.(type) { + case *fxevent.OnStartExecuting: + l.Logger.WithFields(logrus.Fields{ + "callee": e.FunctionName, + "caller": e.CallerName, + }).Debug("OnStart hook executing") + case *fxevent.OnStartExecuted: + if e.Err != nil { + l.Logger.WithFields(logrus.Fields{ + "callee": e.FunctionName, + "caller": e.CallerName, + }).Errorf("OnStart hook failed: %v", e.Err) + } else { + l.Logger.WithFields(logrus.Fields{ + "callee": e.FunctionName, + "caller": e.CallerName, + "runtime": e.Runtime.String(), + }).Debug("OnStart hook executed") + } + case *fxevent.OnStopExecuting: + l.Logger.WithFields(logrus.Fields{ + "callee": e.FunctionName, + "caller": e.CallerName, + }).Debug("OnStop hook executing") + case *fxevent.OnStopExecuted: + if e.Err != nil { + l.Logger.WithFields(logrus.Fields{ + "callee": e.FunctionName, + "caller": e.CallerName, + }).Errorf("OnStop hook failed: %v", e.Err) + } else { + l.Logger.WithFields(logrus.Fields{ + "callee": e.FunctionName, + "caller": e.CallerName, + "runtime": e.Runtime.String(), + }).Debug("OnStop hook executed") + } + case *fxevent.Supplied: + l.Logger.WithFields(logrus.Fields{ + "type": e.TypeName, + "module": e.ModuleName, + }).Debugf("supplied: %v", e.Err) + case *fxevent.Provided: + for _, rtype := range e.OutputTypeNames { + l.Logger.WithFields(logrus.Fields{ + "constructor": e.ConstructorName, + "module": e.ModuleName, + "type": rtype, + }).Debug("provided") + } + if e.Err != nil { + l.Logger.WithFields(logrus.Fields{ + "module": e.ModuleName, + }).Errorf("error encountered while applying options: %v", e.Err) + } + case *fxevent.Replaced: + for _, rtype := range e.OutputTypeNames { + l.Logger.WithFields(logrus.Fields{ + "module": e.ModuleName, + "type": rtype, + }).Debug("replaced") + } + if e.Err != nil { + l.Logger.WithFields(logrus.Fields{ + "module": e.ModuleName, + }).Errorf("error encountered while replacing: %v", e.Err) + } + case *fxevent.Decorated: + for _, rtype := range e.OutputTypeNames { + l.Logger.WithFields(logrus.Fields{ + "module": e.ModuleName, + "type": rtype, + }).Debug("decorated") + } + if e.Err != nil { + l.Logger.WithFields(logrus.Fields{ + "module": e.ModuleName, + }).Errorf("error encountered while applying options: %v", e.Err) + } + case *fxevent.Invoking: + // Do not log stack as it will make logs hard to read. + l.Logger.WithFields(logrus.Fields{ + "function": e.FunctionName, + "module": e.ModuleName, + }).Debug("invoking") + case *fxevent.Invoked: + if e.Err != nil { + l.Logger.WithFields(logrus.Fields{ + "stack": e.Trace, + "function": e.FunctionName, + "module": e.ModuleName, + }).Errorf("invoke failed: %v", e.Err) + } + case *fxevent.Stopping: + l.Logger.Debugf("received signal: %s", strings.ToUpper(e.Signal.String())) + case *fxevent.Stopped: + if e.Err != nil { + l.Logger.Errorf("received signal: %v", e.Err) + } + case *fxevent.RollingBack: + l.Logger.Errorf("start failed, rolling back: %v", e.StartErr) + case *fxevent.RolledBack: + if e.Err != nil { + l.Logger.Errorf("rollback failed: %v", e.Err) + } + case *fxevent.Started: + if e.Err != nil { + l.Logger.Errorf("start failed: %v", e.Err) + } else { + l.Logger.Debug("started") + } + case *fxevent.LoggerInitialized: + if e.Err != nil { + l.Logger.Errorf("custom logger initialization failed: %v", e.Err) + } else { + l.Logger.WithFields(logrus.Fields{ + "function": e.ConstructorName, + }).Debug("initialized custom fxevent.Logger") + } + } +}