opbeat 1.1.1 → 2.0.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.
- checksums.yaml +4 -4
- data/README.md +25 -8
- data/lib/opbeat.rb +0 -1
- data/lib/opbeat/client.rb +3 -6
- data/lib/opbeat/configuration.rb +4 -5
- data/lib/opbeat/filter.rb +63 -0
- data/lib/opbeat/version.rb +1 -1
- data/spec/opbeat/filter_spec.rb +101 -0
- metadata +4 -5
- data/lib/opbeat/processor.rb +0 -15
- data/lib/opbeat/processors/sanitizedata.rb +0 -43
- data/spec/opbeat/sanitizedata_processor_spec.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0cc7e45c2207d40f1deaa655ae2510e7f6c38d7c
|
4
|
+
data.tar.gz: 2793d306ca86292a30fedc2ee831af7086862adc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 388d8dedb07d74f4ee42fa21855a037a0559ea4c783e2107a8158dcc9dd2510e6e4fdc0e90a19b1a4e7fa4fdf290a50ebf23aacab5934ca937ab9edd84a01616
|
7
|
+
data.tar.gz: 2dc336b2815d477d7fc2fd30d2941f60cf5dd95777bdb1e3a3e70440eaa119546daff324ab07798b6d2bc58d2c15083704aa6dabbabb6fdd5fcbebbd287b59b4
|
data/README.md
CHANGED
@@ -4,15 +4,19 @@
|
|
4
4
|
|
5
5
|
A client and integration layer for [Opbeat](https://opbeat.com). Forked from the [raven-ruby](https://github.com/getsentry/raven-ruby) project.
|
6
6
|
|
7
|
-
|
8
7
|
## Installation
|
9
8
|
|
10
9
|
Add the following to your `Gemfile`:
|
11
10
|
|
12
11
|
```ruby
|
13
|
-
gem "opbeat"
|
12
|
+
gem "opbeat", "~> 2.0"
|
14
13
|
```
|
15
14
|
|
15
|
+
The Opbeat gem adhere to [Semantic
|
16
|
+
Versioning](http://guides.rubygems.org/patterns/#semantic-versioning)
|
17
|
+
and so you can safely trust all minor and patch versions (e.g. 2.x.x) to
|
18
|
+
be backwards compatible.
|
19
|
+
|
16
20
|
## Usage
|
17
21
|
|
18
22
|
### Rails 3 and Rails 4
|
@@ -161,13 +165,23 @@ Opbeat.configure do |config|
|
|
161
165
|
end
|
162
166
|
```
|
163
167
|
|
164
|
-
## Sanitizing Data
|
168
|
+
## Sanitizing Data
|
169
|
+
|
170
|
+
The Opbeat agent will sanitize the data sent to the Opbeat server based
|
171
|
+
on the following rules.
|
172
|
+
|
173
|
+
If you are running Rails, the agent will first try to fetch the
|
174
|
+
filtering settings from `Rails.application.config.filter_parameters`.
|
165
175
|
|
166
|
-
If
|
167
|
-
|
168
|
-
sanitize keys that match various patterns (e.g. password) and values that resemble credit card numbers.
|
176
|
+
If those are not set (or if you are not running Rails), the agent will
|
177
|
+
fall back to its own defaults:
|
169
178
|
|
170
|
-
|
179
|
+
```ruby
|
180
|
+
/(authorization|password|passwd|secret)/i
|
181
|
+
```
|
182
|
+
|
183
|
+
To specify your own (or to remove the defaults), simply set the
|
184
|
+
`filter_parameters` configuration parameter:
|
171
185
|
|
172
186
|
```ruby
|
173
187
|
require 'opbeat'
|
@@ -177,10 +191,13 @@ Opbeat.configure do |config|
|
|
177
191
|
config.app_id = '094e250818'
|
178
192
|
config.secret_token = 'f0f5237a221637f561a15614f5fef218f8d6317d'
|
179
193
|
|
180
|
-
config.
|
194
|
+
config.filter_parameters = [:credit_card, /^pass(word)$/i]
|
181
195
|
end
|
182
196
|
```
|
183
197
|
|
198
|
+
Note that only the `data`, `query_string` and `cookies` fields under
|
199
|
+
`http` are filtered.
|
200
|
+
|
184
201
|
## User information
|
185
202
|
|
186
203
|
With Rails, Opbeat expects `controller#current_user` to return an object with `id`, `email` and/or `username` attributes. You can change the name of the current user method in the following manner:
|
data/lib/opbeat.rb
CHANGED
@@ -8,7 +8,6 @@ require 'opbeat/interfaces/message'
|
|
8
8
|
require 'opbeat/interfaces/exception'
|
9
9
|
require 'opbeat/interfaces/stack_trace'
|
10
10
|
require 'opbeat/interfaces/http'
|
11
|
-
require 'opbeat/processors/sanitizedata'
|
12
11
|
|
13
12
|
require 'opbeat/integrations/delayed_job'
|
14
13
|
require 'opbeat/integrations/sidekiq'
|
data/lib/opbeat/client.rb
CHANGED
@@ -5,6 +5,7 @@ require 'faraday'
|
|
5
5
|
|
6
6
|
require 'opbeat/version'
|
7
7
|
require 'opbeat/error'
|
8
|
+
require 'opbeat/filter'
|
8
9
|
|
9
10
|
module Opbeat
|
10
11
|
|
@@ -52,7 +53,7 @@ module Opbeat
|
|
52
53
|
|
53
54
|
@configuration = conf
|
54
55
|
@state = ClientState.new conf
|
55
|
-
@
|
56
|
+
@filter = Filter.new conf.filter_parameters
|
56
57
|
@base_url = "#{conf.server}/api/v1/organizations/#{conf.organization_id}/apps/#{conf.app_id}"
|
57
58
|
@auth_header = 'Bearer ' + conf.secret_token
|
58
59
|
end
|
@@ -69,11 +70,7 @@ module Opbeat
|
|
69
70
|
|
70
71
|
def encode(event)
|
71
72
|
event_hash = event.to_hash
|
72
|
-
|
73
|
-
@processors.each do |p|
|
74
|
-
event_hash = p.process(event_hash)
|
75
|
-
end
|
76
|
-
|
73
|
+
event_hash = @filter.process_event_hash(event_hash)
|
77
74
|
return MultiJson.encode(event_hash)
|
78
75
|
end
|
79
76
|
|
data/lib/opbeat/configuration.rb
CHANGED
@@ -25,8 +25,8 @@ module Opbeat
|
|
25
25
|
# Which exceptions should never be sent
|
26
26
|
attr_accessor :excluded_exceptions
|
27
27
|
|
28
|
-
#
|
29
|
-
attr_accessor :
|
28
|
+
# An array of parameters whould should be filtered from the log
|
29
|
+
attr_accessor :filter_parameters
|
30
30
|
|
31
31
|
# Timeout when waiting for the server to return data in seconds
|
32
32
|
attr_accessor :timeout
|
@@ -48,15 +48,14 @@ module Opbeat
|
|
48
48
|
attr_reader :async
|
49
49
|
|
50
50
|
def initialize
|
51
|
-
self.server = ENV['OPBEAT_SERVER'] || "https://opbeat.com"
|
51
|
+
self.server = ENV['OPBEAT_SERVER'] || "https://intake.opbeat.com"
|
52
52
|
self.secret_token = ENV['OPBEAT_SECRET_TOKEN'] if ENV['OPBEAT_SECRET_TOKEN']
|
53
53
|
self.organization_id = ENV['OPBEAT_ORGANIZATION_ID'] if ENV['OPBEAT_ORGANIZATION_ID']
|
54
54
|
self.app_id = ENV['OPBEAT_APP_ID'] if ENV['OPBEAT_APP_ID']
|
55
55
|
@context_lines = 3
|
56
56
|
self.environments = %w[ development production default ]
|
57
|
-
self.current_environment = (defined?(Rails) && Rails.env) || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
|
57
|
+
self.current_environment = (defined?(::Rails) && ::Rails.env) || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
|
58
58
|
self.excluded_exceptions = []
|
59
|
-
self.processors = [Opbeat::Processor::SanitizeData]
|
60
59
|
self.timeout = 1
|
61
60
|
self.open_timeout = 1
|
62
61
|
self.backoff_multiplier = 2
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Opbeat
|
2
|
+
class Filter
|
3
|
+
MASK = '[FILTERED]'
|
4
|
+
DEFAULT_FILTER = [/(authorization|password|passwd|secret)/i]
|
5
|
+
|
6
|
+
def initialize(filters=nil)
|
7
|
+
if defined?(::Rails)
|
8
|
+
rails_filters = ::Rails.application.config.filter_parameters
|
9
|
+
rails_filters = nil if rails_filters.count == 0
|
10
|
+
end
|
11
|
+
@filters = filters || rails_filters || DEFAULT_FILTER
|
12
|
+
end
|
13
|
+
|
14
|
+
def apply(value, key=nil, &block)
|
15
|
+
if value.is_a?(Hash)
|
16
|
+
value.each.inject({}) do |memo, (k, v)|
|
17
|
+
memo[k] = apply(v, k, &block)
|
18
|
+
memo
|
19
|
+
end
|
20
|
+
elsif value.is_a?(Array)
|
21
|
+
value.map do |value|
|
22
|
+
apply(value, key, &block)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
block.call(key, value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def sanitize(key, value)
|
30
|
+
if !value.is_a?(String) || value.empty?
|
31
|
+
value
|
32
|
+
elsif @filters.any? { |filter| filter.is_a?(Regexp) ? filter.match(key) : filter.to_s == key.to_s }
|
33
|
+
MASK
|
34
|
+
else
|
35
|
+
value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def process_event_hash(data)
|
40
|
+
return data unless data.has_key? 'http'
|
41
|
+
if data['http'].has_key? 'data'
|
42
|
+
data['http']['data'] = process_hash(data['http']['data'])
|
43
|
+
end
|
44
|
+
if data['http'].has_key? 'query_string'
|
45
|
+
data['http']['query_string'] = process_string(data['http']['query_string'], '&')
|
46
|
+
end
|
47
|
+
if data['http'].has_key? 'cookies'
|
48
|
+
data['http']['cookies'] = process_string(data['http']['cookies'], ';')
|
49
|
+
end
|
50
|
+
data
|
51
|
+
end
|
52
|
+
|
53
|
+
def process_hash(data)
|
54
|
+
apply(data) do |key, value|
|
55
|
+
sanitize(key, value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def process_string(str, separator='&')
|
60
|
+
str.split(separator).map { |s| s.split('=') }.map { |a| a[0]+'='+sanitize(a[0], a[1]) }.join(separator)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/opbeat/version.rb
CHANGED
@@ -0,0 +1,101 @@
|
|
1
|
+
require File::expand_path('../../spec_helper', __FILE__)
|
2
|
+
require 'opbeat/filter'
|
3
|
+
|
4
|
+
describe Opbeat::Filter do
|
5
|
+
it 'should filter http data by default' do
|
6
|
+
data = {
|
7
|
+
'http' => {
|
8
|
+
'data' => {
|
9
|
+
'foo' => 'bar',
|
10
|
+
'password' => 'hello',
|
11
|
+
'the_secret' => 'hello',
|
12
|
+
'a_password_here' => 'hello',
|
13
|
+
'mypasswd' => 'hello'
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
filter = Opbeat::Filter.new
|
19
|
+
result = filter.process_event_hash(data)
|
20
|
+
|
21
|
+
vars = result["http"]["data"]
|
22
|
+
expect(vars["foo"]).to eq("bar")
|
23
|
+
expect(vars["password"]).to eq(Opbeat::Filter::MASK)
|
24
|
+
expect(vars["the_secret"]).to eq(Opbeat::Filter::MASK)
|
25
|
+
expect(vars["a_password_here"]).to eq(Opbeat::Filter::MASK)
|
26
|
+
expect(vars["mypasswd"]).to eq(Opbeat::Filter::MASK)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should filter http query_string by default' do
|
30
|
+
data = {
|
31
|
+
'http' => {
|
32
|
+
'query_string' => 'foo=bar&password=secret'
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
filter = Opbeat::Filter.new
|
37
|
+
result = filter.process_event_hash(data)
|
38
|
+
|
39
|
+
expect(result["http"]["query_string"]).to eq('foo=bar&password=' + Opbeat::Filter::MASK)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should filter http cookies by default' do
|
43
|
+
data = {
|
44
|
+
'http' => {
|
45
|
+
'cookies' => 'foo=bar;password=secret'
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
filter = Opbeat::Filter.new
|
50
|
+
result = filter.process_event_hash(data)
|
51
|
+
|
52
|
+
expect(result["http"]["cookies"]).to eq('foo=bar;password=' + Opbeat::Filter::MASK)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should not filter env, extra or headers' do
|
56
|
+
data = {
|
57
|
+
'http' => {
|
58
|
+
'env' => { 'password' => 'hello' },
|
59
|
+
'extra' => { 'password' => 'hello' },
|
60
|
+
'headers' => { 'password' => 'hello' }
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
filter = Opbeat::Filter.new
|
65
|
+
result = filter.process_event_hash(data)
|
66
|
+
|
67
|
+
expect(result).to eq(data)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should be configurable' do
|
71
|
+
data = {
|
72
|
+
'http' => {
|
73
|
+
'data' => {
|
74
|
+
'foo' => 'secret',
|
75
|
+
'bar' => 'secret',
|
76
|
+
'-baz-' => 'secret',
|
77
|
+
'password' => 'public',
|
78
|
+
'the_secret' => 'public',
|
79
|
+
'a_password_here' => 'public',
|
80
|
+
'mypasswd' => 'public'
|
81
|
+
},
|
82
|
+
'query_string' => 'foo=secret&password=public',
|
83
|
+
'cookies' => 'foo=secret;password=public'
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
filter = Opbeat::Filter.new [:foo, 'bar', /baz/]
|
88
|
+
result = filter.process_event_hash(data)
|
89
|
+
|
90
|
+
vars = result["http"]["data"]
|
91
|
+
expect(vars["foo"]).to eq(Opbeat::Filter::MASK)
|
92
|
+
expect(vars["bar"]).to eq(Opbeat::Filter::MASK)
|
93
|
+
expect(vars["-baz-"]).to eq(Opbeat::Filter::MASK)
|
94
|
+
expect(vars["password"]).to eq("public")
|
95
|
+
expect(vars["the_secret"]).to eq("public")
|
96
|
+
expect(vars["a_password_here"]).to eq("public")
|
97
|
+
expect(vars["mypasswd"]).to eq("public")
|
98
|
+
expect(result["http"]["query_string"]).to eq('foo=' + Opbeat::Filter::MASK + '&password=public')
|
99
|
+
expect(result["http"]["cookies"]).to eq('foo=' + Opbeat::Filter::MASK + ';password=public')
|
100
|
+
end
|
101
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opbeat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Watson Steen
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-
|
13
|
+
date: 2015-03-05 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: faraday
|
@@ -164,6 +164,7 @@ files:
|
|
164
164
|
- lib/opbeat/configuration.rb
|
165
165
|
- lib/opbeat/error.rb
|
166
166
|
- lib/opbeat/event.rb
|
167
|
+
- lib/opbeat/filter.rb
|
167
168
|
- lib/opbeat/integrations/delayed_job.rb
|
168
169
|
- lib/opbeat/integrations/resque.rb
|
169
170
|
- lib/opbeat/integrations/sidekiq.rb
|
@@ -174,8 +175,6 @@ files:
|
|
174
175
|
- lib/opbeat/interfaces/stack_trace.rb
|
175
176
|
- lib/opbeat/linecache.rb
|
176
177
|
- lib/opbeat/logger.rb
|
177
|
-
- lib/opbeat/processor.rb
|
178
|
-
- lib/opbeat/processors/sanitizedata.rb
|
179
178
|
- lib/opbeat/rack.rb
|
180
179
|
- lib/opbeat/rails/middleware/debug_exceptions_catcher.rb
|
181
180
|
- lib/opbeat/railtie.rb
|
@@ -186,11 +185,11 @@ files:
|
|
186
185
|
- spec/opbeat/client_spec.rb
|
187
186
|
- spec/opbeat/configuration_spec.rb
|
188
187
|
- spec/opbeat/event_spec.rb
|
188
|
+
- spec/opbeat/filter_spec.rb
|
189
189
|
- spec/opbeat/integrations/delayed_job_spec.rb
|
190
190
|
- spec/opbeat/logger_spec.rb
|
191
191
|
- spec/opbeat/opbeat_spec.rb
|
192
192
|
- spec/opbeat/rack_spec.rb
|
193
|
-
- spec/opbeat/sanitizedata_processor_spec.rb
|
194
193
|
- spec/spec_helper.rb
|
195
194
|
homepage: https://github.com/opbeat/opbeat_ruby
|
196
195
|
licenses:
|
data/lib/opbeat/processor.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
require 'opbeat/processor'
|
2
|
-
|
3
|
-
module Opbeat
|
4
|
-
module Processor
|
5
|
-
class SanitizeData < Processor
|
6
|
-
|
7
|
-
MASK = '********'
|
8
|
-
FIELDS_RE = /(authorization|password|passwd|secret)/i
|
9
|
-
VALUES_RE = /^\d{16}$/
|
10
|
-
|
11
|
-
def apply(value, key=nil, &block)
|
12
|
-
if value.is_a?(Hash)
|
13
|
-
value.each.inject({}) do |memo, (k, v)|
|
14
|
-
memo[k] = apply(v, k, &block)
|
15
|
-
memo
|
16
|
-
end
|
17
|
-
elsif value.is_a?(Array)
|
18
|
-
value.map do |value|
|
19
|
-
apply(value, key, &block)
|
20
|
-
end
|
21
|
-
else
|
22
|
-
block.call(key, value)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def sanitize(key, value)
|
27
|
-
if !value.is_a?(String) || value.empty?
|
28
|
-
value
|
29
|
-
elsif VALUES_RE.match(value) or FIELDS_RE.match(key)
|
30
|
-
MASK
|
31
|
-
else
|
32
|
-
value
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def process(data)
|
37
|
-
apply(data) do |key, value|
|
38
|
-
sanitize(key, value)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
require File::expand_path('../../spec_helper', __FILE__)
|
2
|
-
require 'opbeat/processors/sanitizedata'
|
3
|
-
|
4
|
-
describe Opbeat::Processor::SanitizeData do
|
5
|
-
before do
|
6
|
-
@client = double("client")
|
7
|
-
@processor = Opbeat::Processor::SanitizeData.new(@client)
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'should filter http data' do
|
11
|
-
data = {
|
12
|
-
'http' => {
|
13
|
-
'data' => {
|
14
|
-
'foo' => 'bar',
|
15
|
-
'password' => 'hello',
|
16
|
-
'the_secret' => 'hello',
|
17
|
-
'a_password_here' => 'hello',
|
18
|
-
'mypasswd' => 'hello',
|
19
|
-
}
|
20
|
-
}
|
21
|
-
}
|
22
|
-
|
23
|
-
result = @processor.process(data)
|
24
|
-
|
25
|
-
vars = result["http"]["data"]
|
26
|
-
expect(vars["foo"]).to eq("bar")
|
27
|
-
expect(vars["password"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
28
|
-
expect(vars["the_secret"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
29
|
-
expect(vars["a_password_here"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
30
|
-
expect(vars["mypasswd"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'should filter credit card values' do
|
34
|
-
data = {
|
35
|
-
'ccnumba' => '4242424242424242'
|
36
|
-
}
|
37
|
-
|
38
|
-
result = @processor.process(data)
|
39
|
-
expect(result["ccnumba"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|