macaw_framework 1.3.0 → 1.3.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 +4 -4
- data/.rubocop.yml +13 -9
- data/CHANGELOG.md +14 -0
- data/Gemfile +11 -9
- data/README.md +28 -10
- data/Rakefile +6 -6
- data/lib/macaw_framework/aspects/cache_aspect.rb +3 -3
- data/lib/macaw_framework/aspects/logging_aspect.rb +4 -7
- data/lib/macaw_framework/aspects/prometheus_aspect.rb +3 -3
- data/lib/macaw_framework/cache.rb +91 -0
- data/lib/macaw_framework/core/common/server_base.rb +29 -28
- data/lib/macaw_framework/core/thread_server.rb +13 -17
- data/lib/macaw_framework/data_filters/log_data_filter.rb +9 -9
- data/lib/macaw_framework/data_filters/request_data_filtering.rb +26 -24
- data/lib/macaw_framework/data_filters/response_data_filter.rb +3 -3
- data/lib/macaw_framework/errors/endpoint_not_mapped_error.rb +1 -1
- data/lib/macaw_framework/macaw.rb +264 -0
- data/lib/macaw_framework/middlewares/prometheus_middleware.rb +7 -7
- data/lib/macaw_framework/utils/http_status_code.rb +61 -61
- data/lib/macaw_framework/utils/supported_ssl_versions.rb +6 -6
- data/lib/macaw_framework/version.rb +1 -1
- data/lib/macaw_framework.rb +5 -230
- metadata +6 -7
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative
|
|
3
|
+
require_relative '../errors/endpoint_not_mapped_error'
|
|
4
4
|
|
|
5
5
|
##
|
|
6
6
|
# Module containing methods to filter Strings
|
|
7
7
|
module RequestDataFiltering
|
|
8
|
-
VARIABLE_PATTERN = %r{:[^/]+}
|
|
8
|
+
VARIABLE_PATTERN = %r{:[^/]+}
|
|
9
9
|
|
|
10
10
|
##
|
|
11
11
|
# Method responsible for extracting information
|
|
12
12
|
# provided by the client like Headers and Body
|
|
13
13
|
def self.parse_request_data(client, routes)
|
|
14
|
-
path, parameters = extract_url_parameters(client.gets
|
|
14
|
+
path, parameters = extract_url_parameters(client.gets&.gsub('HTTP/1.1', ''))
|
|
15
15
|
parameters = {} if parameters.nil?
|
|
16
16
|
|
|
17
17
|
method_name = sanitize_method_name(path)
|
|
18
18
|
method_name = select_path(method_name, routes, parameters)
|
|
19
19
|
body_first_line, headers = extract_headers(client)
|
|
20
|
-
body = extract_body(client, body_first_line, headers[
|
|
20
|
+
body = extract_body(client, body_first_line, headers['Content-Length'].to_i)
|
|
21
21
|
[path, method_name, headers, body, parameters]
|
|
22
22
|
end
|
|
23
23
|
|
|
@@ -26,15 +26,15 @@ module RequestDataFiltering
|
|
|
26
26
|
|
|
27
27
|
selected_route = nil
|
|
28
28
|
routes.each do |route|
|
|
29
|
-
split_route = route
|
|
30
|
-
split_name = method_name
|
|
29
|
+
split_route = route&.split('.')
|
|
30
|
+
split_name = method_name&.split('.')
|
|
31
31
|
|
|
32
|
-
next unless split_route
|
|
32
|
+
next unless split_route&.length == split_name&.length
|
|
33
33
|
next unless match_path_with_route(split_name, split_route)
|
|
34
34
|
|
|
35
35
|
selected_route = route
|
|
36
|
-
split_route
|
|
37
|
-
parameters[var[1..].to_sym] = split_name
|
|
36
|
+
split_route&.each_with_index do |var, index|
|
|
37
|
+
parameters[var[1..].to_sym] = split_name&.dig(index) if var =~ VARIABLE_PATTERN
|
|
38
38
|
end
|
|
39
39
|
break
|
|
40
40
|
end
|
|
@@ -45,7 +45,7 @@ module RequestDataFiltering
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def self.match_path_with_route(split_path, split_route)
|
|
48
|
-
split_route
|
|
48
|
+
split_route&.each_with_index do |var, index|
|
|
49
49
|
return false if var != split_path[index] && !var.match?(VARIABLE_PATTERN)
|
|
50
50
|
end
|
|
51
51
|
|
|
@@ -56,26 +56,28 @@ module RequestDataFiltering
|
|
|
56
56
|
# Method responsible for sanitizing the method name
|
|
57
57
|
def self.sanitize_method_name(path)
|
|
58
58
|
path = extract_path(path)
|
|
59
|
-
method_name = path
|
|
60
|
-
method_name
|
|
59
|
+
method_name = path&.gsub('/', '.')&.strip&.downcase
|
|
60
|
+
method_name&.gsub!(' ', '')
|
|
61
61
|
method_name
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
##
|
|
65
65
|
# Method responsible for extracting the path from URI
|
|
66
66
|
def self.extract_path(path)
|
|
67
|
-
|
|
67
|
+
return path if path.nil?
|
|
68
|
+
|
|
69
|
+
path[0] == '/' ? path[1..].gsub('/', '.') : path.gsub('/', '.')
|
|
68
70
|
end
|
|
69
71
|
|
|
70
72
|
##
|
|
71
73
|
# Method responsible for extracting the headers from request
|
|
72
74
|
def self.extract_headers(client)
|
|
73
|
-
header = client.gets
|
|
75
|
+
header = client.gets&.delete("\n")&.delete("\r")
|
|
74
76
|
headers = {}
|
|
75
|
-
while header
|
|
76
|
-
split_header = header.split(
|
|
77
|
+
while header&.match(%r{[a-zA-Z0-9\-/*]*: [a-zA-Z0-9\-/*]})
|
|
78
|
+
split_header = header.split(':')
|
|
77
79
|
headers[split_header[0].strip] = split_header[1].strip
|
|
78
|
-
header = client.gets
|
|
80
|
+
header = client.gets&.delete("\n")&.delete("\r")
|
|
79
81
|
end
|
|
80
82
|
[header, headers]
|
|
81
83
|
end
|
|
@@ -83,7 +85,7 @@ module RequestDataFiltering
|
|
|
83
85
|
##
|
|
84
86
|
# Method responsible for extracting the body from request
|
|
85
87
|
def self.extract_body(client, body_first_line, content_length)
|
|
86
|
-
body = client
|
|
88
|
+
body = client&.read(content_length)
|
|
87
89
|
body_first_line << body.to_s
|
|
88
90
|
end
|
|
89
91
|
|
|
@@ -92,11 +94,11 @@ module RequestDataFiltering
|
|
|
92
94
|
def self.extract_url_parameters(http_first_line)
|
|
93
95
|
return http_first_line, nil unless http_first_line =~ /\?/
|
|
94
96
|
|
|
95
|
-
path_and_parameters = http_first_line.split(
|
|
97
|
+
path_and_parameters = http_first_line.split('?', 2)
|
|
96
98
|
path = "#{path_and_parameters[0]} "
|
|
97
|
-
parameters_array = path_and_parameters[1].split(
|
|
99
|
+
parameters_array = path_and_parameters[1].split('&')
|
|
98
100
|
parameters_array.map! do |item|
|
|
99
|
-
split_item = item.split(
|
|
101
|
+
split_item = item.split('=')
|
|
100
102
|
{ sanitize_parameter_name(split_item[0]) => sanitize_parameter_value(split_item[1]) }
|
|
101
103
|
end
|
|
102
104
|
parameters = {}
|
|
@@ -107,13 +109,13 @@ module RequestDataFiltering
|
|
|
107
109
|
##
|
|
108
110
|
# Method responsible for sanitizing the parameter name
|
|
109
111
|
def self.sanitize_parameter_name(name)
|
|
110
|
-
name
|
|
112
|
+
name&.gsub(/[^\w\s]/, '')
|
|
111
113
|
end
|
|
112
114
|
|
|
113
115
|
##
|
|
114
116
|
# Method responsible for sanitizing the parameter value
|
|
115
117
|
def self.sanitize_parameter_value(value)
|
|
116
|
-
value
|
|
117
|
-
value
|
|
118
|
+
value&.gsub(/[^\w\s]/, '')
|
|
119
|
+
value&.gsub(/\s/, '')
|
|
118
120
|
end
|
|
119
121
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative
|
|
3
|
+
require_relative '../utils/http_status_code'
|
|
4
4
|
|
|
5
5
|
##
|
|
6
6
|
# Module responsible to filter and mount HTTP responses
|
|
@@ -19,9 +19,9 @@ module ResponseDataFilter
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def self.mount_response_headers(headers)
|
|
22
|
-
return
|
|
22
|
+
return '' if headers.nil?
|
|
23
23
|
|
|
24
|
-
response =
|
|
24
|
+
response = ''
|
|
25
25
|
headers.each do |key, value|
|
|
26
26
|
response += "#{key}: #{value}\r\n"
|
|
27
27
|
end
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'errors/endpoint_not_mapped_error'
|
|
4
|
+
require_relative 'middlewares/prometheus_middleware'
|
|
5
|
+
require_relative 'data_filters/request_data_filtering'
|
|
6
|
+
require_relative 'middlewares/memory_invalidation_middleware'
|
|
7
|
+
require_relative 'core/cron_runner'
|
|
8
|
+
require_relative 'core/thread_server'
|
|
9
|
+
require_relative 'version'
|
|
10
|
+
require 'prometheus/client'
|
|
11
|
+
require 'securerandom'
|
|
12
|
+
require 'singleton'
|
|
13
|
+
require 'pathname'
|
|
14
|
+
require 'logger'
|
|
15
|
+
require 'socket'
|
|
16
|
+
require 'json'
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# Main module for all Macaw classes
|
|
20
|
+
module MacawFramework; end
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# Class responsible for creating endpoints and
|
|
24
|
+
# starting the web server.
|
|
25
|
+
class MacawFramework::Macaw
|
|
26
|
+
attr_reader :routes, :macaw_log, :config, :jobs, :cached_methods, :secure_header, :session
|
|
27
|
+
attr_accessor :port, :bind, :threads
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
# Initialize Macaw Class
|
|
31
|
+
# @param {Logger} custom_log
|
|
32
|
+
# @param {ThreadServer} server
|
|
33
|
+
# @param {String?} dir
|
|
34
|
+
def initialize(custom_log: Logger.new($stdout), server: ThreadServer, dir: nil)
|
|
35
|
+
apply_options(custom_log)
|
|
36
|
+
create_endpoint_public_files(dir)
|
|
37
|
+
setup_default_configs
|
|
38
|
+
@server_class = server
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
##
|
|
42
|
+
# Creates a GET endpoint associated
|
|
43
|
+
# with the respective path.
|
|
44
|
+
# @param {String} path
|
|
45
|
+
# @param {Proc} block
|
|
46
|
+
#
|
|
47
|
+
# @example
|
|
48
|
+
# macaw = MacawFramework::Macaw.new
|
|
49
|
+
# macaw.get("/hello") do |context|
|
|
50
|
+
# return "Hello World!", 200, { "Content-Type" => "text/plain" }
|
|
51
|
+
# end
|
|
52
|
+
##
|
|
53
|
+
def get(path, cache: [], &block)
|
|
54
|
+
map_new_endpoint('get', cache, path, &block)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
##
|
|
58
|
+
# Creates a POST endpoint associated
|
|
59
|
+
# with the respective path.
|
|
60
|
+
# @param {String} path
|
|
61
|
+
# @param {Boolean} cache
|
|
62
|
+
# @param {Proc} block
|
|
63
|
+
# @example
|
|
64
|
+
#
|
|
65
|
+
# macaw = MacawFramework::Macaw.new
|
|
66
|
+
# macaw.post("/hello") do |context|
|
|
67
|
+
# return "Hello World!", 200, { "Content-Type" => "text/plain" }
|
|
68
|
+
# end
|
|
69
|
+
##
|
|
70
|
+
def post(path, cache: [], &block)
|
|
71
|
+
map_new_endpoint('post', cache, path, &block)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
##
|
|
75
|
+
# Creates a PUT endpoint associated
|
|
76
|
+
# with the respective path.
|
|
77
|
+
# @param {String} path
|
|
78
|
+
# @param {Proc} block
|
|
79
|
+
# @example
|
|
80
|
+
#
|
|
81
|
+
# macaw = MacawFramework::Macaw.new
|
|
82
|
+
# macaw.put("/hello") do |context|
|
|
83
|
+
# return "Hello World!", 200, { "Content-Type" => "text/plain" }
|
|
84
|
+
# end
|
|
85
|
+
##
|
|
86
|
+
def put(path, cache: [], &block)
|
|
87
|
+
map_new_endpoint('put', cache, path, &block)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
##
|
|
91
|
+
# Creates a PATCH endpoint associated
|
|
92
|
+
# with the respective path.
|
|
93
|
+
# @param {String} path
|
|
94
|
+
# @param {Proc} block
|
|
95
|
+
# @example
|
|
96
|
+
#
|
|
97
|
+
# macaw = MacawFramework::Macaw.new
|
|
98
|
+
# macaw.patch("/hello") do |context|
|
|
99
|
+
# return "Hello World!", 200, { "Content-Type" => "text/plain" }
|
|
100
|
+
# end
|
|
101
|
+
##
|
|
102
|
+
def patch(path, cache: [], &block)
|
|
103
|
+
map_new_endpoint('patch', cache, path, &block)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
##
|
|
107
|
+
# Creates a DELETE endpoint associated
|
|
108
|
+
# with the respective path.
|
|
109
|
+
# @param {String} path
|
|
110
|
+
# @param {Proc} block
|
|
111
|
+
# @example
|
|
112
|
+
#
|
|
113
|
+
# macaw = MacawFramework::Macaw.new
|
|
114
|
+
# macaw.delete("/hello") do |context|
|
|
115
|
+
# return "Hello World!", 200, { "Content-Type" => "text/plain" }
|
|
116
|
+
# end
|
|
117
|
+
##
|
|
118
|
+
def delete(path, cache: [], &block)
|
|
119
|
+
map_new_endpoint('delete', cache, path, &block)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
##
|
|
123
|
+
# Spawn and start a thread running the defined periodic job.
|
|
124
|
+
# @param {Integer} interval
|
|
125
|
+
# @param {Integer?} start_delay
|
|
126
|
+
# @param {String} job_name
|
|
127
|
+
# @param {Proc} block
|
|
128
|
+
# @example
|
|
129
|
+
#
|
|
130
|
+
# macaw = MacawFramework::Macaw.new
|
|
131
|
+
# macaw.setup_job(interval: 60, start_delay: 60, job_name: "job 1") do
|
|
132
|
+
# puts "I'm a periodic job that runs every minute"
|
|
133
|
+
# end
|
|
134
|
+
##
|
|
135
|
+
def setup_job(interval: 60, start_delay: 0, job_name: "job_#{SecureRandom.uuid}", &block)
|
|
136
|
+
@cron_runner ||= CronRunner.new(self)
|
|
137
|
+
@jobs ||= []
|
|
138
|
+
@cron_runner.start_cron_job_thread(interval, start_delay, job_name, &block)
|
|
139
|
+
@jobs << job_name
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
##
|
|
143
|
+
# Starts the web server
|
|
144
|
+
def start!
|
|
145
|
+
if @macaw_log.nil?
|
|
146
|
+
puts('---------------------------------')
|
|
147
|
+
puts("Starting server at port #{@port}")
|
|
148
|
+
puts("Number of threads: #{@threads}")
|
|
149
|
+
puts('---------------------------------')
|
|
150
|
+
else
|
|
151
|
+
@macaw_log.info('---------------------------------')
|
|
152
|
+
@macaw_log.info("Starting server at port #{@port}")
|
|
153
|
+
@macaw_log.info("Number of threads: #{@threads}")
|
|
154
|
+
@macaw_log.info('---------------------------------')
|
|
155
|
+
end
|
|
156
|
+
@server = @server_class.new(self, @endpoints_to_cache, @cache, @prometheus, @prometheus_middleware)
|
|
157
|
+
server_loop(@server)
|
|
158
|
+
rescue Interrupt
|
|
159
|
+
if @macaw_log.nil?
|
|
160
|
+
puts('Stopping server')
|
|
161
|
+
@server.shutdown
|
|
162
|
+
puts('Macaw stop flying for some seeds...')
|
|
163
|
+
else
|
|
164
|
+
@macaw_log.info('Stopping server')
|
|
165
|
+
@server.shutdown
|
|
166
|
+
@macaw_log.info('Macaw stop flying for some seeds...')
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
##
|
|
171
|
+
# This method is intended to start the framework
|
|
172
|
+
# without an web server. This can be useful when
|
|
173
|
+
# you just want to keep cron jobs running, without
|
|
174
|
+
# mapping any HTTP endpoints.
|
|
175
|
+
def start_without_server!
|
|
176
|
+
@macaw_log.nil? ? puts('Application starting') : @macaw_log.info('Application starting')
|
|
177
|
+
loop { sleep(3600) }
|
|
178
|
+
rescue Interrupt
|
|
179
|
+
@macaw_log.nil? ? puts('Macaw stop flying for some seeds.') : @macaw_log.info('Macaw stop flying for some seeds.')
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
private
|
|
183
|
+
|
|
184
|
+
def setup_default_configs
|
|
185
|
+
@port ||= 8080
|
|
186
|
+
@bind ||= 'localhost'
|
|
187
|
+
@config ||= nil
|
|
188
|
+
@threads ||= 200
|
|
189
|
+
@endpoints_to_cache = []
|
|
190
|
+
@prometheus ||= nil
|
|
191
|
+
@prometheus_middleware ||= nil
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def apply_options(custom_log)
|
|
195
|
+
setup_basic_config(custom_log)
|
|
196
|
+
setup_session
|
|
197
|
+
setup_cache
|
|
198
|
+
setup_prometheus
|
|
199
|
+
rescue StandardError => e
|
|
200
|
+
@macaw_log&.warn(e.message)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def setup_cache
|
|
204
|
+
return if @config['macaw']['cache'].nil?
|
|
205
|
+
|
|
206
|
+
@cache = MemoryInvalidationMiddleware.new(@config['macaw']['cache']['cache_invalidation'].to_i || 3_600)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def setup_session
|
|
210
|
+
@session = false
|
|
211
|
+
return if @config['macaw']['session'].nil?
|
|
212
|
+
|
|
213
|
+
@session = true
|
|
214
|
+
@secure_header = @config['macaw']['session']['secure_header'] || 'X-Session-ID'
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def setup_basic_config(custom_log)
|
|
218
|
+
@routes = []
|
|
219
|
+
@cached_methods = {}
|
|
220
|
+
@macaw_log ||= custom_log
|
|
221
|
+
@config = JSON.parse(File.read('application.json'))
|
|
222
|
+
@port = @config['macaw']['port'] || 8080
|
|
223
|
+
@bind = @config['macaw']['bind'] || 'localhost'
|
|
224
|
+
@threads = @config['macaw']['threads'] || 200
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def setup_prometheus
|
|
228
|
+
return unless @config['macaw']['prometheus']
|
|
229
|
+
|
|
230
|
+
@prometheus = Prometheus::Client::Registry.new
|
|
231
|
+
@prometheus_middleware = PrometheusMiddleware.new
|
|
232
|
+
@prometheus_middleware&.configure_prometheus(@prometheus, @config, self)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def server_loop(server)
|
|
236
|
+
server.run
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def map_new_endpoint(prefix, cache, path, &block)
|
|
240
|
+
@endpoints_to_cache << "#{prefix}.#{RequestDataFiltering.sanitize_method_name(path)}" unless cache.empty?
|
|
241
|
+
@cached_methods["#{prefix}.#{RequestDataFiltering.sanitize_method_name(path)}"] = cache unless cache.empty?
|
|
242
|
+
path_clean = RequestDataFiltering.extract_path(path)
|
|
243
|
+
slash = path[0] == '/' ? '' : '/'
|
|
244
|
+
@macaw_log&.info("Defining #{prefix.upcase} endpoint at #{slash}#{path}")
|
|
245
|
+
define_singleton_method("#{prefix}.#{path_clean}", block || lambda {
|
|
246
|
+
|context = { headers: {}, body: '', params: {} }|
|
|
247
|
+
})
|
|
248
|
+
@routes << "#{prefix}.#{path_clean}"
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def get_files_public_folder(dir)
|
|
252
|
+
return [] if dir.nil?
|
|
253
|
+
|
|
254
|
+
folder_path = Pathname.new(File.expand_path('public', dir))
|
|
255
|
+
file_paths = folder_path.glob('**/*').select(&:file?)
|
|
256
|
+
file_paths.map { |path| "public/#{path.relative_path_from(folder_path)}" }
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def create_endpoint_public_files(dir)
|
|
260
|
+
get_files_public_folder(dir).each do |file|
|
|
261
|
+
get(file) { |_context| return File.read(file).to_s, 200, {} }
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require 'prometheus/client'
|
|
4
|
+
require 'prometheus/client/formats/text'
|
|
5
5
|
|
|
6
6
|
##
|
|
7
7
|
# Middleware responsible to configure prometheus
|
|
@@ -14,20 +14,20 @@ class PrometheusMiddleware
|
|
|
14
14
|
|
|
15
15
|
@request_duration_milliseconds = Prometheus::Client::Histogram.new(
|
|
16
16
|
:request_duration_milliseconds,
|
|
17
|
-
docstring:
|
|
17
|
+
docstring: 'The duration of each request in milliseconds',
|
|
18
18
|
labels: [:endpoint],
|
|
19
19
|
buckets: (100..1000).step(100).to_a + (2000..10_000).step(1000).to_a
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
@request_count = Prometheus::Client::Counter.new(
|
|
23
23
|
:request_count,
|
|
24
|
-
docstring:
|
|
24
|
+
docstring: 'The total number of requests received',
|
|
25
25
|
labels: [:endpoint]
|
|
26
26
|
)
|
|
27
27
|
|
|
28
28
|
@response_count = Prometheus::Client::Counter.new(
|
|
29
29
|
:response_count,
|
|
30
|
-
docstring:
|
|
30
|
+
docstring: 'The total number of responses sent',
|
|
31
31
|
labels: %i[endpoint status]
|
|
32
32
|
)
|
|
33
33
|
|
|
@@ -40,9 +40,9 @@ class PrometheusMiddleware
|
|
|
40
40
|
private
|
|
41
41
|
|
|
42
42
|
def prometheus_endpoint(prometheus_registry, configurations, macaw)
|
|
43
|
-
endpoint = configurations[
|
|
43
|
+
endpoint = configurations['macaw']['prometheus']['endpoint'] || '/metrics'
|
|
44
44
|
macaw.get(endpoint) do |_context|
|
|
45
|
-
[Prometheus::Client::Formats::Text.marshal(prometheus_registry), 200, {
|
|
45
|
+
[Prometheus::Client::Formats::Text.marshal(prometheus_registry), 200, { 'Content-Type' => 'plaintext' }]
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
end
|
|
@@ -7,66 +7,66 @@ module HttpStatusCode
|
|
|
7
7
|
##
|
|
8
8
|
# Http Status Code Map
|
|
9
9
|
HTTP_STATUS_CODE_MAP = {
|
|
10
|
-
100 =>
|
|
11
|
-
101 =>
|
|
12
|
-
102 =>
|
|
13
|
-
103 =>
|
|
14
|
-
200 =>
|
|
15
|
-
201 =>
|
|
16
|
-
202 =>
|
|
17
|
-
203 =>
|
|
18
|
-
204 =>
|
|
19
|
-
205 =>
|
|
20
|
-
206 =>
|
|
21
|
-
207 =>
|
|
22
|
-
208 =>
|
|
23
|
-
226 =>
|
|
24
|
-
300 =>
|
|
25
|
-
301 =>
|
|
26
|
-
302 =>
|
|
27
|
-
303 =>
|
|
28
|
-
304 =>
|
|
29
|
-
305 =>
|
|
30
|
-
307 =>
|
|
31
|
-
308 =>
|
|
32
|
-
400 =>
|
|
33
|
-
401 =>
|
|
34
|
-
402 =>
|
|
35
|
-
403 =>
|
|
36
|
-
404 =>
|
|
37
|
-
405 =>
|
|
38
|
-
406 =>
|
|
39
|
-
407 =>
|
|
40
|
-
408 =>
|
|
41
|
-
409 =>
|
|
42
|
-
410 =>
|
|
43
|
-
411 =>
|
|
44
|
-
412 =>
|
|
45
|
-
413 =>
|
|
46
|
-
414 =>
|
|
47
|
-
415 =>
|
|
48
|
-
416 =>
|
|
49
|
-
417 =>
|
|
50
|
-
421 =>
|
|
51
|
-
422 =>
|
|
52
|
-
423 =>
|
|
53
|
-
424 =>
|
|
54
|
-
425 =>
|
|
55
|
-
426 =>
|
|
56
|
-
428 =>
|
|
57
|
-
429 =>
|
|
58
|
-
431 =>
|
|
59
|
-
451 =>
|
|
60
|
-
500 =>
|
|
61
|
-
501 =>
|
|
62
|
-
502 =>
|
|
63
|
-
503 =>
|
|
64
|
-
504 =>
|
|
65
|
-
505 =>
|
|
66
|
-
506 =>
|
|
67
|
-
507 =>
|
|
68
|
-
508 =>
|
|
69
|
-
510 =>
|
|
70
|
-
511 =>
|
|
10
|
+
100 => 'Continue',
|
|
11
|
+
101 => 'Switching Protocols',
|
|
12
|
+
102 => 'Processing',
|
|
13
|
+
103 => 'Early Hints',
|
|
14
|
+
200 => 'OK',
|
|
15
|
+
201 => 'Created',
|
|
16
|
+
202 => 'Accepted',
|
|
17
|
+
203 => 'Non-Authoritative Information',
|
|
18
|
+
204 => 'No Content',
|
|
19
|
+
205 => 'Reset Content',
|
|
20
|
+
206 => 'Partial Content',
|
|
21
|
+
207 => 'Multi-Status',
|
|
22
|
+
208 => 'Already Reported',
|
|
23
|
+
226 => 'IM Used',
|
|
24
|
+
300 => 'Multiple Choices',
|
|
25
|
+
301 => 'Moved Permanently',
|
|
26
|
+
302 => 'Found',
|
|
27
|
+
303 => 'See Other',
|
|
28
|
+
304 => 'Not Modified',
|
|
29
|
+
305 => 'Use Proxy',
|
|
30
|
+
307 => 'Temporary Redirect',
|
|
31
|
+
308 => 'Permanent Redirect',
|
|
32
|
+
400 => 'Bad Request',
|
|
33
|
+
401 => 'Unauthorized',
|
|
34
|
+
402 => 'Payment Required',
|
|
35
|
+
403 => 'Forbidden',
|
|
36
|
+
404 => 'Not Found',
|
|
37
|
+
405 => 'Method Not Allowed',
|
|
38
|
+
406 => 'Not Acceptable',
|
|
39
|
+
407 => 'Proxy Authentication Required',
|
|
40
|
+
408 => 'Request Timeout',
|
|
41
|
+
409 => 'Conflict',
|
|
42
|
+
410 => 'Gone',
|
|
43
|
+
411 => 'Length Required',
|
|
44
|
+
412 => 'Precondition Failed',
|
|
45
|
+
413 => 'Content Too Large',
|
|
46
|
+
414 => 'URI Too Long',
|
|
47
|
+
415 => 'Unsupported Media Type',
|
|
48
|
+
416 => 'Range Not Satisfiable',
|
|
49
|
+
417 => 'Expectation Failed',
|
|
50
|
+
421 => 'Misdirected Request',
|
|
51
|
+
422 => 'Unprocessable Content',
|
|
52
|
+
423 => 'Locked',
|
|
53
|
+
424 => 'Failed Dependency',
|
|
54
|
+
425 => 'Too Early',
|
|
55
|
+
426 => 'Upgrade Required',
|
|
56
|
+
428 => 'Precondition Required',
|
|
57
|
+
429 => 'Too Many Requests',
|
|
58
|
+
431 => 'Request Header Fields Too Large',
|
|
59
|
+
451 => 'Unavailable For Legal Reasons',
|
|
60
|
+
500 => 'Internal Server Error',
|
|
61
|
+
501 => 'Not Implemented',
|
|
62
|
+
502 => 'Bad Gateway',
|
|
63
|
+
503 => 'Service Unavailable',
|
|
64
|
+
504 => 'Gateway Timeout',
|
|
65
|
+
505 => 'HTTP Version Not Supported',
|
|
66
|
+
506 => 'Variant Also Negotiates',
|
|
67
|
+
507 => 'Insufficient Storage',
|
|
68
|
+
508 => 'Loop Detected',
|
|
69
|
+
510 => 'Not Extended (OBSOLETED)',
|
|
70
|
+
511 => 'Network Authentication Required'
|
|
71
71
|
}.freeze
|
|
72
72
|
end
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require 'openssl'
|
|
4
4
|
|
|
5
5
|
module SupportedSSLVersions
|
|
6
6
|
VERSIONS = {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
'SSL2' => OpenSSL::SSL::SSL2_VERSION,
|
|
8
|
+
'SSL3' => OpenSSL::SSL::SSL3_VERSION,
|
|
9
|
+
'TLS1.1' => OpenSSL::SSL::TLS1_1_VERSION,
|
|
10
|
+
'TLS1.2' => OpenSSL::SSL::TLS1_2_VERSION,
|
|
11
|
+
'TLS1.3' => OpenSSL::SSL::TLS1_3_VERSION
|
|
12
12
|
}.freeze
|
|
13
13
|
end
|