supergood 0.1.1 → 0.1.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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +28 -28
- data/lib/supergood/api.rb +31 -40
- data/lib/supergood/client.rb +32 -25
- data/lib/supergood/constants.rb +10 -2
- data/lib/supergood/utils.rb +4 -0
- data/lib/supergood/vendors/http.rb +49 -23
- data/lib/supergood/vendors/net-http.rb +53 -28
- data/lib/supergood/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b55de34e8a2ab872a9d2556a4e1e8a4e544bff0536c02fcf123fb93c30fde87
|
4
|
+
data.tar.gz: 974a1af1a188f5a85e77c603e9545370c360367edeb4327c009c6b12ec44a8b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0c8f7c3b9af56109324314aa9af0220624bf9d05d2e06a8d2706b5cfac3f6d6ba2e7e8613b82803cc7365e66e6e76d85b1180c62d368ae01f55892276b730c3
|
7
|
+
data.tar.gz: 5bf07755f863ca866c5381f465957689616826f6db09734beda707a15099fc55b3a1fcee4b76f5c9df6623a5b5b1d9b26cb1782924a480e5f66dc279ae353a8b
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,50 +1,50 @@
|
|
1
|
-
#
|
1
|
+
# Ruby
|
2
2
|
|
3
|
-
|
3
|
+
The Supergood Ruby client connects Supergood to your Ruby application. Follow these steps to integrate with the Ruby client.
|
4
4
|
|
5
|
-
|
5
|
+
## 1. Install the Supergood library
|
6
6
|
|
7
|
-
|
7
|
+
```bash
|
8
|
+
gem install supergood
|
9
|
+
```
|
8
10
|
|
9
|
-
##
|
11
|
+
## 2. Initialize the Supergood Library
|
10
12
|
|
11
|
-
|
13
|
+
**Environment variables**
|
12
14
|
|
13
|
-
|
14
|
-
gem 'supergood'
|
15
|
-
```
|
15
|
+
Set the environment variables `SUPERGOOD_CLIENT_ID` and `SUPERGOOD_CLIENT_SECRET` using the API keys generated in the [getting started instructions](../../getting-started.md).
|
16
16
|
|
17
|
-
|
17
|
+
Initialize the Supergood client at the root of your application, or anywhere you're making API calls with the following code:
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
Or install it yourself as:
|
19
|
+
```ruby
|
20
|
+
require 'supergood'
|
22
21
|
|
23
|
-
|
22
|
+
Supergood.init()
|
23
|
+
```
|
24
24
|
|
25
|
-
|
25
|
+
**Passing keys**
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
You can also pass the API keys in manually without setting environment variables.\
|
28
|
+
\
|
29
|
+
Replace `<CLIENT_ID>` and `<CLIENT_SECRET>` with the API keys you generated in the [getting started instructions](../../getting-started.md).
|
30
30
|
|
31
|
-
```
|
31
|
+
```ruby
|
32
32
|
require 'supergood'
|
33
33
|
|
34
|
-
Supergood.init(
|
34
|
+
Supergood.init({ client_id: "<CLIENT_ID>", client_secret: "<CLIENT_SECRET>" })
|
35
35
|
```
|
36
|
-
OR
|
37
|
-
|
38
|
-
set `SUPERGOOD_CLIENT_ID` and `SUPERGOOD_CLIENT_SECRET` as environment variables and leave the init function as `Supergood.init`
|
39
36
|
|
37
|
+
#### Local development
|
40
38
|
|
41
|
-
|
39
|
+
Setting the `CLIENT_ID` and `CLIENT_SECRET_ID` to `local-client-id` and `local-client-secret`, respectively, will disable making API calls to the supergood.ai server and instead log the payloads to the local console.
|
42
40
|
|
43
|
-
|
41
|
+
## 3. Monitor your API calls
|
44
42
|
|
45
|
-
|
43
|
+
You're all set to use Supergood!
|
46
44
|
|
47
|
-
|
45
|
+
Head back to your [dashboard](https://dashboard.supergood.ai) to start monitoring your API calls and receiving reports.
|
48
46
|
|
49
|
-
|
47
|
+
## Links
|
50
48
|
|
49
|
+
* [Supergood RubyGems Project](https://rubygems.org/gems/supergood)
|
50
|
+
* [Supergood-rb Source Code](https://github.com/supergoodsystems/supergood-rb)
|
data/lib/supergood/api.rb
CHANGED
@@ -4,9 +4,17 @@ Dotenv.load
|
|
4
4
|
|
5
5
|
module Supergood
|
6
6
|
class Api
|
7
|
-
def initialize(
|
7
|
+
def initialize(client_id, client_secret, base_url)
|
8
8
|
@base_url = base_url
|
9
|
-
@header_options =
|
9
|
+
@header_options = {
|
10
|
+
'Content-Type' => 'application/json',
|
11
|
+
'Authorization' => 'Basic ' + Base64.encode64(client_id + ':' + client_secret).gsub(/\n/, '')
|
12
|
+
}
|
13
|
+
@local_only = client_id == LOCAL_CLIENT_ID && client_secret == LOCAL_CLIENT_SECRET
|
14
|
+
end
|
15
|
+
|
16
|
+
def header_options
|
17
|
+
@header_options
|
10
18
|
end
|
11
19
|
|
12
20
|
def log
|
@@ -17,50 +25,33 @@ module Supergood
|
|
17
25
|
@log = logger
|
18
26
|
end
|
19
27
|
|
20
|
-
def set_event_sink_endpoint(endpoint)
|
21
|
-
@event_sink_endpoint = endpoint
|
22
|
-
end
|
23
|
-
|
24
|
-
def set_error_sink_endpoint(endpoint)
|
25
|
-
@error_sink_endpoint = endpoint
|
26
|
-
end
|
27
|
-
|
28
28
|
def post_events(payload)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
29
|
+
if @local_only
|
30
|
+
@log.debug(payload)
|
31
|
+
else
|
32
|
+
uri = URI(@base_url + '/api/events')
|
33
|
+
response = Net::HTTP.post(uri, payload.to_json, @header_options)
|
34
|
+
if response.code == '200'
|
35
|
+
return JSON.parse(response.body, symbolize_names: true)
|
36
|
+
elsif response.code == '401'
|
37
|
+
raise SupergoodException.new ERRORS[:UNAUTHORIZED]
|
38
|
+
elsif response.code != '200' && response.code != '201'
|
39
|
+
raise SupergoodException.new ERRORS[:POSTING_EVENTS]
|
40
|
+
end
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
40
44
|
def post_errors(payload)
|
41
|
-
|
42
|
-
|
43
|
-
if response.code == '200'
|
44
|
-
return JSON.parse(response.body, symbolize_names: true)
|
45
|
+
if @local_only
|
46
|
+
@log.debug(payload)
|
45
47
|
else
|
46
|
-
@
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
response = Net::HTTP.start(uri.hostname, uri.port) do |http|
|
54
|
-
request['Content-Type'] = 'application/json'
|
55
|
-
request['Authorization'] = @header_options['Authorization']
|
56
|
-
http.request(request)
|
57
|
-
end
|
58
|
-
if response.code == '200'
|
59
|
-
return JSON.parse(response.body, symbolize_names: true)
|
60
|
-
elsif response.code == '401'
|
61
|
-
raise SupergoodException.new ERRORS[:UNAUTHORIZED]
|
62
|
-
elsif response.code != '200' && response.code != '201'
|
63
|
-
raise SupergoodException.new ERRORS[:FETCHING_CONFIG]
|
48
|
+
uri = URI(@base_url + '/api/errors')
|
49
|
+
response = Net::HTTP.post(uri, payload.to_json, @header_options)
|
50
|
+
if response.code == '200'
|
51
|
+
return JSON.parse(response.body, symbolize_names: true)
|
52
|
+
else
|
53
|
+
@log.warn(ERRORS[:POSTING_ERRORS])
|
54
|
+
end
|
64
55
|
end
|
65
56
|
end
|
66
57
|
end
|
data/lib/supergood/client.rb
CHANGED
@@ -12,11 +12,10 @@ Dotenv.load
|
|
12
12
|
module Supergood
|
13
13
|
|
14
14
|
DEFAULT_SUPERGOOD_BASE_URL = 'https://dashboard.supergood.ai'
|
15
|
-
|
16
15
|
class << self
|
17
|
-
def init(
|
18
|
-
supergood_client_id =
|
19
|
-
supergood_client_secret =
|
16
|
+
def init(config={})
|
17
|
+
supergood_client_id = config[:client_id] || ENV['SUPERGOOD_CLIENT_ID']
|
18
|
+
supergood_client_secret = config[:client_secret] || ENV['SUPERGOOD_CLIENT_SECRET']
|
20
19
|
|
21
20
|
if !supergood_client_id
|
22
21
|
raise SupergoodException.new ERRORS[:NO_CLIENT_ID]
|
@@ -26,27 +25,27 @@ module Supergood
|
|
26
25
|
raise SupergoodException.new ERRORS[:NO_CLIENT_SECRET]
|
27
26
|
end
|
28
27
|
|
29
|
-
@base_url =
|
30
|
-
|
31
|
-
|
32
|
-
'Authorization' => 'Basic ' + Base64.encode64(supergood_client_id + ':' + supergood_client_secret).gsub(/\n/, '')
|
33
|
-
}
|
28
|
+
@base_url = ENV['SUPERGOOD_BASE_URL'] || DEFAULT_SUPERGOOD_BASE_URL
|
29
|
+
@api = Supergood::Api.new(supergood_client_id, supergood_client_secret, @base_url)
|
30
|
+
@config = Supergood::Utils.make_config(config)
|
34
31
|
|
35
|
-
@api = Supergood::Api.new(header_options, @base_url)
|
36
|
-
@config = @api.fetch_config
|
37
32
|
@ignored_domains = @config[:ignoredDomains]
|
38
33
|
@keys_to_hash = @config[:keysToHash]
|
39
|
-
@logger = Supergood::Logger.new(@api, @config, header_options)
|
34
|
+
@logger = Supergood::Logger.new(@api, @config, @api.header_options)
|
40
35
|
|
41
|
-
@api.set_error_sink_endpoint(@config[:errorSinkEndpoint])
|
42
|
-
@api.set_event_sink_endpoint(@config[:eventSinkEndpoint])
|
43
36
|
@api.set_logger(@logger)
|
44
37
|
|
45
38
|
@request_cache = {}
|
46
39
|
@response_cache = {}
|
47
40
|
|
48
41
|
@interval_thread = set_interval(@config[:flushInterval]) { flush_cache }
|
49
|
-
|
42
|
+
|
43
|
+
@http_clients = [
|
44
|
+
Supergood::Vendor::NetHTTP,
|
45
|
+
Supergood::Vendor::HTTPrb
|
46
|
+
]
|
47
|
+
|
48
|
+
patch_all()
|
50
49
|
self
|
51
50
|
end
|
52
51
|
|
@@ -83,10 +82,27 @@ module Supergood
|
|
83
82
|
|
84
83
|
end
|
85
84
|
|
85
|
+
def cleanup()
|
86
|
+
@interval_thread.kill
|
87
|
+
unpatch_all()
|
88
|
+
end
|
89
|
+
|
86
90
|
def close(force = true)
|
87
91
|
log.debug('Cleaning up, flushing cache gracefully.')
|
88
|
-
@interval_thread.kill
|
89
92
|
flush_cache(force)
|
93
|
+
cleanup()
|
94
|
+
end
|
95
|
+
|
96
|
+
def patch_all
|
97
|
+
@http_clients.each do |client|
|
98
|
+
client.patch
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def unpatch_all
|
103
|
+
@http_clients.each do |client|
|
104
|
+
client.unpatch
|
105
|
+
end
|
90
106
|
end
|
91
107
|
|
92
108
|
def set_interval(delay)
|
@@ -98,14 +114,6 @@ module Supergood
|
|
98
114
|
end
|
99
115
|
end
|
100
116
|
|
101
|
-
def self.intercept(*args, &block)
|
102
|
-
instance.intercept(*args, &block)
|
103
|
-
end
|
104
|
-
|
105
|
-
def self.instance
|
106
|
-
@instance ||= Supergood.new
|
107
|
-
end
|
108
|
-
|
109
117
|
def intercept(request)
|
110
118
|
request_id = SecureRandom.uuid
|
111
119
|
requested_at = Time.now
|
@@ -159,7 +167,6 @@ module Supergood
|
|
159
167
|
}), @keys_to_hash)
|
160
168
|
@request_cache.delete(request_id)
|
161
169
|
rescue => e
|
162
|
-
puts e
|
163
170
|
log.error(
|
164
171
|
{ request: request_payload, response: response_payload },
|
165
172
|
e, ERRORS[:CACHING_RESPONSE]
|
data/lib/supergood/constants.rb
CHANGED
@@ -4,9 +4,8 @@ ERRORS = {
|
|
4
4
|
DUMPING_DATA_TO_DISK: 'Error Dumping Data to Disk',
|
5
5
|
POSTING_EVENTS: 'Error Posting Events',
|
6
6
|
POSTING_ERRORS: 'Error Posting Errors',
|
7
|
-
FETCHING_CONFIG: 'Error Fetching Config',
|
8
7
|
WRITING_TO_DISK: 'Error writing to disk',
|
9
|
-
TEST_ERROR: 'Test Error for Testing
|
8
|
+
TEST_ERROR: 'Test Error for Testing Purpos es',
|
10
9
|
UNAUTHORIZED: 'Unauthorized: Invalid Client ID or Secret. Exiting.',
|
11
10
|
NO_CLIENT_ID:
|
12
11
|
'No Client ID Provided, set SUPERGOOD_CLIENT_ID or pass it as an argument',
|
@@ -14,8 +13,17 @@ ERRORS = {
|
|
14
13
|
'No Client Secret Provided, set SUPERGOOD_CLIENT_SECRET or pass it as an argument'
|
15
14
|
};
|
16
15
|
|
16
|
+
LOCAL_CLIENT_ID = 'local-client-id';
|
17
|
+
LOCAL_CLIENT_SECRET = 'local-client-secret';
|
18
|
+
|
17
19
|
DEFAULT_SUPERGOOD_BYTE_LIMIT = 500000
|
18
20
|
|
21
|
+
DEFAULT_CONFIG = {
|
22
|
+
keysToHash: [],
|
23
|
+
flushInterval: 1000,
|
24
|
+
ignoredDomains: []
|
25
|
+
}
|
26
|
+
|
19
27
|
# GZIP_START_BYTES = b'\x1f\x8b'
|
20
28
|
|
21
29
|
class SupergoodException < StandardError
|
data/lib/supergood/utils.rb
CHANGED
@@ -1,33 +1,59 @@
|
|
1
1
|
module Supergood
|
2
2
|
module Vendor
|
3
3
|
module HTTPrb
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
original_response = original_perform(original_request_payload, original_options)
|
19
|
-
status, statusText = original_response.status.to_s.split(' ')
|
20
|
-
{
|
21
|
-
headers: original_response.headers.to_hash,
|
22
|
-
status: status,
|
23
|
-
statusText: statusText,
|
24
|
-
body: Supergood::Utils.safe_parse_json(original_response),
|
25
|
-
original_response: original_response
|
4
|
+
def self.patch
|
5
|
+
if !self.existing_patch?
|
6
|
+
|
7
|
+
block = lambda do |x|
|
8
|
+
alias original_perform perform
|
9
|
+
def perform(original_request_payload, original_options)
|
10
|
+
request = {
|
11
|
+
headers: original_request_payload.headers.to_hash,
|
12
|
+
method: original_request_payload.verb.upcase.to_s,
|
13
|
+
body: Supergood::Utils.safe_parse_json(original_request_payload.body.source),
|
14
|
+
url: original_request_payload.uri.to_s,
|
15
|
+
path: original_request_payload.uri.path,
|
16
|
+
search: original_request_payload.uri.query,
|
17
|
+
domain: original_request_payload.uri.host
|
26
18
|
}
|
19
|
+
Supergood.intercept(request) do
|
20
|
+
original_response = original_perform(original_request_payload, original_options)
|
21
|
+
status, statusText = original_response.status.to_s.split(' ')
|
22
|
+
{
|
23
|
+
headers: original_response.headers.to_hash,
|
24
|
+
status: status,
|
25
|
+
statusText: statusText,
|
26
|
+
body: Supergood::Utils.safe_parse_json(original_response),
|
27
|
+
original_response: original_response
|
28
|
+
}
|
29
|
+
end
|
27
30
|
end
|
28
31
|
end
|
29
|
-
|
32
|
+
|
33
|
+
if defined?(HTTP::Client)
|
34
|
+
HTTP::Client.class_eval(&block)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.unpatch
|
41
|
+
if self.existing_patch?
|
42
|
+
block = lambda do |x|
|
43
|
+
alias perform original_perform
|
44
|
+
end
|
45
|
+
|
46
|
+
if defined?(HTTP::Client)
|
47
|
+
HTTP::Client.class_eval(&block)
|
48
|
+
HTTP::Client.undef_method :original_perform
|
49
|
+
end
|
50
|
+
end
|
30
51
|
end
|
52
|
+
|
53
|
+
def self.existing_patch?
|
54
|
+
defined?(HTTP::Client) && HTTP::Client.method_defined?(:original_perform)
|
55
|
+
end
|
56
|
+
|
31
57
|
end
|
32
58
|
end
|
33
59
|
end
|
@@ -5,41 +5,66 @@ require 'uri'
|
|
5
5
|
module Supergood
|
6
6
|
module Vendor
|
7
7
|
module NetHTTP
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
8
|
+
def self.patch
|
9
|
+
if !self.existing_patch?
|
10
|
+
block = lambda do |x|
|
11
|
+
alias original_request_method request
|
12
|
+
def request(original_request_payload, body = nil, &block)
|
13
|
+
http = self;
|
14
|
+
url = Supergood::Utils.request_url(http, original_request_payload)
|
15
|
+
uri = URI.parse(url)
|
16
|
+
request = {
|
17
|
+
headers: Supergood::Utils.get_header(original_request_payload),
|
18
|
+
method: original_request_payload.method,
|
19
|
+
body: original_request_payload.body,
|
20
|
+
url: url,
|
21
|
+
path: original_request_payload.path,
|
22
|
+
search: uri.query,
|
23
|
+
domain: uri.host,
|
24
|
+
}
|
25
|
+
Supergood.intercept(request) do
|
26
|
+
original_response = original_request_method(original_request_payload, body, &block)
|
27
|
+
{
|
28
|
+
headers: Supergood::Utils.get_header(original_response),
|
29
|
+
status: original_response.code,
|
30
|
+
statusText: original_response.message,
|
31
|
+
body: original_response.body,
|
32
|
+
original_response: original_response
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
32
36
|
end
|
37
|
+
|
38
|
+
if defined?(Net::HTTP)
|
39
|
+
Net::HTTP.class_eval(&block)
|
40
|
+
elsif defined?(::WebMock)
|
41
|
+
WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get("@webMockNetHTTP").class_eval(&block)
|
42
|
+
end
|
43
|
+
|
33
44
|
end
|
34
45
|
end
|
35
46
|
|
36
|
-
|
37
|
-
|
47
|
+
def self.unpatch
|
48
|
+
if self.existing_patch?
|
49
|
+
block = lambda do |x|
|
50
|
+
alias request original_request_method
|
51
|
+
end
|
52
|
+
|
53
|
+
if defined?(Net::HTTP)
|
54
|
+
Net::HTTP.class_eval(&block)
|
55
|
+
Net::HTTP.undef_method :original_request_method
|
56
|
+
elsif defined?(::WebMock)
|
57
|
+
WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get("@webMockNetHTTP").class_eval(&block)
|
58
|
+
WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get("@webMockNetHTTP").undef_method :original_request_method
|
59
|
+
end
|
60
|
+
end
|
38
61
|
end
|
39
62
|
|
40
|
-
|
41
|
-
|
63
|
+
def self.existing_patch?
|
64
|
+
(defined?(Net::HTTP) && Net::HTTP.method_defined?(:original_request_method)) ||
|
65
|
+
(defined?(::Webmock) && WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get("@webMockNetHTTP").method_defined?(:original_request_method))
|
42
66
|
end
|
67
|
+
|
43
68
|
end
|
44
69
|
end
|
45
70
|
end
|
data/lib/supergood/version.rb
CHANGED