timber 1.0.13 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +278 -121
  3. data/lib/timber.rb +1 -0
  4. data/lib/timber/context.rb +1 -1
  5. data/lib/timber/contexts.rb +29 -2
  6. data/lib/timber/contexts/runtime.rb +24 -0
  7. data/lib/timber/contexts/system.rb +19 -0
  8. data/lib/timber/current_context.rb +14 -5
  9. data/lib/timber/event.rb +1 -1
  10. data/lib/timber/events.rb +11 -6
  11. data/lib/timber/events/controller_call.rb +1 -1
  12. data/lib/timber/events/custom.rb +1 -1
  13. data/lib/timber/events/exception.rb +1 -1
  14. data/lib/timber/events/{http_request.rb → http_server_request.rb} +1 -1
  15. data/lib/timber/events/{http_response.rb → http_server_response.rb} +2 -1
  16. data/lib/timber/events/sql_query.rb +2 -1
  17. data/lib/timber/events/template_render.rb +2 -1
  18. data/lib/timber/frameworks/rails.rb +12 -1
  19. data/lib/timber/log_devices/http.rb +29 -24
  20. data/lib/timber/log_entry.rb +23 -9
  21. data/lib/timber/logger.rb +20 -6
  22. data/lib/timber/probes.rb +1 -3
  23. data/lib/timber/probes/active_support_tagged_logging.rb +0 -43
  24. data/lib/timber/probes/rails_rack_logger.rb +1 -1
  25. data/lib/timber/rack_middlewares.rb +12 -0
  26. data/lib/timber/rack_middlewares/http_context.rb +30 -0
  27. data/lib/timber/util.rb +1 -0
  28. data/lib/timber/util/struct.rb +16 -0
  29. data/lib/timber/version.rb +1 -1
  30. data/spec/README.md +23 -0
  31. data/spec/support/timber.rb +1 -1
  32. data/spec/timber/contexts_spec.rb +49 -0
  33. data/spec/timber/events_spec.rb +1 -1
  34. data/spec/timber/log_devices/http_spec.rb +7 -7
  35. data/spec/timber/log_entry_spec.rb +15 -0
  36. data/spec/timber/logger_spec.rb +14 -10
  37. data/spec/timber/probes/action_controller_log_subscriber_spec.rb +6 -7
  38. data/spec/timber/probes/action_dispatch_debug_exceptions_spec.rb +1 -1
  39. data/spec/timber/probes/action_view_log_subscriber_spec.rb +2 -2
  40. data/spec/timber/probes/rails_rack_logger_spec.rb +3 -3
  41. data/spec/timber/rack_middlewares/http_context_spec.rb +47 -0
  42. data/timber.gemspec +1 -0
  43. metadata +31 -8
  44. data/lib/timber/contexts/tags.rb +0 -22
  45. data/lib/timber/probes/rack_http_context.rb +0 -51
  46. data/spec/timber/probes/rack_http_context_spec.rb +0 -50
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 271e6ee909502a8d6581ab9b574fe0b11379dd5c
4
- data.tar.gz: 7325365af0abd4c6c83949604c026c64ff0044de
3
+ metadata.gz: 1a526175aa41bf2a0f6124b8081fa68dff14d79f
4
+ data.tar.gz: 85e34c100200bc0c61c576126cf1980d0ac576ca
5
5
  SHA512:
6
- metadata.gz: 671677150f46a95f0dd091ef12dbebc660abeb810ac8b64a27669677f44052a838305461a0724e5ca4f09410c4f0555c080cacd8c73bf45406da0f7eff2b2a4e
7
- data.tar.gz: d74ed9f56a5422f55dd403e98939dfd08b4a589c804ad11ea878e42cd813b0b7e40a0673f0a9607adf68a2fb017d8bf5a4f37383c65e88586e4453dbc385d6b4
6
+ metadata.gz: bbf7e0964fb175ced6f826ff852079373c138f97ee72f1cc8ae367c43c9d11bdd26d318ec365a801fd3657d5cd7d832cae8f6c836e09f93f16ab3f27665f5ee2
7
+ data.tar.gz: f001a84ee2a8d2df95dd339ca467d884b15e75a26b57fc3bce66ccd3b4234254025b2cf4fddb12c447768b483b869a3cc5d7fa99f2d823cf5d183d2ff54858de
data/README.md CHANGED
@@ -1,200 +1,357 @@
1
- # Timber
1
+ # 🌲 Timber - Master your Ruby apps with structured logging
2
2
 
3
3
  <p align="center" style="background: #140f2a;">
4
4
  <a href="http://github.com/timberio/timber-ruby"><img src="http://files.timber.io/images/ruby-library-readme-header.gif" height="469" /></a>
5
5
  </p>
6
6
 
7
+ [![ISC License](https://img.shields.io/badge/license-ISC-ff69b4.svg)](LICENSE.md)
7
8
  [![CircleCI](https://circleci.com/gh/timberio/timber-ruby.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/timberio/timber-ruby/tree/master)
8
9
  [![Coverage Status](https://coveralls.io/repos/github/timberio/timber-ruby/badge.svg?branch=master)](https://coveralls.io/github/timberio/timber-ruby?branch=master)
9
10
  [![Code Climate](https://codeclimate.com/github/timberio/timber-ruby/badges/gpa.svg)](https://codeclimate.com/github/timberio/timber-ruby)
10
11
  [![View docs](https://img.shields.io/badge/docs-viewdocs-blue.svg?style=flat-square "Viewdocs")](http://www.rubydoc.info/github/timberio/timber-ruby)
11
12
 
12
13
 
13
- **Timber is in beta testing. If interested, please email beta@timber.io**
14
+ ---
15
+
16
+ 👉 **Timber is in beta testing, if interested in joining, please email us at
17
+ [beta@timber.io](mailto:beta@timber.io)**
18
+
19
+ ---
14
20
 
21
+ Still logging raw text? Timber is a complete *structured* logging solution that you can setup in
22
+ minutes. It goes beyond traditional log management by focusing on data quality and modern
23
+ developer standards.
24
+
25
+ High quality logs, [a modern UX-first interface](https://timber.io), simple setup,
26
+ zero-maintenance, 6-month retention, and sane prices are just a few of the benefits Timber
27
+ offers.
28
+
29
+ To learn more, checkout out [timber.io](https://timber.io) or the
30
+ ["why we built Timber"](http://moss-ibex2.cloudvent.net/blog/why-were-building-timber/)
31
+ blog post.
32
+
33
+
34
+ ## Overview
35
+
36
+ <details><summary><strong>What are the benefits of using Timber?</strong></summary><p>
37
+
38
+ 1. **Data quality.** The usefulness of your logs starts here. This is why we ship libraries that
39
+ structure logs from *within* your application; a fundamental difference from parsing. Not only
40
+ is it much more stable, but we can include data you couldn't obtain otherwise.
41
+ 2. **Human readability.** Structuring your logs doesn't mean they have to be unreadable. Timber
42
+ *augments* your logs with structured data. Meaning we do not alter the original log message,
43
+ we simply attach metadata to it. And our console is specifically designed to give you access
44
+ to this data, without compromising readability. 😮
45
+ 3. **Reliable downstream consumption.** All log events adhere to a
46
+ [normalized, shared, schema](https://github.com/timberio/log-event-json-schema) that follows
47
+ [semantic versioning](http://semver.org/) and goes through a [standard release process](https://github.com/timberio/log-event-json-schema/releases).
48
+ This means you can *rely* on the structure of your logs and interact consistently with them
49
+ across apps of any language: queries, graphs, alerts, and other downstream consumers.
50
+ 4. **Zero risk of code debt or lock-in.** Logging is a standard that has been around since the dawn
51
+ of computers. It's built into every language, framework, and library. Timber adheres strictly
52
+ to the default `Logger` interface. There are no special APIs, and no need to pepper your app
53
+ with Timber specific code. It's just better logging. If you choose to stop using Timber, you
54
+ can do so without consequence.
55
+ 5. **Long term retention.** Timber is designed on modern big-data principles. As a result, we can
56
+ offer 6+ months of retention at prices cheaper than alternatives offering <1 month.
57
+ This allows you to unlock your logs for purposes beyond debugging.
58
+ ---
15
59
 
16
- 1. [What is timber?](#what-is-timber)
17
- 2. [How it works](#how-it-works)
18
- 3. [Why timber?](#why-timber)
19
- 4. [Logging Custom Events](#logging-custom-events)
20
- 5. [The Timber Console / Pricing](#the-timber-console--pricing)
21
- 6. [Install](#install)
60
+ </p></details>
22
61
 
62
+ <details><summary><strong>What specifically does the Timber library do?</strong></summary><p>
23
63
 
24
- ## What is Timber?
64
+ 1. Captures and structures your framework and 3rd party logs. (see next question)
65
+ 2. Adds useful context to every log line. (see next question)
66
+ 3. Provides a [framework for logging custom structured events](#what-about-custom-events).
67
+ 4. Offers transport strategies to [send your logs](#send-your-logs) to the Timber service.
25
68
 
26
- Using your logs shouldn't be a time consuming, frustrating process! If you were like us, it goes
27
- something like this:
69
+ ---
28
70
 
29
- > I need to centralize my logs, where should I send them? Which provider should I use?
30
- > Wow, this is expensive. Why is searching so difficult and time consuming?
31
- > Would structuring my logs help? Which format should I use? Will they still be human readable?
32
- > What if the structure changes? What about logs from 3rd party libraries? Ahhh!!!
71
+ </p></details>
33
72
 
34
- Timber solves this by providing a complete, managed, end-to-end logging solution that marries
35
- a beautiful, *fast*, console with libraries that automatically structure and enrich your logs.
73
+ <details><summary><strong>What events does Timber capture & structure for me?</strong></summary><p>
36
74
 
75
+ Out of the box you get everything in the [`Timber::Events`](lib/timber/events) namespace:
76
+
77
+ 1. [Controller Call Event](lib/timber/events/controller_call.rb)
78
+ 2. [Exception Event](lib/timber/events/exception.rb)
79
+ 3. [HTTP Client Request Event (net/http outgoing)](lib/timber/events/http_client_request.rb)
80
+ 4. [HTTP Client Response Event (resposne from net/http outgoing)](lib/timber/events/http_client_response.rb)
81
+ 5. [HTTP Server Request Event (incoming client request)](lib/timber/events/http_server_request.rb)
82
+ 6. [HTTP Server Response Event (response to incoming client request)](lib/timber/events/http_server_response.rb)
83
+ 7. [SQL Query Event](lib/timber/events/sql_query.rb)
84
+ 8. [Template Render Event](lib/timber/events/template_render.rb)
85
+ 9. ...more coming soon, [file an issue](https://github.com/timberio/timber-ruby/issues) to request.
86
+
87
+ We also add context to every log, everything in the [`Timber::Contexts`](lib/timber/contexts)
88
+ namespace. Context is structured data representing the current environment when the log line was
89
+ written. It is included in every log line. Think of it like join data for your logs:
90
+
91
+ 1. [HTTP Context](lib/timber/contexts/http.rb)
92
+ 2. [Organization Context](lib/timber/contexts/organization.rb)
93
+ 3. [Process Context](lib/timber/contexts/process.rb)
94
+ 4. [Server Context](lib/timber/contexts/server.rb)
95
+ 5. [Runtime Context](lib/timber/contexts/runtime.rb)
96
+ 5. [User Context](lib/timber/contexts/user.rb)
97
+ 6. ...more coming soon, [file an issue](https://github.com/timberio/timber-ruby/issues) to request.
98
+
99
+ ---
37
100
 
38
- ## How it works
101
+ </p></details>
39
102
 
40
- The Timber ruby library takes care of all of the log structuring madness. For example,
41
- it turns this Rails log line:
103
+ <details><summary><strong>What about my current log statements?</strong></summary><p>
42
104
 
105
+ They'll continue to work as expected. Timber adheres strictly to the default `::Logger` interface
106
+ and will never deviate in *any* way.
107
+
108
+ In fact, traditional log statements for non-meaningful events, debug statements, etc, are
109
+ encouraged. In cases where the data is meaningful, consider [logging a custom event](#usage).
110
+
111
+ </p></details>
112
+
113
+ ## Usage
114
+
115
+ <details><summary><strong>Basic logging</strong></summary><p>
116
+
117
+ Use `Logger` as normal:
118
+
119
+ ```ruby
120
+ logger.info("My log message")
121
+
122
+ # My log message @metadata {"level": "info", "context": {...}}
43
123
  ```
44
- Completed 200 OK in 117ms (Views: 85.2ms | ActiveRecord: 25.3ms)
124
+
125
+ Timber will never deviate from the public `::Logger` interface in *any* way.
126
+
127
+ ---
128
+
129
+ </p></details>
130
+
131
+ <details><summary><strong>Tagging logs</strong></summary><p>
132
+
133
+ Need a quick and easy way to identify a log? Use tags!:
134
+
135
+ ```ruby
136
+ logger.info(message: "My log message", tag: "tag")
137
+
138
+ # My log message @metadata {"level": "info", "tags": ["tag"], "context": {...}}
139
+ ```
140
+
141
+ Multiple tags:
142
+
143
+ ```ruby
144
+ logger.info(message: "My log message", tags: ["tag1", "tag2"])
145
+
146
+ # My log message @metadata {"level": "info", "tags": ["tag1", "tag2"], "context": {...}}
45
147
  ```
46
148
 
47
- Into this:
48
-
49
- ```javascript
50
- {
51
- "dt": "2016-12-01T02:23:12.236543Z",
52
- "level": "info",
53
- "message": "Completed 200 OK in 117ms (Views: 85.2ms | ActiveRecord: 25.3ms)",
54
- "context": {
55
- "http": {
56
- "method": "GET",
57
- "path": "/checkout",
58
- "remote_addr": "123.456.789.10",
59
- "request_id": "abcd1234"
60
- },
61
- "user": { // <---- http://i.giphy.com/EldfH1VJdbrwY.gif
62
- "id": 2,
63
- "name": "Ben Johnson",
64
- "email": "ben@johnson.com"
65
- }
66
- },
67
- "event": {
68
- "http_response": {
69
- "status": 200,
70
- "time_ms": 117
71
- }
72
- }
73
- }
149
+ Using `ActiveSupport::TaggedLogging`? It works with that as well:
150
+
151
+ ```ruby
152
+ logger.tagged("tag") do
153
+ logger.info(message: "My log message", tags: ["important", "slow"])
154
+ end
155
+
156
+ # My log message @metadata {"level": "info", "tags": ["tag"], "context": {...}}
74
157
  ```
75
158
 
76
- Notice we preserve the original log message. When viewing this event in the
77
- [Timber Console](https://timber.io), you'll see the simple, human readable line with the
78
- ability to view, and use, the attached structured data! Also, notice how rich the event is.
79
- Beecause we're inside your application, we can capture data beyond what's in the log line.
159
+ </p></details>
160
+
161
+ <details><summary><strong>Custom events</strong></summary><p>
162
+
163
+ 1. Log a structured Hash (simplest)
80
164
 
81
- (for a full list see [`Timber::Events`](lib/timber/events))
165
+ ```ruby
166
+ Logger.warn message: "Payment rejected", payment_rejected: {customer_id: "abcd1234", amount: 100, reason: "Card expired"}
82
167
 
168
+ # Payment rejected @metadata {"level": "warn", "event": {"payment_rejected": {"customer_id": "abcd1234", "amount": 100, "reason": "Card expired"}}, "context": {...}}
169
+ ```
83
170
 
84
- ## Why Timber?
171
+ * The hash can *only* have a `:message` and "event type" key, where `:payment_rejected` is the event type in the above example.
85
172
 
86
- Glad you asked! :)
173
+ 2. Log a Struct (recommended)
87
174
 
88
- 1. Human readable logs *and* rich structured data. You don't have to choose.
89
- 2. Data beyond what's in the log line itself making your logs exceptionally useful.
90
- 3. Normalized log data. Timber enforces a strict schema, meaning your log data, across all apps
91
- and languages will be normalized.
92
- 4. Absolutely no lock-in or risk of code debt. No fancy API, no proprietary data format locked
93
- away in our servers, Timber is just good ol' loggin'.
94
- 5. Fully managed, all the way from the log messages to the console you use. No fragile parsing
95
- rules or complicated interfaces.
175
+ Defining structs for your important events just feels oh so good :) It creates a strong contract
176
+ with down stream consumers and gives you compile time guarantees.
96
177
 
178
+ ```ruby
179
+ PaymentRejectedEvent = Struct.new(:customer_id, :amount, :reason) do
180
+ def message; "Payment rejected for #{customer_id}"; end
181
+ def type; :payment_rejected; end
182
+ end
183
+ Logger.warn PaymentRejectedEvent.new("abcd1234", 100, "Card expired")
97
184
 
98
- ## Logging Custom Events
185
+ # Payment rejected @metadata {"level": "warn", "event": {"payment_rejected": {"customer_id": "abcd1234", "amount": 100, "reason": "Card expired"}}, "context": {...}}
186
+ ```
99
187
 
100
- > Another service? More lock-in? :*(
188
+ * `:type` is how Timber classifies the event, it creates a namespace for the data you send.
189
+ * For more advanced examples see [`Timber::Logger`](lib/timber.logger.rb).
190
+ * Also, notice there is no mention of Timber in the above code. Just plain old logging.
101
191
 
102
- Nope! Logging custom events is Just Logging™. Check it out:
192
+ #### What about regular Hashes, JSON, or logfmt?
193
+
194
+ Go for it! Timber will parse the data server side, but we *highly* recommend the above examples.
195
+ Providing a `:type` allows timber to classify the event, create a namespace for the data you
196
+ send, and make it easier to search, graph, alert, etc.
103
197
 
104
198
  ```ruby
105
- # Simple string (original Logger interface remains untouched)
106
- Logger.warn "Payment rejected for customer abcd1234, reason: Card expired"
199
+ logger.info({key: "value"})
200
+ # {"key": "value"} @metadata {"level": "info", "context": {...}}
107
201
 
108
- # Structured hash
109
- Logger.warn message: "Payment rejected", type: :payment_rejected,
110
- data: {customer_id: "abcd1234", amount: 100, reason: "Card expired"}
202
+ logger.info('{"key": "value"}')
203
+ # {"key": "value"} @metadata {"level": "info", "context": {...}}
111
204
 
112
- # Using a Struct
113
- PaymentRejectedEvent = Struct.new(:customer_id, :amount, :reason) do
114
- def message; "Payment rejected for #{customer_id}"; end
115
- def type; :payment_rejected; end
116
- end
117
- Logger.warn PaymentRejectedEvent.new("abcd1234", 100, "Card expired")
205
+ logger.info('key=value')
206
+ # key=value @metadata {"level": "info", "context": {...}}
118
207
  ```
119
208
 
120
- (for more examples, see [the `Timber::Logger` docs](lib/timber/logger.rb))
209
+ ---
210
+
211
+ </p></details>
212
+
213
+ <details><summary><strong>Custom contexts</strong></summary><p>
121
214
 
122
- No mention of Timber anywhere!
215
+ Context is structured data representing the current environment when the log line was written.
216
+ It is included in every log line. Think of it like join data for your logs. For example, the
217
+ `http.request_id` field is included in the context, allowing you to find all log lines related
218
+ to that request ID, if desired. This is in contrast to *only* showing log lines that contain this
219
+ value.
123
220
 
221
+ 1. Add a Hash (simplest)
124
222
 
125
- ## The Timber Console / Pricing
223
+ ```ruby
224
+ Timber::CurrentContext.with({build: {version: "1.0.0"}}) do
225
+ logger.info("My log message")
226
+ end
126
227
 
127
- > What good is structured log data if you can't search and visualize it?
228
+ # My log message @metadata {"level": "info", "context": {"build": {"version": "1.0.0"}}}
229
+ ```
128
230
 
129
- The [Timber Console](https://timber.io) is *fast*, modern, and beautiful console designed
130
- specifically for this library.
231
+ This adds data to the context keyspaced by `build`.
131
232
 
132
- A few example queries:
233
+ 2. Add a Struct (recommended)
133
234
 
134
- 1. `context.user.email:ben@johnson.com` - Tail a specific user!
135
- 2. `context.http.request_id:1234` - View *all* logs for a given HTTP request!
136
- 3. `event.http_reponse.time_ms>3000` - Easily find outliers and have the proper context to resolve them!
137
- 4. `level:warn` - Log levels in your logs. Imagine that!
235
+ Just like events, we recommend defining your custom contexts. It makes a stronger contract
236
+ with downstream consumers.
138
237
 
139
- > This is all gravy, but wouldn't the extra data get expensive?
238
+ ```ruby
239
+ BuildContext = Struct.new(:version) do
240
+ def type; :build; end
241
+ end
242
+ build_context = BuildContext.new("1.0.0")
243
+ Timber::CurrentContext.with(build_context) do
244
+ logger.info("My log message")
245
+ end
140
246
 
141
- If you opt to use the [Timber Console](https://timber.io), we only charge for
142
- the size of the `message`, `dt`, and `event.custom` attributes. Everything else is
143
- stored at no cost to you. [Say wha?!](http://i.giphy.com/l0HlL2vlfpWI0meJi.gif). This ensures
144
- pricing remains predictable. We charge per GB sent to us and retained. No user limits,
145
- no weird feature matrixes, just data. Finally, the data is yours, in a simple
146
- non-proprietary JSON format that you can export to S3, Redshift, or any of our other integrations.
247
+ # My log message @metadata {"level": "info", "context": {"build": {"version": "1.0.0"}}}
248
+ ```
147
249
 
148
- For more details checkout out [timber.io](https://timber.io).
250
+ </p></details>
149
251
 
150
- ## Install
151
252
 
152
- **Timber is in beta testing. If interested, please email beta@timber.io**
153
253
 
154
- ### 1. Install the gem:
254
+ ## Installation
155
255
 
156
256
  ```ruby
157
257
  # Gemfile
158
258
  gem 'timber'
159
259
  ```
160
260
 
161
- ### 2. Install the logger:
162
261
 
163
- #### Heroku:
262
+ ## Setup
263
+
264
+ <details><summary><strong>Rails >= 3.0</strong></summary><p>
265
+
266
+ *Replace* any existing `config.logger=` calls in `config/environments/production.rb` with:
164
267
 
165
268
  ```ruby
166
- # config/environments/production.rb (or staging, etc)
167
- config.logger = Timber::Logger.new(STDOUT)
269
+ # config/environments/production.rb
270
+
271
+ config.logger = ActiveSupport::TaggedLogging.new(Timber::Logger.new(STDOUT))
168
272
  ```
169
273
 
170
- The command to add your log drain will be displayed in the [Timber app](https://app.timber.io)
171
- after you add your application.
274
+ * Prefer examples? Checkout our [Ruby / Rails example app](https://github.com/timberio/ruby-rails-example-app),
275
+ you can see all changes by [search for "timber-change"](https://github.com/timberio/ruby-rails-example-app/search?utf8=%E2%9C%93&q=timber-change&type=Code).
172
276
 
173
- #### Non-Heroku:
277
+ ---
174
278
 
175
- ```ruby
176
- # config/environments/production.rb (or staging, etc)
177
- log_device = Timber::LogDevices::HTTP.new(ENV['TIMBER_KEY']) # key can be obtained by signing up at https://timber.io
178
- config.logger = Timber::Logger.new(log_device)
179
- ```
279
+ </p></details>
180
280
 
181
- Your Timber application key will be displayed in the [Timber app](https://app.timber.io)
182
- after you add your application.
281
+ <details><summary><strong>Other</strong></summary><p>
183
282
 
283
+ 1. *Insert* the Timber probes:
184
284
 
185
- *Other transport methods coming soon!*
285
+ This should be executed *immediately after* you have required your dependencies.
186
286
 
287
+ ```ruby
288
+ Timber::Probes.insert!
289
+ ```
187
290
 
188
- #### Rails TaggedLogging?
291
+ 2. *Add* the Rack middlewares:
189
292
 
190
- No probs! Use it as normal, Timber will even pull out the tags and include them in the `context`.
293
+ This should be included where you build your `Rack` application. Usually `config.ru`:
191
294
 
192
- ```ruby
193
- config.logger = ActiveSupport::TaggedLogging.new(Timber::Logger.new(STDOUT))
194
- ```
295
+ ```ruby
296
+ # Most likely config.ru
297
+
298
+ Timber::RackMiddlewares.middlewares.each do |m|
299
+ use m
300
+ end
301
+ ```
302
+
303
+ 2. *Instantiate* the Timber logger:
304
+
305
+ This should be *globally* available to your application:
306
+
307
+ ```ruby
308
+ logger = Timber::Logger.new(STDOUT)
309
+ ```
310
+
311
+ </p></details>
312
+
313
+
314
+ ## Send your logs
315
+
316
+ <details><summary><strong>Heroku (log drains)</strong></summary><p>
317
+
318
+ The recommended strategy for Heroku is to setup a
319
+ [log drain](https://devcenter.heroku.com/articles/log-drains). To get your Timber log drain URL:
320
+
321
+ 👉 **[Add your app to Timber](https://app.timber.io)**
195
322
 
196
323
  ---
197
324
 
198
- <p align="center" style="background: #140f2a;">
325
+ </p></details>
326
+
327
+ <details><summary><strong>All other platforms (Network / HTTP)</strong></summary><p>
328
+
329
+ 1. *Specify* the Timber Network logger backend in `config/environments/production.rb`:
330
+
331
+ Replace any existing `config.logger =` calls with:
332
+
333
+ ```ruby
334
+ # config/environments/production.rb (or staging, etc)
335
+
336
+ network_log_device = Timber::LogDevices::Network.new(ENV['TIMBER_LOGS_KEY'])
337
+ config.logger = Timber::Logger.new(network_log_device) # <-- Use network_log_device instead of STDOUT
338
+ ```
339
+
340
+ 2. Obtain your Timber API :key: by **[adding your app in Timber](https://app.timber.io)**.
341
+
342
+ 3. Assign your API key to the `TIMBER_LOGS_KEY` environment variable.
343
+
344
+ </p></details>
345
+
346
+ <details><summary><strong>Advanced setup (syslog, file tailing agent, etc)</strong></summary><p>
347
+
348
+ Checkout our [docs](https://timber.io/docs) for a comprehensive list of install instructions.
349
+
350
+ </p></details>
351
+
352
+
353
+ ---
354
+
355
+ <p align="center" style="background: #221f40;">
199
356
  <a href="http://github.com/timberio/timber-ruby"><img src="http://files.timber.io/images/ruby-library-readme-log-truth.png" height="947" /></a>
200
- </p>
357
+ </p>