greenfinch-ruby 0.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.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.idea/.gitignore +8 -0
- data/.idea/greenfinch-ruby.iml +16 -0
- data/.idea/inspectionProfiles/Project_Default.xml +6 -0
- data/.idea/misc.xml +4 -0
- data/.idea/modules.xml +8 -0
- data/.idea/vcs.xml +6 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/Gemfile +2 -0
- data/LICENSE +190 -0
- data/README.md +124 -0
- data/Rakefile +13 -0
- data/Readme.rdoc +109 -0
- data/demo/faraday_consumer.rb +40 -0
- data/demo/out_of_process_consumer.rb +71 -0
- data/demo/simple_messages.rb +9 -0
- data/greenfinch-ruby.gemspec +21 -0
- data/lib/greenfinch-ruby.rb +3 -0
- data/lib/greenfinch-ruby/consumer.rb +271 -0
- data/lib/greenfinch-ruby/error.rb +46 -0
- data/lib/greenfinch-ruby/events.rb +140 -0
- data/lib/greenfinch-ruby/groups.rb +201 -0
- data/lib/greenfinch-ruby/people.rb +254 -0
- data/lib/greenfinch-ruby/tracker.rb +184 -0
- data/lib/greenfinch-ruby/version.rb +3 -0
- data/spec/mixpanel-ruby/consumer_spec.rb +208 -0
- data/spec/mixpanel-ruby/error_spec.rb +76 -0
- data/spec/mixpanel-ruby/events_spec.rb +76 -0
- data/spec/mixpanel-ruby/groups_spec.rb +159 -0
- data/spec/mixpanel-ruby/people_spec.rb +220 -0
- data/spec/mixpanel-ruby/tracker_spec.rb +134 -0
- data/spec/spec_helper.rb +15 -0
- metadata +132 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'greenfinch-ruby'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
# The Mixpanel library's default consumer will use the standard
|
5
|
+
# Net::HTTP library to communicate with servers, but you can extend
|
6
|
+
# your consumers to use other libraries. This example sends data using
|
7
|
+
# the Faraday library (so you'll need that library available to run it)
|
8
|
+
|
9
|
+
class FaradayConsumer < Mixpanel::Consumer
|
10
|
+
def request(endpoint, form_data)
|
11
|
+
conn = ::Faraday.new(endpoint)
|
12
|
+
response = conn.post(nil, form_data)
|
13
|
+
[response.status, response.body]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if __FILE__ == $0
|
18
|
+
# Replace this with the token from your project settings
|
19
|
+
DEMO_TOKEN = '072f77c15bd04a5d0044d3d76ced7fea'
|
20
|
+
faraday_consumer = FaradayConsumer.new
|
21
|
+
|
22
|
+
faraday_tracker = Mixpanel::Tracker.new(DEMO_TOKEN) do |type, message|
|
23
|
+
faraday_consumer.send!(type, message)
|
24
|
+
end
|
25
|
+
faraday_tracker.track('ID', 'Event tracked through Faraday')
|
26
|
+
|
27
|
+
# It's also easy to delegate from a BufferedConsumer to your custom
|
28
|
+
# consumer.
|
29
|
+
|
30
|
+
buffered_faraday_consumer = Mixpanel::BufferedConsumer.new do |type, message|
|
31
|
+
faraday_consumer.send!(type, message)
|
32
|
+
end
|
33
|
+
|
34
|
+
buffered_faraday_tracker = Mixpanel::Tracker.new(DEMO_TOKEN) do |type, message|
|
35
|
+
buffered_faraday_consumer.send!(type, message)
|
36
|
+
end
|
37
|
+
|
38
|
+
buffered_faraday_tracker.track('ID', 'Event tracked (buffered) through faraday')
|
39
|
+
buffered_faraday_consumer.flush
|
40
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'greenfinch-ruby'
|
2
|
+
require 'thread'
|
3
|
+
require 'json'
|
4
|
+
require 'securerandom'
|
5
|
+
|
6
|
+
# As your application scales, it's likely you'll want to
|
7
|
+
# to detect events in one place and send them somewhere
|
8
|
+
# else. For example, you might write the events to a queue
|
9
|
+
# to be consumed by another process.
|
10
|
+
#
|
11
|
+
# This demo shows how you might do things, using
|
12
|
+
# the block constructor in Mixpanel to enqueue events,
|
13
|
+
# and a MixpanelBufferedConsumer to send them to
|
14
|
+
# Mixpanel
|
15
|
+
|
16
|
+
# Mixpanel uses the Net::HTTP library, which by default
|
17
|
+
# will not verify remote SSL certificates. In your app,
|
18
|
+
# you'll need to call Mixpanel.config_http with the path
|
19
|
+
# to your Certificate authority resources, or the library
|
20
|
+
# won't verify the remote certificate identity.
|
21
|
+
Mixpanel.config_http do |http|
|
22
|
+
http.ca_path = '/etc/ssl/certs'
|
23
|
+
http.ca_file = "/etc/ssl/certs/ca-certificates.crt"
|
24
|
+
http.use_ssl = true
|
25
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
26
|
+
end
|
27
|
+
|
28
|
+
class OutOfProcessExample
|
29
|
+
class << self
|
30
|
+
def run(token, distinct_id)
|
31
|
+
open('|-', 'w+') do |subprocess|
|
32
|
+
if subprocess
|
33
|
+
# This is the tracking process. Once we configure
|
34
|
+
# The tracker to write to our subprocess, we can quickly
|
35
|
+
# call #track without delaying our other work.
|
36
|
+
mixpanel_tracker = Mixpanel::Tracker.new(token) do |*message|
|
37
|
+
subprocess.write(message.to_json + "\n")
|
38
|
+
end
|
39
|
+
|
40
|
+
100.times do |i|
|
41
|
+
event = 'Tick'
|
42
|
+
mixpanel_tracker.track(distinct_id, event, {'Tick Number' => i})
|
43
|
+
puts "tick #{i}"
|
44
|
+
end
|
45
|
+
|
46
|
+
else
|
47
|
+
# This is the consumer process. In your applications, code
|
48
|
+
# like this may end up in queue consumers or in a separate
|
49
|
+
# thread.
|
50
|
+
mixpanel_consumer = Mixpanel::BufferedConsumer.new
|
51
|
+
begin
|
52
|
+
$stdin.each_line do |line|
|
53
|
+
message = JSON.load(line)
|
54
|
+
type, content = message
|
55
|
+
mixpanel_consumer.send!(type, content)
|
56
|
+
end
|
57
|
+
ensure
|
58
|
+
mixpanel_consumer.flush
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end # run
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
if __FILE__ == $0
|
67
|
+
# Replace this with the token from your project settings
|
68
|
+
DEMO_TOKEN = '072f77c15bd04a5d0044d3d76ced7fea'
|
69
|
+
run_id = SecureRandom.base64
|
70
|
+
OutOfProcessExample.run(DEMO_TOKEN, run_id)
|
71
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
$LOAD_PATH << "/Users/terry/Documents/Github/greenfinch-ruby/lib"
|
2
|
+
require 'greenfinch-ruby'
|
3
|
+
|
4
|
+
if __FILE__ == $0
|
5
|
+
# Replace this with the token from your project settings
|
6
|
+
DEMO_TOKEN = 'eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTE2NzIwMzksImV4cCI6MzY4NTI3MDAwMDAwMCwic2VydmljZV9uYW1lIjoiZmx5Y2F0Y2hlciJ9.lY6RVf1rsaYkuLCLfCs4cKFRNTvcbmZcR2IXEYZkdzw'
|
7
|
+
tracker = Greenfinch::Tracker.new(DEMO_TOKEN, 'flycatcher', true)
|
8
|
+
tracker.track('ID', 'Script run')
|
9
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'lib/greenfinch-ruby/version.rb')
|
2
|
+
|
3
|
+
spec = Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'greenfinch-ruby'
|
5
|
+
spec.version = Greenfinch::VERSION
|
6
|
+
spec.files = Dir.glob(`git ls-files`.split("\n"))
|
7
|
+
spec.require_paths = ['lib']
|
8
|
+
spec.summary = 'Official Greenfinch tracking library for ruby'
|
9
|
+
spec.description = 'The official Greenfinch tracking library for ruby'
|
10
|
+
spec.authors = [ 'KoreaCreditData' ]
|
11
|
+
spec.email = 'terry@kcd.co.kr'
|
12
|
+
spec.homepage = 'https://github.com/koreacreditdata/greenfinch-ruby'
|
13
|
+
spec.license = 'Apache-2.0'
|
14
|
+
|
15
|
+
spec.required_ruby_version = '>= 2.0.0'
|
16
|
+
|
17
|
+
spec.add_development_dependency 'activesupport', '~> 4.0'
|
18
|
+
spec.add_development_dependency 'rake', '~> 0'
|
19
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
20
|
+
spec.add_development_dependency 'webmock', '~> 1.18'
|
21
|
+
end
|
@@ -0,0 +1,271 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'json'
|
3
|
+
require 'net/https'
|
4
|
+
|
5
|
+
module Greenfinch
|
6
|
+
@@init_http = nil
|
7
|
+
|
8
|
+
# This method exists for backwards compatibility. The preferred
|
9
|
+
# way to customize or configure the HTTP library of a consumer
|
10
|
+
# is to override Consumer#request.
|
11
|
+
#
|
12
|
+
# Ruby's default SSL does not verify the server certificate.
|
13
|
+
# To verify a certificate, or install a proxy, pass a block
|
14
|
+
# to Greenfinch.config_http that configures the Net::HTTP object.
|
15
|
+
# For example, if running in Ubuntu Linux, you can run
|
16
|
+
#
|
17
|
+
# Greenfinch.config_http do |http|
|
18
|
+
# http.ca_path = '/etc/ssl/certs'
|
19
|
+
# http.ca_file = '/etc/ssl/certs/ca-certificates.crt'
|
20
|
+
# http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# \Greenfinch Consumer and BufferedConsumer will call your block
|
24
|
+
# to configure their connections
|
25
|
+
def self.config_http(&block)
|
26
|
+
@@init_http = block
|
27
|
+
end
|
28
|
+
|
29
|
+
# A Consumer receives messages from a Greenfinch::Tracker, and
|
30
|
+
# sends them elsewhere- probably to Greenfinch's analytics services,
|
31
|
+
# but can also enqueue them for later processing, log them to a
|
32
|
+
# file, or do whatever else you might find useful.
|
33
|
+
#
|
34
|
+
# You can provide your own consumer to your Greenfinch::Trackers,
|
35
|
+
# either by passing in an argument with a #send! method when you construct
|
36
|
+
# the tracker, or just passing a block to Greenfinch::Tracker.new
|
37
|
+
#
|
38
|
+
# tracker = Greenfinch::Tracker.new(YOUR_GREENFINCH_TOKEN) do |type, message|
|
39
|
+
# # type will be one of :event, :profile_update or :import
|
40
|
+
# @kestrel.set(ANALYTICS_QUEUE, [type, message].to_json)
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# You can also instantiate the library consumers yourself, and use
|
44
|
+
# them wherever you would like. For example, the working that
|
45
|
+
# consumes the above queue might work like this:
|
46
|
+
#
|
47
|
+
# greenfinch = Greenfinch::Consumer
|
48
|
+
# while true
|
49
|
+
# message_json = @kestrel.get(ANALYTICS_QUEUE)
|
50
|
+
# greenfinch.send!(*JSON.load(message_json))
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# Greenfinch::Consumer is the default consumer. It sends each message,
|
54
|
+
# as the message is recieved, directly to Greenfinch.
|
55
|
+
class Consumer
|
56
|
+
|
57
|
+
# Create a Greenfinch::Consumer. If you provide endpoint arguments,
|
58
|
+
# they will be used instead of the default Greenfinch endpoints.
|
59
|
+
# This can be useful for proxying, debugging, or if you prefer
|
60
|
+
# not to use SSL for your events.
|
61
|
+
def initialize(events_endpoint=nil,
|
62
|
+
update_endpoint=nil,
|
63
|
+
groups_endpoint=nil,
|
64
|
+
import_endpoint=nil)
|
65
|
+
|
66
|
+
@events_endpoint = events_endpoint || 'https://event.kcd.partners/api/publish'
|
67
|
+
@update_endpoint = update_endpoint || 'https://api.greenfinch.com/engage'
|
68
|
+
@groups_endpoint = groups_endpoint || 'https://api.greenfinch.com/groups'
|
69
|
+
@import_endpoint = import_endpoint || 'https://api.greenfinch.com/import'
|
70
|
+
end
|
71
|
+
|
72
|
+
# Send the given string message to Greenfinch. Type should be
|
73
|
+
# one of :event, :profile_update or :import, which will determine the endpoint.
|
74
|
+
#
|
75
|
+
# Greenfinch::Consumer#send! sends messages to Greenfinch immediately on
|
76
|
+
# each call. To reduce the overall bandwidth you use when communicating
|
77
|
+
# with Greenfinch, you can also use Greenfinch::BufferedConsumer
|
78
|
+
def send!(type, message)
|
79
|
+
type = type.to_sym
|
80
|
+
endpoint = {
|
81
|
+
:event => @events_endpoint,
|
82
|
+
:profile_update => @update_endpoint,
|
83
|
+
:group_update => @groups_endpoint,
|
84
|
+
:import => @import_endpoint,
|
85
|
+
}[type]
|
86
|
+
|
87
|
+
decoded_message = JSON.load(message)
|
88
|
+
jwt_token = decoded_message["jwt_token"]
|
89
|
+
service_name = decoded_message["service_name"]
|
90
|
+
debug = decoded_message["debug"]
|
91
|
+
api_key = decoded_message["api_key"]
|
92
|
+
|
93
|
+
if debug == true
|
94
|
+
endpoint = "https://event-staging.kcd.partners/api/publish/#{service_name}"
|
95
|
+
else
|
96
|
+
endpoint = "#{endpoint}/#{service_name}"
|
97
|
+
end
|
98
|
+
|
99
|
+
data = decoded_message["data"]
|
100
|
+
|
101
|
+
form_data = { "data" => data, "verbose" => 1 }
|
102
|
+
form_data.merge!("api_key" => api_key) if api_key
|
103
|
+
|
104
|
+
begin
|
105
|
+
response_code, response_body = request(endpoint, form_data, jwt_token)
|
106
|
+
rescue => e
|
107
|
+
raise ConnectionError.new("Could not connect to Greenfinch, with error \"#{e.message}\".")
|
108
|
+
end
|
109
|
+
|
110
|
+
result = {}
|
111
|
+
if response_code.to_i == 200
|
112
|
+
begin
|
113
|
+
result = JSON.parse(response_body.to_s)
|
114
|
+
rescue JSON::JSONError
|
115
|
+
raise ServerError.new("Could not interpret Greenfinch server response: '#{response_body}'")
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
if result['status'] != 1
|
120
|
+
raise ServerError.new("Could not write to Greenfinch, server responded with #{response_code} returning: '#{response_body}'")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# This method was deprecated in release 2.0.0, please use send! instead
|
125
|
+
def send(type, message)
|
126
|
+
warn '[DEPRECATION] send has been deprecated as of release 2.0.0, please use send! instead'
|
127
|
+
send!(type, message)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Request takes an endpoint HTTP or HTTPS url, and a Hash of data
|
131
|
+
# to post to that url. It should return a pair of
|
132
|
+
#
|
133
|
+
# [response code, response body]
|
134
|
+
#
|
135
|
+
# as the result of the response. Response code should be nil if
|
136
|
+
# the request never receives a response for some reason.
|
137
|
+
def request(endpoint, form_data, jwt_token=nil)
|
138
|
+
uri = URI(endpoint)
|
139
|
+
|
140
|
+
headers = {
|
141
|
+
"jwt" => jwt_token,
|
142
|
+
"content-type" => "application/json",
|
143
|
+
"label" => "ruby"
|
144
|
+
}
|
145
|
+
|
146
|
+
client = Net::HTTP.new(uri.host, uri.port)
|
147
|
+
client.use_ssl = true
|
148
|
+
client.open_timeout = 10
|
149
|
+
client.continue_timeout = 10
|
150
|
+
client.read_timeout = 10
|
151
|
+
client.ssl_timeout = 10
|
152
|
+
|
153
|
+
Greenfinch.with_http(client)
|
154
|
+
|
155
|
+
response = client.request_post uri.request_uri, form_data.to_json, headers
|
156
|
+
|
157
|
+
[response.code, response.body]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# BufferedConsumer buffers messages in memory, and sends messages as
|
162
|
+
# a batch. This can improve performance, but calls to #send! may
|
163
|
+
# still block if the buffer is full. If you use this consumer, you
|
164
|
+
# should call #flush when your application exits or the messages
|
165
|
+
# remaining in the buffer will not be sent.
|
166
|
+
#
|
167
|
+
# To use a BufferedConsumer directly with a Greenfinch::Tracker,
|
168
|
+
# instantiate your Tracker like this
|
169
|
+
#
|
170
|
+
# buffered_consumer = Greenfinch::BufferedConsumer.new
|
171
|
+
# begin
|
172
|
+
# buffered_tracker = Greenfinch::Tracker.new(YOUR_GREENFINCH_TOKEN) do |type, message|
|
173
|
+
# buffered_consumer.send!(type, message)
|
174
|
+
# end
|
175
|
+
# # Do some tracking here
|
176
|
+
# ...
|
177
|
+
# ensure
|
178
|
+
# buffered_consumer.flush
|
179
|
+
# end
|
180
|
+
#
|
181
|
+
class BufferedConsumer
|
182
|
+
MAX_LENGTH = 50
|
183
|
+
|
184
|
+
# Create a Greenfinch::BufferedConsumer. If you provide endpoint arguments,
|
185
|
+
# they will be used instead of the default Greenfinch endpoints.
|
186
|
+
# This can be useful for proxying, debugging, or if you prefer
|
187
|
+
# not to use SSL for your events.
|
188
|
+
#
|
189
|
+
# You can also change the preferred buffer size before the
|
190
|
+
# consumer automatically sends its buffered events. The Greenfinch
|
191
|
+
# endpoints have a limit of 50 events per HTTP request, but
|
192
|
+
# you can lower the limit if your individual events are very large.
|
193
|
+
#
|
194
|
+
# By default, BufferedConsumer will use a standard Greenfinch
|
195
|
+
# consumer to send the events once the buffer is full (or on calls
|
196
|
+
# to #flush), but you can override this behavior by passing a
|
197
|
+
# block to the constructor, in the same way you might pass a block
|
198
|
+
# to the Greenfinch::Tracker constructor. If a block is passed to
|
199
|
+
# the constructor, the *_endpoint constructor arguments are
|
200
|
+
# ignored.
|
201
|
+
def initialize(events_endpoint=nil, update_endpoint=nil, import_endpoint=nil, max_buffer_length=MAX_LENGTH, &block)
|
202
|
+
@max_length = [max_buffer_length, MAX_LENGTH].min
|
203
|
+
@buffers = {
|
204
|
+
:event => [],
|
205
|
+
:profile_update => [],
|
206
|
+
}
|
207
|
+
|
208
|
+
if block
|
209
|
+
@sink = block
|
210
|
+
else
|
211
|
+
consumer = Consumer.new(events_endpoint, update_endpoint, import_endpoint)
|
212
|
+
@sink = consumer.method(:send!)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# Stores a message for Greenfinch in memory. When the buffer
|
217
|
+
# hits a maximum length, the consumer will flush automatically.
|
218
|
+
# Flushes are synchronous when they occur.
|
219
|
+
#
|
220
|
+
# Currently, only :event and :profile_update messages are buffered,
|
221
|
+
# :import messages will be send immediately on call.
|
222
|
+
def send!(type, message)
|
223
|
+
type = type.to_sym
|
224
|
+
|
225
|
+
if @buffers.has_key? type
|
226
|
+
@buffers[type] << message
|
227
|
+
flush_type(type) if @buffers[type].length >= @max_length
|
228
|
+
else
|
229
|
+
@sink.call(type, message)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# This method was deprecated in release 2.0.0, please use send! instead
|
234
|
+
def send(type, message)
|
235
|
+
warn '[DEPRECATION] send has been deprecated as of release 2.0.0, please use send! instead'
|
236
|
+
send!(type, message)
|
237
|
+
end
|
238
|
+
|
239
|
+
# Pushes all remaining messages in the buffer to Greenfinch.
|
240
|
+
# You should call #flush before your application exits or
|
241
|
+
# messages may not be sent.
|
242
|
+
def flush
|
243
|
+
@buffers.keys.each { |k| flush_type(k) }
|
244
|
+
end
|
245
|
+
|
246
|
+
private
|
247
|
+
|
248
|
+
def flush_type(type)
|
249
|
+
sent_messages = 0
|
250
|
+
begin
|
251
|
+
@buffers[type].each_slice(@max_length) do |chunk|
|
252
|
+
data = chunk.map {|message| JSON.load(message)['data'] }
|
253
|
+
@sink.call(type, {'data' => data}.to_json)
|
254
|
+
sent_messages += chunk.length
|
255
|
+
end
|
256
|
+
rescue
|
257
|
+
@buffers[type].slice!(0, sent_messages)
|
258
|
+
raise
|
259
|
+
end
|
260
|
+
@buffers[type] = []
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
private
|
265
|
+
|
266
|
+
def self.with_http(http)
|
267
|
+
if @@init_http
|
268
|
+
@@init_http.call(http)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Greenfinch
|
2
|
+
|
3
|
+
# Greenfinch specific errors that are thrown in the gem.
|
4
|
+
# In the default consumer we catch all errors and raise
|
5
|
+
# Greenfinch specific errors that can be handled using a
|
6
|
+
# custom error handler.
|
7
|
+
class GreenfinchError < StandardError
|
8
|
+
end
|
9
|
+
|
10
|
+
class ConnectionError < GreenfinchError
|
11
|
+
end
|
12
|
+
|
13
|
+
class ServerError < GreenfinchError
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# The default behavior of the gem is to silence all errors
|
18
|
+
# thrown in the consumer. If you wish to handle GreenfinchErrors
|
19
|
+
# yourself you can pass an instance of a class that extends
|
20
|
+
# Greenfinch::ErrorHandler to Greenfinch::Tracker on initialize.
|
21
|
+
#
|
22
|
+
# require 'logger'
|
23
|
+
#
|
24
|
+
# class MyErrorHandler < Greenfinch::ErrorHandler
|
25
|
+
#
|
26
|
+
# def initialize
|
27
|
+
# @logger = Logger.new('mylogfile.log')
|
28
|
+
# @logger.level = Logger::ERROR
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# def handle(error)
|
32
|
+
# logger.error "#{error.inspect}\n Backtrace: #{error.backtrace}"
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# my_error_handler = MyErrorHandler.new
|
38
|
+
# tracker = Greenfinch::Tracker.new(YOUR_GREENFINCH_TOKEN, my_error_handler)
|
39
|
+
class ErrorHandler
|
40
|
+
|
41
|
+
# Override #handle to customize error handling
|
42
|
+
def handle(error)
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|