tpt-rails 1.6.1 → 1.7.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: '0395183e764d77487d191133045533748b1120aa919bd2904d19e923c58b5c1d'
4
- data.tar.gz: f8591848d97fb4324aed4318183198db27ccfcff116ad43f806cd2322aadcb57
3
+ metadata.gz: 831a524d39259635bc860e843b2d2670f6c9915cdae576077b23fbfefbf238ad
4
+ data.tar.gz: 8ad8e1171dbf2b6c8d2bae9ffac26a570364df1634adef7b26987fb100555077
5
5
  SHA512:
6
- metadata.gz: 3093e622d8895edf09b3d2ee025c1356e89bdd6d7ea95dd623e5f870e8d2adab915bc4f279c548f24d0636ee902825c163b1ea61f7ce21ef5a66c970dc0c55f8
7
- data.tar.gz: 11459ad795f7603c051f7c509ff475bdfd21bd52ce37b26ad4792da3a833fdea0a4294f614965cd28a0716f51ed79039b5fe39ebde21458e2901595e6f0ca1e7
6
+ metadata.gz: 3a4b96042265fa07dc0d02263107d71946b346ca2913e89965ff0e11fb53a57f5b048df17700eb4d57f5df3af8bc34a4e7bd148b1cfe38d811db65b0eee067ca
7
+ data.tar.gz: ae189a0490e15964749f69eaf85431be09d2a57a25bcca5f74af42335889b7a1c44b7ce4934ee47a404a7807b433ebd24f7ffaab1e7dd7a540b19a1ea34cac72
data/README.md CHANGED
@@ -74,25 +74,47 @@ See the documentation in [lib/tpt/rails.rb](lib/tpt/rails.rb).
74
74
  gem "aws-sdk-eventbridge", "~> 1.3.0"
75
75
  ```
76
76
 
77
- 2. In an initializer, pass in the `Datadog::Statsd` object you're using to the class method ::set_metrics.
78
- (Failure to do so will result in an error.) When testing, you can pass in a local Statsd, eg:
77
+ 2. Instantiate with
79
78
 
80
79
  ```ruby
81
- Tpt::Rails::EventBridgePublisher.set_metrics(
82
- Datadog::Statsd.new('localhost', 8125)
83
- )
80
+ Tpt::Rails::EventBridgePublisher.new
84
81
  ```
85
82
 
86
83
  3. By default (#new with no arguments) EventBridgePublisher will try to use the following environment
87
84
  variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `TPT_EVENT_SOURCE`, `TPT_SHARED_EVENT_BUS_NAME`.
88
85
 
89
86
  Additional configuration can be set as part of the constructor;
90
- [see event_bridge_publisher.rb implementation](https://github.com/TeachersPayTeachers/tpt-rails/blob/ad768d3bac0c8bd28e60a48a89aed36f01c4e17b/app/models/tpt/rails/event_bridge_publisher.rb) for more details.
87
+ [see event_bridge_publisher.rb implementation](https://github.com/TeachersPayTeachers/tpt-rails/blob/master/app/models/tpt/rails/event_bridge_publisher.rb) for more details.
91
88
 
92
89
  4. Create events by instantiating or inheriting from `Tpt::Rails::ApplicationEvent`. Event types are derived from the text before
93
90
  "Event", so ResourceEvent has the event_type "Resource". Pass in an event or an array of events to EventBridgePublisher#publish
94
91
  and they will be published immediately. Large arrays will be batched (default 10 per batch).
95
92
 
93
+ 5. EventBridgePublisher uses Tpt::Rails.statsd as its datadog instance by default. If you want to change that behavior, call `Tpt::Rails::EventBridgePublisher.set_metrics`
94
+ with the statsd you want to use inside an initializer, as part of a `reloader.to_prepare` call:
95
+
96
+ ```ruby
97
+ Rails.application.reloader.to_prepare do
98
+ Tpt::Rails::EventBridgePublisher.set_metrics(
99
+ # your statsd here
100
+ )
101
+ end
102
+ ```
103
+
104
+ You can also do this when testing by using the default test publisher (see below).
105
+
106
+ ### EventBridge Testing
107
+
108
+ 1. To create a ready-made test publisher, use
109
+
110
+ ```ruby
111
+ Tpt::Rails::EventBridgeTestHelper.publisher
112
+ ```
113
+
114
+ This method accepts two parameters, batch_size and stub_responses. [See implementation docs](https://github.com/TeachersPayTeachers/tpt-rails/blob/master/app/helpers/tpt/rails/event_bridge_test_helper.rb) for more details.
115
+
116
+ 2. The test publisher overwrites statsd that EventBridgePublisher uses to be a dummy statsd when called.
117
+
96
118
  ### Error reporting (e.g. Bugsnag/Rollbar)
97
119
 
98
120
  If you configure `rollbar_access_token` & `rollbar_enabled`, or `bugsnag_api_key` then your project
@@ -0,0 +1,27 @@
1
+ module Tpt::Rails
2
+ module EventBridgeTestHelper
3
+ ###
4
+ # @description: Instantiates an EventBridgePublisher ready for testing. AWS and DataDog info is faked. Note that this sets the
5
+ # metrics object for the class to be a stub. The AWS EventBridge gem will never actually be called as the gem's
6
+ # #put_events method is replaced with a stub.
7
+ # @param {batch_size}: The number of events to send per batch.
8
+ # @param {stub_responses}: Responses to stub, eg. { put_events: { failed_entry_count: 0, entries: [{ event_id: "1" }, { event_id: "2" }] } }
9
+ # @return {EventBridgePublisher}: The EventBridgePublisher object.
10
+ ###
11
+ def self.publisher(batch_size: 10, stub_responses: {})
12
+ Tpt::Rails::EventBridgePublisher.set_metrics(
13
+ Datadog::Statsd.new('localhost', 8125)
14
+ )
15
+
16
+ Tpt::Rails::EventBridgePublisher.new(
17
+ event_source: ENV.fetch('TPT_EVENT_SOURCE', 'test-source'),
18
+ batch_size: batch_size,
19
+ client_options: {
20
+ access_key_id: '1234',
21
+ secret_access_key: 'abcd',
22
+ stub_responses: stub_responses
23
+ }
24
+ )
25
+ end
26
+ end
27
+ end
@@ -1,6 +1,9 @@
1
1
  module Tpt::Rails
2
2
  class EventBridgePublisher
3
+ class NoEntriesInResponseData < StandardError; end
4
+
3
5
  attr_accessor :batch_size
6
+ attr_reader :client
4
7
 
5
8
  def initialize(
6
9
  event_bus_name: default_event_bus_name,
@@ -29,7 +32,8 @@ module Tpt::Rails
29
32
  end
30
33
 
31
34
  private
32
- attr_reader :client, :event_bus_name, :event_source
35
+
36
+ attr_reader :event_bus_name, :event_source
33
37
 
34
38
  def publish_batch(events)
35
39
  metrics.time('tpt.event_bridge.publish_batch') do
@@ -47,7 +51,7 @@ module Tpt::Rails
47
51
  metrics.increment('tpt.event_bridge.publish_failure', by: events.length, tags: ["error_code:publish_batch_failure"])
48
52
 
49
53
  # re-reraise the error for users to handle
50
- raise e
54
+ raise
51
55
  end
52
56
 
53
57
  def wrap_events(events)
@@ -63,6 +67,15 @@ module Tpt::Rails
63
67
  end
64
68
 
65
69
  def handle_response(res, events)
70
+ unless res&.data&.entries
71
+ logger.error({
72
+ msg: "No entries in the response data",
73
+ response: res,
74
+ events: events,
75
+ })
76
+ raise NoEntriesInResponseData, "No entries in the response data"
77
+ end
78
+
66
79
  res.data.entries.each_with_index do |entry, index|
67
80
  if entry.error_code.present?
68
81
  metrics.increment('tpt.event_bridge.publish_failure', tags: ["error_code:#{entry.error_code}"])
@@ -86,8 +99,8 @@ module Tpt::Rails
86
99
  access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID', nil),
87
100
  secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY', nil),
88
101
  region: ENV.fetch('AWS_REGION', 'us-east-1'),
89
- http_open_timeout: 1, # default is 15
90
- http_read_timeout: 1, # default is 60
102
+ http_open_timeout: 3, # default is 15
103
+ http_read_timeout: 15, # default is 60
91
104
  }.merge(options)
92
105
 
93
106
  Aws::EventBridge::Client.new(all_options)
@@ -125,8 +138,9 @@ module Tpt::Rails
125
138
  end
126
139
 
127
140
  def metrics
128
- raise "metrics object not set; use EventBridgePublisher#set_metrics" unless @@statsd
141
+ @@statsd ||= Tpt::Rails.statsd
129
142
 
143
+ raise "metrics object not set and no default found; use EventBridgePublisher#set_metrics" unless @@statsd
130
144
  @@statsd
131
145
  end
132
146
  end
@@ -11,4 +11,32 @@ Tpt::Rails.configure do |config|
11
11
 
12
12
  config.datadog_statsd_url = ENV["DOGSTATSD_URL"].presence
13
13
  config.datadog_trace_url = ENV["DATADOG_TRACE_URL"].presence
14
+
15
+ # Setup for Statsd
16
+ #
17
+ # Either by setting a statsd url (a nil url will create a dummy statsd object):
18
+ # config.datadog_statsd_url = "statsd://localhost:1234"
19
+ #
20
+ # Or by setting a custom statsd instance:
21
+ # config.statsd = Tpt::Rails::DatadogFactory.make(
22
+ # statsd_url: datadog_statsd_url,
23
+ # )
24
+ #
25
+ # See documentation in tpt-rails for all the options available on the make method
26
+
27
+ # Setup for Tracing
28
+ #
29
+ # To disable tracing (you should disable tracing in most environments):
30
+ # config.datadog_disable_trace = true
31
+ #
32
+ # To use default tracing options and just set url:
33
+ # config.datadog_trace_url = "datadog://localhost:1234"
34
+ #
35
+ # Or for full customization:
36
+ # Tpt::Rails::DatadogFactory.configure_tracing(
37
+ # trace_url: "datadog://localhost:1234",
38
+ # environment: "my_env",
39
+ # trace_tags: ["mytag1:hello", "mytag2:goodbye"],
40
+ # trace_debug: true
41
+ # )
14
42
  end
@@ -1,4 +1,4 @@
1
- require 'tpt/rails/internal/datadog'
1
+ require 'tpt/rails/datadog_factory'
2
2
  require 'tpt/rails/internal/error_reporter'
3
3
  require 'tpt/rails/internal/health_checks'
4
4
 
@@ -13,10 +13,14 @@ class Tpt::Rails::Config
13
13
  attr_accessor :app_name
14
14
  # A project-specific api key from Bugsnag
15
15
  attr_accessor :bugsnag_api_key
16
- # Set this in the form of: statsd://[host]:[port]'
16
+ # Allow setting a customized Statsd; supercedes setting urls
17
+ attr_accessor :statsd
18
+ # Set this in the form of: statsd://[host]:[port]
17
19
  attr_accessor :datadog_statsd_url
18
- # Set this in the form of: datadog://[host]:[port]'
20
+ # Set this in the form of: datadog://[host]:[port]
19
21
  attr_accessor :datadog_trace_url
22
+ # Set to true to disable tracing
23
+ attr_accessor :datadog_disable_trace
20
24
  # Set this in the form of: redis://:[password]@[hostname]:[port]/[db]
21
25
  attr_accessor :redis_url
22
26
  # A project-specific access token from rollbar
@@ -56,10 +60,19 @@ class Tpt::Rails::Config
56
60
  Redis.current = Redis.new(url: redis_url, driver: :hiredis)
57
61
  end
58
62
 
59
- @datadog = Tpt::Rails::Internal::Datadog.new(
60
- statsd_url: datadog_statsd_url,
61
- trace_url: datadog_trace_url,
62
- )
63
+ if statsd
64
+ @statsd = statsd
65
+ else
66
+ @statsd = Tpt::Rails::DatadogFactory.make(
67
+ statsd_url: datadog_statsd_url,
68
+ )
69
+ end
70
+
71
+ if datadog_disable_trace
72
+ Tpt::Rails::DatadogFactory.disable_tracing
73
+ elsif datadog_trace_url
74
+ Tpt::Rails::DatadogFactory.configure_tracing(trace_url: datadog_trace_url)
75
+ end
63
76
 
64
77
  @health_checks.setup
65
78
 
@@ -71,7 +84,7 @@ class Tpt::Rails::Config
71
84
  end
72
85
 
73
86
  def statsd # :nodoc:
74
- @datadog.statsd
87
+ @statsd
75
88
  end
76
89
 
77
90
  def report(error) # :nodoc:
@@ -0,0 +1,100 @@
1
+ #
2
+ # Configures Datadog metrics and tracing
3
+ #
4
+
5
+ require 'datadog/statsd'
6
+ require 'ddtrace'
7
+
8
+ class Tpt::Rails::DatadogFactory
9
+ DEFAULT_STATSD_PORT = 8125
10
+ DEFAULT_TRACE_PORT = 8126
11
+
12
+ private_class_method :new
13
+
14
+ class << self
15
+ ###
16
+ # @description: Instantiates a datadog statsd instance. Note: has side effects, as it configures tracing.
17
+ # @param {statsd_url}: The url to sends stats to; if nil, a dummy url is used. Form: statsd://[host]:[port]
18
+ # @param {environment}: Wrapped in "env:#{environment}" and added to tags; if nil, Tpt::Rails.app_env is used;
19
+ # If using eg. reporting env this is where you put it
20
+ # @param {statsd_tags}: Set your own tags. If nil, default tags are used.
21
+ # If missing, no env tag is supplied, a default (optionally using environment param) is pushed into it.
22
+ # tpt-rails version is always pushed into it.
23
+ # @return {Datadog::Statsd}
24
+ ###
25
+ def make(statsd_url: nil, environment: nil, statsd_tags: nil)
26
+ statsd_tags = Array.wrap(statsd_tags)
27
+
28
+ # Fall back to a dummy client so callers don't have to worry about null checking the client
29
+ url = statsd_url || 'statsd://localhost'
30
+ uri = URI.parse(url)
31
+
32
+ tags = statsd_tags.nil? ? [] : statsd_tags
33
+ tags << "env:#{to_env(environment)}" unless tags.map { |t| t.split(':')[0] }.include?("env")
34
+ tags << "tpt-rails_release_version:#{Tpt::Rails.release_version}" if Tpt::Rails.release_version
35
+
36
+ ::Datadog::Statsd.new(
37
+ uri.host,
38
+ uri.port || DEFAULT_STATSD_PORT,
39
+ namespace: Tpt::Rails.app_name,
40
+ tags: tags,
41
+ )
42
+ end
43
+
44
+ def make_dummy
45
+ make
46
+ end
47
+
48
+ # @description: Configure tracing. Just passing trace_url: is enough for a basic config.
49
+ # @param {trace_url}: The url to send traces to; if nil, tracing is disabled. Form: datadog://[host]:[port]
50
+ # @param {trace_tags}: Set your own trace tags. If missing, default tags are used (optionally using environment param).
51
+ # @param {trace_debug}: boolean; passed to c.tracer enabled
52
+ # @param {&block}: Pass to set custom configuration for tracing as part of a .configure call.
53
+ # Accepts one parameter that is the configuration object.
54
+ def configure_tracing(trace_url: nil, environment:nil, trace_tags: nil, trace_debug: false)
55
+ uri = URI.parse(trace_url)
56
+ tags = { 'env' => to_env(environment) }
57
+ tags["tpt_release_version"] = Tpt::Rails.release_version if Tpt::Rails.release_version
58
+
59
+ ::Datadog.configure do |c|
60
+ # This will activate auto-instrumentation for Rails
61
+ c.use :rails, {
62
+ analytics_enabled: true,
63
+ service_name: Tpt::Rails.app_name,
64
+ }
65
+
66
+ c.tracer(
67
+ enabled: true,
68
+ debug: trace_debug,
69
+ hostname: uri.host,
70
+ port: uri.port || DEFAULT_TRACE_PORT,
71
+ tags: tags,
72
+ )
73
+
74
+ c.logger.level = ::Logger::WARN
75
+
76
+ yield(c) if block_given?
77
+ end
78
+
79
+ ::Datadog::Pipeline.before_flush(
80
+ ::Datadog::Pipeline::SpanFilter.new { |span|
81
+ span.resource =~ /TptRails::HealthChecksController/
82
+ },
83
+ )
84
+ end
85
+
86
+ def disable_tracing
87
+ ::Datadog.configure { |c| c.tracer(enabled: false) }
88
+ end
89
+
90
+ private
91
+
92
+ def to_env(environment)
93
+ if environment.nil?
94
+ Tpt::Rails.app_env
95
+ else
96
+ environment
97
+ end
98
+ end
99
+ end
100
+ end
@@ -1,6 +1,6 @@
1
1
  module Tpt
2
2
  module Rails
3
3
  # Do not change this manually. Our tooling will do it automatically.
4
- VERSION = '1.6.1'
4
+ VERSION = '1.7.0'
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tpt-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.1
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - TpT
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-20 00:00:00.000000000 Z
11
+ date: 2022-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -114,6 +114,7 @@ files:
114
114
  - app/controllers/tpt/rails/error_tests_controller.rb
115
115
  - app/controllers/tpt/rails/health_checks_controller.rb
116
116
  - app/helpers/tpt/rails/application_helper.rb
117
+ - app/helpers/tpt/rails/event_bridge_test_helper.rb
117
118
  - app/jobs/tpt/rails/application_job.rb
118
119
  - app/mailers/tpt/rails/application_mailer.rb
119
120
  - app/models/tpt/rails/application_event.rb
@@ -147,9 +148,9 @@ files:
147
148
  - lib/generators/tpt/rails/postman/postman.yaml.tt
148
149
  - lib/tpt/rails.rb
149
150
  - lib/tpt/rails/config.rb
151
+ - lib/tpt/rails/datadog_factory.rb
150
152
  - lib/tpt/rails/engine.rb
151
153
  - lib/tpt/rails/internal.rb
152
- - lib/tpt/rails/internal/datadog.rb
153
154
  - lib/tpt/rails/internal/error_reporter.rb
154
155
  - lib/tpt/rails/internal/health_checks.rb
155
156
  - lib/tpt/rails/puma_stats_collector.rb
@@ -1,71 +0,0 @@
1
- #
2
- # Configures Datadog metrics and tracing, based on Tpt::Rails.config
3
- #
4
-
5
- require 'datadog/statsd'
6
- require 'ddtrace'
7
-
8
- class Tpt::Rails::Internal::Datadog # :nodoc:
9
- DEFAULT_STATSD_PORT = 8125
10
- DEFAULT_TRACE_PORT = 8126
11
-
12
- attr_reader :statsd
13
-
14
- def initialize(statsd_url: nil, trace_url: nil)
15
- @statsd_url = statsd_url
16
- @trace_url = trace_url
17
-
18
- @statsd = create_statsd
19
-
20
- if @trace_url
21
- configure_tracing
22
- end
23
- end
24
-
25
- private
26
-
27
- def create_statsd
28
- # Fall back to a dummy client so callers don't have to worry about null checking the client
29
- url = @statsd_url || 'statsd://localhost'
30
- uri = URI.parse(url)
31
-
32
- tags = ["env:#{Tpt::Rails.app_env}"]
33
- tags << ["tpt_release_version:#{Tpt::Rails.release_version}"] if Tpt::Rails.release_version
34
-
35
- ::Datadog::Statsd.new(
36
- uri.host,
37
- uri.port || DEFAULT_STATSD_PORT,
38
- namespace: Tpt::Rails.app_name,
39
- tags: tags,
40
- )
41
- end
42
-
43
- def configure_tracing
44
- uri = URI.parse(@trace_url)
45
- tags = { 'env' => Tpt::Rails.app_env }
46
- tags["tpt_release_version"] = Tpt::Rails.release_version if Tpt::Rails.release_version
47
-
48
- ::Datadog.configure do |c|
49
- # This will activate auto-instrumentation for Rails
50
- c.use :rails, {
51
- analytics_enabled: true,
52
- service_name: Tpt::Rails.app_name,
53
- }
54
-
55
- c.tracer(
56
- enabled: true,
57
- hostname: uri.host,
58
- port: uri.port || DEFAULT_TRACE_PORT,
59
- tags: tags,
60
- )
61
-
62
- c.logger.level = ::Logger::WARN
63
- end
64
-
65
- ::Datadog::Pipeline.before_flush(
66
- ::Datadog::Pipeline::SpanFilter.new { |span|
67
- span.resource =~ /TptRails::HealthChecksController/
68
- },
69
- )
70
- end
71
- end