ecoportal-api 0.10.2 → 0.10.3

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: 4cc0547ca88715ad6b0f2d3bc7ed4661bab0f9259117ce28aa5d43aab0761d02
4
- data.tar.gz: 1e109b427a0e71bd91edf1d4e9ce6e7cf9ac2df998662c97746df30b8e07998b
3
+ metadata.gz: dde26458f8ba991809f2218f6a4594101350f861a811d1bf4c6b508b2194ef67
4
+ data.tar.gz: f9bd67ceaea38ec6ea82d9a53ae0651c36fb7f74e417b37029acd7d72fd00d97
5
5
  SHA512:
6
- metadata.gz: 44eba3743e30beff3c04e71b1191900b8477d81af1371f1a5003cb6847384e384d535e51390e4f8db39e8aa81a0cbf7fc200a87ac18036c45e56530b72b09342
7
- data.tar.gz: 1749045310b0748e8935027cd0d1b9d69e7a84c4534b27017bd1581848d579c6359e59dedfe19e3cbe451038e2a4c70fb82150a01ca4c9260eadde64bfac5a92
6
+ metadata.gz: '09dd4b2cde2bd8f6c6689433c7472fedb6110d076603afcd8edc39f5275aed0296470e57900eaceb335dc875f31554d515925c6b1eae060786a055ac706f6a66'
7
+ data.tar.gz: 3363216e775f38601146617ee80abab13625163c46739f536d77f94c17247fcce139331cad8af02b4cbcc0848a352211a34c476d0d766082e18b5d4b222f43cf
data/CHANGELOG.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
- ## [0.10.3] - 2024-09-xx
5
+ ## [0.10.4] - 2024-10-xx
6
6
 
7
7
  ### Added
8
8
 
@@ -10,6 +10,14 @@ All notable changes to this project will be documented in this file.
10
10
 
11
11
  ### Fixed
12
12
 
13
+ ## [0.10.3] - 2024-10-01
14
+
15
+ ### Changed
16
+
17
+ - refactored Client
18
+ - initialized with `deep_logging` named argumnet
19
+ - previously `response_logging`
20
+
13
21
  ## [0.10.2] - 2024-09-27
14
22
 
15
23
  ### Added
@@ -4,11 +4,12 @@ module Ecoportal
4
4
  class BatchOperation
5
5
  include Common::DocHelpers
6
6
 
7
- def initialize(base_path, wrapper, logger: nil)
8
- @base_path = base_path
9
- @wrapper = wrapper
10
- @operations = []
11
- @logger = logger
7
+ def initialize(base_path, wrapper, logger: nil, deep_logging: false)
8
+ @base_path = base_path
9
+ @wrapper = wrapper
10
+ @operations = []
11
+ @logger = logger
12
+ @deep_logging = deep_logging
12
13
  end
13
14
 
14
15
  def count
@@ -25,11 +26,12 @@ module Ecoportal
25
26
 
26
27
  def process_response(response)
27
28
  unless response.success?
28
- log(:error) { "Total failure in batch operation." }
29
- raise "Total failure in batch operation"
29
+ msg = "Error: total failure in batch operation."
30
+ log(:debug) { msg }
31
+ raise msg
30
32
  end
31
33
 
32
- log(:info) { "Processing batch responses" }
34
+ log(:debug) { "Processing batch responses" } if deep_logging?
33
35
 
34
36
  body_data(response.body).each.with_index do |subresponse, idx|
35
37
  status = subresponse["status"]
@@ -110,14 +112,19 @@ module Ecoportal
110
112
  end
111
113
 
112
114
  def log_batch_response(operation, response)
113
- log(:info) { "BATCH #{operation[:method]} #{operation[:path]}" }
114
- log(:info) { "Status #{response.status}" }
115
+ return unless deep_logging?
115
116
 
116
- level = response.success?? :debug : :warn
117
- log(level) { "Response: #{JSON.pretty_generate(response.body)}" }
117
+ log(:debug) { "BATCH #{operation[:method]} #{operation[:path]}" }
118
+ log(:debug) { "Status #{response.status}" }
119
+ log(:debug) { "Response: #{JSON.pretty_generate(response.body)}" }
120
+ end
121
+
122
+ def deep_logging?
123
+ @deep_logging
118
124
  end
119
125
 
120
126
  def log(level, &block)
127
+ puts "(#{level}) #{yield}"
121
128
  @logger&.send(level, &block)
122
129
  end
123
130
  end
@@ -0,0 +1,111 @@
1
+ require 'elastic-apm'
2
+ module Ecoportal
3
+ module API
4
+ module Common
5
+ class Client
6
+ module ElasticApmIntegration
7
+ include Ecoportal::API::Common::Client::Error::Checks
8
+
9
+ APM_SERVICE_NAME = 'ecoportal-api-gem'.freeze
10
+
11
+ # Log only errors that are only server's responsibility
12
+ def log_unexpected_server_error(response)
13
+ msg = "Expecting Ecoportal::API::Common::Response. Given: #{response.class}"
14
+ raise msg unless response.is_a?(Common::Response)
15
+
16
+ return unless elastic_apm_service
17
+ return unless unexpected_server_error_code?(response.status)
18
+ return unless ElasticAPM.running?
19
+
20
+ ElasticAPM.report(
21
+ Ecoportal::API::Common::Client::Error::UnexpectedServerError.new(
22
+ response.body,
23
+ code: response.status
24
+ )
25
+ )
26
+ end
27
+
28
+ private
29
+
30
+ # finalizer to stop the agent
31
+ close_elastic_apm = proc do |_id|
32
+ next unless ElasticAPM.running?
33
+
34
+ puts "Stopping ElasticAPM service"
35
+ ElasticAPM.stop
36
+ rescue StandardError
37
+ # Silent
38
+ end
39
+
40
+ ObjectSpace.define_finalizer("ElasticAPM", close_elastic_apm)
41
+
42
+ def elastic_apm_service
43
+ return false if @disable_apm
44
+
45
+ ElasticAPM.start(**elastic_apm_options) unless ElasticAPM.running?
46
+ rescue StandardError => err
47
+ @disable_apm = true
48
+ puts "ElasticAPM services not available: #{err}"
49
+ end
50
+
51
+ def elastic_apm_options
52
+ {
53
+ service_name: APM_SERVICE_NAME,
54
+ server_url: elastic_apm_url,
55
+ secret_token: elastic_apm_key,
56
+ environment: environment,
57
+ # http_compression: false,
58
+ transaction_sample_rate: 0.1,
59
+ transaction_max_spans: 100,
60
+ span_frames_min_duration: "5ms"
61
+ }.tap do |options|
62
+ # next unless false
63
+
64
+ options.merge!({
65
+ log_level: Logger::DEBUG,
66
+ log_path: File.join(__dir__, "elastic_apm.log")
67
+ })
68
+ end
69
+ end
70
+
71
+ def elastic_apm_url
72
+ @elastic_apm_url ||= "https://".tap do |url|
73
+ url << elastic_apm_account_id.to_s
74
+ url << ".#{elastic_apm_base_url}"
75
+ url << ":#{elastic_apm_port}"
76
+ end
77
+ end
78
+
79
+ def elastic_apm_key
80
+ @elastic_apm_key ||= ENV['ELASTIC_APM_KEY']
81
+ end
82
+
83
+ def elastic_apm_account_id
84
+ @elastic_apm_account_id ||= ENV['ELASTIC_APM_ACCOUNT_ID']
85
+ end
86
+
87
+ def elastic_apm_base_url
88
+ @elastic_apm_base_url ||= "apm.#{elastic_apm_region}.aws.cloud.es.io"
89
+ end
90
+
91
+ def elastic_apm_region
92
+ @elastic_apm_region ||= ENV['ELASTIC_APM_REGION'] || "ap-southeast-2"
93
+ end
94
+
95
+ def elastic_apm_port
96
+ @elastic_apm_port ||= ENV['ELASTIC_APM_PORT'] || "443"
97
+ end
98
+
99
+ def environment
100
+ @environment ||= "unknown".tap do |value|
101
+ next unless instance_variable_defined?(:@host)
102
+ next unless (env = @host.gsub(".ecoportal.com", ''))
103
+
104
+ value.clear << env
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,39 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ class Client
5
+ module Error
6
+ module Checks
7
+ private
8
+
9
+ def unexpected_server_error_code?(code)
10
+ return true unless code
11
+ return true if (code >= 500) && (code <= 599)
12
+
13
+ code <= 99
14
+ end
15
+
16
+ # Sometimes response body is wrong but status code
17
+ # doesn't reflect. Let it retry
18
+ def some_unexpected_error?(response)
19
+ return true if unexpected_server_error_code?(response.status)
20
+
21
+ unexpected_body?(response)
22
+ end
23
+
24
+ def unexpected_body?(response)
25
+ response.body.nil?.tap do |wrong|
26
+ next unless wrong
27
+
28
+ msg = "Received non json body in response "
29
+ msg << "(#{response.src_body.class}):\n "
30
+ msg << response.src_body
31
+ puts
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,17 @@
1
+ require 'ecoportal/api/common/client/error/checks'
2
+
3
+ module Ecoportal
4
+ module API
5
+ module Common
6
+ class Client
7
+ module Error
8
+ class UnexpectedServerError < StandardError
9
+ def initialize(msg, code:)
10
+ super("Code: #{code} -- Error: #{msg}")
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ class Client
5
+ module TimeOut
6
+ MIN_THROUGHPUT = 0.2 # people per second
7
+ MIN_SIZE = 10
8
+
9
+ private
10
+
11
+ def min_throughput
12
+ self.class::MIN_THROUGHPUT
13
+ end
14
+
15
+ def min_size
16
+ self.class::MIN_SIZE
17
+ end
18
+
19
+ def timeout_for(count)
20
+ count = 1 unless count&.positive?
21
+ count = min_size if count < min_size
22
+ (count.ceil / min_throughput).ceil
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,86 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ class Client
5
+ module WithRetry
6
+ DELAY_REQUEST_RETRY = 5
7
+ RETRY_ATTEMPTS = 5
8
+ HANDLED_CONNECTION_ERRORS = [
9
+ HTTP::ConnectionError,
10
+ IOError
11
+ ].freeze
12
+
13
+ include Ecoportal::API::Common::Client::ElasticApmIntegration
14
+
15
+ private
16
+
17
+ # Helper to ensure unexpected server errors do not bring
18
+ # client scripts immediately down
19
+ # @note it manages limited range of errors, the rest
20
+ # are not handled.
21
+ def with_retry(
22
+ attempts = retry_attemps,
23
+ delay = delay_request_retry,
24
+ error_safe: true,
25
+ &block
26
+ )
27
+ response = nil
28
+
29
+ attempts.times do |i|
30
+ remaining = attempts - i - 1
31
+
32
+ response = with_connection_error_handling(
33
+ remaining,
34
+ error_safe: error_safe,
35
+ callback: block
36
+ ) do
37
+ block.call
38
+ end
39
+
40
+ return response unless some_unexpected_error?(response)
41
+
42
+ # handle server errors (5xx) & server bugs (i.e. empty body)
43
+ msg = "re-attempting (remaining: "
44
+ msg << "#{remaining} attempts out of #{attempts})"
45
+ log(:debug) { msg }
46
+
47
+ log_unexpected_server_error(response)
48
+
49
+ msg = "Got server error (#{response.status}): #{response.body}\n"
50
+ msg << "Going to retry (##{i} of #{attempts})"
51
+ log(:debug) { msg }
52
+
53
+ sleep(delay) if i < attempts
54
+ end
55
+
56
+ response
57
+ end
58
+
59
+ def with_connection_error_handling(remaining, callback:, error_safe: true)
60
+ yield
61
+ rescue *handled_connection_errors => err
62
+ raise unless error_safe && remaining.positive?
63
+
64
+ msg = "Got #{err.class}: #{err.message}"
65
+ log(:debug) { msg }
66
+
67
+ with_retry(remaining, error_safe: error_safe, &callback)
68
+ end
69
+
70
+ # Add here other connection errors
71
+ def handled_connection_errors
72
+ self.class::HANDLED_CONNECTION_ERRORS
73
+ end
74
+
75
+ def retry_attemps
76
+ self.class::RETRY_ATTEMPTS
77
+ end
78
+
79
+ def delay_request_retry
80
+ self.class::DELAY_REQUEST_RETRY
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,4 +1,10 @@
1
1
  require 'http'
2
+
3
+ require 'ecoportal/api/common/client/error'
4
+ require 'ecoportal/api/common/client/elastic_apm_integration'
5
+ require 'ecoportal/api/common/client/time_out'
6
+ require 'ecoportal/api/common/client/with_retry'
7
+
2
8
  module Ecoportal
3
9
  module API
4
10
  module Common
@@ -16,9 +22,7 @@ module Ecoportal
16
22
  # @attr_reader logger [Logger] the logger.
17
23
  # @attr_reader host [String] the remote target server.
18
24
  class Client
19
- include Common::ElasticApmIntegration
20
- DELAY_REQUEST_RETRY = 5
21
- RETRY_ATTEMPTS = 5
25
+ include WithRetry
22
26
 
23
27
  attr_accessor :logger
24
28
  attr_reader :host
@@ -28,40 +32,32 @@ module Ecoportal
28
32
  # @param version [String] it is part of the base url and will determine the api version we query against.
29
33
  # @param host [String] api server domain.
30
34
  # @param logger [Logger] an object with `Logger` interface to generate logs.
31
- # @param response_logging [Boolean] whether or not batch responses should be logged
35
+ # @param deep_logging [Boolean] whether or not batch responses should be logged
32
36
  # @return [Client] an object that holds the configuration of the api connection.
33
- def initialize(api_key:, version: "v1", host: "live.ecoportal.com", logger: nil, response_logging: false)
34
- @version = version
35
- @api_key = api_key
36
- @logger = logger
37
- @host = host
38
- @response_logging_enabled = response_logging
37
+ def initialize(api_key:, version: "v1", host: "live.ecoportal.com", logger: nil, deep_logging: false)
38
+ @version = version
39
+ @api_key = api_key
40
+ @logger = logger
41
+ @host = host
42
+ @deep_logging = deep_logging
39
43
 
40
44
  if host.match(/^localhost|^127\.0\.0\.1/)
41
45
  @base_uri = "http://#{host}/api/"
42
46
  else
43
47
  @base_uri = "https://#{host}/api/"
44
48
  end
45
- log(:info) { "#{version} client initialized pointing at #{host}" }
49
+
50
+ if deep_logging?
51
+ log(:debug) {
52
+ "#{version} client initialized pointing at #{host}"
53
+ }
54
+ end
46
55
 
47
56
  return unless @api_key.nil? || @api_key.match(/\A\W*\z/)
48
57
 
49
58
  log(:error) { "Api-key missing!" }
50
59
  end
51
60
 
52
- # Logger interface.
53
- # @example:
54
- # log(:info) {"General information on what's going on"}
55
- # log(:warn) {"This is a warning that something is likely to have gone amiss"}
56
- # log(:error) {"Something went wrong"}
57
- # log(:fatal) {"An unrecoverable error has happend"}
58
- # @param level [Symbol] the level that the message should be logged.
59
- # @yield [] generates the message.
60
- # @yieldreturn [String] the generated message.
61
- def log(level, &block)
62
- logger&.send(level, &block)
63
- end
64
-
65
61
  # Sends an http `GET` request against the api version using `path` to complete the base url,
66
62
  # and adding the key_value pairs of `params` in the http _header_.
67
63
  # @param path [String] the tail that completes the url of the request.
@@ -152,7 +148,7 @@ module Ecoportal
152
148
  # @param path [String] the tail that completes the url of the request.
153
149
  # @return [String] the final url.
154
150
  def url_for(path)
155
- @base_uri+@version+path
151
+ "#{@base_uri}#{@version}#{path}"
156
152
  end
157
153
 
158
154
  private
@@ -161,71 +157,43 @@ module Ecoportal
161
157
  raise "Expected block" unless block_given?
162
158
 
163
159
  start_time = Time.now.to_f
164
- log(:info) { "#{method} #{url_for(path)}" }
165
- log(:debug) { "Data: #{JSON.pretty_generate(data)}" }
160
+
161
+ if deep_logging?
162
+ log(:debug) { "#{method} #{url_for(path)}" }
163
+ log(:debug) { "Data: #{JSON.pretty_generate(data)}" }
164
+ end
166
165
 
167
166
  with_retry(&block).tap do |result|
167
+ next unless deep_logging?
168
+
168
169
  end_time = Time.now.to_f
169
- log(result.success?? :info : :warn) {
170
+
171
+ log(:debug) {
170
172
  "Took %.2fs, Status #{result.status}" % (end_time - start_time) # rubocop:disable Style/FormatString
171
173
  }
172
174
 
173
- next unless @response_logging_enabled
174
-
175
- log(result.success?? :debug : :warn) {
175
+ log(:debug) {
176
176
  "Response: #{JSON.pretty_generate(result.body)}"
177
177
  }
178
178
  end
179
179
  end
180
180
 
181
- # Helper to ensure unexpected server errors do not bring client scripts immediately down
182
- def with_retry(attempts = RETRY_ATTEMPTS, delay = DELAY_REQUEST_RETRY, error_safe: true, &block)
183
- response = nil
184
- attempts.times do |i|
185
- remaining = attempts - i - 1
186
-
187
- begin
188
- response = block.call
189
- rescue HTTP::ConnectionError => e
190
- raise unless error_safe && remaining.positive?
191
- log(:error) { "Got connection error: #{e.message}" }
192
- response = with_retry(remaining, error_safe: error_safe, &block)
193
- rescue IOError => e
194
- raise unless error_safe && remaining.positive?
195
- log(:error) { "Got IO error: #{e.message}" }
196
- response = with_retry(remaining, error_safe: error_safe, &block)
197
- end
198
-
199
- return response unless some_unexpected_error?(response)
200
-
201
- puts "re-attempting (remaining: #{remaining} attempts out of #{attempts})"
202
-
203
- log_unexpected_server_error(response)
204
-
205
- msg = "Got server error (#{response.status}): #{response.body}\n"
206
- msg += "Going to retry (#{i} out of #{attempts})"
207
- log(:error) { msg }
208
-
209
- sleep(delay) if i < attempts
210
- end
211
- response
212
- end
213
-
214
- # Sometimes response body is wrong but status code
215
- # doesn't reflect. Let it retry
216
- def some_unexpected_error?(response)
217
- unexpected_server_error?(response.status) ||
218
- unexpected_body?(response)
181
+ def deep_logging?
182
+ @deep_logging
219
183
  end
220
184
 
221
- def unexpected_body?(response)
222
- response.body.nil?.tap do |wrong|
223
- next unless wrong
224
-
225
- msg = "Received non json body in response "
226
- msg << "(#{response.src_body.class}):\n #{response.src_body}"
227
- puts
228
- end
185
+ # Logger interface.
186
+ # @example:
187
+ # log(:info) {"General information on what's going on"}
188
+ # log(:warn) {"This is a warning that something is likely to have gone amiss"}
189
+ # log(:error) {"Something went wrong"}
190
+ # log(:fatal) {"An unrecoverable error has happend"}
191
+ # @param level [Symbol] the level that the message should be logged.
192
+ # @yield [] generates the message.
193
+ # @yieldreturn [String] the generated message.
194
+ def log(level, &block)
195
+ puts "(#{level}) #{yield}"
196
+ logger&.send(level, &block)
229
197
  end
230
198
  end
231
199
  end
@@ -10,8 +10,6 @@ require 'ecoportal/api/common/hash_diff'
10
10
  require 'ecoportal/api/common/base_model'
11
11
  require 'ecoportal/api/common/doc_helpers'
12
12
  require 'ecoportal/api/common/logging'
13
- require 'ecoportal/api/common/elastic_apm_integration'
14
- require 'ecoportal/api/common/time_out'
15
13
  require 'ecoportal/api/common/client'
16
14
  require 'ecoportal/api/common/response'
17
15
  require 'ecoportal/api/common/wrapped_response'
@@ -6,7 +6,7 @@ module Ecoportal
6
6
  class People
7
7
  extend Common::BaseClass
8
8
  include Common::DocHelpers
9
- include Common::TimeOut
9
+ include Common::Client::TimeOut
10
10
  include Enumerable
11
11
 
12
12
  DELAY_STATUS_CHECK = 5
@@ -1,5 +1,5 @@
1
1
  module Ecoportal
2
2
  module API
3
- VERSION = '0.10.2'.freeze
3
+ VERSION = '0.10.3'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ecoportal-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.2
4
+ version: 0.10.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tapio Saarinen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-09-27 00:00:00.000000000 Z
11
+ date: 2024-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -209,12 +209,15 @@ files:
209
209
  - lib/ecoportal/api/common/batch_operation.rb
210
210
  - lib/ecoportal/api/common/batch_response.rb
211
211
  - lib/ecoportal/api/common/client.rb
212
+ - lib/ecoportal/api/common/client/elastic_apm_integration.rb
213
+ - lib/ecoportal/api/common/client/error.rb
214
+ - lib/ecoportal/api/common/client/error/checks.rb
215
+ - lib/ecoportal/api/common/client/time_out.rb
216
+ - lib/ecoportal/api/common/client/with_retry.rb
212
217
  - lib/ecoportal/api/common/doc_helpers.rb
213
- - lib/ecoportal/api/common/elastic_apm_integration.rb
214
218
  - lib/ecoportal/api/common/hash_diff.rb
215
219
  - lib/ecoportal/api/common/logging.rb
216
220
  - lib/ecoportal/api/common/response.rb
217
- - lib/ecoportal/api/common/time_out.rb
218
221
  - lib/ecoportal/api/common/wrapped_response.rb
219
222
  - lib/ecoportal/api/errors.rb
220
223
  - lib/ecoportal/api/errors/base.rb
@@ -1,112 +0,0 @@
1
- require 'elastic-apm'
2
- module Ecoportal
3
- module API
4
- module Common
5
- module ElasticApmIntegration
6
-
7
- class UnexpectedServerError < StandardError
8
- def initialize(code, msg)
9
- super("Code: #{code} -- Error: #{msg}")
10
- end
11
- end
12
-
13
- APM_SERVICE_NAME = 'ecoportal-api-gem'
14
-
15
- # Log only errors that are only server's responsibility
16
- def log_unexpected_server_error(response)
17
- raise "Expecting Ecoportal::API::Common::Response. Given: #{response.class}" unless response.is_a?(Common::Response)
18
- return nil unless elastic_apm_service
19
- return nil unless unexpected_server_error?(response.status)
20
- if ElasticAPM.running?
21
- ElasticAPM.report(UnexpectedServerError.new(response.status, response.body))
22
- end
23
- end
24
-
25
- private
26
-
27
- def unexpected_server_error?(code)
28
- !code || ((code >= 500) && (code <= 599)) || (code <= 99)
29
- end
30
-
31
- # finalizer to stop the agent
32
- close_elastic_apm = Proc.new do |id|
33
- begin
34
- if ElasticAPM.running?
35
- puts "Stopping ElasticAPM service"
36
- ElasticAPM.stop
37
- end
38
- rescue StandardError => e
39
- # Silent
40
- end
41
- end
42
- ObjectSpace.define_finalizer("ElasticAPM", close_elastic_apm)
43
-
44
- def elastic_apm_service
45
- return false if @disable_apm
46
- begin
47
- ElasticAPM.start(**elastic_apm_options) unless ElasticAPM.running?
48
- rescue StandardError => e
49
- @disable_apm = true
50
- puts "ElasticAPM services not available: #{e}"
51
- end
52
- end
53
-
54
- def elastic_apm_options
55
- {
56
- service_name: APM_SERVICE_NAME,
57
- server_url: elastic_apm_url,
58
- secret_token: elastic_apm_key,
59
- environment: environment,
60
- #http_compression: false,
61
- transaction_sample_rate: 0.1,
62
- transaction_max_spans: 100,
63
- span_frames_min_duration: "5ms"
64
- }.tap do |options|
65
- options.merge!({
66
- log_level: Logger::DEBUG,
67
- log_path: File.join(__dir__, "elastic_apm.log")
68
- }) if false
69
- end
70
- end
71
-
72
- def elastic_apm_url
73
- @elastic_apm_url ||= "https://".tap do |url|
74
- url << "#{elastic_apm_account_id}"
75
- url << ".#{elastic_apm_base_url}"
76
- url << ":#{elastic_apm_port}"
77
- end
78
- end
79
-
80
- def elastic_apm_key
81
- @elastic_apm_key ||= ENV['ELASTIC_APM_KEY']
82
- end
83
-
84
- def elastic_apm_account_id
85
- @elastic_apm_account_id ||= ENV['ELASTIC_APM_ACCOUNT_ID']
86
- end
87
-
88
- def elastic_apm_base_url
89
- @elastic_apm_base_url ||= "apm.#{elastic_apm_region}.aws.cloud.es.io"
90
- end
91
-
92
- def elastic_apm_region
93
- @elastic_apm_region ||= ENV['ELASTIC_APM_REGION'] || "ap-southeast-2"
94
- end
95
-
96
-
97
- def elastic_apm_port
98
- @elastic_apm_port ||= ENV['ELASTIC_APM_PORT'] || "443"
99
- end
100
-
101
- def environment
102
- @environment ||= "unknown".tap do |value|
103
- if instance_variable_defined?(:@host) && env = @host.gsub(".ecoportal.com", '')
104
- value.clear << env
105
- end
106
- end
107
- end
108
-
109
- end
110
- end
111
- end
112
- end
@@ -1,26 +0,0 @@
1
- module Ecoportal
2
- module API
3
- module Common
4
- module TimeOut
5
- MIN_THROUGHPUT = 0.2 # people per second
6
- MIN_SIZE = 10
7
-
8
- private
9
-
10
- def min_throughput
11
- self.class::MIN_THROUGHPUT
12
- end
13
-
14
- def min_size
15
- self.class::MIN_SIZE
16
- end
17
-
18
- def timeout_for(count)
19
- count = 1 unless count&.positive?
20
- count = min_size if count < min_size
21
- (count.ceil / min_throughput).ceil
22
- end
23
- end
24
- end
25
- end
26
- end