mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-23 18:31:00 +00:00
Merge pull request #1569 from bradrydzewski/master
backport ginrus logging and godotenv from 0.5
This commit is contained in:
commit
89f4f500f3
32 changed files with 1202 additions and 243 deletions
|
@ -1,10 +0,0 @@
|
||||||
# build environment used in .drone.yml
|
|
||||||
#
|
|
||||||
# docker build --rm=true -t drone/golang:1.5 -f Dockerfile.env .
|
|
||||||
|
|
||||||
FROM golang:1.5
|
|
||||||
ADD contrib/*.sh /usr/local/bin/
|
|
||||||
RUN chmod +x /usr/local/bin/setup-sassc.sh && \
|
|
||||||
chmod +x /usr/local/bin/setup-sqlite.sh && \
|
|
||||||
/usr/local/bin/setup-sassc.sh && \
|
|
||||||
/usr/local/bin/setup-sqlite.sh
|
|
46
drone.go
46
drone.go
|
@ -1,7 +1,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/drone/drone/engine"
|
"github.com/drone/drone/engine"
|
||||||
"github.com/drone/drone/remote"
|
"github.com/drone/drone/remote"
|
||||||
|
@ -10,27 +11,34 @@ import (
|
||||||
"github.com/drone/drone/router/middleware/context"
|
"github.com/drone/drone/router/middleware/context"
|
||||||
"github.com/drone/drone/router/middleware/header"
|
"github.com/drone/drone/router/middleware/header"
|
||||||
"github.com/drone/drone/shared/envconfig"
|
"github.com/drone/drone/shared/envconfig"
|
||||||
"github.com/drone/drone/shared/server"
|
|
||||||
"github.com/drone/drone/store/datastore"
|
"github.com/drone/drone/store/datastore"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/gin-gonic/contrib/ginrus"
|
||||||
|
"github.com/ianschenck/envflag"
|
||||||
|
_ "github.com/joho/godotenv/autoload"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
dotenv = flag.String("config", ".env", "")
|
addr = envflag.String("SERVER_ADDR", ":8000", "")
|
||||||
debug = flag.Bool("debug", false, "")
|
cert = envflag.String("SERVER_CERT", "", "")
|
||||||
|
key = envflag.String("SERVER_KEY", "", "")
|
||||||
|
|
||||||
|
debug = envflag.Bool("DEBUG", false, "")
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
envflag.Parse()
|
||||||
|
|
||||||
// debug level if requested by user
|
// debug level if requested by user
|
||||||
if *debug {
|
if *debug {
|
||||||
logrus.SetLevel(logrus.DebugLevel)
|
logrus.SetLevel(logrus.DebugLevel)
|
||||||
|
} else {
|
||||||
|
logrus.SetLevel(logrus.WarnLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the configuration from env file
|
// Load the configuration from env file
|
||||||
env := envconfig.Load(*dotenv)
|
env := envconfig.Load(".env")
|
||||||
|
|
||||||
// Setup the database driver
|
// Setup the database driver
|
||||||
store_ := datastore.Load(env)
|
store_ := datastore.Load(env)
|
||||||
|
@ -42,14 +50,22 @@ func main() {
|
||||||
engine_ := engine.Load(env, store_)
|
engine_ := engine.Load(env, store_)
|
||||||
|
|
||||||
// setup the server and start the listener
|
// setup the server and start the listener
|
||||||
server_ := server.Load(env)
|
handler := router.Load(
|
||||||
server_.Run(
|
ginrus.Ginrus(logrus.StandardLogger(), time.RFC3339, true),
|
||||||
router.Load(
|
header.Version,
|
||||||
header.Version,
|
cache.Default(),
|
||||||
cache.Default(),
|
context.SetStore(store_),
|
||||||
context.SetStore(store_),
|
context.SetRemote(remote_),
|
||||||
context.SetRemote(remote_),
|
context.SetEngine(engine_),
|
||||||
context.SetEngine(engine_),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if *cert != "" {
|
||||||
|
logrus.Fatal(
|
||||||
|
http.ListenAndServeTLS(*addr, *cert, *key, handler),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
logrus.Fatal(
|
||||||
|
http.ListenAndServe(*addr, handler),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func Load(middleware ...gin.HandlerFunc) http.Handler {
|
func Load(middleware ...gin.HandlerFunc) http.Handler {
|
||||||
e := gin.Default()
|
e := gin.New()
|
||||||
|
e.Use(gin.Recovery())
|
||||||
|
|
||||||
e.SetHTMLTemplate(template.Load())
|
e.SetHTMLTemplate(template.Load())
|
||||||
e.StaticFS("/static", static.FileSystem())
|
e.StaticFS("/static", static.FileSystem())
|
||||||
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/drone/drone/shared/envconfig"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Server struct {
|
|
||||||
Addr string
|
|
||||||
Cert string
|
|
||||||
Key string
|
|
||||||
}
|
|
||||||
|
|
||||||
func Load(env envconfig.Env) *Server {
|
|
||||||
return &Server{
|
|
||||||
Addr: env.String("SERVER_ADDR", ":8000"),
|
|
||||||
Cert: env.String("SERVER_CERT", ""),
|
|
||||||
Key: env.String("SERVER_KEY", ""),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) Run(handler http.Handler) {
|
|
||||||
log.Infof("starting server %s", s.Addr)
|
|
||||||
|
|
||||||
if len(s.Cert) != 0 {
|
|
||||||
log.Fatal(
|
|
||||||
http.ListenAndServeTLS(s.Addr, s.Cert, s.Key, handler),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
log.Fatal(
|
|
||||||
http.ListenAndServe(s.Addr, handler),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
66
vendor/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
Normal file
66
vendor/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
# 0.10.0
|
||||||
|
|
||||||
|
* feature: Add a test hook (#180)
|
||||||
|
* feature: `ParseLevel` is now case-insensitive (#326)
|
||||||
|
* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
|
||||||
|
* performance: avoid re-allocations on `WithFields` (#335)
|
||||||
|
|
||||||
|
# 0.9.0
|
||||||
|
|
||||||
|
* logrus/text_formatter: don't emit empty msg
|
||||||
|
* logrus/hooks/airbrake: move out of main repository
|
||||||
|
* logrus/hooks/sentry: move out of main repository
|
||||||
|
* logrus/hooks/papertrail: move out of main repository
|
||||||
|
* logrus/hooks/bugsnag: move out of main repository
|
||||||
|
* logrus/core: run tests with `-race`
|
||||||
|
* logrus/core: detect TTY based on `stderr`
|
||||||
|
* logrus/core: support `WithError` on logger
|
||||||
|
* logrus/core: Solaris support
|
||||||
|
|
||||||
|
# 0.8.7
|
||||||
|
|
||||||
|
* logrus/core: fix possible race (#216)
|
||||||
|
* logrus/doc: small typo fixes and doc improvements
|
||||||
|
|
||||||
|
|
||||||
|
# 0.8.6
|
||||||
|
|
||||||
|
* hooks/raven: allow passing an initialized client
|
||||||
|
|
||||||
|
# 0.8.5
|
||||||
|
|
||||||
|
* logrus/core: revert #208
|
||||||
|
|
||||||
|
# 0.8.4
|
||||||
|
|
||||||
|
* formatter/text: fix data race (#218)
|
||||||
|
|
||||||
|
# 0.8.3
|
||||||
|
|
||||||
|
* logrus/core: fix entry log level (#208)
|
||||||
|
* logrus/core: improve performance of text formatter by 40%
|
||||||
|
* logrus/core: expose `LevelHooks` type
|
||||||
|
* logrus/core: add support for DragonflyBSD and NetBSD
|
||||||
|
* formatter/text: print structs more verbosely
|
||||||
|
|
||||||
|
# 0.8.2
|
||||||
|
|
||||||
|
* logrus: fix more Fatal family functions
|
||||||
|
|
||||||
|
# 0.8.1
|
||||||
|
|
||||||
|
* logrus: fix not exiting on `Fatalf` and `Fatalln`
|
||||||
|
|
||||||
|
# 0.8.0
|
||||||
|
|
||||||
|
* logrus: defaults to stderr instead of stdout
|
||||||
|
* hooks/sentry: add special field for `*http.Request`
|
||||||
|
* formatter/text: ignore Windows for colors
|
||||||
|
|
||||||
|
# 0.7.3
|
||||||
|
|
||||||
|
* formatter/\*: allow configuration of timestamp layout
|
||||||
|
|
||||||
|
# 0.7.2
|
||||||
|
|
||||||
|
* formatter/text: Add configuration option for time format (#158)
|
168
vendor/github.com/Sirupsen/logrus/README.md
generated
vendored
168
vendor/github.com/Sirupsen/logrus/README.md
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus) [![godoc reference](https://godoc.org/github.com/Sirupsen/logrus?status.png)][godoc]
|
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](https://godoc.org/github.com/Sirupsen/logrus)
|
||||||
|
|
||||||
Logrus is a structured logger for Go (golang), completely API compatible with
|
Logrus is a structured logger for Go (golang), completely API compatible with
|
||||||
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
|
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
|
||||||
|
@ -12,7 +12,7 @@ plain text):
|
||||||
|
|
||||||
![Colored](http://i.imgur.com/PY7qMwd.png)
|
![Colored](http://i.imgur.com/PY7qMwd.png)
|
||||||
|
|
||||||
With `log.Formatter = new(logrus.JSONFormatter)`, for easy parsing by logstash
|
With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash
|
||||||
or Splunk:
|
or Splunk:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
@ -32,16 +32,18 @@ ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
||||||
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
||||||
```
|
```
|
||||||
|
|
||||||
With the default `log.Formatter = new(logrus.TextFormatter)` when a TTY is not
|
With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not
|
||||||
attached, the output is compatible with the
|
attached, the output is compatible with the
|
||||||
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
time="2014-04-20 15:36:23.830442383 -0400 EDT" level="info" msg="A group of walrus emerges from the ocean" animal="walrus" size=10
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
|
||||||
time="2014-04-20 15:36:23.830584199 -0400 EDT" level="warning" msg="The group's number increased tremendously!" omg=true number=122
|
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
|
||||||
time="2014-04-20 15:36:23.830596521 -0400 EDT" level="info" msg="A giant walrus appears!" animal="walrus" size=10
|
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
|
||||||
time="2014-04-20 15:36:23.830611837 -0400 EDT" level="info" msg="Tremendously sized cow enters the ocean." animal="walrus" size=9
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
||||||
time="2014-04-20 15:36:23.830626464 -0400 EDT" level="fatal" msg="The ice breaks!" omg=true number=100
|
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
||||||
|
exit status 1
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
@ -73,17 +75,12 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/Sirupsen/logrus/hooks/airbrake"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Log as JSON instead of the default ASCII formatter.
|
// Log as JSON instead of the default ASCII formatter.
|
||||||
log.SetFormatter(&log.JSONFormatter{})
|
log.SetFormatter(&log.JSONFormatter{})
|
||||||
|
|
||||||
// Use the Airbrake hook to report errors that have Error severity or above to
|
|
||||||
// an exception tracker. You can create custom hooks, see the Hooks section.
|
|
||||||
log.AddHook(&logrus_airbrake.AirbrakeHook{})
|
|
||||||
|
|
||||||
// Output to stderr instead of stdout, could also be a file.
|
// Output to stderr instead of stdout, could also be a file.
|
||||||
log.SetOutput(os.Stderr)
|
log.SetOutput(os.Stderr)
|
||||||
|
|
||||||
|
@ -106,6 +103,16 @@ func main() {
|
||||||
"omg": true,
|
"omg": true,
|
||||||
"number": 100,
|
"number": 100,
|
||||||
}).Fatal("The ice breaks!")
|
}).Fatal("The ice breaks!")
|
||||||
|
|
||||||
|
// A common pattern is to re-use fields between logging statements by re-using
|
||||||
|
// the logrus.Entry returned from WithFields()
|
||||||
|
contextLogger := log.WithFields(log.Fields{
|
||||||
|
"common": "this is a common field",
|
||||||
|
"other": "I also should be logged always",
|
||||||
|
})
|
||||||
|
|
||||||
|
contextLogger.Info("I'll be logged with common and other field")
|
||||||
|
contextLogger.Info("Me too")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -164,54 +171,22 @@ You can add hooks for logging levels. For example to send errors to an exception
|
||||||
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
||||||
multiple places simultaneously, e.g. syslog.
|
multiple places simultaneously, e.g. syslog.
|
||||||
|
|
||||||
```go
|
Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
||||||
// Not the real implementation of the Airbrake hook. Just a simple sample.
|
`init`:
|
||||||
import (
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
log.AddHook(new(AirbrakeHook))
|
|
||||||
}
|
|
||||||
|
|
||||||
type AirbrakeHook struct{}
|
|
||||||
|
|
||||||
// `Fire()` takes the entry that the hook is fired for. `entry.Data[]` contains
|
|
||||||
// the fields for the entry. See the Fields section of the README.
|
|
||||||
func (hook *AirbrakeHook) Fire(entry *logrus.Entry) error {
|
|
||||||
err := airbrake.Notify(entry.Data["error"].(error))
|
|
||||||
if err != nil {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"source": "airbrake",
|
|
||||||
"endpoint": airbrake.Endpoint,
|
|
||||||
}).Info("Failed to send error to Airbrake")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// `Levels()` returns a slice of `Levels` the hook is fired for.
|
|
||||||
func (hook *AirbrakeHook) Levels() []log.Level {
|
|
||||||
return []log.Level{
|
|
||||||
log.ErrorLevel,
|
|
||||||
log.FatalLevel,
|
|
||||||
log.PanicLevel,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Logrus comes with built-in hooks. Add those, or your custom hook, in `init`:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/Sirupsen/logrus/hooks/airbrake"
|
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
|
||||||
"github.com/Sirupsen/logrus/hooks/syslog"
|
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
|
||||||
"log/syslog"
|
"log/syslog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.AddHook(new(logrus_airbrake.AirbrakeHook))
|
|
||||||
|
// Use the Airbrake hook to report errors that have Error severity or above to
|
||||||
|
// an exception tracker. You can create custom hooks, see the Hooks section.
|
||||||
|
log.AddHook(airbrake.NewHook(123, "xyz", "production"))
|
||||||
|
|
||||||
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -221,26 +196,37 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
|
||||||
|
|
||||||
* [`github.com/Sirupsen/logrus/hooks/airbrake`](https://github.com/Sirupsen/logrus/blob/master/hooks/airbrake/airbrake.go)
|
| Hook | Description |
|
||||||
Send errors to an exception tracking service compatible with the Airbrake API.
|
| ----- | ----------- |
|
||||||
Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes.
|
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
|
||||||
|
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
|
||||||
|
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
|
||||||
|
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
||||||
|
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
||||||
|
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
|
||||||
|
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
|
||||||
|
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
||||||
|
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
||||||
|
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
||||||
|
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
|
||||||
|
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
|
||||||
|
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
|
||||||
|
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
|
||||||
|
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
|
||||||
|
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
|
||||||
|
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
|
||||||
|
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
|
||||||
|
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
|
||||||
|
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
|
||||||
|
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
|
||||||
|
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
|
||||||
|
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
|
||||||
|
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
|
||||||
|
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
|
||||||
|
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
|
||||||
|
|
||||||
* [`github.com/Sirupsen/logrus/hooks/papertrail`](https://github.com/Sirupsen/logrus/blob/master/hooks/papertrail/papertrail.go)
|
|
||||||
Send errors to the Papertrail hosted logging service via UDP.
|
|
||||||
|
|
||||||
* [`github.com/Sirupsen/logrus/hooks/syslog`](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go)
|
|
||||||
Send errors to remote syslog server.
|
|
||||||
Uses standard library `log/syslog` behind the scenes.
|
|
||||||
|
|
||||||
* [`github.com/nubo/hiprus`](https://github.com/nubo/hiprus)
|
|
||||||
Send errors to a channel in hipchat.
|
|
||||||
|
|
||||||
* [`github.com/sebest/logrusly`](https://github.com/sebest/logrusly)
|
|
||||||
Send logs to Loggly (https://www.loggly.com/)
|
|
||||||
|
|
||||||
* [`github.com/johntdyer/slackrus`](https://github.com/johntdyer/slackrus)
|
|
||||||
Hook for Slack chat.
|
|
||||||
|
|
||||||
#### Level logging
|
#### Level logging
|
||||||
|
|
||||||
|
@ -296,10 +282,10 @@ init() {
|
||||||
// do something here to set environment depending on an environment variable
|
// do something here to set environment depending on an environment variable
|
||||||
// or command-line flag
|
// or command-line flag
|
||||||
if Environment == "production" {
|
if Environment == "production" {
|
||||||
log.SetFormatter(logrus.JSONFormatter)
|
log.SetFormatter(&log.JSONFormatter{})
|
||||||
} else {
|
} else {
|
||||||
// The TextFormatter is default, you don't actually have to do this.
|
// The TextFormatter is default, you don't actually have to do this.
|
||||||
log.SetFormatter(logrus.TextFormatter)
|
log.SetFormatter(&log.TextFormatter{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -318,10 +304,16 @@ The built-in logging formatters are:
|
||||||
field to `true`. To force no colored output even if there is a TTY set the
|
field to `true`. To force no colored output even if there is a TTY set the
|
||||||
`DisableColors` field to `true`
|
`DisableColors` field to `true`
|
||||||
* `logrus.JSONFormatter`. Logs fields as JSON.
|
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||||
|
* `logrus/formatters/logstash.LogstashFormatter`. Logs fields as [Logstash](http://logstash.net) Events.
|
||||||
|
|
||||||
|
```go
|
||||||
|
logrus.SetFormatter(&logstash.LogstashFormatter{Type: "application_name"})
|
||||||
|
```
|
||||||
|
|
||||||
Third party logging formatters:
|
Third party logging formatters:
|
||||||
|
|
||||||
* [`zalgo`](https://github.com/aybabtme/logzalgo): invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
||||||
|
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||||
|
|
||||||
You can define your formatter by implementing the `Formatter` interface,
|
You can define your formatter by implementing the `Formatter` interface,
|
||||||
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
||||||
|
@ -334,7 +326,7 @@ type MyJSONFormatter struct {
|
||||||
|
|
||||||
log.SetFormatter(new(MyJSONFormatter))
|
log.SetFormatter(new(MyJSONFormatter))
|
||||||
|
|
||||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
// Note this doesn't include Time, Level and Message which are available on
|
// Note this doesn't include Time, Level and Message which are available on
|
||||||
// the Entry. Consult `godoc` on information about those fields or read the
|
// the Entry. Consult `godoc` on information about those fields or read the
|
||||||
// source of the official loggers.
|
// source of the official loggers.
|
||||||
|
@ -348,7 +340,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
|
||||||
#### Logger as an `io.Writer`
|
#### Logger as an `io.Writer`
|
||||||
|
|
||||||
Logrus can be transormed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
|
Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
w := logger.Writer()
|
w := logger.Writer()
|
||||||
|
@ -370,5 +362,27 @@ Log rotation is not provided with Logrus. Log rotation should be done by an
|
||||||
external program (like `logrotate(8)`) that can compress and delete old log
|
external program (like `logrotate(8)`) that can compress and delete old log
|
||||||
entries. It should not be a feature of the application-level logger.
|
entries. It should not be a feature of the application-level logger.
|
||||||
|
|
||||||
|
#### Tools
|
||||||
|
|
||||||
[godoc]: https://godoc.org/github.com/Sirupsen/logrus
|
| Tool | Description |
|
||||||
|
| ---- | ----------- |
|
||||||
|
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
|
||||||
|
|
||||||
|
#### Testing
|
||||||
|
|
||||||
|
Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
|
||||||
|
|
||||||
|
* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook
|
||||||
|
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
|
||||||
|
|
||||||
|
```go
|
||||||
|
logger, hook := NewNullLogger()
|
||||||
|
logger.Error("Hello error")
|
||||||
|
|
||||||
|
assert.Equal(1, len(hook.Entries))
|
||||||
|
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
|
||||||
|
assert.Equal("Hello error", hook.LastEntry().Message)
|
||||||
|
|
||||||
|
hook.Reset()
|
||||||
|
assert.Nil(hook.LastEntry())
|
||||||
|
```
|
||||||
|
|
26
vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
Normal file
26
vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
|
||||||
|
|
||||||
|
|
||||||
|
The simplest way to use Logrus is simply the package-level exported logger:
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"number": 1,
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A walrus appears")
|
||||||
|
}
|
||||||
|
|
||||||
|
Output:
|
||||||
|
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
|
||||||
|
|
||||||
|
For a full guide visit https://github.com/Sirupsen/logrus
|
||||||
|
*/
|
||||||
|
package logrus
|
20
vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
20
vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
|
@ -8,6 +8,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Defines the key when adding errors using WithError.
|
||||||
|
var ErrorKey = "error"
|
||||||
|
|
||||||
// An entry is the final or intermediate Logrus logging entry. It contains all
|
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||||
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
||||||
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
||||||
|
@ -53,6 +56,11 @@ func (entry *Entry) String() (string, error) {
|
||||||
return reader.String(), err
|
return reader.String(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
|
||||||
|
func (entry *Entry) WithError(err error) *Entry {
|
||||||
|
return entry.WithField(ErrorKey, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Add a single field to the Entry.
|
// Add a single field to the Entry.
|
||||||
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||||
return entry.WithFields(Fields{key: value})
|
return entry.WithFields(Fields{key: value})
|
||||||
|
@ -60,7 +68,7 @@ func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||||
|
|
||||||
// Add a map of fields to the Entry.
|
// Add a map of fields to the Entry.
|
||||||
func (entry *Entry) WithFields(fields Fields) *Entry {
|
func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||||
data := Fields{}
|
data := make(Fields, len(entry.Data)+len(fields))
|
||||||
for k, v := range entry.Data {
|
for k, v := range entry.Data {
|
||||||
data[k] = v
|
data[k] = v
|
||||||
}
|
}
|
||||||
|
@ -70,12 +78,14 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||||
return &Entry{Logger: entry.Logger, Data: data}
|
return &Entry{Logger: entry.Logger, Data: data}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) log(level Level, msg string) {
|
// This function is not declared with a pointer value because otherwise
|
||||||
|
// race conditions will occur when using multiple goroutines
|
||||||
|
func (entry Entry) log(level Level, msg string) {
|
||||||
entry.Time = time.Now()
|
entry.Time = time.Now()
|
||||||
entry.Level = level
|
entry.Level = level
|
||||||
entry.Message = msg
|
entry.Message = msg
|
||||||
|
|
||||||
if err := entry.Logger.Hooks.Fire(level, entry); err != nil {
|
if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
|
||||||
entry.Logger.mu.Lock()
|
entry.Logger.mu.Lock()
|
||||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||||
entry.Logger.mu.Unlock()
|
entry.Logger.mu.Unlock()
|
||||||
|
@ -100,7 +110,7 @@ func (entry *Entry) log(level Level, msg string) {
|
||||||
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||||
// directly here.
|
// directly here.
|
||||||
if level <= PanicLevel {
|
if level <= PanicLevel {
|
||||||
panic(entry)
|
panic(&entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,6 +198,7 @@ func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||||
if entry.Logger.Level >= FatalLevel {
|
if entry.Logger.Level >= FatalLevel {
|
||||||
entry.Fatal(fmt.Sprintf(format, args...))
|
entry.Fatal(fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||||
|
@ -234,6 +245,7 @@ func (entry *Entry) Fatalln(args ...interface{}) {
|
||||||
if entry.Logger.Level >= FatalLevel {
|
if entry.Logger.Level >= FatalLevel {
|
||||||
entry.Fatal(entry.sprintlnn(args...))
|
entry.Fatal(entry.sprintlnn(args...))
|
||||||
}
|
}
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Panicln(args ...interface{}) {
|
func (entry *Entry) Panicln(args ...interface{}) {
|
||||||
|
|
7
vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
7
vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
|
@ -36,6 +36,8 @@ func SetLevel(level Level) {
|
||||||
|
|
||||||
// GetLevel returns the standard logger level.
|
// GetLevel returns the standard logger level.
|
||||||
func GetLevel() Level {
|
func GetLevel() Level {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
return std.Level
|
return std.Level
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +48,11 @@ func AddHook(hook Hook) {
|
||||||
std.Hooks.Add(hook)
|
std.Hooks.Add(hook)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
||||||
|
func WithError(err error) *Entry {
|
||||||
|
return std.WithField(ErrorKey, err)
|
||||||
|
}
|
||||||
|
|
||||||
// WithField creates an entry from the standard logger and adds a field to
|
// WithField creates an entry from the standard logger and adds a field to
|
||||||
// it. If you want multiple fields, use `WithFields`.
|
// it. If you want multiple fields, use `WithFields`.
|
||||||
//
|
//
|
||||||
|
|
4
vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
4
vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
|
@ -1,5 +1,9 @@
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
const DefaultTimestampFormat = time.RFC3339
|
||||||
|
|
||||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||||
// `Entry`. It exposes all the fields, including the default ones:
|
// `Entry`. It exposes all the fields, including the default ones:
|
||||||
//
|
//
|
||||||
|
|
6
vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
6
vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
|
@ -11,11 +11,11 @@ type Hook interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal type for storing the hooks on a logger instance.
|
// Internal type for storing the hooks on a logger instance.
|
||||||
type levelHooks map[Level][]Hook
|
type LevelHooks map[Level][]Hook
|
||||||
|
|
||||||
// Add a hook to an instance of logger. This is called with
|
// Add a hook to an instance of logger. This is called with
|
||||||
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
||||||
func (hooks levelHooks) Add(hook Hook) {
|
func (hooks LevelHooks) Add(hook Hook) {
|
||||||
for _, level := range hook.Levels() {
|
for _, level := range hook.Levels() {
|
||||||
hooks[level] = append(hooks[level], hook)
|
hooks[level] = append(hooks[level], hook)
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ func (hooks levelHooks) Add(hook Hook) {
|
||||||
|
|
||||||
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
||||||
// appropriate hooks for a log entry.
|
// appropriate hooks for a log entry.
|
||||||
func (hooks levelHooks) Fire(level Level, entry *Entry) error {
|
func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
|
||||||
for _, hook := range hooks[level] {
|
for _, hook := range hooks[level] {
|
||||||
if err := hook.Fire(entry); err != nil {
|
if err := hook.Fire(entry); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
23
vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
23
vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
|
@ -3,18 +3,33 @@ package logrus
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type JSONFormatter struct{}
|
type JSONFormatter struct {
|
||||||
|
// TimestampFormat sets the format used for marshaling timestamps.
|
||||||
|
TimestampFormat string
|
||||||
|
}
|
||||||
|
|
||||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
data := make(Fields, len(entry.Data)+3)
|
data := make(Fields, len(entry.Data)+3)
|
||||||
for k, v := range entry.Data {
|
for k, v := range entry.Data {
|
||||||
data[k] = v
|
switch v := v.(type) {
|
||||||
|
case error:
|
||||||
|
// Otherwise errors are ignored by `encoding/json`
|
||||||
|
// https://github.com/Sirupsen/logrus/issues/137
|
||||||
|
data[k] = v.Error()
|
||||||
|
default:
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
}
|
}
|
||||||
prefixFieldClashes(data)
|
prefixFieldClashes(data)
|
||||||
data["time"] = entry.Time.Format(time.RFC3339)
|
|
||||||
|
timestampFormat := f.TimestampFormat
|
||||||
|
if timestampFormat == "" {
|
||||||
|
timestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
data["time"] = entry.Time.Format(timestampFormat)
|
||||||
data["msg"] = entry.Message
|
data["msg"] = entry.Message
|
||||||
data["level"] = entry.Level.String()
|
data["level"] = entry.Level.String()
|
||||||
|
|
||||||
|
|
105
vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
105
vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
|
@ -8,13 +8,13 @@ import (
|
||||||
|
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||||
// file, or leave it default which is `os.Stdout`. You can also set this to
|
// file, or leave it default which is `os.Stderr`. You can also set this to
|
||||||
// something more adventorous, such as logging to Kafka.
|
// something more adventorous, such as logging to Kafka.
|
||||||
Out io.Writer
|
Out io.Writer
|
||||||
// Hooks for the logger instance. These allow firing events based on logging
|
// Hooks for the logger instance. These allow firing events based on logging
|
||||||
// levels and log entries. For example, to send errors to an error tracking
|
// levels and log entries. For example, to send errors to an error tracking
|
||||||
// service, log to StatsD or dump the core on fatal errors.
|
// service, log to StatsD or dump the core on fatal errors.
|
||||||
Hooks levelHooks
|
Hooks LevelHooks
|
||||||
// All log entries pass through the formatter before logged to Out. The
|
// All log entries pass through the formatter before logged to Out. The
|
||||||
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
||||||
// TextFormatter is the default. In development (when a TTY is attached) it
|
// TextFormatter is the default. In development (when a TTY is attached) it
|
||||||
|
@ -37,23 +37,23 @@ type Logger struct {
|
||||||
// var log = &Logger{
|
// var log = &Logger{
|
||||||
// Out: os.Stderr,
|
// Out: os.Stderr,
|
||||||
// Formatter: new(JSONFormatter),
|
// Formatter: new(JSONFormatter),
|
||||||
// Hooks: make(levelHooks),
|
// Hooks: make(LevelHooks),
|
||||||
// Level: logrus.DebugLevel,
|
// Level: logrus.DebugLevel,
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// It's recommended to make this a global instance called `log`.
|
// It's recommended to make this a global instance called `log`.
|
||||||
func New() *Logger {
|
func New() *Logger {
|
||||||
return &Logger{
|
return &Logger{
|
||||||
Out: os.Stdout,
|
Out: os.Stderr,
|
||||||
Formatter: new(TextFormatter),
|
Formatter: new(TextFormatter),
|
||||||
Hooks: make(levelHooks),
|
Hooks: make(LevelHooks),
|
||||||
Level: InfoLevel,
|
Level: InfoLevel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a field to the log entry, note that you it doesn't log until you call
|
// Adds a field to the log entry, note that you it doesn't log until you call
|
||||||
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
||||||
// Ff you want multiple fields, use `WithFields`.
|
// If you want multiple fields, use `WithFields`.
|
||||||
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||||
return NewEntry(logger).WithField(key, value)
|
return NewEntry(logger).WithField(key, value)
|
||||||
}
|
}
|
||||||
|
@ -64,12 +64,22 @@ func (logger *Logger) WithFields(fields Fields) *Entry {
|
||||||
return NewEntry(logger).WithFields(fields)
|
return NewEntry(logger).WithFields(fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add an error as single field to the log entry. All it does is call
|
||||||
|
// `WithError` for the given `error`.
|
||||||
|
func (logger *Logger) WithError(err error) *Entry {
|
||||||
|
return NewEntry(logger).WithError(err)
|
||||||
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Debugf(format, args...)
|
if logger.Level >= DebugLevel {
|
||||||
|
NewEntry(logger).Debugf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Infof(format, args...)
|
if logger.Level >= InfoLevel {
|
||||||
|
NewEntry(logger).Infof(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Printf(format string, args ...interface{}) {
|
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||||
|
@ -77,31 +87,46 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Warnf(format, args...)
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Warnf(format, args...)
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Errorf(format, args...)
|
if logger.Level >= ErrorLevel {
|
||||||
|
NewEntry(logger).Errorf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Fatalf(format, args...)
|
if logger.Level >= FatalLevel {
|
||||||
|
NewEntry(logger).Fatalf(format, args...)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Panicf(format, args...)
|
if logger.Level >= PanicLevel {
|
||||||
|
NewEntry(logger).Panicf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debug(args ...interface{}) {
|
func (logger *Logger) Debug(args ...interface{}) {
|
||||||
NewEntry(logger).Debug(args...)
|
if logger.Level >= DebugLevel {
|
||||||
|
NewEntry(logger).Debug(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Info(args ...interface{}) {
|
func (logger *Logger) Info(args ...interface{}) {
|
||||||
NewEntry(logger).Info(args...)
|
if logger.Level >= InfoLevel {
|
||||||
|
NewEntry(logger).Info(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Print(args ...interface{}) {
|
func (logger *Logger) Print(args ...interface{}) {
|
||||||
|
@ -109,31 +134,46 @@ func (logger *Logger) Print(args ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warn(args ...interface{}) {
|
func (logger *Logger) Warn(args ...interface{}) {
|
||||||
NewEntry(logger).Warn(args...)
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warn(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warning(args ...interface{}) {
|
func (logger *Logger) Warning(args ...interface{}) {
|
||||||
NewEntry(logger).Warn(args...)
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warn(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Error(args ...interface{}) {
|
func (logger *Logger) Error(args ...interface{}) {
|
||||||
NewEntry(logger).Error(args...)
|
if logger.Level >= ErrorLevel {
|
||||||
|
NewEntry(logger).Error(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Fatal(args ...interface{}) {
|
func (logger *Logger) Fatal(args ...interface{}) {
|
||||||
NewEntry(logger).Fatal(args...)
|
if logger.Level >= FatalLevel {
|
||||||
|
NewEntry(logger).Fatal(args...)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panic(args ...interface{}) {
|
func (logger *Logger) Panic(args ...interface{}) {
|
||||||
NewEntry(logger).Panic(args...)
|
if logger.Level >= PanicLevel {
|
||||||
|
NewEntry(logger).Panic(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debugln(args ...interface{}) {
|
func (logger *Logger) Debugln(args ...interface{}) {
|
||||||
NewEntry(logger).Debugln(args...)
|
if logger.Level >= DebugLevel {
|
||||||
|
NewEntry(logger).Debugln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Infoln(args ...interface{}) {
|
func (logger *Logger) Infoln(args ...interface{}) {
|
||||||
NewEntry(logger).Infoln(args...)
|
if logger.Level >= InfoLevel {
|
||||||
|
NewEntry(logger).Infoln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Println(args ...interface{}) {
|
func (logger *Logger) Println(args ...interface{}) {
|
||||||
|
@ -141,21 +181,32 @@ func (logger *Logger) Println(args ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warnln(args ...interface{}) {
|
func (logger *Logger) Warnln(args ...interface{}) {
|
||||||
NewEntry(logger).Warnln(args...)
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warningln(args ...interface{}) {
|
func (logger *Logger) Warningln(args ...interface{}) {
|
||||||
NewEntry(logger).Warnln(args...)
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Errorln(args ...interface{}) {
|
func (logger *Logger) Errorln(args ...interface{}) {
|
||||||
NewEntry(logger).Errorln(args...)
|
if logger.Level >= ErrorLevel {
|
||||||
|
NewEntry(logger).Errorln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||||
NewEntry(logger).Fatalln(args...)
|
if logger.Level >= FatalLevel {
|
||||||
|
NewEntry(logger).Fatalln(args...)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panicln(args ...interface{}) {
|
func (logger *Logger) Panicln(args ...interface{}) {
|
||||||
NewEntry(logger).Panicln(args...)
|
if logger.Level >= PanicLevel {
|
||||||
|
NewEntry(logger).Panicln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
53
vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
53
vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
|
@ -3,6 +3,7 @@ package logrus
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fields type, used to pass to `WithFields`.
|
// Fields type, used to pass to `WithFields`.
|
||||||
|
@ -33,7 +34,7 @@ func (level Level) String() string {
|
||||||
|
|
||||||
// ParseLevel takes a string level and returns the Logrus log level constant.
|
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||||
func ParseLevel(lvl string) (Level, error) {
|
func ParseLevel(lvl string) (Level, error) {
|
||||||
switch lvl {
|
switch strings.ToLower(lvl) {
|
||||||
case "panic":
|
case "panic":
|
||||||
return PanicLevel, nil
|
return PanicLevel, nil
|
||||||
case "fatal":
|
case "fatal":
|
||||||
|
@ -52,6 +53,16 @@ func ParseLevel(lvl string) (Level, error) {
|
||||||
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A constant exposing all logging levels
|
||||||
|
var AllLevels = []Level{
|
||||||
|
PanicLevel,
|
||||||
|
FatalLevel,
|
||||||
|
ErrorLevel,
|
||||||
|
WarnLevel,
|
||||||
|
InfoLevel,
|
||||||
|
DebugLevel,
|
||||||
|
}
|
||||||
|
|
||||||
// These are the different logging levels. You can set the logging level to log
|
// These are the different logging levels. You can set the logging level to log
|
||||||
// on your instance of logger, obtained with `logrus.New()`.
|
// on your instance of logger, obtained with `logrus.New()`.
|
||||||
const (
|
const (
|
||||||
|
@ -74,7 +85,11 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Won't compile if StdLogger can't be realized by a log.Logger
|
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||||
var _ StdLogger = &log.Logger{}
|
var (
|
||||||
|
_ StdLogger = &log.Logger{}
|
||||||
|
_ StdLogger = &Entry{}
|
||||||
|
_ StdLogger = &Logger{}
|
||||||
|
)
|
||||||
|
|
||||||
// StdLogger is what your logrus-enabled library should take, that way
|
// StdLogger is what your logrus-enabled library should take, that way
|
||||||
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
||||||
|
@ -92,3 +107,37 @@ type StdLogger interface {
|
||||||
Panicf(string, ...interface{})
|
Panicf(string, ...interface{})
|
||||||
Panicln(...interface{})
|
Panicln(...interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The FieldLogger interface generalizes the Entry and Logger types
|
||||||
|
type FieldLogger interface {
|
||||||
|
WithField(key string, value interface{}) *Entry
|
||||||
|
WithFields(fields Fields) *Entry
|
||||||
|
WithError(err error) *Entry
|
||||||
|
|
||||||
|
Debugf(format string, args ...interface{})
|
||||||
|
Infof(format string, args ...interface{})
|
||||||
|
Printf(format string, args ...interface{})
|
||||||
|
Warnf(format string, args ...interface{})
|
||||||
|
Warningf(format string, args ...interface{})
|
||||||
|
Errorf(format string, args ...interface{})
|
||||||
|
Fatalf(format string, args ...interface{})
|
||||||
|
Panicf(format string, args ...interface{})
|
||||||
|
|
||||||
|
Debug(args ...interface{})
|
||||||
|
Info(args ...interface{})
|
||||||
|
Print(args ...interface{})
|
||||||
|
Warn(args ...interface{})
|
||||||
|
Warning(args ...interface{})
|
||||||
|
Error(args ...interface{})
|
||||||
|
Fatal(args ...interface{})
|
||||||
|
Panic(args ...interface{})
|
||||||
|
|
||||||
|
Debugln(args ...interface{})
|
||||||
|
Infoln(args ...interface{})
|
||||||
|
Println(args ...interface{})
|
||||||
|
Warnln(args ...interface{})
|
||||||
|
Warningln(args ...interface{})
|
||||||
|
Errorln(args ...interface{})
|
||||||
|
Fatalln(args ...interface{})
|
||||||
|
Panicln(args ...interface{})
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// +build darwin freebsd openbsd netbsd dragonfly
|
||||||
|
|
||||||
package logrus
|
package logrus
|
||||||
|
|
12
vendor/github.com/Sirupsen/logrus/terminal_darwin.go
generated
vendored
12
vendor/github.com/Sirupsen/logrus/terminal_darwin.go
generated
vendored
|
@ -1,12 +0,0 @@
|
||||||
// Based on ssh/terminal:
|
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
const ioctlReadTermios = syscall.TIOCGETA
|
|
||||||
|
|
||||||
type Termios syscall.Termios
|
|
20
vendor/github.com/Sirupsen/logrus/terminal_freebsd.go
generated
vendored
20
vendor/github.com/Sirupsen/logrus/terminal_freebsd.go
generated
vendored
|
@ -1,20 +0,0 @@
|
||||||
/*
|
|
||||||
Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin.
|
|
||||||
*/
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
const ioctlReadTermios = syscall.TIOCGETA
|
|
||||||
|
|
||||||
type Termios struct {
|
|
||||||
Iflag uint32
|
|
||||||
Oflag uint32
|
|
||||||
Cflag uint32
|
|
||||||
Lflag uint32
|
|
||||||
Cc [20]uint8
|
|
||||||
Ispeed uint32
|
|
||||||
Ospeed uint32
|
|
||||||
}
|
|
6
vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
6
vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
|
@ -3,7 +3,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build linux darwin freebsd openbsd
|
// +build linux darwin freebsd openbsd netbsd dragonfly
|
||||||
|
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
|
@ -12,9 +12,9 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||||
func IsTerminal() bool {
|
func IsTerminal() bool {
|
||||||
fd := syscall.Stdout
|
fd := syscall.Stderr
|
||||||
var termios Termios
|
var termios Termios
|
||||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||||
return err == 0
|
return err == 0
|
||||||
|
|
15
vendor/github.com/Sirupsen/logrus/terminal_solaris.go
generated
vendored
Normal file
15
vendor/github.com/Sirupsen/logrus/terminal_solaris.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// +build solaris
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal() bool {
|
||||||
|
_, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
|
||||||
|
return err == nil
|
||||||
|
}
|
4
vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
4
vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
|
@ -18,9 +18,9 @@ var (
|
||||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||||
func IsTerminal() bool {
|
func IsTerminal() bool {
|
||||||
fd := syscall.Stdout
|
fd := syscall.Stderr
|
||||||
var st uint32
|
var st uint32
|
||||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
||||||
return r != 0 && e == 0
|
return r != 0 && e == 0
|
||||||
|
|
85
vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
85
vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
|
@ -3,7 +3,7 @@ package logrus
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -15,12 +15,12 @@ const (
|
||||||
green = 32
|
green = 32
|
||||||
yellow = 33
|
yellow = 33
|
||||||
blue = 34
|
blue = 34
|
||||||
|
gray = 37
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
baseTimestamp time.Time
|
baseTimestamp time.Time
|
||||||
isTerminal bool
|
isTerminal bool
|
||||||
noQuoteNeeded *regexp.Regexp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -34,35 +34,59 @@ func miniTS() int {
|
||||||
|
|
||||||
type TextFormatter struct {
|
type TextFormatter struct {
|
||||||
// Set to true to bypass checking for a TTY before outputting colors.
|
// Set to true to bypass checking for a TTY before outputting colors.
|
||||||
ForceColors bool
|
ForceColors bool
|
||||||
|
|
||||||
|
// Force disabling colors.
|
||||||
DisableColors bool
|
DisableColors bool
|
||||||
// Set to true to disable timestamp logging (useful when the output
|
|
||||||
// is redirected to a logging system already adding a timestamp)
|
// Disable timestamp logging. useful when output is redirected to logging
|
||||||
|
// system that already adds timestamps.
|
||||||
DisableTimestamp bool
|
DisableTimestamp bool
|
||||||
|
|
||||||
|
// Enable logging the full timestamp when a TTY is attached instead of just
|
||||||
|
// the time passed since beginning of execution.
|
||||||
|
FullTimestamp bool
|
||||||
|
|
||||||
|
// TimestampFormat to use for display when a full timestamp is printed
|
||||||
|
TimestampFormat string
|
||||||
|
|
||||||
|
// The fields are sorted by default for a consistent output. For applications
|
||||||
|
// that log extremely frequently and don't use the JSON formatter this may not
|
||||||
|
// be desired.
|
||||||
|
DisableSorting bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
|
||||||
var keys []string = make([]string, 0, len(entry.Data))
|
var keys []string = make([]string, 0, len(entry.Data))
|
||||||
for k := range entry.Data {
|
for k := range entry.Data {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
}
|
}
|
||||||
sort.Strings(keys)
|
|
||||||
|
if !f.DisableSorting {
|
||||||
|
sort.Strings(keys)
|
||||||
|
}
|
||||||
|
|
||||||
b := &bytes.Buffer{}
|
b := &bytes.Buffer{}
|
||||||
|
|
||||||
prefixFieldClashes(entry.Data)
|
prefixFieldClashes(entry.Data)
|
||||||
|
|
||||||
isColored := (f.ForceColors || isTerminal) && !f.DisableColors
|
isColorTerminal := isTerminal && (runtime.GOOS != "windows")
|
||||||
|
isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
|
||||||
|
|
||||||
|
timestampFormat := f.TimestampFormat
|
||||||
|
if timestampFormat == "" {
|
||||||
|
timestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
if isColored {
|
if isColored {
|
||||||
printColored(b, entry, keys)
|
f.printColored(b, entry, keys, timestampFormat)
|
||||||
} else {
|
} else {
|
||||||
if !f.DisableTimestamp {
|
if !f.DisableTimestamp {
|
||||||
f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
|
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
|
||||||
}
|
}
|
||||||
f.appendKeyValue(b, "level", entry.Level.String())
|
f.appendKeyValue(b, "level", entry.Level.String())
|
||||||
f.appendKeyValue(b, "msg", entry.Message)
|
if entry.Message != "" {
|
||||||
|
f.appendKeyValue(b, "msg", entry.Message)
|
||||||
|
}
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
f.appendKeyValue(b, key, entry.Data[key])
|
f.appendKeyValue(b, key, entry.Data[key])
|
||||||
}
|
}
|
||||||
|
@ -72,9 +96,11 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
return b.Bytes(), nil
|
return b.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func printColored(b *bytes.Buffer, entry *Entry, keys []string) {
|
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
|
||||||
var levelColor int
|
var levelColor int
|
||||||
switch entry.Level {
|
switch entry.Level {
|
||||||
|
case DebugLevel:
|
||||||
|
levelColor = gray
|
||||||
case WarnLevel:
|
case WarnLevel:
|
||||||
levelColor = yellow
|
levelColor = yellow
|
||||||
case ErrorLevel, FatalLevel, PanicLevel:
|
case ErrorLevel, FatalLevel, PanicLevel:
|
||||||
|
@ -85,10 +111,14 @@ func printColored(b *bytes.Buffer, entry *Entry, keys []string) {
|
||||||
|
|
||||||
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
||||||
|
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
if !f.FullTimestamp {
|
||||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
|
||||||
|
}
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
v := entry.Data[k]
|
v := entry.Data[k]
|
||||||
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v)
|
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +126,7 @@ func needsQuoting(text string) bool {
|
||||||
for _, ch := range text {
|
for _, ch := range text {
|
||||||
if !((ch >= 'a' && ch <= 'z') ||
|
if !((ch >= 'a' && ch <= 'z') ||
|
||||||
(ch >= 'A' && ch <= 'Z') ||
|
(ch >= 'A' && ch <= 'Z') ||
|
||||||
(ch >= '0' && ch < '9') ||
|
(ch >= '0' && ch <= '9') ||
|
||||||
ch == '-' || ch == '.') {
|
ch == '-' || ch == '.') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -104,21 +134,28 @@ func needsQuoting(text string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key, value interface{}) {
|
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
||||||
switch value.(type) {
|
|
||||||
|
b.WriteString(key)
|
||||||
|
b.WriteByte('=')
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
if needsQuoting(value.(string)) {
|
if needsQuoting(value) {
|
||||||
fmt.Fprintf(b, "%v=%s ", key, value)
|
b.WriteString(value)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(b, "%v=%q ", key, value)
|
fmt.Fprintf(b, "%q", value)
|
||||||
}
|
}
|
||||||
case error:
|
case error:
|
||||||
if needsQuoting(value.(error).Error()) {
|
errmsg := value.Error()
|
||||||
fmt.Fprintf(b, "%v=%s ", key, value)
|
if needsQuoting(errmsg) {
|
||||||
|
b.WriteString(errmsg)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(b, "%v=%q ", key, value)
|
fmt.Fprintf(b, "%q", value)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
fmt.Fprintf(b, "%v=%v ", key, value)
|
fmt.Fprint(b, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.WriteByte(' ')
|
||||||
}
|
}
|
||||||
|
|
2
vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
2
vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
|
@ -6,7 +6,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (logger *Logger) Writer() (*io.PipeWriter) {
|
func (logger *Logger) Writer() *io.PipeWriter {
|
||||||
reader, writer := io.Pipe()
|
reader, writer := io.Pipe()
|
||||||
|
|
||||||
go logger.writerScanner(reader)
|
go logger.writerScanner(reader)
|
||||||
|
|
51
vendor/github.com/gin-gonic/contrib/ginrus/ginrus.go
generated
vendored
Normal file
51
vendor/github.com/gin-gonic/contrib/ginrus/ginrus.go
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// Package ginrus provides log handling using logrus package.
|
||||||
|
//
|
||||||
|
// Based on github.com/stephenmuss/ginerus but adds more options.
|
||||||
|
package ginrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Ginrus returns a gin.HandlerFunc (middleware) that logs requests using logrus.
|
||||||
|
//
|
||||||
|
// Requests with errors are logged using logrus.Error().
|
||||||
|
// Requests without errors are logged using logrus.Info().
|
||||||
|
//
|
||||||
|
// It receives:
|
||||||
|
// 1. A time package format string (e.g. time.RFC3339).
|
||||||
|
// 2. A boolean stating whether to use UTC time zone or local.
|
||||||
|
func Ginrus(logger *logrus.Logger, timeFormat string, utc bool) gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
start := time.Now()
|
||||||
|
// some evil middlewares modify this values
|
||||||
|
path := c.Request.URL.Path
|
||||||
|
c.Next()
|
||||||
|
|
||||||
|
end := time.Now()
|
||||||
|
latency := end.Sub(start)
|
||||||
|
if utc {
|
||||||
|
end = end.UTC()
|
||||||
|
}
|
||||||
|
|
||||||
|
entry := logger.WithFields(logrus.Fields{
|
||||||
|
"status": c.Writer.Status(),
|
||||||
|
"method": c.Request.Method,
|
||||||
|
"path": path,
|
||||||
|
"ip": c.ClientIP(),
|
||||||
|
"latency": latency,
|
||||||
|
"user-agent": c.Request.UserAgent(),
|
||||||
|
"time": end.Format(timeFormat),
|
||||||
|
})
|
||||||
|
|
||||||
|
if len(c.Errors) > 0 {
|
||||||
|
// Append error field if this is an erroneous request.
|
||||||
|
entry.Error(c.Errors.String())
|
||||||
|
} else {
|
||||||
|
entry.Info()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
vendor/github.com/ianschenck/envflag/LICENSE
generated
vendored
Normal file
27
vendor/github.com/ianschenck/envflag/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2013, Ian Schenck
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
Redistributions in binary form must reproduce the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
|
||||||
|
Neither the name of Ian Schenck nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this
|
||||||
|
software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
37
vendor/github.com/ianschenck/envflag/README.md
generated
vendored
Normal file
37
vendor/github.com/ianschenck/envflag/README.md
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
envflag
|
||||||
|
=======
|
||||||
|
|
||||||
|
Golang flags, but bolted onto the environment rather than the command-line.
|
||||||
|
|
||||||
|
Read the [godocs](http://godoc.org/github.com/ianschenck/envflag).
|
||||||
|
|
||||||
|
Motivation
|
||||||
|
==========
|
||||||
|
|
||||||
|
Some like the distinction that command-line flags control behavior
|
||||||
|
while environment variables configure. Also
|
||||||
|
[12-factor](http://12factor.net/) recommends the use of environment
|
||||||
|
variables for configuration. The interface of the golang flag package
|
||||||
|
is well designed and easy to use, and allows for other lists
|
||||||
|
(os.Environ() vs os.Args) to be parsed as flags. It makes sense then
|
||||||
|
to use the same interface, the same types, and the same parsing
|
||||||
|
(caveat: there is some ugly string hacking to make environment
|
||||||
|
variables look like flags) to the same ends.
|
||||||
|
|
||||||
|
Differences
|
||||||
|
===========
|
||||||
|
|
||||||
|
Calling `flag.Parse()` will not parse environment flags. Calling
|
||||||
|
`envflag.Parse()` will not parse command-line flags. There is no good
|
||||||
|
reason to combine these two when the net savings is a single line in a
|
||||||
|
`func main()`. Furthermore, doing so would require users to accept a
|
||||||
|
precedence order of my choosing.
|
||||||
|
|
||||||
|
The presence of an environment variable named `h` or `help` will
|
||||||
|
probably cause problems (print Usage and os.Exit(0)). Work around this
|
||||||
|
by defining those flags somewhere (and ignoring them).
|
||||||
|
|
||||||
|
Before calling `Flagset.Parse` on `EnvironmentFlags`, the environment
|
||||||
|
variables being passed to `Parse` are trimmed down using
|
||||||
|
`Lookup`. This behavior is different from `flag.Parse` in that extra
|
||||||
|
environment variables are ignored (and won't crash `envflag.Parse`).
|
192
vendor/github.com/ianschenck/envflag/envflag.go
generated
vendored
Normal file
192
vendor/github.com/ianschenck/envflag/envflag.go
generated
vendored
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
// Copyright 2013 Ian Schenck. Use of this source code is governed by
|
||||||
|
// a license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package envflag adds environment variable flags to the flag package.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
Define flags using envflag.String(), Bool(), Int(), etc. This package
|
||||||
|
works nearly the same as the stdlib flag package. Parsing the
|
||||||
|
Environment flags is done by calling envflag.Parse()
|
||||||
|
|
||||||
|
It will *not* attempt to parse any normally-defined command-line
|
||||||
|
flags. Command-line flags are explicitly left alone and separate.
|
||||||
|
*/
|
||||||
|
package envflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VisitAll visits the environment flags in lexicographical order,
|
||||||
|
// calling fn for each. It visits all flags, even those not set.
|
||||||
|
func VisitAll(fn func(*flag.Flag)) {
|
||||||
|
EnvironmentFlags.VisitAll(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visit visits the environment flags in lexicographical order,
|
||||||
|
// calling fn for each. It visits only those flags that have been
|
||||||
|
// set.
|
||||||
|
func Visit(fn func(*flag.Flag)) {
|
||||||
|
EnvironmentFlags.Visit(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup returns the Flag structure of the named environment flag,
|
||||||
|
// returning nil if none exists.
|
||||||
|
func Lookup(name string) *flag.Flag {
|
||||||
|
return EnvironmentFlags.Lookup(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the value of the named environment flag.
|
||||||
|
func Set(name, value string) error {
|
||||||
|
return EnvironmentFlags.Set(name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolVar defines a bool flag with specified name, default value, and
|
||||||
|
// usage string. The argument p points to a bool variable in which to
|
||||||
|
// store the value of the flag.
|
||||||
|
func BoolVar(p *bool, name string, value bool, usage string) {
|
||||||
|
EnvironmentFlags.BoolVar(p, name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool defines a bool flag with specified name, default value, and
|
||||||
|
// usage string. The return value is the address of a bool variable
|
||||||
|
// that stores the value of the flag.
|
||||||
|
func Bool(name string, value bool, usage string) *bool {
|
||||||
|
return EnvironmentFlags.Bool(name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntVar defines an int flag with specified name, default value, and
|
||||||
|
// usage string. The argument p points to an int variable in which to
|
||||||
|
// store the value of the flag.
|
||||||
|
func IntVar(p *int, name string, value int, usage string) {
|
||||||
|
EnvironmentFlags.IntVar(p, name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int defines an int flag with specified name, default value, and
|
||||||
|
// usage string. The return value is the address of an int variable
|
||||||
|
// that stores the value of the flag.
|
||||||
|
func Int(name string, value int, usage string) *int {
|
||||||
|
return EnvironmentFlags.Int(name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64Var defines an int64 flag with specified name, default value,
|
||||||
|
// and usage string. The argument p points to an int64 variable in
|
||||||
|
// which to store the value of the flag.
|
||||||
|
func Int64Var(p *int64, name string, value int64, usage string) {
|
||||||
|
EnvironmentFlags.Int64Var(p, name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64 defines an int64 flag with specified name, default value, and
|
||||||
|
// usage string. The return value is the address of an int64 variable
|
||||||
|
// that stores the value of the flag.
|
||||||
|
func Int64(name string, value int64, usage string) *int64 {
|
||||||
|
return EnvironmentFlags.Int64(name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintVar defines a uint flag with specified name, default value, and
|
||||||
|
// usage string. The argument p points to a uint variable in which to
|
||||||
|
// store the value of the flag.
|
||||||
|
func UintVar(p *uint, name string, value uint, usage string) {
|
||||||
|
EnvironmentFlags.UintVar(p, name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint defines a uint flag with specified name, default value, and
|
||||||
|
// usage string. The return value is the address of a uint variable
|
||||||
|
// that stores the value of the flag.
|
||||||
|
func Uint(name string, value uint, usage string) *uint {
|
||||||
|
return EnvironmentFlags.Uint(name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64Var defines a uint64 flag with specified name, default value,
|
||||||
|
// and usage string. The argument p points to a uint64 variable in
|
||||||
|
// which to store the value of the flag.
|
||||||
|
func Uint64Var(p *uint64, name string, value uint64, usage string) {
|
||||||
|
EnvironmentFlags.Uint64Var(p, name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64 defines a uint64 flag with specified name, default value,
|
||||||
|
// and usage string. The return value is the address of a uint64
|
||||||
|
// variable that stores the value of the flag.
|
||||||
|
func Uint64(name string, value uint64, usage string) *uint64 {
|
||||||
|
return EnvironmentFlags.Uint64(name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringVar defines a string flag with specified name, default value,
|
||||||
|
// and usage string. The argument p points to a string variable in
|
||||||
|
// which to store the value of the flag.
|
||||||
|
func StringVar(p *string, name string, value string, usage string) {
|
||||||
|
EnvironmentFlags.StringVar(p, name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String defines a string flag with specified name, default value,
|
||||||
|
// and usage string. The return value is the address of a string
|
||||||
|
// variable that stores the value of the flag.
|
||||||
|
func String(name string, value string, usage string) *string {
|
||||||
|
return EnvironmentFlags.String(name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Var defines a float64 flag with specified name, default
|
||||||
|
// value, and usage string. The argument p points to a float64
|
||||||
|
// variable in which to store the value of the flag.
|
||||||
|
func Float64Var(p *float64, name string, value float64, usage string) {
|
||||||
|
EnvironmentFlags.Float64Var(p, name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64 defines a float64 flag with specified name, default value,
|
||||||
|
// and usage string. The return value is the address of a float64
|
||||||
|
// variable that stores the value of the flag.
|
||||||
|
func Float64(name string, value float64, usage string) *float64 {
|
||||||
|
return EnvironmentFlags.Float64(name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DurationVar defines a time.Duration flag with specified name,
|
||||||
|
// default value, and usage string. The argument p points to a
|
||||||
|
// time.Duration variable in which to store the value of the flag.
|
||||||
|
func DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
|
||||||
|
EnvironmentFlags.DurationVar(p, name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duration defines a time.Duration flag with specified name, default
|
||||||
|
// value, and usage string. The return value is the address of a
|
||||||
|
// time.Duration variable that stores the value of the flag.
|
||||||
|
func Duration(name string, value time.Duration, usage string) *time.Duration {
|
||||||
|
return EnvironmentFlags.Duration(name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintDefaults prints to standard error the default values of all
|
||||||
|
// defined environment flags.
|
||||||
|
func PrintDefaults() {
|
||||||
|
EnvironmentFlags.PrintDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses the environment flags from os.Environ. Must be called
|
||||||
|
// after all flags are defined and before flags are accessed by the
|
||||||
|
// program.
|
||||||
|
func Parse() {
|
||||||
|
env := os.Environ()
|
||||||
|
// Clean up and "fake" some flag k/v pairs.
|
||||||
|
args := make([]string, 0, len(env))
|
||||||
|
for _, value := range env {
|
||||||
|
if Lookup(value[:strings.Index(value, "=")]) == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
args = append(args, fmt.Sprintf("-%s", value))
|
||||||
|
}
|
||||||
|
EnvironmentFlags.Parse(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsed returns true if the environment flags have been parsed.
|
||||||
|
func Parsed() bool {
|
||||||
|
return EnvironmentFlags.Parsed()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnvironmentFlags is the default set of environment flags, parsed
|
||||||
|
// from os.Environ(). The top-level functions such as BoolVar, Arg,
|
||||||
|
// and on are wrappers for the methods of EnvironmentFlags.
|
||||||
|
var EnvironmentFlags = flag.NewFlagSet("environment", flag.ExitOnError)
|
23
vendor/github.com/joho/godotenv/LICENCE
generated
vendored
Normal file
23
vendor/github.com/joho/godotenv/LICENCE
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
Copyright (c) 2013 John Barton
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
127
vendor/github.com/joho/godotenv/README.md
generated
vendored
Normal file
127
vendor/github.com/joho/godotenv/README.md
generated
vendored
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
# GoDotEnv [![wercker status](https://app.wercker.com/status/507594c2ec7e60f19403a568dfea0f78 "wercker status")](https://app.wercker.com/project/bykey/507594c2ec7e60f19403a568dfea0f78)
|
||||||
|
|
||||||
|
A Go (golang) port of the Ruby dotenv project (which loads env vars from a .env file)
|
||||||
|
|
||||||
|
From the original Library:
|
||||||
|
|
||||||
|
> Storing configuration in the environment is one of the tenets of a twelve-factor app. Anything that is likely to change between deployment environments–such as resource handles for databases or credentials for external services–should be extracted from the code into environment variables.
|
||||||
|
>
|
||||||
|
> But it is not always practical to set environment variables on development machines or continuous integration servers where multiple projects are run. Dotenv load variables from a .env file into ENV when the environment is bootstrapped.
|
||||||
|
|
||||||
|
It can be used as a library (for loading in env for your own daemons etc) or as a bin command.
|
||||||
|
|
||||||
|
There is test coverage and CI for both linuxish and windows environments, but I make no guarantees about the bin version working on windows.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
As a library
|
||||||
|
|
||||||
|
```shell
|
||||||
|
go get github.com/joho/godotenv
|
||||||
|
```
|
||||||
|
|
||||||
|
or if you want to use it as a bin command
|
||||||
|
```shell
|
||||||
|
go get github.com/joho/godotenv/cmd/godotenv
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Add your application configuration to your `.env` file in the root of your project:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
S3_BUCKET=YOURS3BUCKET
|
||||||
|
SECRET_KEY=YOURSECRETKEYGOESHERE
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in your Go app you can do something like
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := godotenv.Load()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error loading .env file")
|
||||||
|
}
|
||||||
|
|
||||||
|
s3Bucket := os.Getenv("S3_BUCKET")
|
||||||
|
secretKey := os.Getenv("SECRET_KEY")
|
||||||
|
|
||||||
|
// now do something with s3 or whatever
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're even lazier than that, you can just take advantage of the autoload package which will read in `.env` on import
|
||||||
|
|
||||||
|
```go
|
||||||
|
import _ "github.com/joho/godotenv/autoload"
|
||||||
|
```
|
||||||
|
|
||||||
|
While `.env` in the project root is the default, you don't have to be constrained, both examples below are 100% legit
|
||||||
|
|
||||||
|
```go
|
||||||
|
_ = godotenv.Load("somerandomfile")
|
||||||
|
_ = godotenv.Load("filenumberone.env", "filenumbertwo.env")
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to be really fancy with your env file you can do comments and exports (below is a valid env file)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# I am a comment and that is OK
|
||||||
|
SOME_VAR=someval
|
||||||
|
FOO=BAR # comments at line end are OK too
|
||||||
|
export BAR=BAZ
|
||||||
|
```
|
||||||
|
|
||||||
|
Or finally you can do YAML(ish) style
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
FOO: bar
|
||||||
|
BAR: baz
|
||||||
|
```
|
||||||
|
|
||||||
|
as a final aside, if you don't want godotenv munging your env you can just get a map back instead
|
||||||
|
|
||||||
|
```go
|
||||||
|
var myEnv map[string]string
|
||||||
|
myEnv, err := godotenv.Read()
|
||||||
|
|
||||||
|
s3Bucket := myEnv["S3_BUCKET"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Command Mode
|
||||||
|
|
||||||
|
Assuming you've installed the command as above and you've got `$GOPATH/bin` in your `$PATH`
|
||||||
|
|
||||||
|
```
|
||||||
|
godotenv -f /some/path/to/.env some_command with some args
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don't specify `-f` it will fall back on the default of loading `.env` in `PWD`
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are most welcome! The parser itself is pretty stupidly naive and I wouldn't be surprised if it breaks with edge cases.
|
||||||
|
|
||||||
|
*code changes without tests will not be accepted*
|
||||||
|
|
||||||
|
1. Fork it
|
||||||
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||||
|
3. Commit your changes (`git commit -am 'Added some feature'`)
|
||||||
|
4. Push to the branch (`git push origin my-new-feature`)
|
||||||
|
5. Create new Pull Request
|
||||||
|
|
||||||
|
## CI
|
||||||
|
|
||||||
|
Linux: [![wercker status](https://app.wercker.com/status/507594c2ec7e60f19403a568dfea0f78/m "wercker status")](https://app.wercker.com/project/bykey/507594c2ec7e60f19403a568dfea0f78) Windows: [![Build status](https://ci.appveyor.com/api/projects/status/9v40vnfvvgde64u4)](https://ci.appveyor.com/project/joho/godotenv)
|
||||||
|
|
||||||
|
## Who?
|
||||||
|
|
||||||
|
The original library [dotenv](https://github.com/bkeepers/dotenv) was written by [Brandon Keepers](http://opensoul.org/), and this port was done by [John Barton](http://whoisjohnbarton.com) based off the tests/fixtures in the original library.
|
15
vendor/github.com/joho/godotenv/autoload/autoload.go
generated
vendored
Normal file
15
vendor/github.com/joho/godotenv/autoload/autoload.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package autoload
|
||||||
|
|
||||||
|
/*
|
||||||
|
You can just read the .env file on import just by doing
|
||||||
|
|
||||||
|
import _ "github.com/joho/godotenv/autoload"
|
||||||
|
|
||||||
|
And bob's your mother's brother
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "github.com/joho/godotenv"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
godotenv.Load()
|
||||||
|
}
|
229
vendor/github.com/joho/godotenv/godotenv.go
generated
vendored
Normal file
229
vendor/github.com/joho/godotenv/godotenv.go
generated
vendored
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
// Package godotenv is a go port of the ruby dotenv library (https://github.com/bkeepers/dotenv)
|
||||||
|
//
|
||||||
|
// Examples/readme can be found on the github page at https://github.com/joho/godotenv
|
||||||
|
//
|
||||||
|
// The TL;DR is that you make a .env file that looks something like
|
||||||
|
//
|
||||||
|
// SOME_ENV_VAR=somevalue
|
||||||
|
//
|
||||||
|
// and then in your go code you can call
|
||||||
|
//
|
||||||
|
// godotenv.Load()
|
||||||
|
//
|
||||||
|
// and all the env vars declared in .env will be avaiable through os.Getenv("SOME_ENV_VAR")
|
||||||
|
package godotenv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Load will read your env file(s) and load them into ENV for this process.
|
||||||
|
//
|
||||||
|
// Call this function as close as possible to the start of your program (ideally in main)
|
||||||
|
//
|
||||||
|
// If you call Load without any args it will default to loading .env in the current path
|
||||||
|
//
|
||||||
|
// You can otherwise tell it which files to load (there can be more than one) like
|
||||||
|
//
|
||||||
|
// godotenv.Load("fileone", "filetwo")
|
||||||
|
//
|
||||||
|
// It's important to note that it WILL NOT OVERRIDE an env variable that already exists - consider the .env file to set dev vars or sensible defaults
|
||||||
|
func Load(filenames ...string) (err error) {
|
||||||
|
filenames = filenamesOrDefault(filenames)
|
||||||
|
|
||||||
|
for _, filename := range filenames {
|
||||||
|
err = loadFile(filename, false)
|
||||||
|
if err != nil {
|
||||||
|
return // return early on a spazout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload will read your env file(s) and load them into ENV for this process.
|
||||||
|
//
|
||||||
|
// Call this function as close as possible to the start of your program (ideally in main)
|
||||||
|
//
|
||||||
|
// If you call Overload without any args it will default to loading .env in the current path
|
||||||
|
//
|
||||||
|
// You can otherwise tell it which files to load (there can be more than one) like
|
||||||
|
//
|
||||||
|
// godotenv.Overload("fileone", "filetwo")
|
||||||
|
//
|
||||||
|
// It's important to note this WILL OVERRIDE an env variable that already exists - consider the .env file to forcefilly set all vars.
|
||||||
|
func Overload(filenames ...string) (err error) {
|
||||||
|
filenames = filenamesOrDefault(filenames)
|
||||||
|
|
||||||
|
for _, filename := range filenames {
|
||||||
|
err = loadFile(filename, true)
|
||||||
|
if err != nil {
|
||||||
|
return // return early on a spazout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read all env (with same file loading semantics as Load) but return values as
|
||||||
|
// a map rather than automatically writing values into env
|
||||||
|
func Read(filenames ...string) (envMap map[string]string, err error) {
|
||||||
|
filenames = filenamesOrDefault(filenames)
|
||||||
|
envMap = make(map[string]string)
|
||||||
|
|
||||||
|
for _, filename := range filenames {
|
||||||
|
individualEnvMap, individualErr := readFile(filename)
|
||||||
|
|
||||||
|
if individualErr != nil {
|
||||||
|
err = individualErr
|
||||||
|
return // return early on a spazout
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range individualEnvMap {
|
||||||
|
envMap[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec loads env vars from the specified filenames (empty map falls back to default)
|
||||||
|
// then executes the cmd specified.
|
||||||
|
//
|
||||||
|
// Simply hooks up os.Stdin/err/out to the command and calls Run()
|
||||||
|
//
|
||||||
|
// If you want more fine grained control over your command it's recommended
|
||||||
|
// that you use `Load()` or `Read()` and the `os/exec` package yourself.
|
||||||
|
func Exec(filenames []string, cmd string, cmdArgs []string) error {
|
||||||
|
Load(filenames...)
|
||||||
|
|
||||||
|
command := exec.Command(cmd, cmdArgs...)
|
||||||
|
command.Stdin = os.Stdin
|
||||||
|
command.Stdout = os.Stdout
|
||||||
|
command.Stderr = os.Stderr
|
||||||
|
return command.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func filenamesOrDefault(filenames []string) []string {
|
||||||
|
if len(filenames) == 0 {
|
||||||
|
return []string{".env"}
|
||||||
|
}
|
||||||
|
return filenames
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadFile(filename string, overload bool) error {
|
||||||
|
envMap, err := readFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range envMap {
|
||||||
|
if os.Getenv(key) == "" || overload {
|
||||||
|
os.Setenv(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readFile(filename string) (envMap map[string]string, err error) {
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
envMap = make(map[string]string)
|
||||||
|
|
||||||
|
var lines []string
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
lines = append(lines, scanner.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fullLine := range lines {
|
||||||
|
if !isIgnoredLine(fullLine) {
|
||||||
|
key, value, err := parseLine(fullLine)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
envMap[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLine(line string) (key string, value string, err error) {
|
||||||
|
if len(line) == 0 {
|
||||||
|
err = errors.New("zero length string")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ditch the comments (but keep quoted hashes)
|
||||||
|
if strings.Contains(line, "#") {
|
||||||
|
segmentsBetweenHashes := strings.Split(line, "#")
|
||||||
|
quotesAreOpen := false
|
||||||
|
var segmentsToKeep []string
|
||||||
|
for _, segment := range segmentsBetweenHashes {
|
||||||
|
if strings.Count(segment, "\"") == 1 || strings.Count(segment, "'") == 1 {
|
||||||
|
if quotesAreOpen {
|
||||||
|
quotesAreOpen = false
|
||||||
|
segmentsToKeep = append(segmentsToKeep, segment)
|
||||||
|
} else {
|
||||||
|
quotesAreOpen = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(segmentsToKeep) == 0 || quotesAreOpen {
|
||||||
|
segmentsToKeep = append(segmentsToKeep, segment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
line = strings.Join(segmentsToKeep, "#")
|
||||||
|
}
|
||||||
|
|
||||||
|
// now split key from value
|
||||||
|
splitString := strings.SplitN(line, "=", 2)
|
||||||
|
|
||||||
|
if len(splitString) != 2 {
|
||||||
|
// try yaml mode!
|
||||||
|
splitString = strings.SplitN(line, ":", 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(splitString) != 2 {
|
||||||
|
err = errors.New("Can't separate key from value")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the key
|
||||||
|
key = splitString[0]
|
||||||
|
if strings.HasPrefix(key, "export") {
|
||||||
|
key = strings.TrimPrefix(key, "export")
|
||||||
|
}
|
||||||
|
key = strings.Trim(key, " ")
|
||||||
|
|
||||||
|
// Parse the value
|
||||||
|
value = splitString[1]
|
||||||
|
// trim
|
||||||
|
value = strings.Trim(value, " ")
|
||||||
|
|
||||||
|
// check if we've got quoted values
|
||||||
|
if strings.Count(value, "\"") == 2 || strings.Count(value, "'") == 2 {
|
||||||
|
// pull the quotes off the edges
|
||||||
|
value = strings.Trim(value, "\"'")
|
||||||
|
|
||||||
|
// expand quotes
|
||||||
|
value = strings.Replace(value, "\\\"", "\"", -1)
|
||||||
|
// expand newlines
|
||||||
|
value = strings.Replace(value, "\\n", "\n", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func isIgnoredLine(line string) bool {
|
||||||
|
trimmedLine := strings.Trim(line, " \n\t")
|
||||||
|
return len(trimmedLine) == 0 || strings.HasPrefix(trimmedLine, "#")
|
||||||
|
}
|
1
vendor/github.com/joho/godotenv/wercker.yml
generated
vendored
Normal file
1
vendor/github.com/joho/godotenv/wercker.yml
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
box: pjvds/golang
|
24
vendor/vendor.json
vendored
24
vendor/vendor.json
vendored
|
@ -9,8 +9,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "github.com/Sirupsen/logrus",
|
"path": "github.com/Sirupsen/logrus",
|
||||||
"revision": "273bd5984cd7deae8d4b71b0ba9bfc5767f7284b",
|
"revision": "4b6ea7319e214d98c938f12692336f7ca9348d6b",
|
||||||
"revisionTime": "2015-02-17T12:42:44-05:00"
|
"revisionTime": "2016-03-17T14:11:10Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"origin": "github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew",
|
"origin": "github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew",
|
||||||
|
@ -53,6 +53,11 @@
|
||||||
"revision": "889391d730237f8aca06ce3e62975112983f96b4",
|
"revision": "889391d730237f8aca06ce3e62975112983f96b4",
|
||||||
"revisionTime": "2016-01-23T18:11:54-03:00"
|
"revisionTime": "2016-01-23T18:11:54-03:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "github.com/gin-gonic/contrib/ginrus",
|
||||||
|
"revision": "14f66d54cdb96059bafca98665bcc6d9df4951f2",
|
||||||
|
"revisionTime": "2015-08-15T19:25:43+02:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "github.com/gin-gonic/gin",
|
"path": "github.com/gin-gonic/gin",
|
||||||
"revision": "3d002e382355cafc15d706b92899b1961d5b79e9",
|
"revision": "3d002e382355cafc15d706b92899b1961d5b79e9",
|
||||||
|
@ -98,6 +103,21 @@
|
||||||
"revision": "1b0c7f6e9ab3d7f500fd7d50c7ad835ff428139b",
|
"revision": "1b0c7f6e9ab3d7f500fd7d50c7ad835ff428139b",
|
||||||
"revisionTime": "2014-04-09T13:11:00+02:00"
|
"revisionTime": "2014-04-09T13:11:00+02:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "github.com/ianschenck/envflag",
|
||||||
|
"revision": "9111d830d133f952887a936367fb0211c3134f0d",
|
||||||
|
"revisionTime": "2014-07-20T15:03:42-06:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "github.com/joho/godotenv",
|
||||||
|
"revision": "4ed13390c0acd2ff4e371e64d8b97c8954138243",
|
||||||
|
"revisionTime": "2015-09-07T11:02:28+10:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "github.com/joho/godotenv/autoload",
|
||||||
|
"revision": "4ed13390c0acd2ff4e371e64d8b97c8954138243",
|
||||||
|
"revisionTime": "2015-09-07T11:02:28+10:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "github.com/koding/cache",
|
"path": "github.com/koding/cache",
|
||||||
"revision": "487fc0ca06f9aa1a02d796f5510784b47d5afae2",
|
"revision": "487fc0ca06f9aa1a02d796f5510784b47d5afae2",
|
||||||
|
|
Loading…
Reference in a new issue