salestation 3.4.0 → 3.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d9174def3fd040598bc0d97a1e0aeac15005df69
4
- data.tar.gz: d248d26c1d3f5ac3241da5263408a4324c1d3a9f
2
+ SHA256:
3
+ metadata.gz: 2fe9755ef3152c1d5e9821aa2a7be920245b35f7ee95f26fd1e0fe3fb5934468
4
+ data.tar.gz: f9b1e080731f605cfe7f3ccd2194b923fe70b668757198b105c5ee697ca29637
5
5
  SHA512:
6
- metadata.gz: a25ca2cf30a5f8e49f265779cf4a87010e06884de56cf99429bcc656633abe281c0bc4be30e03af96d946158a47eaff1ea5a0a1e4d6d3fdff0a9c33532c8e5d5
7
- data.tar.gz: 74cf0cc00b2c8f925a45651a6f9a8fdb69adacc76e893d97e9f2e91e96bcdb20fb87bcda498746404ef85984d5e8522dbbed278a05975b5eac0d9243025b922d
6
+ metadata.gz: c5988265e60fdfa3f8dc7fe1915e38cd6d3afc1aabeca923de08bf9726c21db355d04ce6d9047bfda8d7b8fa4773104fdacbd169a12de6c75ce702aafbd5e6dd
7
+ data.tar.gz: 1f3351524846ddea69d54281ab5262ffaa138a4fdf83092614030ca7d60bcb99d44a4944aa1690c04ecf88e41e39cf1d3209588e6730bd92566cf25e66393cec
@@ -1,6 +1,4 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.4
5
- - 2.5
6
- before_install: gem install bundler -v 1.17.3
4
+ - 2.7
data/README.md CHANGED
@@ -142,17 +142,26 @@ end
142
142
 
143
143
  Salestation provides a StatsD middleware which can be used record request
144
144
  execution time. A `timing` call with elapsed seconds is made to the provided
145
- StatsD instance with `path`, `method`, `status` tags.
145
+ StatsD instance with `path`, `method`, `status` and `status_class` tags.
146
146
 
147
147
  ```ruby
148
148
  class Webapp < Sinatra::Base
149
149
  # ...
150
150
  use Salestation::Web::StatsdMiddleware,
151
151
  Statsd.new(host, port),
152
- metric: 'my-metric'
152
+ metric: 'my_service.response.time'
153
153
  end
154
154
  ```
155
155
 
156
+ You can configure per-request tags by defining `salestation.statsd.tags` in sinatra `env`:
157
+
158
+ ```ruby
159
+ def my_handler(env)
160
+ env['salestation.statsd.tags'] = ['foo:bar']
161
+ # ...
162
+ end
163
+ ```
164
+
156
165
  ## Development
157
166
 
158
167
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -7,7 +7,7 @@ require 'dry-types'
7
7
  module Salestation
8
8
  class App
9
9
  module Types
10
- include Dry::Types.module
10
+ include Dry::Types()
11
11
  end
12
12
 
13
13
  def initialize(env:, hooks: {})
@@ -5,7 +5,7 @@ module Salestation
5
5
  module Errors
6
6
  class InvalidInput < Dry::Struct
7
7
  attribute :errors, Types::Strict::Hash
8
- attribute :hints, Types::Coercible::Hash.default({})
8
+ attribute :hints, Types::Coercible::Hash.default({}.freeze)
9
9
  attribute? :debug_message, Types::Strict::String
10
10
  end
11
11
 
@@ -8,7 +8,7 @@ require 'json'
8
8
  module Salestation
9
9
  class Web < Module
10
10
  module Types
11
- include Dry::Types.module
11
+ include Dry::Types()
12
12
  end
13
13
 
14
14
  def initialize(errors: {})
@@ -32,19 +32,27 @@ module Salestation
32
32
  class Error < Response
33
33
  attribute :status, Types::Strict::Integer
34
34
  attribute :message, Types::Strict::String
35
- attribute :debug_message, Types::String.default('')
36
- attribute :context, Types::Hash.default({})
37
- attribute :headers, Types::Hash.default({})
35
+ attribute :debug_message, Types::Coercible::String.default('')
36
+ attribute :context, Types::Hash.default({}.freeze)
37
+ attribute :headers, Types::Hash.default({}.freeze)
38
38
 
39
39
  def body
40
40
  {message: message, debug_message: debug_message}
41
41
  end
42
42
  end
43
43
 
44
+ class UnprocessableEntityError < Error
45
+ attribute :form_errors, Types::Hash.default({}.freeze)
46
+
47
+ def body
48
+ super.merge(form_errors: errors)
49
+ end
50
+ end
51
+
44
52
  class Success < Response
45
53
  attribute :status, Types::Strict::Integer
46
54
  attribute :body, Types::Strict::Hash | Types::Strict::Array
47
- attribute :headers, Types::Hash.default({})
55
+ attribute :headers, Types::Hash.default({}.freeze)
48
56
  end
49
57
 
50
58
  class UnprocessableEntityFromSchemaErrors
@@ -52,7 +60,7 @@ module Salestation
52
60
  message = parse_errors(errors)
53
61
  debug_message = parse_hints(hints)
54
62
 
55
- UnprocessableEntity.new(message: message, debug_message: debug_message)
63
+ UnprocessableEntity.new(message: message, debug_message: debug_message, form_errors: errors)
56
64
  end
57
65
 
58
66
  def self.parse_errors(errors)
@@ -99,7 +107,7 @@ module Salestation
99
107
  Conflict = Error.with_code(409)
100
108
  RequestEntityTooLarge = Error.with_code(413)
101
109
  UnsupportedMediaType = Error.with_code(415)
102
- UnprocessableEntity = Error.with_code(422)
110
+ UnprocessableEntity = UnprocessableEntityError.with_code(422)
103
111
 
104
112
  InternalError = Error.with_code(500)
105
113
  ServiceUnavailable = Error.with_code(503)
@@ -3,6 +3,9 @@
3
3
  module Salestation
4
4
  class Web < Module
5
5
  class StatsdMiddleware
6
+ EXTRA_TAGS_ENV_KEY = 'salestation.statsd.tags'
7
+
8
+ DURATION_MILLISECOND_PRECISION = 3
6
9
 
7
10
  def initialize(app, statsd, metric:)
8
11
  @app = app
@@ -11,7 +14,7 @@ module Salestation
11
14
  end
12
15
 
13
16
  def call(env)
14
- start = Time.now
17
+ start = system_monotonic_time
15
18
 
16
19
  status, header, body = @app.call env
17
20
 
@@ -23,14 +26,27 @@ module Salestation
23
26
  'unknown-route'
24
27
  end
25
28
 
26
- @statsd.timing(@metric, (Time.now - start) * 1000, tags: [
27
- "path:#{ path }",
28
- "method:#{ method }",
29
- "status:#{ status }"
30
- ])
29
+ tags = [
30
+ "path:#{path}",
31
+ "method:#{method}",
32
+ "status:#{status}",
33
+ "status_class:#{status / 100}xx"
34
+ ] + env.fetch(EXTRA_TAGS_ENV_KEY, [])
35
+
36
+ @statsd.timing(@metric, duration_ms(from: start), tags: tags)
31
37
 
32
38
  [status, header, body]
33
39
  end
40
+
41
+ private
42
+
43
+ def duration_ms(from:)
44
+ ((system_monotonic_time - from) * 1000).round(DURATION_MILLISECOND_PRECISION)
45
+ end
46
+
47
+ def system_monotonic_time
48
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
49
+ end
34
50
  end
35
51
  end
36
52
  end
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "salestation"
7
- spec.version = "3.4.0"
7
+ spec.version = "3.8.0"
8
8
  spec.authors = ["Glia TechMovers"]
9
9
  spec.email = ["techmovers@glia.com"]
10
10
 
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_development_dependency "bundler", "~> 1.13"
23
- spec.add_development_dependency "rake", "~> 10.0"
22
+ spec.add_development_dependency "bundler", "~> 2.0"
23
+ spec.add_development_dependency "rake", "~> 13.0"
24
24
  spec.add_development_dependency "rspec", "~> 3.0"
25
25
  spec.add_development_dependency "pry", "~> 0.10.4"
26
26
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: salestation
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.0
4
+ version: 3.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Glia TechMovers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-03 00:00:00.000000000 Z
11
+ date: 2020-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.13'
19
+ version: '2.0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.13'
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -158,8 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
158
  - !ruby/object:Gem::Version
159
159
  version: '0'
160
160
  requirements: []
161
- rubyforge_project:
162
- rubygems_version: 2.6.14.4
161
+ rubygems_version: 3.0.3
163
162
  signing_key:
164
163
  specification_version: 4
165
164
  summary: ''