readme-metrics 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17dad1b40b974d05ae3d57a664e6f95c393cbaf8e807071631c11800b2ee118c
4
- data.tar.gz: 2d3595d321dea5bac6b5577180f608a2f9045e333592e5c33cca4c52a3e997ea
3
+ metadata.gz: df0dd7efcddca3f324e4e6f7b61fd70a1bee3d3d81571ffa1dc72e090bf2934e
4
+ data.tar.gz: b99811540e9195cecad5c8ee3cf7807fb3340e87353327d021a166af5f34a112
5
5
  SHA512:
6
- metadata.gz: a586f8ae1273269473451ea60bfeccb5e9fd01b6fa4ddacfd99b5918dfed24aa340a9e61aba6036a96b572c1eef50c4d2e1a9cd87162442197a02a4ff2456b2c
7
- data.tar.gz: a7d894c039bdc676164f1dcd083650ae8ce026152baad7d83ea790a3ee4850e4de59246e922a641d6446943389c456557c1712b8b34c2085d4398e226c323c86
6
+ metadata.gz: 6d39db68ce16afde0e0139a4e31bfac53f5bef2066972777165502eac78fd09ed292a23e945d7584385148e3375d72f8d254275a7367e7e07278a16a79b85819
7
+ data.tar.gz: c8e5b439466d50cbac88269d6036c22f7aa84864590cc28862976bf005ada580431b3e9a4a8e652a6ae5ecadb687b2bf59e6607f0cd87e15315f26b86a003d12
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- readme-metrics (0.2.0)
4
+ readme-metrics (1.1.0)
5
5
  httparty (~> 0.18)
6
6
 
7
7
  GEM
@@ -21,7 +21,7 @@ GEM
21
21
  addressable (>= 2.4)
22
22
  mime-types (3.3.1)
23
23
  mime-types-data (~> 3.2015)
24
- mime-types-data (3.2020.0512)
24
+ mime-types-data (3.2021.0225)
25
25
  multi_xml (0.6.0)
26
26
  parallel (1.19.2)
27
27
  parser (2.7.1.4)
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
- # readmeio
1
+ # readme-metrics
2
2
 
3
3
  Track your API metrics within ReadMe.
4
4
 
5
+ [![RubyGems](https://img.shields.io/gem/v/readme-metrics)](https://rubygems.org/gems/readme-metrics)
5
6
  [![Build](https://github.com/readmeio/metrics-sdks/workflows/ruby/badge.svg)](https://github.com/readmeio/metrics-sdks)
6
7
 
7
8
  [![](https://d3vv6lp55qjaqc.cloudfront.net/items/1M3C3j0I0s0j3T362344/Untitled-2.png)](https://readme.io)
@@ -26,8 +27,8 @@ current_user for a given request from the environment.
26
27
 
27
28
  ### Batching requests
28
29
 
29
- By default, the middleware will batch requests to the ReadMe API in groups of
30
- 10. For every 10 requests made to your application, the middleware will make a
30
+ By default, the middleware will batch requests to the ReadMe API in groups of 10.
31
+ For every 10 requests made to your application, the middleware will make a
31
32
  single request to ReadMe. If you wish to override this, provide a
32
33
  `buffer_length` option when configuring the middleware.
33
34
 
@@ -51,7 +52,7 @@ You may only specify either `reject_params` or `allow_only` keys, not both.
51
52
  require "readme/metrics"
52
53
 
53
54
  options = {
54
- api_key: "YOUR_API_KEY",
55
+ api_key: "<<apiKey>>",
55
56
  development: false,
56
57
  reject_params: ["not_included", "dont_send"],
57
58
  buffer_length: 5,
@@ -62,13 +63,13 @@ config.middleware.use Readme::Metrics, options do |env|
62
63
 
63
64
  if current_user.present?
64
65
  {
65
- id: current_user.id,
66
+ api_key: current_user.api_key, # Not the same as the ReadMe API Key
66
67
  label: current_user.name,
67
68
  email: current_user.email
68
69
  }
69
70
  else
70
71
  {
71
- id: "guest",
72
+ api_key: "guest",
72
73
  label: "Guest User",
73
74
  email: "guest@example.com"
74
75
  }
@@ -81,16 +82,16 @@ end
81
82
  ```ruby
82
83
  # config.ru
83
84
  options = {
84
- api_key: "YOUR_API_KEY",
85
+ api_key: "<<apiKey>>",
85
86
  development: false,
86
87
  reject_params: ["not_included", "dont_send"]
87
88
  }
88
89
 
89
90
  use Readme::Metrics, options do |env|
90
91
  {
91
- id: "my_application_id"
92
- label: "My Application",
93
- email: "my.application@example.com"
92
+ api_key: "owlbert_api_key"
93
+ label: "Owlbert",
94
+ email: "owlbert@example.com"
94
95
  }
95
96
  end
96
97
 
@@ -105,4 +106,4 @@ run YourApp.new
105
106
 
106
107
  ## License
107
108
 
108
- [View our license here](https://github.com/readmeio/metrics-sdks/tree/master/packages/ruby/LICENSE)
109
+ [View our license here](https://github.com/readmeio/metrics-sdks/tree/main/packages/ruby/LICENSE)
@@ -0,0 +1,17 @@
1
+ module Readme
2
+ module ContentTypeHelper
3
+ # Assumes the includer has a `content_type` method defined.
4
+
5
+ JSON_MIME_TYPES = [
6
+ "application/json",
7
+ "application/x-json",
8
+ "text/json",
9
+ "text/x-json",
10
+ "+json"
11
+ ]
12
+
13
+ def json?
14
+ JSON_MIME_TYPES.any? { |mime_type| content_type.include?(mime_type) }
15
+ end
16
+ end
17
+ end
data/lib/readme/errors.rb CHANGED
@@ -25,7 +25,7 @@ module Readme
25
25
  middleware.
26
26
 
27
27
  Expected a hash with the shape:
28
- { id: "unique_id", label: "Your user label", email: "Your user email" }
28
+ { api_key: "Your user api key", label: "Your user label", email: "Your user email" }
29
29
 
30
30
  Received value:
31
31
  #{result}
data/lib/readme/filter.rb CHANGED
@@ -1,58 +1,73 @@
1
- class Filter
2
- def self.for(reject: nil, allow_only: nil)
3
- if !reject.nil? && !allow_only.nil?
4
- raise FilterArgsError
5
- elsif !reject.nil?
6
- RejectParams.new(reject)
7
- elsif !allow_only.nil?
8
- AllowOnly.new(allow_only)
9
- else
10
- None.new
1
+ module Readme
2
+ class Filter
3
+ def self.for(reject: nil, allow_only: nil)
4
+ if !reject.nil? && !allow_only.nil?
5
+ raise FilterArgsError
6
+ elsif !reject.nil?
7
+ RejectParams.new(reject)
8
+ elsif !allow_only.nil?
9
+ AllowOnly.new(allow_only)
10
+ else
11
+ None.new
12
+ end
11
13
  end
12
- end
13
14
 
14
- class AllowOnly
15
- def initialize(filter_values)
16
- @filter_values = filter_values.map(&:downcase)
15
+ def self.redact(rejected_params)
16
+ rejected_params.each_with_object({}) do |(k, v), hash|
17
+ # If it's a string then return the length of the redacted field
18
+ hash[k.to_str] = "[REDACTED#{v.is_a?(String) ? " #{v.length}" : ""}]"
19
+ end
17
20
  end
18
21
 
19
- def filter(hash)
20
- hash.select { |key, _value| @filter_values.include?(key.downcase) }
21
- end
22
+ class AllowOnly
23
+ def initialize(filter_fields)
24
+ @allowed_fields = filter_fields
25
+ end
22
26
 
23
- def pass_through?
24
- false
25
- end
26
- end
27
+ def filter(hash)
28
+ allowed_fields = @allowed_fields.map(&:downcase)
29
+ allowed_params, rejected_params = hash.partition { |key, _value| allowed_fields.include?(key.downcase) }.map(&:to_h)
27
30
 
28
- class RejectParams
29
- def initialize(filter_values)
30
- @filter_values = filter_values.map(&:downcase)
31
- end
31
+ allowed_params.merge(Filter.redact(rejected_params))
32
+ end
32
33
 
33
- def filter(hash)
34
- hash.reject { |key, _value| @filter_values.include?(key.downcase) }
34
+ def pass_through?
35
+ false
36
+ end
35
37
  end
36
38
 
37
- def pass_through?
38
- false
39
- end
40
- end
39
+ class RejectParams
40
+ def initialize(filter_fields)
41
+ @rejected_fields = filter_fields
42
+ end
43
+
44
+ def filter(hash)
45
+ rejected_fields = @rejected_fields.map(&:downcase)
46
+ rejected_params, allowed_params = hash.partition { |key, _value| rejected_fields.include?(key.downcase) }.map(&:to_h)
47
+
48
+ allowed_params.merge(Filter.redact(rejected_params))
49
+ end
41
50
 
42
- class None
43
- def filter(hash)
44
- hash
51
+ def pass_through?
52
+ false
53
+ end
45
54
  end
46
55
 
47
- def pass_through?
48
- true
56
+ class None
57
+ def filter(hash)
58
+ hash
59
+ end
60
+
61
+ def pass_through?
62
+ true
63
+ end
49
64
  end
50
- end
51
65
 
52
- class FilterArgsError < StandardError
53
- def initialize
54
- msg = "Can only supply either reject_params or allow_only, not both."
55
- super(msg)
66
+ class FilterArgsError < StandardError
67
+ def initialize
68
+ msg = "Can only supply either reject_params or allow_only, not both."
69
+ super(msg)
70
+ end
56
71
  end
57
72
  end
58
73
  end
@@ -0,0 +1,101 @@
1
+ require "rack"
2
+ require "rack/request"
3
+ require_relative "content_type_helper"
4
+
5
+ module Readme
6
+ class HttpRequest
7
+ include ContentTypeHelper
8
+
9
+ HTTP_NON_HEADERS = [
10
+ Rack::HTTP_COOKIE,
11
+ Rack::HTTP_VERSION,
12
+ Rack::HTTP_HOST,
13
+ Rack::HTTP_PORT
14
+ ]
15
+
16
+ def initialize(env)
17
+ @request = Rack::Request.new(env)
18
+ end
19
+
20
+ def url
21
+ @request.url
22
+ end
23
+
24
+ def query_params
25
+ @request.GET
26
+ end
27
+
28
+ def cookies
29
+ @request.cookies
30
+ end
31
+
32
+ def http_version
33
+ @request.get_header(Rack::HTTP_VERSION)
34
+ end
35
+
36
+ def request_method
37
+ @request.request_method
38
+ end
39
+
40
+ def content_type
41
+ @request.content_type
42
+ end
43
+
44
+ def form_data?
45
+ @request.form_data?
46
+ end
47
+
48
+ def content_length
49
+ @request.content_length.to_i
50
+ end
51
+
52
+ def options?
53
+ @request.request_method == "OPTIONS"
54
+ end
55
+
56
+ def headers
57
+ @request
58
+ .each_header
59
+ .select { |key, _| http_header?(key) }
60
+ .to_h
61
+ .transform_keys { |header| normalize_header_name(header) }
62
+ .merge unprefixed_headers
63
+ end
64
+
65
+ def body
66
+ @request.body.rewind
67
+ content = @request.body.read
68
+ @request.body.rewind
69
+
70
+ content
71
+ end
72
+
73
+ def parsed_form_data
74
+ @request.POST
75
+ end
76
+
77
+ private
78
+
79
+ # "headers" in Rack::Request just means any key in the env. The HTTP headers
80
+ # are all the headers prefixed with `HTTP_` as per the spec:
81
+ # https://github.com/rack/rack/blob/master/SPEC.rdoc#the-environment-
82
+ # Other "headers" like version and host are prefixed with `HTTP_` by Rack but
83
+ # don't seem to be considered legit HTTP headers.
84
+ def http_header?(name)
85
+ name.start_with?("HTTP") && !HTTP_NON_HEADERS.include?(name)
86
+ end
87
+
88
+ # Headers like `Content-Type: application/json` come into rack like
89
+ # `"HTTP_CONTENT_TYPE" => "application/json"`.
90
+ def normalize_header_name(header)
91
+ header.delete_prefix("HTTP_").split("_").map(&:capitalize).join("-")
92
+ end
93
+
94
+ # These special headers are explicitly _not_ prefixed with HTTP_ in the Rack
95
+ # env so we need to add them in manually
96
+ def unprefixed_headers
97
+ {"Content-Type" => @request.content_type,
98
+ "Content-Length" => @request.content_length}.compact
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,45 @@
1
+ require "rack"
2
+ require "rack/response"
3
+ require_relative "content_type_helper"
4
+
5
+ module Readme
6
+ class HttpResponse < SimpleDelegator
7
+ include ContentTypeHelper
8
+
9
+ def self.from_parts(status, headers, body)
10
+ new(Rack::Response.new(body, status, headers))
11
+ end
12
+
13
+ def body
14
+ if raw_body.respond_to?(:rewind)
15
+ raw_body.rewind
16
+ content = raw_body.each.reduce("", :+)
17
+ raw_body.rewind
18
+
19
+ content
20
+ else
21
+ raw_body.each.reduce("", :+)
22
+ end
23
+ end
24
+
25
+ def content_length
26
+ if empty_body_status?
27
+ 0
28
+ elsif !headers["Content-Length"]
29
+ body.bytesize
30
+ else
31
+ headers["Content-Length"].to_i
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def raw_body
38
+ __getobj__.body
39
+ end
40
+
41
+ def empty_body_status?
42
+ Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status.to_i)
43
+ end
44
+ end
45
+ end
@@ -4,8 +4,8 @@ require "readme/filter"
4
4
  require "readme/payload"
5
5
  require "readme/request_queue"
6
6
  require "readme/errors"
7
- require "http_request"
8
- require "http_response"
7
+ require "readme/http_request"
8
+ require "readme/http_response"
9
9
  require "httparty"
10
10
  require "logger"
11
11
 
@@ -14,7 +14,8 @@ module Readme
14
14
  SDK_NAME = "Readme.io Ruby SDK"
15
15
  DEFAULT_BUFFER_LENGTH = 10
16
16
  ENDPOINT = "https://metrics.readme.io/v1/request"
17
- USER_INFO_KEYS = [:id, :label, :email]
17
+ USER_INFO_KEYS = [:api_key, :label, :email]
18
+ USER_INFO_KEYS_DEPRECATED = [:id, :label, :email]
18
19
 
19
20
  def self.logger
20
21
  @@logger
@@ -65,7 +66,7 @@ module Readme
65
66
  har = Har::Serializer.new(request, response, start_time, end_time, @filter)
66
67
  user_info = @get_user_info.call(env)
67
68
 
68
- if user_info_invalid?(user_info)
69
+ if !user_info_valid?(user_info)
69
70
  Readme::Metrics.logger.warn Errors.bad_block_message(user_info)
70
71
  elsif request.options?
71
72
  Readme::Metrics.logger.info "OPTIONS request omitted from ReadMe API logging"
@@ -132,10 +133,12 @@ module Readme
132
133
  arg == true || arg == false
133
134
  end
134
135
 
135
- def user_info_invalid?(user_info)
136
- user_info.nil? ||
137
- user_info.values.any?(&:nil?) ||
138
- USER_INFO_KEYS.sort != user_info.keys.sort
136
+ def user_info_valid?(user_info)
137
+ sorted_user_info_keys = user_info.keys.sort
138
+ !user_info.nil? &&
139
+ !user_info.values.any?(&:nil?) &&
140
+ (sorted_user_info_keys === USER_INFO_KEYS.sort ||
141
+ sorted_user_info_keys === USER_INFO_KEYS_DEPRECATED.sort)
139
142
  end
140
143
  end
141
144
  end
@@ -1,5 +1,5 @@
1
1
  module Readme
2
2
  class Metrics
3
- VERSION = "1.0.0"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
@@ -2,6 +2,8 @@ module Readme
2
2
  class Payload
3
3
  def initialize(har, user_info, development:)
4
4
  @har = har
5
+ # swap api_key for id
6
+ user_info[:id] = user_info.delete :api_key unless user_info[:api_key].nil?
5
7
  @user_info = user_info
6
8
  @development = development
7
9
  end
@@ -13,8 +13,8 @@ Gem::Specification.new do |spec|
13
13
  spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
14
14
 
15
15
  spec.metadata["homepage_uri"] = spec.homepage
16
- spec.metadata["source_code_uri"] = "https://github.com/readmeio/metrics-sdks/blob/master/packages/ruby"
17
- spec.metadata["changelog_uri"] = "https://github.com/readmeio/metrics-sdks/blob/master/packages/ruby/CHANGELOG.md"
16
+ spec.metadata["source_code_uri"] = "https://github.com/readmeio/metrics-sdks/blob/main/packages/ruby"
17
+ spec.metadata["changelog_uri"] = "https://github.com/readmeio/metrics-sdks/blob/main/packages/ruby/CHANGELOG.md"
18
18
 
19
19
  # Specify which files should be added to the gem when it is released.
20
20
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: readme-metrics
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ReadMe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-28 00:00:00.000000000 Z
11
+ date: 2021-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -40,15 +40,15 @@ files:
40
40
  - Rakefile
41
41
  - bin/console
42
42
  - bin/setup
43
- - lib/content_type_helper.rb
44
- - lib/http_request.rb
45
- - lib/http_response.rb
43
+ - lib/readme/content_type_helper.rb
46
44
  - lib/readme/errors.rb
47
45
  - lib/readme/filter.rb
48
46
  - lib/readme/har/collection.rb
49
47
  - lib/readme/har/request_serializer.rb
50
48
  - lib/readme/har/response_serializer.rb
51
49
  - lib/readme/har/serializer.rb
50
+ - lib/readme/http_request.rb
51
+ - lib/readme/http_response.rb
52
52
  - lib/readme/metrics.rb
53
53
  - lib/readme/metrics/version.rb
54
54
  - lib/readme/payload.rb
@@ -59,8 +59,8 @@ licenses:
59
59
  - ISC
60
60
  metadata:
61
61
  homepage_uri: https://docs.readme.com/metrics/docs/getting-started-with-api-metrics
62
- source_code_uri: https://github.com/readmeio/metrics-sdks/blob/master/packages/ruby
63
- changelog_uri: https://github.com/readmeio/metrics-sdks/blob/master/packages/ruby/CHANGELOG.md
62
+ source_code_uri: https://github.com/readmeio/metrics-sdks/blob/main/packages/ruby
63
+ changelog_uri: https://github.com/readmeio/metrics-sdks/blob/main/packages/ruby/CHANGELOG.md
64
64
  post_install_message:
65
65
  rdoc_options: []
66
66
  require_paths:
@@ -76,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
78
  requirements: []
79
- rubygems_version: 3.1.2
79
+ rubygems_version: 3.1.4
80
80
  signing_key:
81
81
  specification_version: 4
82
82
  summary: SDK for Readme's metrics API
@@ -1,15 +0,0 @@
1
- module ContentTypeHelper
2
- # Assumes the includer has a `content_type` method defined.
3
-
4
- JSON_MIME_TYPES = [
5
- "application/json",
6
- "application/x-json",
7
- "text/json",
8
- "text/x-json",
9
- "+json"
10
- ]
11
-
12
- def json?
13
- JSON_MIME_TYPES.any? { |mime_type| content_type.include?(mime_type) }
14
- end
15
- end
data/lib/http_request.rb DELETED
@@ -1,99 +0,0 @@
1
- require "rack"
2
- require "rack/request"
3
- require "content_type_helper"
4
-
5
- class HttpRequest
6
- include ContentTypeHelper
7
-
8
- HTTP_NON_HEADERS = [
9
- Rack::HTTP_COOKIE,
10
- Rack::HTTP_VERSION,
11
- Rack::HTTP_HOST,
12
- Rack::HTTP_PORT
13
- ]
14
-
15
- def initialize(env)
16
- @request = Rack::Request.new(env)
17
- end
18
-
19
- def url
20
- @request.url
21
- end
22
-
23
- def query_params
24
- @request.GET
25
- end
26
-
27
- def cookies
28
- @request.cookies
29
- end
30
-
31
- def http_version
32
- @request.get_header(Rack::HTTP_VERSION)
33
- end
34
-
35
- def request_method
36
- @request.request_method
37
- end
38
-
39
- def content_type
40
- @request.content_type
41
- end
42
-
43
- def form_data?
44
- @request.form_data?
45
- end
46
-
47
- def content_length
48
- @request.content_length.to_i
49
- end
50
-
51
- def options?
52
- @request.request_method == "OPTIONS"
53
- end
54
-
55
- def headers
56
- @request
57
- .each_header
58
- .select { |key, _| http_header?(key) }
59
- .to_h
60
- .transform_keys { |header| normalize_header_name(header) }
61
- .merge unprefixed_headers
62
- end
63
-
64
- def body
65
- @request.body.rewind
66
- content = @request.body.read
67
- @request.body.rewind
68
-
69
- content
70
- end
71
-
72
- def parsed_form_data
73
- @request.POST
74
- end
75
-
76
- private
77
-
78
- # "headers" in Rack::Request just means any key in the env. The HTTP headers
79
- # are all the headers prefixed with `HTTP_` as per the spec:
80
- # https://github.com/rack/rack/blob/master/SPEC.rdoc#the-environment-
81
- # Other "headers" like version and host are prefixed with `HTTP_` by Rack but
82
- # don't seem to be considered legit HTTP headers.
83
- def http_header?(name)
84
- name.start_with?("HTTP") && !HTTP_NON_HEADERS.include?(name)
85
- end
86
-
87
- # Headers like `Content-Type: application/json` come into rack like
88
- # `"HTTP_CONTENT_TYPE" => "application/json"`.
89
- def normalize_header_name(header)
90
- header.delete_prefix("HTTP_").split("_").map(&:capitalize).join("-")
91
- end
92
-
93
- # These special headers are explicitly _not_ prefixed with HTTP_ in the Rack
94
- # env so we need to add them in manually
95
- def unprefixed_headers
96
- {"Content-Type" => @request.content_type,
97
- "Content-Length" => @request.content_length}.compact
98
- end
99
- end
data/lib/http_response.rb DELETED
@@ -1,43 +0,0 @@
1
- require "rack"
2
- require "rack/response"
3
- require "content_type_helper"
4
-
5
- class HttpResponse < SimpleDelegator
6
- include ContentTypeHelper
7
-
8
- def self.from_parts(status, headers, body)
9
- new(Rack::Response.new(body, status, headers))
10
- end
11
-
12
- def body
13
- if raw_body.respond_to?(:rewind)
14
- raw_body.rewind
15
- content = raw_body.each.reduce("", :+)
16
- raw_body.rewind
17
-
18
- content
19
- else
20
- raw_body.each.reduce("", :+)
21
- end
22
- end
23
-
24
- def content_length
25
- if empty_body_status?
26
- 0
27
- elsif !headers["Content-Length"]
28
- body.bytesize
29
- else
30
- headers["Content-Length"].to_i
31
- end
32
- end
33
-
34
- private
35
-
36
- def raw_body
37
- __getobj__.body
38
- end
39
-
40
- def empty_body_status?
41
- Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status.to_i)
42
- end
43
- end