nexaas-queue_time 0.2.0 → 0.3.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
2
  SHA256:
3
- metadata.gz: e48475f10c2bf68a6e0486bbf1d0c2c1b66f2e71d56ad35392707807ac158d66
4
- data.tar.gz: bad0970dfd5d9ee2496fec837a0fb7fb4e2b63ede476820682c80175ef2bbc17
3
+ metadata.gz: 87997f283ea190bbdcba83290a11d23dbc446db1a11c32d48b51d8b3bc110219
4
+ data.tar.gz: 57746b20d94c1ddd326b405906ba6dfc887089cb3f43c66d89e6d9131beec209
5
5
  SHA512:
6
- metadata.gz: 20cba9c3530a8e066ee0261486c69a486565dc6a1c86314bf3db4798662d1203bdde51625a4319e4cbe277a301342a6771ad32d3f7c04978d5cb6cdb040da787
7
- data.tar.gz: f7cf37772229044a1f72b0cd4dc1109e4fbd8a14469d2c25bfc48f0a6cbb927aa691b7908e2be2442a87057069da8602663b033431a619779b1f2c6536da3126
6
+ metadata.gz: ecb3f250ee9abb4caa347d1209e2696f89b4d2e4a977d11a5dd109d007d861ee8f0739d1792e693c213ce0487026974b3e0fccfab7705ec52d4f046112a59d63
7
+ data.tar.gz: 16467b32806ef5813cf070d4efe9d86171022caab30c2ecbd407e694ec0e24f1df8352f386172106785976b204d9ae954b921d52da38e43aebf28ebe7c598a10
data/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.3.0] - 2019-07-01
6
+
7
+ ### Added
8
+
9
+ - Document middleware class
10
+ - Test for header pattern before calculating `queue_time`
11
+
12
+ ### Changed
13
+
14
+ - Do not calculate `queue_time` if header is not present
15
+
16
+ ### Fixed
17
+
18
+ - Use `String =~` instead of `String#match?` due to Ruby 2.3
19
+
5
20
  ## [0.2.0] - 2019-06-28
6
21
 
7
22
  ### Fixed
@@ -15,28 +30,4 @@ All notable changes to this project will be documented in this file.
15
30
  - Initial implementation of the gem
16
31
 
17
32
 
18
- [6.0.0]: https://github.com/kickstarter/rack-attack/compare/v5.4.2...v6.0.0/
19
- [5.4.2]: https://github.com/kickstarter/rack-attack/compare/v5.4.1...v5.4.2/
20
- [5.4.1]: https://github.com/kickstarter/rack-attack/compare/v5.4.0...v5.4.1/
21
- [5.4.0]: https://github.com/kickstarter/rack-attack/compare/v5.3.2...v5.4.0/
22
- [5.3.2]: https://github.com/kickstarter/rack-attack/compare/v5.3.1...v5.3.2/
23
- [5.3.1]: https://github.com/kickstarter/rack-attack/compare/v5.3.0...v5.3.1/
24
- [5.3.0]: https://github.com/kickstarter/rack-attack/compare/v5.2.0...v5.3.0/
25
- [5.2.0]: https://github.com/kickstarter/rack-attack/compare/v5.1.0...v5.2.0/
26
- [5.1.0]: https://github.com/kickstarter/rack-attack/compare/v5.0.1...v5.1.0/
27
- [5.0.1]: https://github.com/kickstarter/rack-attack/compare/v5.0.0...v5.0.1/
28
- [5.0.0]: https://github.com/kickstarter/rack-attack/compare/v4.4.1...v5.0.0/
29
- [4.4.1]: https://github.com/kickstarter/rack-attack/compare/v4.4.0...v4.4.1/
30
- [4.4.0]: https://github.com/kickstarter/rack-attack/compare/v4.3.1...v4.4.0/
31
- [4.3.1]: https://github.com/kickstarter/rack-attack/compare/v4.3.0...v4.3.1/
32
- [4.3.0]: https://github.com/kickstarter/rack-attack/compare/v4.2.0...v4.3.0/
33
- [4.2.0]: https://github.com/kickstarter/rack-attack/compare/v4.1.1...v4.2.0/
34
- [4.1.1]: https://github.com/kickstarter/rack-attack/compare/v4.1.0...v4.1.1/
35
- [4.1.0]: https://github.com/kickstarter/rack-attack/compare/v4.0.1...v4.1.0/
36
- [4.0.1]: https://github.com/kickstarter/rack-attack/compare/v4.0.0...v4.0.1/
37
- [4.0.0]: https://github.com/kickstarter/rack-attack/compare/v3.0.0...v4.0.0/
38
- [3.0.0]: https://github.com/kickstarter/rack-attack/compare/v2.3.0...v3.0.0/
39
- [2.3.0]: https://github.com/kickstarter/rack-attack/compare/v2.2.1...v2.3.0/
40
- [2.2.1]: https://github.com/kickstarter/rack-attack/compare/v2.2.0...v2.2.1/
41
- [2.2.0]: https://github.com/kickstarter/rack-attack/compare/v2.1.1...v2.2.0/
42
-
33
+ [0.2.0]: https://github.com/myfreecomm/nexaas-queue_time/compare/v0.1.0...v0.2.0/
@@ -4,40 +4,62 @@ require 'datadog/statsd'
4
4
 
5
5
  module Nexaas
6
6
  module QueueTime
7
+ # This middleware calculates the time a request has been waiting
8
+ # in the queue before being served by the application server.
9
+ #
10
+ # It requires the header `X_REQUEST_START`. This header contains
11
+ # the timestamp of when the request first apperead in the stack.
12
+ # This header is usually set by a LoadBalancer, Reverse Proxy or Router.
13
+ #
14
+ # The format of the header **must** match:
15
+ # `t=TIMESTAMP`, where TIMESTAMP is the unix timestamp.
16
+ # This format is supported by APMs such as New Relic and Scout
7
17
  class Middleware
8
18
  METRIC_NAME = 'request.queue_time'
19
+ HEADER_FORMAT_PATTERN = /
20
+ ^ # Beginning of line
21
+ t= #
22
+ \d+ # At least 1 digit
23
+ \.? # Optionally a dot may be used for fractional timestamps
24
+ \d* # Optionally more digits after the dot
25
+ $ # End of line
26
+ /x
9
27
 
10
28
  def initialize(app)
11
29
  @app = app
12
30
  end
13
31
 
14
32
  def call(env)
15
- left_queue = Time.now.to_f
16
- metric = queue_time_in_ms(left_queue, env)
17
- send_metric(metric)
33
+ request_start_header = env['HTTP_X_REQUEST_START']
34
+ if request_start_header && request_start_header =~ HEADER_FORMAT_PATTERN
35
+ left_queue_at = Time.now.to_f
36
+ metric = calculate_queue_time_in_ms(left_queue_at, request_start_header)
37
+ send_metric(metric)
38
+ end
18
39
 
19
40
  @app.call(env)
20
41
  end
21
42
 
22
43
  private
23
44
 
24
- def queue_time_in_ms(left_queue, env)
25
- entered_queue = env['HTTP_X_REQUEST_START']
26
- return nil if entered_queue.nil?
27
-
28
- entered_queue = extract_timestamp(entered_queue)
29
- (left_queue - entered_queue.to_f) * 1000
45
+ def calculate_queue_time_in_ms(left_queue_at, request_start_header)
46
+ entered_queue_at = extract_timestamp(request_start_header)
47
+ (left_queue_at - entered_queue_at.to_f) * 1000
30
48
  end
31
49
 
32
- # The header actually comes as `t=1234567890`,
33
- # so we need to extract the timestamp.
34
50
  def extract_timestamp(entered_queue)
35
51
  entered_queue.delete('t=')
36
52
  end
37
53
 
54
+ # By default, Datadog::Statsd opens a UDP connection with a given host and port.
55
+ # Instead, we are giving it a socket path so it communicates with the statsd server via UDS.
56
+ #
57
+ # This approach is easier to setup in containerized environments since all it requires
58
+ # is the path to the socket file instead of the host address.
59
+ #
60
+ # UDS also performs better than UDP,
61
+ # although the app would need to receive huge traffic to actually feel the difference.
38
62
  def send_metric(metric)
39
- return unless metric
40
-
41
63
  Datadog::Statsd.open(nil, nil, socket_path: '/var/run/datadog/dsd.socket') do |statsd|
42
64
  statsd.timing(METRIC_NAME, metric.to_i, sample_rate: 1)
43
65
  end
@@ -1,5 +1,5 @@
1
1
  module Nexaas
2
2
  module QueueTime
3
- VERSION = '0.2.0'
3
+ VERSION = '0.3.0'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexaas-queue_time
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucas Mansur
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-06-28 00:00:00.000000000 Z
11
+ date: 2019-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dogstatsd-ruby