timber 1.0.3
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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.yardopts +6 -0
- data/Appraisals +41 -0
- data/Gemfile +30 -0
- data/LICENSE.md +15 -0
- data/README.md +194 -0
- data/circle.yml +33 -0
- data/lib/timber/config.rb +18 -0
- data/lib/timber/context.rb +17 -0
- data/lib/timber/contexts/custom.rb +27 -0
- data/lib/timber/contexts/http.rb +28 -0
- data/lib/timber/contexts/organization.rb +35 -0
- data/lib/timber/contexts/user.rb +36 -0
- data/lib/timber/contexts.rb +10 -0
- data/lib/timber/current_context.rb +43 -0
- data/lib/timber/event.rb +17 -0
- data/lib/timber/events/controller_call.rb +40 -0
- data/lib/timber/events/custom.rb +42 -0
- data/lib/timber/events/exception.rb +35 -0
- data/lib/timber/events/http_request.rb +50 -0
- data/lib/timber/events/http_response.rb +36 -0
- data/lib/timber/events/sql_query.rb +26 -0
- data/lib/timber/events/template_render.rb +26 -0
- data/lib/timber/events.rb +37 -0
- data/lib/timber/frameworks/rails.rb +13 -0
- data/lib/timber/frameworks.rb +19 -0
- data/lib/timber/log_devices/http.rb +87 -0
- data/lib/timber/log_devices.rb +8 -0
- data/lib/timber/log_entry.rb +59 -0
- data/lib/timber/logger.rb +142 -0
- data/lib/timber/probe.rb +23 -0
- data/lib/timber/probes/action_controller_log_subscriber/log_subscriber.rb +64 -0
- data/lib/timber/probes/action_controller_log_subscriber.rb +20 -0
- data/lib/timber/probes/action_dispatch_debug_exceptions.rb +80 -0
- data/lib/timber/probes/action_view_log_subscriber/log_subscriber.rb +62 -0
- data/lib/timber/probes/action_view_log_subscriber.rb +20 -0
- data/lib/timber/probes/active_record_log_subscriber/log_subscriber.rb +29 -0
- data/lib/timber/probes/active_record_log_subscriber.rb +20 -0
- data/lib/timber/probes/rack_http_context.rb +51 -0
- data/lib/timber/probes/rails_rack_logger.rb +76 -0
- data/lib/timber/probes.rb +21 -0
- data/lib/timber/util/active_support_log_subscriber.rb +33 -0
- data/lib/timber/util/hash.rb +14 -0
- data/lib/timber/util.rb +8 -0
- data/lib/timber/version.rb +3 -0
- data/lib/timber.rb +22 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/support/action_controller.rb +4 -0
- data/spec/support/action_view.rb +4 -0
- data/spec/support/active_record.rb +28 -0
- data/spec/support/coveralls.rb +2 -0
- data/spec/support/rails/templates/_partial.html +1 -0
- data/spec/support/rails/templates/template.html +1 -0
- data/spec/support/rails.rb +37 -0
- data/spec/support/simplecov.rb +9 -0
- data/spec/support/socket_hostname.rb +12 -0
- data/spec/support/timber.rb +4 -0
- data/spec/support/timecop.rb +3 -0
- data/spec/support/webmock.rb +2 -0
- data/spec/timber/events_spec.rb +55 -0
- data/spec/timber/log_devices/http_spec.rb +62 -0
- data/spec/timber/logger_spec.rb +89 -0
- data/spec/timber/probes/action_controller_log_subscriber_spec.rb +70 -0
- data/spec/timber/probes/action_dispatch_debug_exceptions_spec.rb +51 -0
- data/spec/timber/probes/action_view_log_subscriber_spec.rb +61 -0
- data/spec/timber/probes/active_record_log_subscriber_spec.rb +52 -0
- data/spec/timber/probes/rack_http_context_spec.rb +54 -0
- data/spec/timber/probes/rails_rack_logger_spec.rb +46 -0
- data/timber.gemspec +22 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8580577f8c85abeb5eacec510136a2bf05d72406
|
4
|
+
data.tar.gz: 7a08aa6f00eda500d016c413ccf2b95d759b9266
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b906867c8198c1d94052856b6e7b402af88bd252b770ed9a8a33aae7284a3f562569f4fde7202c759eb786e28f8b85b0b5a2b1ab8c2b5d63bde56f1ee686d404
|
7
|
+
data.tar.gz: d4afc694df19c1c90a4711b7d1762bb0f203cf4521aa44a1f63d5e7f66c8cef37258f7af2c8e6fb73b166305aa43a1b4bfce3a2ea0c625e1951e9bc0726657dc
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.yardopts
ADDED
data/Appraisals
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
appraise "rails-2.3.X" do
|
2
|
+
gem "rails", "~> 2.3.18"
|
3
|
+
end
|
4
|
+
|
5
|
+
appraise "rails-3.0.X" do
|
6
|
+
gem "rails", "~> 3.0.20"
|
7
|
+
end
|
8
|
+
|
9
|
+
appraise "rails-3.1.X" do
|
10
|
+
gem "rails", "~> 3.1.12"
|
11
|
+
end
|
12
|
+
|
13
|
+
appraise "rails-3.2.X" do
|
14
|
+
gem "rails", "~> 3.2.22"
|
15
|
+
end
|
16
|
+
|
17
|
+
appraise "rails-4.0.X" do
|
18
|
+
gem "minitest"
|
19
|
+
gem "rails", "~> 4.0.13"
|
20
|
+
end
|
21
|
+
|
22
|
+
appraise "rails-4.1.X" do
|
23
|
+
gem "minitest"
|
24
|
+
gem "rails", "~> 4.1.15"
|
25
|
+
end
|
26
|
+
|
27
|
+
appraise "rails-4.2.X" do
|
28
|
+
gem "minitest"
|
29
|
+
gem "rails", "~> 4.2.7"
|
30
|
+
end
|
31
|
+
|
32
|
+
appraise "rails-5.0.X" do
|
33
|
+
gem "minitest"
|
34
|
+
gem "rails", "~> 5.0.0"
|
35
|
+
end
|
36
|
+
|
37
|
+
appraise "rails-edge" do
|
38
|
+
gem 'rack', github: 'rack/rack', branch: 'master'
|
39
|
+
gem 'arel', github: 'rails/arel', branch: 'master'
|
40
|
+
gem 'rails', github: 'rails/rails', branch: 'master'
|
41
|
+
end
|
data/Gemfile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
gemspec
|
3
|
+
|
4
|
+
group :test do
|
5
|
+
gem 'appraisal'
|
6
|
+
gem 'coveralls', require: false
|
7
|
+
gem 'json', '~> 1'
|
8
|
+
gem 'pry'
|
9
|
+
gem 'rails_stdout_logging'
|
10
|
+
gem 'rake'
|
11
|
+
gem 'rspec', '~> 3.4'
|
12
|
+
gem 'rspec-its'
|
13
|
+
gem 'simplecov', require: false
|
14
|
+
gem 'sqlite3'
|
15
|
+
gem 'terminal-table'
|
16
|
+
gem 'timecop'
|
17
|
+
|
18
|
+
ruby_version = Gem::Version.new("#{RUBY_VERSION}")
|
19
|
+
if ruby_version < Gem::Version.new("2.0.0")
|
20
|
+
gem 'public_suffix', '~> 1.4.6'
|
21
|
+
gem 'term-ansicolor', '~> 1.3.2'
|
22
|
+
gem 'webmock', '~> 2.2.0'
|
23
|
+
else
|
24
|
+
gem 'webmock'
|
25
|
+
end
|
26
|
+
|
27
|
+
# for coveralls
|
28
|
+
gem 'rest-client', '~> 1.8' # >= 2.0 requires ruby 2+, we have tests for 1.9
|
29
|
+
gem 'tins', '~> 1.6.0' # > 1.6 requires ruby 2+, we have tests for 1.9
|
30
|
+
end
|
data/LICENSE.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# License
|
2
|
+
|
3
|
+
Copyright (c) 2016, Timber Technologies, Inc.
|
4
|
+
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
6
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
7
|
+
and this permission notice appear in all copies.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
11
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
13
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
14
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
15
|
+
THIS SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
# Timber
|
2
|
+
|
3
|
+
<p align="center" style="background: #140f2a;">
|
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
|
+
</p>
|
6
|
+
|
7
|
+
[](https://circleci.com/gh/timberio/timber-ruby/tree/master)
|
8
|
+
[](https://coveralls.io/github/timberio/timber-ruby?branch=master)
|
9
|
+
[](https://codeclimate.com/github/timberio/timber-ruby)
|
10
|
+
[](http://www.rubydoc.info/github/timberio/timber-ruby)
|
11
|
+
|
12
|
+
|
13
|
+
1. [What is timber?](#what-is-timber)
|
14
|
+
1. [How does it work?](#what-is-timber)
|
15
|
+
2. [Logging Custom Events](#logging-custom-events)
|
16
|
+
3. [The Timber Console / Pricing](#the-timber-console-pricing)
|
17
|
+
2. [Install](#install)
|
18
|
+
|
19
|
+
|
20
|
+
## What is Timber?
|
21
|
+
|
22
|
+
Timber automatically structures your logs with events and context in a non-proprietary JSON format.
|
23
|
+
It’s simple, quick, managed, and has absolutely no risk of code debt or lock-in.
|
24
|
+
It’s just good ol’ logging.
|
25
|
+
|
26
|
+
Timber’s philosophy is that application insight should be open and owned by you.
|
27
|
+
And there is no better vehicle than logging:
|
28
|
+
|
29
|
+
1. It’s a shared practice that has been around since the dawn of computers.
|
30
|
+
2. It’s baked into every language, library, and framework. Even your own apps.
|
31
|
+
3. The data is entirely owned by you.
|
32
|
+
|
33
|
+
The problem is that logs are messy, noisy, and hard to use. Timber solves this by being
|
34
|
+
application aware, properly structuring your logs, and optionally providing a [fast, modern,
|
35
|
+
and beautiful console](https://timber.io) -- allowing you to realize the power of
|
36
|
+
your logs.
|
37
|
+
|
38
|
+
|
39
|
+
## How does it work?
|
40
|
+
|
41
|
+
Glad you asked! :) Timber automatically structures your logs by taking advantage of public APIs.
|
42
|
+
|
43
|
+
For example, by subscribing to `ActiveSupport::Notifications`, Timber can automatically turn this:
|
44
|
+
|
45
|
+
```
|
46
|
+
Completed 200 OK in 117ms (Views: 85.2ms | ActiveRecord: 25.3ms)
|
47
|
+
```
|
48
|
+
|
49
|
+
Into this:
|
50
|
+
|
51
|
+
```json
|
52
|
+
{
|
53
|
+
"dt": "2016-12-01T02:23:12.236543Z",
|
54
|
+
"level": "info",
|
55
|
+
"message": "Completed 200 OK in 117ms (Views: 85.2ms | ActiveRecord: 25.3ms)",
|
56
|
+
"context": {
|
57
|
+
"http": {
|
58
|
+
"method": "GET",
|
59
|
+
"path": "/checkout",
|
60
|
+
"remote_addr": "123.456.789.10",
|
61
|
+
"request_id": "abcd1234"
|
62
|
+
},
|
63
|
+
"user": {
|
64
|
+
"id": 2,
|
65
|
+
"name": "Ben Johnson",
|
66
|
+
"email": "ben@johnson.com"
|
67
|
+
}
|
68
|
+
},
|
69
|
+
"event": {
|
70
|
+
"http_response": {
|
71
|
+
"status": 200,
|
72
|
+
"time_ms": 117
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
```
|
77
|
+
|
78
|
+
It does the same for `http requests`, `sql queries`, `exceptions`, `template renderings`,
|
79
|
+
and any other event your framework logs. (for a full list see `Timber::Events`)
|
80
|
+
|
81
|
+
|
82
|
+
## Logging Custom Events
|
83
|
+
|
84
|
+
> Another service? More code debt? :*(
|
85
|
+
|
86
|
+
Nope! Logging custom events is Just Logging™. Check it out:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
# Simple string (original Logger interface remains untouched)
|
90
|
+
Logger.warn "Payment rejected for customer abcd1234, reason: Card expired"
|
91
|
+
|
92
|
+
# Structured hash
|
93
|
+
Logger.warn message: "Payment rejected", type: :payment_rejected,
|
94
|
+
data: %{customer_id: "abcd1234", amount: 100, reason: "Card expired"}
|
95
|
+
|
96
|
+
# Using a Struct
|
97
|
+
PaymentRejectedEvent = Struct.new(:customer_id, :amount, :reason) do
|
98
|
+
def message; "Payment rejected for #{customer_id}"; end
|
99
|
+
def type; :payment_rejected; end
|
100
|
+
end
|
101
|
+
Logger.warn PaymentRejectedEvent.new("abcd1234", 100, "Card expired")
|
102
|
+
```
|
103
|
+
|
104
|
+
(for more examples, see the `Timber::Logger` docs)
|
105
|
+
|
106
|
+
No mention of Timber anywhere! In fact, this approach pushes things the opposite way. What if,
|
107
|
+
as a result of structured logging, you could start decoupling other services from your application?
|
108
|
+
|
109
|
+
Before:
|
110
|
+
|
111
|
+
```
|
112
|
+
|---[HTTP]---> sentry / bugsnag / etc
|
113
|
+
My Application |---[HTTP]---> librato / graphite / etc
|
114
|
+
|---[HTTP]---> new relic / etc
|
115
|
+
|--[STDOUT]--> logs
|
116
|
+
|---> Logging service
|
117
|
+
|---> S3
|
118
|
+
|---> RedShift
|
119
|
+
```
|
120
|
+
|
121
|
+
|
122
|
+
After:
|
123
|
+
|
124
|
+
```
|
125
|
+
|-- sentry / bugsnag / etc
|
126
|
+
|-- librato / graphite / etc
|
127
|
+
My Application |--[STDOUT]--> logs ---> Timber ---> |-- new relic / etc
|
128
|
+
^ |-- S3
|
129
|
+
| |-- RedShift
|
130
|
+
| ^
|
131
|
+
fast, efficient, durable, |
|
132
|
+
replayable, auditable, change any of these without
|
133
|
+
just logging touching your code
|
134
|
+
*and* backfill them!
|
135
|
+
```
|
136
|
+
|
137
|
+
[Mind-blown!](http://i.giphy.com/EldfH1VJdbrwY.gif)
|
138
|
+
|
139
|
+
|
140
|
+
|
141
|
+
## The Timber Console / Pricing
|
142
|
+
|
143
|
+
> This is all gravy, but wouldn't the extra data get expensive?
|
144
|
+
|
145
|
+
If you opt use the [Timber Console](https://timber.io), we only charge for
|
146
|
+
the size of the `message`, `dt`, and `event.custom` attributes. Everything else is
|
147
|
+
stored at no cost to you. [Say wha?!](http://i.giphy.com/l0HlL2vlfpWI0meJi.gif). This ensures
|
148
|
+
pricing remains predictable. We charge per GB sent to us and retained. No user limits,
|
149
|
+
no weird feature matrixes, just data. Finally, the data is yours, in a simple
|
150
|
+
non-proprietary JSON format that you can export to S3, Redshift, or any of our other integrations.
|
151
|
+
|
152
|
+
For more details checkout out [timber.io](https://timber.io).
|
153
|
+
|
154
|
+
## Install
|
155
|
+
|
156
|
+
### 1. Install the gem:
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
# Gemfile
|
160
|
+
gem 'timber'
|
161
|
+
```
|
162
|
+
|
163
|
+
### 2. Install the logger:
|
164
|
+
|
165
|
+
#### Heroku:
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
# config/environments/production.rb (or staging, etc)
|
169
|
+
config.logger = Timber::Logger.new(STDOUT)
|
170
|
+
```
|
171
|
+
|
172
|
+
The command to add your log drain will be displayed in the [Timber app](https://app.timber.io)
|
173
|
+
after you add your application.
|
174
|
+
|
175
|
+
#### Non-Heroku:
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
# config/environments/production.rb (or staging, etc)
|
179
|
+
log_device = Timber::LogDevices::HTTP.new(ENV['TIMBER_KEY']) # key can be obtained by signing up at https://timber.io
|
180
|
+
config.logger = Timber::Logger.new(log_device)
|
181
|
+
```
|
182
|
+
|
183
|
+
Your Timber application key will be displayed in the [Timber app](https://app.timber.io)
|
184
|
+
after you add your application.
|
185
|
+
|
186
|
+
|
187
|
+
*Other transport methods coming soon!*
|
188
|
+
|
189
|
+
---
|
190
|
+
|
191
|
+
That's it! Log to your heart's content.
|
192
|
+
|
193
|
+
For documentation on logging structured events, and other features,
|
194
|
+
checkout [the docs](http://thedocs.com/). For more information on Timber visit [timber.io](https://timber.io).
|
data/circle.yml
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
machine:
|
2
|
+
environment:
|
3
|
+
COVERALLS_REPO_TOKEN: fzLA6t2EFT4KBemv3du0AdHGcqTzyRzlr
|
4
|
+
|
5
|
+
dependencies:
|
6
|
+
override:
|
7
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/bin:$PATH rvm-exec 1.9.3 bundle install
|
8
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/bin:$PATH rvm-exec 1.9.3 appraisal generate
|
9
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/bin:$PATH rvm-exec 1.9.3 appraisal rails-2.3.X bundle install
|
10
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/bin:$PATH rvm-exec 1.9.3 appraisal rails-3.0.X bundle install
|
11
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/bin:$PATH rvm-exec 1.9.3 appraisal rails-3.1.X bundle install
|
12
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/bin:$PATH rvm-exec 1.9.3 appraisal rails-3.2.X bundle install
|
13
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.2.6/bin:$PATH rvm-exec 2.2.6 bundle install
|
14
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.2.6/bin:$PATH rvm-exec 2.2.6 appraisal install
|
15
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.3.3/bin:$PATH rvm-exec 2.3.3 bundle install
|
16
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.3.3/bin:$PATH rvm-exec 2.3.3 appraisal install
|
17
|
+
|
18
|
+
test:
|
19
|
+
override:
|
20
|
+
- RAILS_23=true PATH=/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/bin:$PATH rvm-exec 1.9.3 appraisal rails-2.3.X rspec --tag rails_23
|
21
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/bin:$PATH rvm-exec 1.9.3 appraisal rails-3.0.X rspec
|
22
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/bin:$PATH rvm-exec 1.9.3 appraisal rails-3.1.X rspec
|
23
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/bin:$PATH rvm-exec 1.9.3 appraisal rails-3.2.X rspec
|
24
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.2.6/bin:$PATH rvm-exec 2.2.6 appraisal rails-4.0.X rspec
|
25
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.2.6/bin:$PATH rvm-exec 2.2.6 appraisal rails-4.1.X rspec
|
26
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.2.6/bin:$PATH rvm-exec 2.2.6 appraisal rails-4.2.X rspec
|
27
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.2.6/bin:$PATH rvm-exec 2.2.6 appraisal rails-5.0.X rspec
|
28
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.2.6/bin:$PATH rvm-exec 2.2.6 appraisal rails-edge rspec
|
29
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.3.3/bin:$PATH rvm-exec 2.3.3 appraisal rails-4.0.X rspec
|
30
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.3.3/bin:$PATH rvm-exec 2.3.3 appraisal rails-4.1.X rspec
|
31
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.3.3/bin:$PATH rvm-exec 2.3.3 appraisal rails-4.2.X rspec
|
32
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.3.3/bin:$PATH rvm-exec 2.3.3 appraisal rails-5.0.X rspec
|
33
|
+
- PATH=/home/ubuntu/.rvm/gems/ruby-2.3.3/bin:$PATH rvm-exec 2.3.3 appraisal rails-edge rspec
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "singleton"
|
2
|
+
|
3
|
+
module Timber
|
4
|
+
# Interface for configuring Timber.
|
5
|
+
#
|
6
|
+
# @note If using rails this will be installed in the `config` object via `config.timber`.
|
7
|
+
class Config
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
attr_writer :logger
|
11
|
+
|
12
|
+
# Set a logger to view internal Timber library log message.
|
13
|
+
# Useful for debugging. Defaults to `::Logger.new(nil)`.
|
14
|
+
def logger
|
15
|
+
@logger ||= Logger.new(nil)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Timber
|
2
|
+
# Base class for all `Timber::Contexts::*` classes.
|
3
|
+
# @private
|
4
|
+
class Context
|
5
|
+
def keyspace
|
6
|
+
raise NoImplementedError.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def as_json(options = {})
|
10
|
+
raise NotImplementedError.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_json(options = {})
|
14
|
+
Util::Hash.compact(as_json).to_json(options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Timber
|
2
|
+
module Contexts
|
3
|
+
# Custom contexts allow you to add application specific context not covered elsewhere.
|
4
|
+
#
|
5
|
+
# @example Adding a context
|
6
|
+
# custom_context = Timber::Contexts::Custom.new(type: :keyspace, data: %{my: "data"})
|
7
|
+
# Timber::CurrentContext.with(custom_context) do
|
8
|
+
# # ... anything logged here will have the context ...
|
9
|
+
# end
|
10
|
+
class Custom < Context
|
11
|
+
attr_reader :type, :data
|
12
|
+
|
13
|
+
def initialize(attributes)
|
14
|
+
@type = attributes[:type] || raise(ArgumentError.new(":type is required"))
|
15
|
+
@data = attributes[:data] || raise(ArgumentError.new(":data is required"))
|
16
|
+
end
|
17
|
+
|
18
|
+
def keyspace
|
19
|
+
:custom
|
20
|
+
end
|
21
|
+
|
22
|
+
def as_json(_options = {})
|
23
|
+
{type => data}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Timber
|
2
|
+
module Contexts
|
3
|
+
# The HTTP content tracks the current HTTP request being processed. This serves
|
4
|
+
# as join data across your logs, allowing you to query all logs for any attribute
|
5
|
+
# presented here. For example, viewing all logs for a given request_id.
|
6
|
+
#
|
7
|
+
# @note This context should be installed automatically through probes,
|
8
|
+
# such as the {Probes::RackHTTPContext} probe.
|
9
|
+
class HTTP < Context
|
10
|
+
attr_reader :method, :path, :remote_addr, :request_id
|
11
|
+
|
12
|
+
def initialize(attributes)
|
13
|
+
@method = attributes[:method] || raise(ArgumentError.new(":method is required"))
|
14
|
+
@path = attributes[:path] || raise(ArgumentError.new(":path is required"))
|
15
|
+
@remote_addr = attributes[:remote_addr]
|
16
|
+
@request_id = attributes[:request_id]
|
17
|
+
end
|
18
|
+
|
19
|
+
def keyspace
|
20
|
+
:http
|
21
|
+
end
|
22
|
+
|
23
|
+
def as_json(_options = {})
|
24
|
+
{:method => method, :path => path, :remote_addr => remote_addr, :request_id => request_id}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Timber
|
2
|
+
module Contexts
|
3
|
+
# The organization context tracks the organization of the currently
|
4
|
+
# authenticated user.
|
5
|
+
#
|
6
|
+
# You will want to add this context at the time you determine
|
7
|
+
# the organization a user belongs to, typically in the authentication
|
8
|
+
# flow.
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
#
|
12
|
+
# organization_context = Timber::Contexts::Organization.new(id: "abc1234", name: "Timber Inc")
|
13
|
+
# Timber::CurrentContext.with(organization_context) do
|
14
|
+
# # Logging will automatically include this context
|
15
|
+
# logger.info("This is a log message")
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
class Organization < Context
|
19
|
+
attr_reader :id, :name
|
20
|
+
|
21
|
+
def initialize(attributes)
|
22
|
+
@id = attributes[:id]
|
23
|
+
@name = attributes[:name]
|
24
|
+
end
|
25
|
+
|
26
|
+
def keyspace
|
27
|
+
:organization
|
28
|
+
end
|
29
|
+
|
30
|
+
def as_json(_options = {})
|
31
|
+
{id: id, name: name}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Timber
|
2
|
+
module Contexts
|
3
|
+
# The user context tracks the currently authenticated user.
|
4
|
+
#
|
5
|
+
# You will want to add this context at the time log the user in, typically
|
6
|
+
# during the authentication flow.
|
7
|
+
#
|
8
|
+
# Note: Timber will attempt to automatically add this if you add a #current_user
|
9
|
+
# method to your controllers. Most authentication solutions do this for you automatically.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
#
|
13
|
+
# user_context = Timber::Contexts::User.new(id: "abc1234", name: "Ben Johnson")
|
14
|
+
# Timber::CurrentContext.with(user_context) do
|
15
|
+
# # Logging will automatically include this context
|
16
|
+
# logger.info("This is a log message")
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
class User < Context
|
20
|
+
attr_reader :id, :name
|
21
|
+
|
22
|
+
def initialize(attributes)
|
23
|
+
@id = attributes[:id]
|
24
|
+
@name = attributes[:name]
|
25
|
+
end
|
26
|
+
|
27
|
+
def keyspace
|
28
|
+
:user
|
29
|
+
end
|
30
|
+
|
31
|
+
def as_json(_options = {})
|
32
|
+
{id: id, name: name}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "singleton"
|
2
|
+
|
3
|
+
module Timber
|
4
|
+
# Holds the current context in a thread safe memory storage. This context is
|
5
|
+
# appended to every log line. Think of context as join data between your log lines,
|
6
|
+
# allowing you to relate them and filter them appropriately.
|
7
|
+
class CurrentContext
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
THREAD_NAMESPACE = :_timber_current_context.freeze
|
11
|
+
|
12
|
+
class << self
|
13
|
+
# Convenience method for {#with}.
|
14
|
+
#
|
15
|
+
# @example Adding a context
|
16
|
+
# custom_context = Timber::Contexts::Custom.new(type: :keyspace, data: %{my: "data"})
|
17
|
+
# Timber::CurrentContext.with(custom_context) do
|
18
|
+
# # ... anything logged here will have the context ...
|
19
|
+
# end
|
20
|
+
def with(*args, &block)
|
21
|
+
instance.with(*args, &block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Adds a context to the current stack.
|
26
|
+
def with(data)
|
27
|
+
key = data.keyspace
|
28
|
+
hash[key] = data
|
29
|
+
yield
|
30
|
+
ensure
|
31
|
+
hash.delete(key)
|
32
|
+
end
|
33
|
+
|
34
|
+
def snapshot
|
35
|
+
hash.clone
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def hash
|
40
|
+
Thread.current[THREAD_NAMESPACE] ||= {}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/timber/event.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Timber
|
2
|
+
# Base class for `Timber::Events::*`
|
3
|
+
# @private
|
4
|
+
class Event
|
5
|
+
def message
|
6
|
+
raise NotImplementedError.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def as_json(options = {})
|
10
|
+
raise NotImplementedError.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_json(options = {})
|
14
|
+
Util::Hash.compact(as_json).to_json(options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Timber
|
2
|
+
module Events
|
3
|
+
# The controller call event tracks controller invocations. For example, this line in Rails:
|
4
|
+
#
|
5
|
+
# Processing by PagesController#home as HTML
|
6
|
+
#
|
7
|
+
# @note This event should be installed automatically through probes,
|
8
|
+
# such as the {Probes::ActionControllerLogSubscriber} probe.
|
9
|
+
class ControllerCall < Timber::Event
|
10
|
+
attr_reader :controller, :action, :params, :format
|
11
|
+
|
12
|
+
def initialize(attributes)
|
13
|
+
@controller = attributes[:controller] || raise(ArgumentError.new(":controller is required"))
|
14
|
+
@action = attributes[:action] || raise(ArgumentError.new(":action is required"))
|
15
|
+
@params = attributes[:params]
|
16
|
+
@format = attributes[:format]
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_hash
|
20
|
+
{controller: controller, action: action}
|
21
|
+
end
|
22
|
+
alias to_h to_hash
|
23
|
+
|
24
|
+
def as_json(_options = {})
|
25
|
+
{:controller_call => to_hash}
|
26
|
+
end
|
27
|
+
|
28
|
+
def message
|
29
|
+
message = "Processing by #{controller}##{action}"
|
30
|
+
if !message.nil?
|
31
|
+
message << " as #{format}"
|
32
|
+
end
|
33
|
+
if !params.nil? && params.length > 0
|
34
|
+
message << "\n Parameters: #{params.inspect}"
|
35
|
+
end
|
36
|
+
message
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Timber
|
2
|
+
module Events
|
3
|
+
# Allows for custom events that aren't covered elsewhere.
|
4
|
+
#
|
5
|
+
# Custom events can be used to encode information about events that are central
|
6
|
+
# to your line of business like receiving credit card payments, saving a draft of a post,
|
7
|
+
# or changing a user's password.
|
8
|
+
#
|
9
|
+
# For examples of logging custom events see {Logger}.
|
10
|
+
class Custom < Timber::Event
|
11
|
+
attr_reader :type, :message, :data
|
12
|
+
|
13
|
+
# Instantiates a new custom event that can be logged. See {Logger} for examples
|
14
|
+
# on logging custom events.
|
15
|
+
#
|
16
|
+
# @param [Hash] attributes the options to create a custom event with.
|
17
|
+
# @option attributes [Symbol] :type *required* The custom event type. This should be in
|
18
|
+
# snake case. Example: `:my_custom_event`.
|
19
|
+
# @option attributes [String] :message *required* The message to be logged.
|
20
|
+
# @option attributes [Hash] :data A hash of JSON encodable data to be stored with the
|
21
|
+
# log line.
|
22
|
+
def initialize(attributes)
|
23
|
+
@type = attributes[:type] || raise(ArgumentError.new(":type is required"))
|
24
|
+
@message = attributes[:message] || raise(ArgumentError.new(":message is required"))
|
25
|
+
@data = attributes[:data]
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_hash
|
29
|
+
{type => data}
|
30
|
+
end
|
31
|
+
alias to_h to_hash
|
32
|
+
|
33
|
+
def as_json(_options = {})
|
34
|
+
{:custom => to_hash}
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_json(options = {})
|
38
|
+
as_json().to_json(options)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|