readme-metrics 2.0.1 → 2.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: 8f8fe458fadd08b945bcd32ba4d64a4ba2ba6a609dde94f3a501c50bc505967d
4
- data.tar.gz: bfa8ff8c37330c3487d8572e2d9ec207147780334295810dc3d0aecfe529e951
3
+ metadata.gz: edf64efc0c1f3a7ba72f9f6d30aaebbd1caf64774258fe7dc69e343751358adb
4
+ data.tar.gz: 36dd67292da34691382b5e3d9f7234275c9d14d4b133f8067ed22c2c0c861a02
5
5
  SHA512:
6
- metadata.gz: 0b849b923ddafe6073b039ebedd9387b1f17fb93e990c3ffa7bcd8c407b5349a387001a6f46684fe7202d955826c705892d46dadc8da20db503546cf2a0d7e83
7
- data.tar.gz: c728319d845cb1ae8d368c0f995a71f0f1451ad03a8f94064aaa782b4d6cc094cf2269c46c0e5c2d86dbde5ea3527edab4371b4e617df5ad24599558bb29fd3c
6
+ metadata.gz: 20c0d88a3e19f49a742ad52555b22f4cfa1d6fc34eeea60dbeb3410f97050d546ed9caa4d00ba5c518822296d9660a6e24c84c7232165724251cafd68dadab53
7
+ data.tar.gz: c29cb1edddfd487996d345be984f402353a1940c4626aad107b4df33537800de0cab8ba41cf294d9a7bfaae5f221cf266012bea8d925ac8794e717b7059c3238
data/.rubocop.yml ADDED
@@ -0,0 +1,67 @@
1
+ require:
2
+ - rubocop-performance
3
+ - rubocop-rspec
4
+
5
+ AllCops:
6
+ NewCops: enable
7
+ TargetRubyVersion: 2.7
8
+
9
+ # https://docs.rubocop.org/rubocop/cops_layout.html
10
+ Layout/LineLength:
11
+ Max: 150
12
+
13
+ # https://docs.rubocop.org/rubocop/cops_metrics.html
14
+ Metrics/AbcSize:
15
+ Enabled: false
16
+ Metrics/CyclomaticComplexity:
17
+ Max: 20
18
+ Metrics/BlockLength:
19
+ Exclude:
20
+ - spec/readme/*.rb
21
+ - spec/readme/har/*.rb
22
+ Metrics/ClassLength:
23
+ Enabled: false
24
+ Metrics/MethodLength:
25
+ Enabled: false
26
+ Metrics/PerceivedComplexity:
27
+ Max: 20
28
+
29
+ # https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec
30
+ RSpec/AnyInstance:
31
+ Enabled: false
32
+ RSpec/ExampleLength:
33
+ Enabled: false
34
+ RSpec/LeakyConstantDeclaration:
35
+ Exclude:
36
+ - spec/readme/*.rb
37
+ RSpec/MultipleExpectations:
38
+ Enabled: false
39
+ RSpec/VerifiedDoubles:
40
+ Enabled: false
41
+
42
+ # https://docs.rubocop.org/rubocop/cops_style.html
43
+ Style/BlockDelimiters:
44
+ Exclude:
45
+ - spec/**/*
46
+ Style/ClassVars:
47
+ Exclude:
48
+ - 'lib/readme/metrics.rb'
49
+ Style/Documentation:
50
+ Enabled: false
51
+ Style/ExpandPathArguments:
52
+ Enabled: false
53
+ Style/FrozenStringLiteralComment:
54
+ Enabled: false
55
+ Style/GuardClause:
56
+ Exclude:
57
+ - 'lib/readme/filter.rb'
58
+ - 'lib/readme/metrics.rb'
59
+ Style/IfUnlessModifier:
60
+ Exclude:
61
+ - 'lib/readme/metrics.rb'
62
+ Style/RescueStandardError:
63
+ # We should ideally have this rule enabled but I'm paranoid that we don't have full documentation
64
+ # on all types of errors that might be thrown in the couple places this rule is being suppressed
65
+ # and by only catching `StandardError` we'll miss out on something else and potentially take down
66
+ # someones integration.
67
+ Enabled: false
data/Gemfile CHANGED
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source "https://rubygems.org"
3
+ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in readme-metrics.gemspec
6
6
  gemspec
7
7
 
8
- gem "json-schema"
9
- gem "rack-test"
10
- gem "rake", "~> 12.0"
11
- gem "rspec", "~> 3.0"
12
- gem "standard"
13
- gem "webmock"
14
- gem "os"
15
- gem "uuid"
8
+ gem 'json-schema'
9
+ gem 'rack-test'
10
+ gem 'rake', '~> 12.0'
11
+ gem 'rspec', '~> 3.0'
12
+ gem 'rubocop', require: false
13
+ gem 'rubocop-performance', require: false
14
+ gem 'rubocop-rspec', require: false
15
+ gem 'uuid'
16
+ gem 'webmock'
data/Gemfile.lock CHANGED
@@ -3,7 +3,6 @@ PATH
3
3
  specs:
4
4
  readme-metrics (2.0.1)
5
5
  httparty (~> 0.18)
6
- os (~> 1.1.4)
7
6
  uuid (~> 2.3.8)
8
7
 
9
8
  GEM
@@ -27,12 +26,11 @@ GEM
27
26
  mime-types-data (~> 3.2015)
28
27
  mime-types-data (3.2022.0105)
29
28
  multi_xml (0.6.0)
30
- os (1.1.4)
31
29
  parallel (1.19.2)
32
30
  parser (2.7.1.4)
33
31
  ast (~> 2.4.1)
34
32
  public_suffix (4.0.6)
35
- rack (2.2.3)
33
+ rack (2.2.3.1)
36
34
  rack-test (1.1.0)
37
35
  rack (>= 1.0, < 3)
38
36
  rainbow (3.0.0)
@@ -63,13 +61,12 @@ GEM
63
61
  unicode-display_width (>= 1.4.0, < 2.0)
64
62
  rubocop-ast (0.3.0)
65
63
  parser (>= 2.7.1.4)
66
- rubocop-performance (1.6.1)
67
- rubocop (>= 0.71.0)
64
+ rubocop-performance (1.7.1)
65
+ rubocop (>= 0.82.0)
66
+ rubocop-rspec (1.41.0)
67
+ rubocop (>= 0.68.1)
68
68
  ruby-progressbar (1.10.1)
69
69
  safe_yaml (1.0.5)
70
- standard (0.4.7)
71
- rubocop (~> 0.85.0)
72
- rubocop-performance (~> 1.6.0)
73
70
  systemu (2.6.5)
74
71
  unicode-display_width (1.7.0)
75
72
  uuid (2.3.9)
@@ -84,12 +81,13 @@ PLATFORMS
84
81
 
85
82
  DEPENDENCIES
86
83
  json-schema
87
- os
88
84
  rack-test
89
85
  rake (~> 12.0)
90
86
  readme-metrics!
91
87
  rspec (~> 3.0)
92
- standard
88
+ rubocop
89
+ rubocop-performance
90
+ rubocop-rspec
93
91
  uuid
94
92
  webmock
95
93
 
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2020, ReadMe
1
+ Copyright (c) 2022, ReadMe
2
2
 
3
3
  Permission to use, copy, modify, and/or distribute this software for any purpose
4
4
  with or without fee is hereby granted, provided that the above copyright notice
data/Makefile ADDED
@@ -0,0 +1,14 @@
1
+ install: ## Install all dependencies
2
+ bundle
3
+
4
+ lint: ## Run code standard checks
5
+ bundle exec rubocop
6
+
7
+ lint-fix: ## Attempt to automatically fix any code standard violations
8
+ bundle exec rubocop --auto-correct
9
+
10
+ test: ## Run unit tests
11
+ rake spec
12
+
13
+ help: ## Show this help
14
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
data/README.md CHANGED
@@ -1,111 +1,30 @@
1
- # readme-metrics
1
+ # ReadMe Metrics
2
2
 
3
- Track your API metrics within ReadMe.
3
+ <p align="center">
4
+ <img src="https://user-images.githubusercontent.com/33762/182927634-2aebeb46-c215-4ac3-9e98-61f931e33583.png" />
5
+ </p>
4
6
 
5
- [![RubyGems](https://img.shields.io/gem/v/readme-metrics)](https://rubygems.org/gems/readme-metrics)
6
- [![Build](https://github.com/readmeio/metrics-sdks/workflows/ruby/badge.svg)](https://github.com/readmeio/metrics-sdks)
7
+ <p align="center">
8
+ Track usage of your API and troubleshoot issues faster.
9
+ </p>
7
10
 
8
- [![](https://d3vv6lp55qjaqc.cloudfront.net/items/1M3C3j0I0s0j3T362344/Untitled-2.png)](https://readme.io)
11
+ <p align="center">
12
+ <a href="https://rubygems.org/gems/readme-metrics"><img src="https://img.shields.io/gem/v/readme-metrics.svg?style=for-the-badge" alt="Latest release"></a>
13
+ <a href="https://github.com/readmeio/metrics-sdks"><img src="https://img.shields.io/github/workflow/status/readmeio/metrics-sdks/ruby.svg?style=for-the-badge" alt="Build status"></a>
14
+ </p>
9
15
 
10
- ## Installation
16
+ With [ReadMe's Metrics API](https://readme.com/metrics) your team can get deep insights into your API's usage. If you're a developer, it takes a few small steps to send your API logs to [ReadMe](http://readme.com). Here's an overview of how the integration works:
11
17
 
12
- Add it to your Gemfile
18
+ - You add the ReadMe middleware to your Rails application.
19
+ - The middleware sends to ReadMe the request and response objects that your Express server generates each time a user makes a request to your API. The entire objects are sent, unless you allow or deny keys.
20
+ - ReadMe extracts information to display in Metrics, such as which endpoint is being called, response code, and error messages. It also identifies the customer who called your API, using whichever keys in the middleware you call out as containing relevant customer info.
13
21
 
14
- `gem "readme-metrics"`
15
-
16
- ## Usage
17
-
18
- `Readme::Metrics` is a Rack middleware and is compatible with all Rack-based
19
- apps, including Rails.
20
-
21
- When configuring the middleware, you must provide a block to tell the
22
- middleware how to get values for the current user. These may be values taken
23
- from the environment, or you may hardcode them.
24
-
25
- If you're using Warden-based authentication like Devise, you may fetch the
26
- current_user for a given request from the environment.
27
-
28
- ### SDK Options
29
-
30
- Option | Type | Description
31
- -----------------|------------------|---------
32
- `reject_params` | Array of strings | If you have sensitive data you'd like to prevent from being sent to the Metrics API via headers, query params or payload bodies, you can specify a list of keys to filter via the `reject_params` option. NOTE: cannot be used in conjunction with `allow_only`. You may only specify either `reject_params` or `allow_only` keys, not both.
33
- `allow_only` | Array of strings | The inverse of `reject_params`. If included all parameters but those in this list will be redacted. NOTE: cannot be used in conjunction with `reject_params`. You may only specify either `reject_params` or `allow_only` keys, not both.
34
- `development` | bool | Defaults to `false`. When `true`, the log will be marked as a development log. This is great for separating staging or test data from data coming from customers.
35
- `buffer_length` | number | Defaults to `1`. This value should be a number representing the amount of requests to group up before sending them over the network. Increasing this value may increase performance by batching, but will also delay the time until logs show up in the dashboard given the buffer size needs to be reached in order for the logs to be sent.
36
-
37
- ### Payload Data
38
-
39
- Option | Required? | Type | Description
40
- --------------------|-----------|------------------|----------
41
- `api_key` | yes | string | API Key used to make the request. Note that this is different from the `readmeAPIKey` described above in the options data. This should be a value from your API that is unique to each of your users.
42
- `label` | no | string | This will be the user's display name in the API Metrics Dashboard, since it's much easier to remember a name than an API key.
43
- `email` | no | string | Email of the user that is making the call.
44
- `log_id` | no | string | A UUIDv4 identifier. If not provided this will be automatically generated for you. Providing your own `log_id` is useful if you want to know the URL of the log in advance, i.e. `{your_base_url}/logs/{your_log_id}`.
45
- `ignore` | no | bool | A flag that when set to `true` will suppress sending the log.
46
-
47
- ### Rails
48
-
49
- ```ruby
50
- # config/environments/development.rb or config/environments/production.rb
51
- require "readme/metrics"
52
-
53
- sdk_options = {
54
- api_key: "<<apiKey>>",
55
- development: false,
56
- reject_params: ["not_included", "dont_send"],
57
- buffer_length: 5,
58
- }
59
-
60
- config.middleware.use Readme::Metrics, sdk_options do |env|
61
- current_user = env['warden'].authenticate
62
-
63
- payload_data = current_user.present? ? {
64
- api_key: current_user.api_key, # Not the same as the ReadMe API Key
65
- label: current_user.name,
66
- email: current_user.email
67
- } : {
68
- api_key: "guest",
69
- label: "Guest User",
70
- email: "guest@example.com"
71
- }
72
-
73
- payload_data
74
- end
22
+ ```bash
23
+ gem "readme-metrics"
75
24
  ```
76
25
 
77
- ### Rack
78
-
79
- ```ruby
80
- # config.ru
81
- sdk_options = {
82
- api_key: "<<apiKey>>",
83
- development: false,
84
- reject_params: ["not_included", "dont_send"]
85
- }
86
-
87
- use Readme::Metrics, sdk_options do |env|
88
- {
89
- api_key: "owlbert_api_key"
90
- label: "Owlbert",
91
- email: "owlbert@example.com",
92
- log_id: SecureRandom.uuid
93
- }
94
- end
95
-
96
- run YourApp.new
97
- ```
98
-
99
- ### Sample Applications
100
-
101
- - [Rails](https://github.com/readmeio/metrics-sdk-rails-sample)
102
- - [Rack](https://github.com/readmeio/metrics-sdk-racks-sample)
103
- - [Sinatra](https://github.com/readmeio/metrics-sdk-sinatra-example)
104
-
105
- ### Contributing
106
-
107
- Ensure you are running the version of ruby specified in the `Gemfile.lock`; use `rvm` to easy manage ruby versions. Run `bundle` to install dependencies, `rake` or `rspec` to ensure tests pass, and `bundle exec standardrb` to lint the code.
108
-
109
- ## License
26
+ **For more information on setup, check out our [integration documentation](https://docs.readme.com/docs/ruby-api-metrics-set-up).**
110
27
 
111
- [View our license here](https://github.com/readmeio/metrics-sdks/tree/main/packages/ruby/LICENSE)
28
+ > 🚧 Any Issues?
29
+ >
30
+ > Integrations can be tricky! [Contact support](https://docs.readme.com/guides/docs/contact-support) if you have any questions/issues.
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
data/bin/console CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "readme/metrics"
3
+ require 'bundler/setup'
4
+ require 'readme/metrics'
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +10,5 @@ require "readme/metrics"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
- require "irb"
13
+ require 'irb'
14
14
  IRB.start(__FILE__)
@@ -3,12 +3,12 @@ module Readme
3
3
  # Assumes the includer has a `content_type` method defined.
4
4
 
5
5
  JSON_MIME_TYPES = [
6
- "application/json",
7
- "application/x-json",
8
- "text/json",
9
- "text/x-json",
10
- "+json"
11
- ]
6
+ 'application/json',
7
+ 'application/x-json',
8
+ 'text/json',
9
+ 'text/x-json',
10
+ '+json'
11
+ ].freeze
12
12
 
13
13
  def json?
14
14
  JSON_MIME_TYPES.any? { |mime_type| content_type.include?(mime_type) }
data/lib/readme/errors.rb CHANGED
@@ -1,10 +1,12 @@
1
+ # frozen-string-literal: true
2
+
1
3
  module Readme
2
4
  class Errors
3
- API_KEY_ERROR = "Missing API Key"
4
- REJECT_PARAMS_ERROR = "The `reject_params` option must be an array of strings"
5
- ALLOW_ONLY_ERROR = "The `allow_only` option must be an array of strings"
6
- BUFFER_LENGTH_ERROR = "The `buffer_length` must be an Integer"
7
- DEVELOPMENT_ERROR = "The `development` option must be a boolean"
5
+ API_KEY_ERROR = 'Missing API Key'
6
+ REJECT_PARAMS_ERROR = 'The `reject_params` option must be an array of strings'
7
+ ALLOW_ONLY_ERROR = 'The `allow_only` option must be an array of strings'
8
+ BUFFER_LENGTH_ERROR = 'The `buffer_length` must be an Integer'
9
+ DEVELOPMENT_ERROR = 'The `development` option must be a boolean'
8
10
  LOGGER_ERROR = <<~MESSAGE
9
11
  The `logger` option must be class that responds to the following messages:
10
12
  :unkown, :fatal, :error, :warn, :info, :debug, :level
data/lib/readme/filter.rb CHANGED
@@ -15,7 +15,7 @@ module Readme
15
15
  def self.redact(rejected_params)
16
16
  rejected_params.each_with_object({}) do |(k, v), hash|
17
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}" : ""}]"
18
+ hash[k.to_str] = "[REDACTED#{v.is_a?(String) ? " #{v.length}" : ''}]"
19
19
  end
20
20
  end
21
21
 
@@ -65,7 +65,7 @@ module Readme
65
65
 
66
66
  class FilterArgsError < StandardError
67
67
  def initialize
68
- msg = "Can only supply either reject_params or allow_only, not both."
68
+ msg = 'Can only supply either reject_params or allow_only, not both.'
69
69
  super(msg)
70
70
  end
71
71
  end
@@ -11,7 +11,7 @@ module Readme
11
11
  end
12
12
 
13
13
  def to_a
14
- filtered_hash.map { |name, value| {name: name, value: value} }
14
+ filtered_hash.map { |name, value| { name: name, value: value } }
15
15
  end
16
16
 
17
17
  private
@@ -1,6 +1,6 @@
1
- require "cgi"
2
- require "readme/har/collection"
3
- require "readme/filter"
1
+ require 'cgi'
2
+ require 'readme/har/collection'
3
+ require 'readme/filter'
4
4
 
5
5
  module Readme
6
6
  module Har
@@ -18,7 +18,7 @@ module Readme
18
18
  httpVersion: @request.http_version,
19
19
  headers: Har::Collection.new(@filter, @request.headers).to_a,
20
20
  cookies: Har::Collection.new(@filter, @request.cookies).to_a,
21
- postData: postData,
21
+ postData: post_data,
22
22
  headersSize: -1,
23
23
  bodySize: @request.content_length
24
24
  }.compact
@@ -29,14 +29,14 @@ module Readme
29
29
  def url
30
30
  url = URI(@request.url)
31
31
  headers = @request.headers
32
- forward_proto = headers["X-Forwarded-Proto"]
33
- forward_host = headers["X-Forwarded-Host"]
32
+ forward_proto = headers['X-Forwarded-Proto']
33
+ forward_host = headers['X-Forwarded-Host']
34
34
  url.host = forward_host if forward_host.is_a?(String)
35
35
  url.scheme = forward_proto if forward_proto.is_a?(String)
36
36
  url.to_s
37
37
  end
38
38
 
39
- def postData
39
+ def post_data
40
40
  if @request.content_type.nil?
41
41
  nil
42
42
  elsif @request.form_data?
@@ -59,22 +59,22 @@ module Readme
59
59
  def request_body
60
60
  if @filter.pass_through?
61
61
  pass_through_body
62
- elsif is_form_urlencoded?
62
+ elsif form_urlencoded?
63
63
  form_urlencoded_body
64
- elsif is_json?
64
+ elsif json?
65
65
  json_body
66
66
  else
67
67
  @request.body
68
68
  end
69
69
  end
70
70
 
71
- def is_json?
72
- ["application/json", "application/x-json", "text/json", "text/x-json"]
73
- .include?(@request.content_type) || @request.content_type.include?("+json")
71
+ def json?
72
+ ['application/json', 'application/x-json', 'text/json', 'text/x-json']
73
+ .include?(@request.content_type) || @request.content_type.include?('+json')
74
74
  end
75
75
 
76
- def is_form_urlencoded?
77
- @request.content_type == "application/x-www-form-urlencoded"
76
+ def form_urlencoded?
77
+ @request.content_type == 'application/x-www-form-urlencoded'
78
78
  end
79
79
 
80
80
  def json_body
@@ -1,5 +1,5 @@
1
- require "rack/utils"
2
- require "readme/har/collection"
1
+ require 'rack/utils'
2
+ require 'readme/har/collection'
3
3
 
4
4
  module Readme
5
5
  module Har
@@ -37,7 +37,7 @@ module Readme
37
37
  end
38
38
 
39
39
  def empty_content
40
- {mimeType: "", size: 0}
40
+ { mimeType: '', size: 0 }
41
41
  end
42
42
 
43
43
  def json_content
@@ -1,13 +1,15 @@
1
- require "rack"
2
- require "readme/metrics"
3
- require "readme/har/request_serializer"
4
- require "readme/har/response_serializer"
5
- require "readme/har/collection"
1
+ # frozen-string-literal: true
2
+
3
+ require 'rack'
4
+ require 'readme/metrics'
5
+ require 'readme/har/request_serializer'
6
+ require 'readme/har/response_serializer'
7
+ require 'readme/har/collection'
6
8
 
7
9
  module Readme
8
10
  module Har
9
11
  class Serializer
10
- HAR_VERSION = "1.2"
12
+ HAR_VERSION = '1.2'
11
13
 
12
14
  def initialize(request, response, start_time, end_time, filter)
13
15
  @http_request = request
@@ -17,7 +19,7 @@ module Readme
17
19
  @filter = filter
18
20
  end
19
21
 
20
- def to_json
22
+ def to_json(*_args)
21
23
  {
22
24
  log: {
23
25
  version: HAR_VERSION,
@@ -31,9 +33,9 @@ module Readme
31
33
 
32
34
  def creator
33
35
  {
34
- name: Readme::Metrics::SDK_NAME,
36
+ name: 'readme-metrics (ruby)',
35
37
  version: Readme::Metrics::VERSION,
36
- comment: "#{Readme::Metrics::PLATFORM}/#{RUBY_VERSION}"
38
+ comment: "#{RUBY_PLATFORM}/#{RUBY_VERSION}" # arm64-darwin21/2.7.2
37
39
  }
38
40
  end
39
41
 
@@ -1,6 +1,6 @@
1
- require "rack"
2
- require "rack/request"
3
- require_relative "content_type_helper"
1
+ require 'rack'
2
+ require 'rack/request'
3
+ require_relative 'content_type_helper'
4
4
 
5
5
  module Readme
6
6
  class HttpRequest
@@ -11,7 +11,7 @@ module Readme
11
11
  Rack::HTTP_VERSION,
12
12
  Rack::HTTP_HOST,
13
13
  Rack::HTTP_PORT
14
- ]
14
+ ].freeze
15
15
 
16
16
  def initialize(env)
17
17
  @request = Rack::Request.new(env)
@@ -50,7 +50,7 @@ module Readme
50
50
  end
51
51
 
52
52
  def options?
53
- @request.request_method == "OPTIONS"
53
+ @request.request_method == 'OPTIONS'
54
54
  end
55
55
 
56
56
  def headers
@@ -82,20 +82,22 @@ module Readme
82
82
  # Other "headers" like version and host are prefixed with `HTTP_` by Rack but
83
83
  # don't seem to be considered legit HTTP headers.
84
84
  def http_header?(name)
85
- name.start_with?("HTTP") && !HTTP_NON_HEADERS.include?(name)
85
+ name.start_with?('HTTP') && !HTTP_NON_HEADERS.include?(name)
86
86
  end
87
87
 
88
88
  # Headers like `Content-Type: application/json` come into rack like
89
89
  # `"HTTP_CONTENT_TYPE" => "application/json"`.
90
90
  def normalize_header_name(header)
91
- header.delete_prefix("HTTP_").split("_").map(&:capitalize).join("-")
91
+ header.delete_prefix('HTTP_').split('_').map(&:capitalize).join('-')
92
92
  end
93
93
 
94
94
  # These special headers are explicitly _not_ prefixed with HTTP_ in the Rack
95
95
  # env so we need to add them in manually
96
96
  def unprefixed_headers
97
- {"Content-Type" => @request.content_type,
98
- "Content-Length" => @request.content_length}.compact
97
+ {
98
+ 'Content-Type' => @request.content_type,
99
+ 'Content-Length' => @request.content_length
100
+ }.compact
99
101
  end
100
102
  end
101
103
  end
@@ -1,6 +1,6 @@
1
- require "rack"
2
- require "rack/response"
3
- require_relative "content_type_helper"
1
+ require 'rack'
2
+ require 'rack/response'
3
+ require_relative 'content_type_helper'
4
4
 
5
5
  module Readme
6
6
  class HttpResponse < SimpleDelegator
@@ -13,22 +13,22 @@ module Readme
13
13
  def body
14
14
  if raw_body.respond_to?(:rewind)
15
15
  raw_body.rewind
16
- content = raw_body.each.reduce("", :+)
16
+ content = raw_body.each.reduce('', :+)
17
17
  raw_body.rewind
18
18
 
19
19
  content
20
20
  else
21
- raw_body.each.reduce("", :+)
21
+ raw_body.each.reduce('', :+)
22
22
  end
23
23
  end
24
24
 
25
25
  def content_length
26
26
  if empty_body_status?
27
27
  0
28
- elsif !headers["Content-Length"]
28
+ elsif !headers['Content-Length']
29
29
  body.bytesize
30
30
  else
31
- headers["Content-Length"].to_i
31
+ headers['Content-Length'].to_i
32
32
  end
33
33
  end
34
34
 
@@ -1,5 +1,7 @@
1
+ # frozen-string-literal: true
2
+
1
3
  module Readme
2
4
  class Metrics
3
- VERSION = "2.0.1"
5
+ VERSION = '2.1.0'
4
6
  end
5
7
  end
@@ -1,33 +1,21 @@
1
- require "readme/metrics/version"
2
- require "readme/har/serializer"
3
- require "readme/filter"
4
- require "readme/payload"
5
- require "readme/request_queue"
6
- require "readme/errors"
7
- require "readme/http_request"
8
- require "readme/http_response"
9
- require "httparty"
10
- require "logger"
11
- require "os"
1
+ # frozen-string-literal: true
2
+
3
+ require 'readme/metrics/version'
4
+ require 'readme/har/serializer'
5
+ require 'readme/filter'
6
+ require 'readme/payload'
7
+ require 'readme/request_queue'
8
+ require 'readme/errors'
9
+ require 'readme/http_request'
10
+ require 'readme/http_response'
11
+ require 'httparty'
12
+ require 'logger'
12
13
 
13
14
  module Readme
14
15
  class Metrics
15
- def self.platform
16
- if OS.windows?
17
- "windows"
18
- elsif OS.mac?
19
- "mac"
20
- elsif OS.linux?
21
- "linux"
22
- else
23
- "unknown"
24
- end
25
- end
26
-
27
- SDK_NAME = "Readme.io Ruby SDK"
28
- PLATFORM = platform
16
+ SDK_NAME = 'readme-metrics'
29
17
  DEFAULT_BUFFER_LENGTH = 1
30
- ENDPOINT = "https://metrics.readme.io/v1/request"
18
+ ENDPOINT = 'https://metrics.readme.io/v1/request'
31
19
 
32
20
  def self.logger
33
21
  @@logger
@@ -77,15 +65,16 @@ module Readme
77
65
  request = HttpRequest.new(env)
78
66
  har = Har::Serializer.new(request, response, start_time, end_time, @filter)
79
67
  user_info = @get_user_info.call(env)
68
+ ip = env['REMOTE_ADDR']
80
69
 
81
70
  if !user_info_valid?(user_info)
82
71
  Readme::Metrics.logger.warn Errors.bad_block_message(user_info)
83
72
  elsif request.options?
84
- Readme::Metrics.logger.info "OPTIONS request omitted from ReadMe API logging"
73
+ Readme::Metrics.logger.info 'OPTIONS request omitted from ReadMe API logging'
85
74
  elsif !can_filter? request, response
86
75
  Readme::Metrics.logger.warn "Request or response body MIME type isn't supported for filtering. Omitting request from ReadMe API logging"
87
76
  else
88
- payload = Payload.new(har, user_info, development: @development)
77
+ payload = Payload.new(har, user_info, ip, development: @development)
89
78
  @@request_queue.push(payload.to_json) unless payload.ignore
90
79
  end
91
80
  end
@@ -121,34 +110,36 @@ module Readme
121
110
  raise Errors::ConfigurationError, Errors::BUFFER_LENGTH_ERROR
122
111
  end
123
112
 
124
- if options[:development] && !is_a_boolean?(options[:development])
113
+ if options[:development] && !a_boolean?(options[:development])
125
114
  raise Errors::ConfigurationError, Errors::DEVELOPMENT_ERROR
126
115
  end
127
116
 
128
- if options[:logger] && has_logger_inferface?(options[:logger])
117
+ if options[:logger] && logger_inferface?(options[:logger])
129
118
  raise Errors::ConfigurationError, Errors::LOGGER_ERROR
130
119
  end
131
120
  end
132
121
 
133
- def has_logger_inferface?(logger)
134
- [
135
- :unknown,
136
- :fatal,
137
- :error,
138
- :warn,
139
- :info,
140
- :debug
122
+ def logger_inferface?(logger)
123
+ %i[
124
+ unknown
125
+ fatal
126
+ error
127
+ warn
128
+ info
129
+ debug
141
130
  ].any? { |message| !logger.respond_to? message }
142
131
  end
143
132
 
144
- def is_a_boolean?(arg)
145
- arg == true || arg == false
133
+ def a_boolean?(arg)
134
+ [true, false].include?(arg)
146
135
  end
147
136
 
137
+ # rubocop:disable Style/InverseMethods
148
138
  def user_info_valid?(user_info)
149
139
  !user_info.nil? &&
150
140
  !user_info.values.any?(&:nil?) &&
151
- user_info.has_key?(:api_key) || user_info.has_key?(:id)
141
+ user_info.key?(:api_key) || user_info.key?(:id)
152
142
  end
143
+ # rubocop:enable Style/InverseMethods
153
144
  end
154
145
  end
@@ -1,24 +1,26 @@
1
- require "uuid"
1
+ require 'socket'
2
+ require 'uuid'
2
3
 
3
4
  module Readme
4
5
  class Payload
5
6
  attr_reader :ignore
6
7
 
7
- def initialize(har, info, development:)
8
+ def initialize(har, info, ip_address, development:)
8
9
  @har = har
9
10
  @user_info = info.slice(:id, :label, :email)
10
11
  @user_info[:id] = info[:api_key] unless info[:api_key].nil? # swap api_key for id if api_key is present
11
12
  @log_id = info[:log_id]
12
13
  @ignore = info[:ignore]
14
+ @ip_address = ip_address
13
15
  @development = development
14
16
  @uuid = UUID.new
15
17
  end
16
18
 
17
- def to_json
19
+ def to_json(*_args)
18
20
  {
19
21
  logId: UUID.validate(@log_id) ? @log_id : @uuid.generate,
20
22
  group: @user_info,
21
- clientIPAddress: "1.1.1.1",
23
+ clientIPAddress: @ip_address,
22
24
  development: @development,
23
25
  request: JSON.parse(@har.to_json)
24
26
  }.to_json
@@ -1,4 +1,4 @@
1
- require "readme/metrics"
1
+ require 'readme/metrics'
2
2
 
3
3
  module Readme
4
4
  class RequestQueue
@@ -30,8 +30,8 @@ module Readme
30
30
  Thread.new do
31
31
  HTTParty.post(
32
32
  Readme::Metrics::ENDPOINT,
33
- basic_auth: {username: @api_key, password: ""},
34
- headers: {"Content-Type" => "application/json"},
33
+ basic_auth: { username: @api_key, password: '' },
34
+ headers: { 'Content-Type' => 'application/json' },
35
35
  body: to_json(payloads)
36
36
  )
37
37
  end
@@ -42,7 +42,7 @@ module Readme
42
42
  end
43
43
 
44
44
  def to_json(payloads)
45
- "[#{payloads.join(", ")}]"
45
+ "[#{payloads.join(', ')}]"
46
46
  end
47
47
  end
48
48
  end
@@ -1,31 +1,31 @@
1
- require_relative "lib/readme/metrics/version"
1
+ require_relative 'lib/readme/metrics/version'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
- spec.name = "readme-metrics"
4
+ spec.name = 'readme-metrics'
5
5
  spec.version = Readme::Metrics::VERSION
6
- spec.authors = ["ReadMe"]
7
- spec.email = ["support@readme.io"]
8
- spec.license = "ISC"
6
+ spec.authors = ['ReadMe']
7
+ spec.email = ['support@readme.io']
8
+ spec.license = 'ISC'
9
9
 
10
10
  spec.summary = "SDK for Readme's metrics API"
11
11
  spec.description = "Middleware for logging requests to Readme's metrics API"
12
- spec.homepage = "https://docs.readme.com/metrics/docs/getting-started-with-api-metrics"
13
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
12
+ spec.homepage = 'https://docs.readme.com/metrics/docs/getting-started-with-api-metrics'
13
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
14
14
 
15
- spec.metadata["homepage_uri"] = spec.homepage
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"
15
+ spec.metadata['homepage_uri'] = spec.homepage
16
+ spec.metadata['source_code_uri'] = 'https://github.com/readmeio/metrics-sdks/tree/main/packages/ruby'
17
+ spec.metadata['changelog_uri'] = 'https://github.com/readmeio/metrics-sdks/blob/main/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.
21
- spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
21
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
22
22
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
23
  end
24
+
24
25
  # spec.bindir = "exe"
25
26
  # spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
- spec.require_paths = ["lib"]
27
+ spec.require_paths = ['lib']
27
28
 
28
- spec.add_runtime_dependency "httparty", "~> 0.18"
29
- spec.add_runtime_dependency "uuid", "~> 2.3.8"
30
- spec.add_runtime_dependency "os", "~> 1.1.4"
29
+ spec.add_runtime_dependency 'httparty', '~> 0.18'
30
+ spec.add_runtime_dependency 'uuid', '~> 2.3.8'
31
31
  end
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: 2.0.1
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ReadMe
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-21 00:00:00.000000000 Z
11
+ date: 2022-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 2.3.8
41
- - !ruby/object:Gem::Dependency
42
- name: os
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: 1.1.4
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: 1.1.4
55
41
  description: Middleware for logging requests to Readme's metrics API
56
42
  email:
57
43
  - support@readme.io
@@ -61,12 +47,13 @@ extra_rdoc_files: []
61
47
  files:
62
48
  - ".gitignore"
63
49
  - ".rspec"
50
+ - ".rubocop.yml"
64
51
  - Gemfile
65
52
  - Gemfile.lock
66
53
  - LICENSE
54
+ - Makefile
67
55
  - README.md
68
56
  - Rakefile
69
- - SECURITY.md
70
57
  - bin/console
71
58
  - bin/setup
72
59
  - lib/readme/content_type_helper.rb
@@ -88,9 +75,9 @@ licenses:
88
75
  - ISC
89
76
  metadata:
90
77
  homepage_uri: https://docs.readme.com/metrics/docs/getting-started-with-api-metrics
91
- source_code_uri: https://github.com/readmeio/metrics-sdks/blob/main/packages/ruby
92
- changelog_uri: https://github.com/readmeio/metrics-sdks/blob/main/packages/ruby/CHANGELOG.md
93
- post_install_message:
78
+ source_code_uri: https://github.com/readmeio/metrics-sdks/tree/main/packages/ruby
79
+ changelog_uri: https://github.com/readmeio/metrics-sdks/blob/main/CHANGELOG.md
80
+ post_install_message:
94
81
  rdoc_options: []
95
82
  require_paths:
96
83
  - lib
@@ -105,8 +92,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
92
  - !ruby/object:Gem::Version
106
93
  version: '0'
107
94
  requirements: []
108
- rubygems_version: 3.1.4
109
- signing_key:
95
+ rubygems_version: 3.0.3.1
96
+ signing_key:
110
97
  specification_version: 4
111
98
  summary: SDK for Readme's metrics API
112
99
  test_files: []
data/SECURITY.md DELETED
@@ -1,12 +0,0 @@
1
- # Security Policy
2
-
3
- ## Reporting a Vulnerability
4
-
5
- If there are any vulnerabilities in `readme-metrics`, don't hesitate to _report them_.
6
-
7
- Please email security@readme.io and describe what you've found.
8
-
9
- - If you have a fix, explain or attach it.
10
- - In the near time, expect a reply with the required steps. Also, there may be a demand for a pull request which include the fixes.
11
-
12
- > You should not disclose the vulnerability publicly if you haven't received an answer in some weeks. If the vulnerability is rejected, you may post it publicly within some hour of rejection, unless the rejection is withdrawn within that time period. After the vulnerability has been fixed, you may disclose the vulnerability details publicly over some days.