]>
Commit | Line | Data |
---|---|---|
9b12e4fe JC |
1 | # 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] |
2 | ||
3 | Logrus is a structured logger for Go (golang), completely API compatible with | |
4 | the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not | |
5 | yet stable (pre 1.0). Logrus itself is completely stable and has been used in | |
6 | many large deployments. The core API is unlikely to change much but please | |
7 | version control your Logrus to make sure you aren't fetching latest `master` on | |
8 | every build.** | |
9 | ||
10 | Nicely color-coded in development (when a TTY is attached, otherwise just | |
11 | plain text): | |
12 | ||
13 | ![Colored](http://i.imgur.com/PY7qMwd.png) | |
14 | ||
15 | With `log.Formatter = new(logrus.JSONFormatter)`, for easy parsing by logstash | |
16 | or Splunk: | |
17 | ||
18 | ```json | |
19 | {"animal":"walrus","level":"info","msg":"A group of walrus emerges from the | |
20 | ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} | |
21 | ||
22 | {"level":"warning","msg":"The group's number increased tremendously!", | |
23 | "number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"} | |
24 | ||
25 | {"animal":"walrus","level":"info","msg":"A giant walrus appears!", | |
26 | "size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"} | |
27 | ||
28 | {"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.", | |
29 | "size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"} | |
30 | ||
31 | {"level":"fatal","msg":"The ice breaks!","number":100,"omg":true, | |
32 | "time":"2014-03-10 19:57:38.562543128 -0400 EDT"} | |
33 | ``` | |
34 | ||
35 | With the default `log.Formatter = new(&log.TextFormatter{})` when a TTY is not | |
36 | attached, the output is compatible with the | |
37 | [logfmt](http://godoc.org/github.com/kr/logfmt) format: | |
38 | ||
39 | ```text | |
40 | time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 | |
41 | time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 | |
42 | time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true | |
43 | time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 | |
44 | time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 | |
45 | 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 | |
46 | exit status 1 | |
47 | ``` | |
48 | ||
49 | #### Example | |
50 | ||
51 | The simplest way to use Logrus is simply the package-level exported logger: | |
52 | ||
53 | ```go | |
54 | package main | |
55 | ||
56 | import ( | |
57 | log "github.com/Sirupsen/logrus" | |
58 | ) | |
59 | ||
60 | func main() { | |
61 | log.WithFields(log.Fields{ | |
62 | "animal": "walrus", | |
63 | }).Info("A walrus appears") | |
64 | } | |
65 | ``` | |
66 | ||
67 | Note that it's completely api-compatible with the stdlib logger, so you can | |
68 | replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"` | |
69 | and you'll now have the flexibility of Logrus. You can customize it all you | |
70 | want: | |
71 | ||
72 | ```go | |
73 | package main | |
74 | ||
75 | import ( | |
76 | "os" | |
77 | log "github.com/Sirupsen/logrus" | |
78 | ) | |
79 | ||
80 | func init() { | |
81 | // Log as JSON instead of the default ASCII formatter. | |
82 | log.SetFormatter(&log.JSONFormatter{}) | |
83 | ||
84 | // Output to stderr instead of stdout, could also be a file. | |
85 | log.SetOutput(os.Stderr) | |
86 | ||
87 | // Only log the warning severity or above. | |
88 | log.SetLevel(log.WarnLevel) | |
89 | } | |
90 | ||
91 | func main() { | |
92 | log.WithFields(log.Fields{ | |
93 | "animal": "walrus", | |
94 | "size": 10, | |
95 | }).Info("A group of walrus emerges from the ocean") | |
96 | ||
97 | log.WithFields(log.Fields{ | |
98 | "omg": true, | |
99 | "number": 122, | |
100 | }).Warn("The group's number increased tremendously!") | |
101 | ||
102 | log.WithFields(log.Fields{ | |
103 | "omg": true, | |
104 | "number": 100, | |
105 | }).Fatal("The ice breaks!") | |
106 | ||
107 | // A common pattern is to re-use fields between logging statements by re-using | |
108 | // the logrus.Entry returned from WithFields() | |
109 | contextLogger := log.WithFields(log.Fields{ | |
110 | "common": "this is a common field", | |
111 | "other": "I also should be logged always", | |
112 | }) | |
113 | ||
114 | contextLogger.Info("I'll be logged with common and other field") | |
115 | contextLogger.Info("Me too") | |
116 | } | |
117 | ``` | |
118 | ||
119 | For more advanced usage such as logging to multiple locations from the same | |
120 | application, you can also create an instance of the `logrus` Logger: | |
121 | ||
122 | ```go | |
123 | package main | |
124 | ||
125 | import ( | |
126 | "github.com/Sirupsen/logrus" | |
127 | ) | |
128 | ||
129 | // Create a new instance of the logger. You can have any number of instances. | |
130 | var log = logrus.New() | |
131 | ||
132 | func main() { | |
133 | // The API for setting attributes is a little different than the package level | |
134 | // exported logger. See Godoc. | |
135 | log.Out = os.Stderr | |
136 | ||
137 | log.WithFields(logrus.Fields{ | |
138 | "animal": "walrus", | |
139 | "size": 10, | |
140 | }).Info("A group of walrus emerges from the ocean") | |
141 | } | |
142 | ``` | |
143 | ||
144 | #### Fields | |
145 | ||
146 | Logrus encourages careful, structured logging though logging fields instead of | |
147 | long, unparseable error messages. For example, instead of: `log.Fatalf("Failed | |
148 | to send event %s to topic %s with key %d")`, you should log the much more | |
149 | discoverable: | |
150 | ||
151 | ```go | |
152 | log.WithFields(log.Fields{ | |
153 | "event": event, | |
154 | "topic": topic, | |
155 | "key": key, | |
156 | }).Fatal("Failed to send event") | |
157 | ``` | |
158 | ||
159 | We've found this API forces you to think about logging in a way that produces | |
160 | much more useful logging messages. We've been in countless situations where just | |
161 | a single added field to a log statement that was already there would've saved us | |
162 | hours. The `WithFields` call is optional. | |
163 | ||
164 | In general, with Logrus using any of the `printf`-family functions should be | |
165 | seen as a hint you should add a field, however, you can still use the | |
166 | `printf`-family functions with Logrus. | |
167 | ||
168 | #### Hooks | |
169 | ||
170 | You can add hooks for logging levels. For example to send errors to an exception | |
171 | tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to | |
172 | multiple places simultaneously, e.g. syslog. | |
173 | ||
174 | Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in | |
175 | `init`: | |
176 | ||
177 | ```go | |
178 | import ( | |
179 | log "github.com/Sirupsen/logrus" | |
180 | "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake" | |
181 | logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog" | |
182 | "log/syslog" | |
183 | ) | |
184 | ||
185 | func init() { | |
186 | ||
187 | // Use the Airbrake hook to report errors that have Error severity or above to | |
188 | // an exception tracker. You can create custom hooks, see the Hooks section. | |
189 | log.AddHook(airbrake.NewHook(123, "xyz", "production")) | |
190 | ||
191 | hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") | |
192 | if err != nil { | |
193 | log.Error("Unable to connect to local syslog daemon") | |
194 | } else { | |
195 | log.AddHook(hook) | |
196 | } | |
197 | } | |
198 | ``` | |
199 | 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). | |
200 | ||
201 | | Hook | Description | | |
202 | | ----- | ----------- | | |
203 | | [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. | | |
204 | | [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. | | |
205 | | [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. | | |
206 | | [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. | | |
207 | | [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. | | |
208 | | [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. | | |
209 | | [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. | | |
210 | | [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) | | |
211 | | [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. | | |
212 | | [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` | | |
213 | | [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) | | |
214 | | [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) | | |
215 | | [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem | | |
216 | | [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger | | |
217 | | [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail | | |
218 | | [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar | | |
219 | | [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd | | |
220 | | [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb | | |
221 | | [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb | | |
222 | | [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit | | |
223 | | [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic | | |
224 | ||
225 | #### Level logging | |
226 | ||
227 | Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic. | |
228 | ||
229 | ```go | |
230 | log.Debug("Useful debugging information.") | |
231 | log.Info("Something noteworthy happened!") | |
232 | log.Warn("You should probably take a look at this.") | |
233 | log.Error("Something failed but I'm not quitting.") | |
234 | // Calls os.Exit(1) after logging | |
235 | log.Fatal("Bye.") | |
236 | // Calls panic() after logging | |
237 | log.Panic("I'm bailing.") | |
238 | ``` | |
239 | ||
240 | You can set the logging level on a `Logger`, then it will only log entries with | |
241 | that severity or anything above it: | |
242 | ||
243 | ```go | |
244 | // Will log anything that is info or above (warn, error, fatal, panic). Default. | |
245 | log.SetLevel(log.InfoLevel) | |
246 | ``` | |
247 | ||
248 | It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose | |
249 | environment if your application has that. | |
250 | ||
251 | #### Entries | |
252 | ||
253 | Besides the fields added with `WithField` or `WithFields` some fields are | |
254 | automatically added to all logging events: | |
255 | ||
256 | 1. `time`. The timestamp when the entry was created. | |
257 | 2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after | |
258 | the `AddFields` call. E.g. `Failed to send event.` | |
259 | 3. `level`. The logging level. E.g. `info`. | |
260 | ||
261 | #### Environments | |
262 | ||
263 | Logrus has no notion of environment. | |
264 | ||
265 | If you wish for hooks and formatters to only be used in specific environments, | |
266 | you should handle that yourself. For example, if your application has a global | |
267 | variable `Environment`, which is a string representation of the environment you | |
268 | could do: | |
269 | ||
270 | ```go | |
271 | import ( | |
272 | log "github.com/Sirupsen/logrus" | |
273 | ) | |
274 | ||
275 | init() { | |
276 | // do something here to set environment depending on an environment variable | |
277 | // or command-line flag | |
278 | if Environment == "production" { | |
279 | log.SetFormatter(&log.JSONFormatter{}) | |
280 | } else { | |
281 | // The TextFormatter is default, you don't actually have to do this. | |
282 | log.SetFormatter(&log.TextFormatter{}) | |
283 | } | |
284 | } | |
285 | ``` | |
286 | ||
287 | This configuration is how `logrus` was intended to be used, but JSON in | |
288 | production is mostly only useful if you do log aggregation with tools like | |
289 | Splunk or Logstash. | |
290 | ||
291 | #### Formatters | |
292 | ||
293 | The built-in logging formatters are: | |
294 | ||
295 | * `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise | |
296 | without colors. | |
297 | * *Note:* to force colored output when there is no TTY, set the `ForceColors` | |
298 | field to `true`. To force no colored output even if there is a TTY set the | |
299 | `DisableColors` field to `true` | |
300 | * `logrus.JSONFormatter`. Logs fields as JSON. | |
301 | * `logrus/formatters/logstash.LogstashFormatter`. Logs fields as [Logstash](http://logstash.net) Events. | |
302 | ||
303 | ```go | |
304 | logrus.SetFormatter(&logstash.LogstashFormatter{Type: "application_name"}) | |
305 | ``` | |
306 | ||
307 | Third party logging formatters: | |
308 | ||
309 | * [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. | |
310 | * [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦. | |
311 | ||
312 | You can define your formatter by implementing the `Formatter` interface, | |
313 | requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a | |
314 | `Fields` type (`map[string]interface{}`) with all your fields as well as the | |
315 | default ones (see Entries section above): | |
316 | ||
317 | ```go | |
318 | type MyJSONFormatter struct { | |
319 | } | |
320 | ||
321 | log.SetFormatter(new(MyJSONFormatter)) | |
322 | ||
323 | func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { | |
324 | // Note this doesn't include Time, Level and Message which are available on | |
325 | // the Entry. Consult `godoc` on information about those fields or read the | |
326 | // source of the official loggers. | |
327 | serialized, err := json.Marshal(entry.Data) | |
328 | if err != nil { | |
329 | return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) | |
330 | } | |
331 | return append(serialized, '\n'), nil | |
332 | } | |
333 | ``` | |
334 | ||
335 | #### Logger as an `io.Writer` | |
336 | ||
337 | 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. | |
338 | ||
339 | ```go | |
340 | w := logger.Writer() | |
341 | defer w.Close() | |
342 | ||
343 | srv := http.Server{ | |
344 | // create a stdlib log.Logger that writes to | |
345 | // logrus.Logger. | |
346 | ErrorLog: log.New(w, "", 0), | |
347 | } | |
348 | ``` | |
349 | ||
350 | Each line written to that writer will be printed the usual way, using formatters | |
351 | and hooks. The level for those entries is `info`. | |
352 | ||
353 | #### Rotation | |
354 | ||
355 | Log rotation is not provided with Logrus. Log rotation should be done by an | |
356 | external program (like `logrotate(8)`) that can compress and delete old log | |
357 | entries. It should not be a feature of the application-level logger. | |
358 | ||
359 | #### Tools | |
360 | ||
361 | | Tool | Description | | |
362 | | ---- | ----------- | | |
363 | |[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.| | |
364 | ||
365 | [godoc]: https://godoc.org/github.com/Sirupsen/logrus |