apisonator 2.100.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 +7 -0
- data/CHANGELOG.md +317 -0
- data/Gemfile +11 -0
- data/Gemfile.base +65 -0
- data/Gemfile.lock +319 -0
- data/Gemfile.on_prem +1 -0
- data/Gemfile.on_prem.lock +297 -0
- data/LICENSE +202 -0
- data/NOTICE +15 -0
- data/README.md +230 -0
- data/Rakefile +287 -0
- data/apisonator.gemspec +47 -0
- data/app/api/api.rb +13 -0
- data/app/api/internal/alert_limits.rb +32 -0
- data/app/api/internal/application_keys.rb +49 -0
- data/app/api/internal/application_referrer_filters.rb +43 -0
- data/app/api/internal/applications.rb +77 -0
- data/app/api/internal/errors.rb +54 -0
- data/app/api/internal/events.rb +42 -0
- data/app/api/internal/internal.rb +104 -0
- data/app/api/internal/metrics.rb +40 -0
- data/app/api/internal/service_tokens.rb +46 -0
- data/app/api/internal/services.rb +58 -0
- data/app/api/internal/stats.rb +42 -0
- data/app/api/internal/usagelimits.rb +62 -0
- data/app/api/internal/utilization.rb +23 -0
- data/bin/3scale_backend +223 -0
- data/bin/3scale_backend_worker +26 -0
- data/config.ru +4 -0
- data/config/puma.rb +192 -0
- data/config/schedule.rb +9 -0
- data/ext/mkrf_conf.rb +64 -0
- data/lib/3scale/backend.rb +67 -0
- data/lib/3scale/backend/alert_limit.rb +56 -0
- data/lib/3scale/backend/alerts.rb +137 -0
- data/lib/3scale/backend/analytics/kinesis.rb +3 -0
- data/lib/3scale/backend/analytics/kinesis/adapter.rb +180 -0
- data/lib/3scale/backend/analytics/kinesis/exporter.rb +86 -0
- data/lib/3scale/backend/analytics/kinesis/job.rb +135 -0
- data/lib/3scale/backend/analytics/redshift.rb +3 -0
- data/lib/3scale/backend/analytics/redshift/adapter.rb +367 -0
- data/lib/3scale/backend/analytics/redshift/importer.rb +83 -0
- data/lib/3scale/backend/analytics/redshift/job.rb +33 -0
- data/lib/3scale/backend/application.rb +330 -0
- data/lib/3scale/backend/application_events.rb +76 -0
- data/lib/3scale/backend/background_job.rb +65 -0
- data/lib/3scale/backend/configurable.rb +20 -0
- data/lib/3scale/backend/configuration.rb +151 -0
- data/lib/3scale/backend/configuration/loader.rb +42 -0
- data/lib/3scale/backend/constants.rb +19 -0
- data/lib/3scale/backend/cors.rb +84 -0
- data/lib/3scale/backend/distributed_lock.rb +67 -0
- data/lib/3scale/backend/environment.rb +21 -0
- data/lib/3scale/backend/error_storage.rb +52 -0
- data/lib/3scale/backend/errors.rb +343 -0
- data/lib/3scale/backend/event_storage.rb +120 -0
- data/lib/3scale/backend/experiment.rb +84 -0
- data/lib/3scale/backend/extensions.rb +5 -0
- data/lib/3scale/backend/extensions/array.rb +19 -0
- data/lib/3scale/backend/extensions/hash.rb +26 -0
- data/lib/3scale/backend/extensions/nil_class.rb +13 -0
- data/lib/3scale/backend/extensions/redis.rb +44 -0
- data/lib/3scale/backend/extensions/string.rb +13 -0
- data/lib/3scale/backend/extensions/time.rb +110 -0
- data/lib/3scale/backend/failed_jobs_scheduler.rb +141 -0
- data/lib/3scale/backend/job_fetcher.rb +122 -0
- data/lib/3scale/backend/listener.rb +728 -0
- data/lib/3scale/backend/listener_metrics.rb +99 -0
- data/lib/3scale/backend/logging.rb +48 -0
- data/lib/3scale/backend/logging/external.rb +44 -0
- data/lib/3scale/backend/logging/external/impl.rb +93 -0
- data/lib/3scale/backend/logging/external/impl/airbrake.rb +66 -0
- data/lib/3scale/backend/logging/external/impl/bugsnag.rb +69 -0
- data/lib/3scale/backend/logging/external/impl/default.rb +18 -0
- data/lib/3scale/backend/logging/external/resque.rb +57 -0
- data/lib/3scale/backend/logging/logger.rb +18 -0
- data/lib/3scale/backend/logging/middleware.rb +62 -0
- data/lib/3scale/backend/logging/middleware/json_writer.rb +21 -0
- data/lib/3scale/backend/logging/middleware/text_writer.rb +60 -0
- data/lib/3scale/backend/logging/middleware/writer.rb +143 -0
- data/lib/3scale/backend/logging/worker.rb +107 -0
- data/lib/3scale/backend/manifest.rb +80 -0
- data/lib/3scale/backend/memoizer.rb +277 -0
- data/lib/3scale/backend/metric.rb +275 -0
- data/lib/3scale/backend/metric/collection.rb +91 -0
- data/lib/3scale/backend/oauth.rb +4 -0
- data/lib/3scale/backend/oauth/token.rb +26 -0
- data/lib/3scale/backend/oauth/token_key.rb +30 -0
- data/lib/3scale/backend/oauth/token_storage.rb +313 -0
- data/lib/3scale/backend/oauth/token_value.rb +25 -0
- data/lib/3scale/backend/period.rb +3 -0
- data/lib/3scale/backend/period/boundary.rb +107 -0
- data/lib/3scale/backend/period/cache.rb +28 -0
- data/lib/3scale/backend/period/period.rb +402 -0
- data/lib/3scale/backend/queue_storage.rb +16 -0
- data/lib/3scale/backend/rack.rb +49 -0
- data/lib/3scale/backend/rack/exception_catcher.rb +136 -0
- data/lib/3scale/backend/rack/internal_error_catcher.rb +23 -0
- data/lib/3scale/backend/rack/prometheus.rb +19 -0
- data/lib/3scale/backend/saas.rb +6 -0
- data/lib/3scale/backend/saas_analytics.rb +4 -0
- data/lib/3scale/backend/server.rb +30 -0
- data/lib/3scale/backend/server/falcon.rb +52 -0
- data/lib/3scale/backend/server/puma.rb +71 -0
- data/lib/3scale/backend/service.rb +317 -0
- data/lib/3scale/backend/service_token.rb +97 -0
- data/lib/3scale/backend/stats.rb +8 -0
- data/lib/3scale/backend/stats/aggregator.rb +170 -0
- data/lib/3scale/backend/stats/aggregators/base.rb +72 -0
- data/lib/3scale/backend/stats/aggregators/response_code.rb +58 -0
- data/lib/3scale/backend/stats/aggregators/usage.rb +34 -0
- data/lib/3scale/backend/stats/bucket_reader.rb +135 -0
- data/lib/3scale/backend/stats/bucket_storage.rb +108 -0
- data/lib/3scale/backend/stats/cleaner.rb +195 -0
- data/lib/3scale/backend/stats/codes_commons.rb +14 -0
- data/lib/3scale/backend/stats/delete_job_def.rb +60 -0
- data/lib/3scale/backend/stats/key_generator.rb +73 -0
- data/lib/3scale/backend/stats/keys.rb +104 -0
- data/lib/3scale/backend/stats/partition_eraser_job.rb +58 -0
- data/lib/3scale/backend/stats/partition_generator_job.rb +46 -0
- data/lib/3scale/backend/stats/period_commons.rb +34 -0
- data/lib/3scale/backend/stats/stats_parser.rb +141 -0
- data/lib/3scale/backend/stats/storage.rb +113 -0
- data/lib/3scale/backend/statsd.rb +14 -0
- data/lib/3scale/backend/storable.rb +35 -0
- data/lib/3scale/backend/storage.rb +40 -0
- data/lib/3scale/backend/storage_async.rb +4 -0
- data/lib/3scale/backend/storage_async/async_redis.rb +21 -0
- data/lib/3scale/backend/storage_async/client.rb +205 -0
- data/lib/3scale/backend/storage_async/pipeline.rb +79 -0
- data/lib/3scale/backend/storage_async/resque_extensions.rb +30 -0
- data/lib/3scale/backend/storage_helpers.rb +278 -0
- data/lib/3scale/backend/storage_key_helpers.rb +9 -0
- data/lib/3scale/backend/storage_sync.rb +43 -0
- data/lib/3scale/backend/transaction.rb +62 -0
- data/lib/3scale/backend/transactor.rb +177 -0
- data/lib/3scale/backend/transactor/limit_headers.rb +54 -0
- data/lib/3scale/backend/transactor/notify_batcher.rb +139 -0
- data/lib/3scale/backend/transactor/notify_job.rb +47 -0
- data/lib/3scale/backend/transactor/process_job.rb +33 -0
- data/lib/3scale/backend/transactor/report_job.rb +84 -0
- data/lib/3scale/backend/transactor/status.rb +236 -0
- data/lib/3scale/backend/transactor/usage_report.rb +182 -0
- data/lib/3scale/backend/usage.rb +63 -0
- data/lib/3scale/backend/usage_limit.rb +115 -0
- data/lib/3scale/backend/use_cases/provider_key_change_use_case.rb +60 -0
- data/lib/3scale/backend/util.rb +17 -0
- data/lib/3scale/backend/validators.rb +26 -0
- data/lib/3scale/backend/validators/base.rb +36 -0
- data/lib/3scale/backend/validators/key.rb +17 -0
- data/lib/3scale/backend/validators/limits.rb +57 -0
- data/lib/3scale/backend/validators/oauth_key.rb +15 -0
- data/lib/3scale/backend/validators/oauth_setting.rb +15 -0
- data/lib/3scale/backend/validators/redirect_uri.rb +33 -0
- data/lib/3scale/backend/validators/referrer.rb +60 -0
- data/lib/3scale/backend/validators/service_state.rb +15 -0
- data/lib/3scale/backend/validators/state.rb +15 -0
- data/lib/3scale/backend/version.rb +5 -0
- data/lib/3scale/backend/views/oauth_access_tokens.builder +14 -0
- data/lib/3scale/backend/views/oauth_app_id_by_token.builder +4 -0
- data/lib/3scale/backend/worker.rb +87 -0
- data/lib/3scale/backend/worker_async.rb +88 -0
- data/lib/3scale/backend/worker_metrics.rb +44 -0
- data/lib/3scale/backend/worker_sync.rb +32 -0
- data/lib/3scale/bundler_shim.rb +17 -0
- data/lib/3scale/prometheus_server.rb +10 -0
- data/lib/3scale/tasks/connectivity.rake +41 -0
- data/lib/3scale/tasks/helpers.rb +3 -0
- data/lib/3scale/tasks/helpers/environment.rb +23 -0
- data/lib/3scale/tasks/stats.rake +131 -0
- data/lib/3scale/tasks/swagger.rake +46 -0
- data/licenses.xml +1215 -0
- metadata +227 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Add an application-wide logger UNRELATED to the request's logs.
|
|
2
|
+
#
|
|
3
|
+
# This allows for additional instrumentation and information gathering
|
|
4
|
+
# in production environment.
|
|
5
|
+
#
|
|
6
|
+
require 'logger'
|
|
7
|
+
|
|
8
|
+
module ThreeScale
|
|
9
|
+
module Backend
|
|
10
|
+
module Logging
|
|
11
|
+
class Logger
|
|
12
|
+
def self.new(*args)
|
|
13
|
+
::Logger.new(*args)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require '3scale/backend/logging/middleware/writer'
|
|
2
|
+
require '3scale/backend/logging/middleware/text_writer'
|
|
3
|
+
require '3scale/backend/logging/middleware/json_writer'
|
|
4
|
+
|
|
5
|
+
module ThreeScale
|
|
6
|
+
module Backend
|
|
7
|
+
module Logging
|
|
8
|
+
class Middleware
|
|
9
|
+
WRITERS = { text: TextWriter, json: JsonWriter }.freeze
|
|
10
|
+
private_constant :WRITERS
|
|
11
|
+
|
|
12
|
+
DEFAULT_WRITERS = [WRITERS[:text].new].freeze
|
|
13
|
+
private_constant :DEFAULT_WRITERS
|
|
14
|
+
|
|
15
|
+
class UnsupportedLoggerType < StandardError
|
|
16
|
+
def initialize(logger)
|
|
17
|
+
super "#{logger} is not a supported logger type."
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# writers is an array of symbols. WRITERS contains the accepted values
|
|
22
|
+
def initialize(app, writers: DEFAULT_WRITERS)
|
|
23
|
+
@app = app
|
|
24
|
+
@writers = writers
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def call(env)
|
|
28
|
+
began_at = Time.now
|
|
29
|
+
begin
|
|
30
|
+
status, header, body = @app.call(env)
|
|
31
|
+
rescue Exception => e
|
|
32
|
+
@writers.each do |writer|
|
|
33
|
+
writer.log_error(env, 500, e.message, began_at)
|
|
34
|
+
end
|
|
35
|
+
raise e
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
header = ::Rack::Utils::HeaderHash.new(header)
|
|
39
|
+
body = ::Rack::BodyProxy.new(body) do
|
|
40
|
+
@writers.each do |writer|
|
|
41
|
+
writer.log(env, status, header, began_at)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
[status, header, body]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Returns the Writer instances that correspond to the loggers given.
|
|
49
|
+
# If no loggers are given, returns the default writers.
|
|
50
|
+
def self.writers(loggers)
|
|
51
|
+
writers = Array(loggers).map do |logger|
|
|
52
|
+
writer_class = WRITERS[logger]
|
|
53
|
+
raise UnsupportedLoggerType.new(logger) unless writer_class
|
|
54
|
+
writer_class.new
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
writers.empty? ? DEFAULT_WRITERS : writers
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require '3scale/backend/logging/middleware/writer'
|
|
2
|
+
|
|
3
|
+
module ThreeScale
|
|
4
|
+
module Backend
|
|
5
|
+
module Logging
|
|
6
|
+
class Middleware
|
|
7
|
+
class JsonWriter
|
|
8
|
+
include Middleware::Writer
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def formatted_log(data)
|
|
13
|
+
data.to_json + "\n".freeze
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
alias_method :formatted_error, :formatted_log
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require '3scale/backend/logging/middleware/writer'
|
|
2
|
+
|
|
3
|
+
module ThreeScale
|
|
4
|
+
module Backend
|
|
5
|
+
module Logging
|
|
6
|
+
class Middleware
|
|
7
|
+
class TextWriter
|
|
8
|
+
include Middleware::Writer
|
|
9
|
+
|
|
10
|
+
FORMAT = "%s - %s [%s] \"%s %s%s %s\" %d %s %s 0 0 0 %s %s %s %s %s\n".freeze
|
|
11
|
+
private_constant :FORMAT
|
|
12
|
+
|
|
13
|
+
ERROR_FORMAT = "%s - %s [%s] \"%s %s%s %s\" %d \"%s\" %s %s %s\n".freeze
|
|
14
|
+
private_constant :ERROR_FORMAT
|
|
15
|
+
|
|
16
|
+
SORTED_LOG_FIELDS = [:forwarded_for,
|
|
17
|
+
:remote_user,
|
|
18
|
+
:time,
|
|
19
|
+
:method,
|
|
20
|
+
:path_info,
|
|
21
|
+
:query_string,
|
|
22
|
+
:http_version,
|
|
23
|
+
:status,
|
|
24
|
+
:length,
|
|
25
|
+
:response_time,
|
|
26
|
+
:memoizer_size,
|
|
27
|
+
:memoizer_count,
|
|
28
|
+
:memoizer_hits,
|
|
29
|
+
:request_id,
|
|
30
|
+
:extensions].freeze
|
|
31
|
+
private_constant :SORTED_LOG_FIELDS
|
|
32
|
+
|
|
33
|
+
SORTED_ERROR_LOG_FIELDS = [:forwarded_for,
|
|
34
|
+
:remote_user,
|
|
35
|
+
:time,
|
|
36
|
+
:method,
|
|
37
|
+
:path_info,
|
|
38
|
+
:query_string,
|
|
39
|
+
:http_version,
|
|
40
|
+
:status,
|
|
41
|
+
:error,
|
|
42
|
+
:response_time,
|
|
43
|
+
:request_id,
|
|
44
|
+
:extensions].freeze
|
|
45
|
+
private_constant :SORTED_ERROR_LOG_FIELDS
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def formatted_log(data)
|
|
50
|
+
FORMAT % SORTED_LOG_FIELDS.map { |field| data[field] }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def formatted_error(data)
|
|
54
|
+
ERROR_FORMAT % SORTED_ERROR_LOG_FIELDS.map { |field| data[field] }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
module ThreeScale
|
|
2
|
+
module Backend
|
|
3
|
+
module Logging
|
|
4
|
+
class Middleware
|
|
5
|
+
module Writer
|
|
6
|
+
Z3_RANGE = 0..3.freeze
|
|
7
|
+
private_constant :Z3_RANGE
|
|
8
|
+
|
|
9
|
+
private_constant(*[
|
|
10
|
+
:HTTP_X_FORWARDED_FOR,
|
|
11
|
+
:REMOTE_ADDR,
|
|
12
|
+
:REMOTE_USER,
|
|
13
|
+
:REQUEST_METHOD,
|
|
14
|
+
:PATH_INFO,
|
|
15
|
+
:HTTP_VERSION,
|
|
16
|
+
:HTTP_X_REQUEST_ID,
|
|
17
|
+
:QUERY_STRING,
|
|
18
|
+
:HTTP_3SCALE_OPTIONS
|
|
19
|
+
].each do |k|
|
|
20
|
+
const_set(k, k.to_s.freeze)
|
|
21
|
+
end)
|
|
22
|
+
|
|
23
|
+
private_constant(*{
|
|
24
|
+
DATE_FORMAT: '%d/%b/%Y %H:%M:%S %Z',
|
|
25
|
+
STR_PROVIDER_KEY: 'provider_key',
|
|
26
|
+
STR_POST: 'POST',
|
|
27
|
+
STR_EQUAL: '=',
|
|
28
|
+
STR_DASH: '-',
|
|
29
|
+
STR_AMPERSAND: '&',
|
|
30
|
+
STR_ZERO: '0',
|
|
31
|
+
STR_RACK_ERRORS: 'rack.errors',
|
|
32
|
+
STR_EMPTY: '',
|
|
33
|
+
STR_QUESTION_MARK: '?',
|
|
34
|
+
STR_NEWLINE: "\n",
|
|
35
|
+
STR_DQUOTE: '"',
|
|
36
|
+
STR_ESCAPED_DQUOTE: '\"',
|
|
37
|
+
STR_CONTENT_LENGTH: 'Content-Length'
|
|
38
|
+
}.map do |k, v|
|
|
39
|
+
const_set(k, v.freeze)
|
|
40
|
+
k
|
|
41
|
+
end)
|
|
42
|
+
|
|
43
|
+
def initialize(logger=STDOUT)
|
|
44
|
+
@logger = logger
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def log(env, status, header, began_at)
|
|
48
|
+
data = log_data(env, status, header, began_at)
|
|
49
|
+
log = formatted_log(data)
|
|
50
|
+
logger(env).write(log)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def log_error(env, status, error, began_at)
|
|
54
|
+
data = log_error_data(env, status, error, began_at)
|
|
55
|
+
error = formatted_error(data)
|
|
56
|
+
logger(env).write(error)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def logger(env)
|
|
62
|
+
@logger || env[STR_RACK_ERRORS] || STDERR
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def log_data(env, status, header, began_at)
|
|
66
|
+
common_request_data(env, status, began_at)
|
|
67
|
+
.merge(success_specific_data(header))
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def log_error_data(env, status, error, began_at)
|
|
71
|
+
common_request_data(env, status, began_at)
|
|
72
|
+
.merge(error_specific_data(error))
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def common_request_data(env, status, began_at)
|
|
76
|
+
now = Time.now.getutc
|
|
77
|
+
|
|
78
|
+
{ forwarded_for: env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || STR_DASH,
|
|
79
|
+
remote_user: env[REMOTE_USER] || STR_DASH,
|
|
80
|
+
time: now.strftime(DATE_FORMAT),
|
|
81
|
+
method: env[REQUEST_METHOD],
|
|
82
|
+
path_info: env[PATH_INFO],
|
|
83
|
+
query_string: extract_query_string(env),
|
|
84
|
+
http_version: env[HTTP_VERSION],
|
|
85
|
+
status: status.to_s[Z3_RANGE],
|
|
86
|
+
response_time: now - began_at,
|
|
87
|
+
request_id: env[HTTP_X_REQUEST_ID] || STR_DASH,
|
|
88
|
+
extensions: extensions(env) }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def success_specific_data(header)
|
|
92
|
+
{ length: extract_content_length(header) }.merge(memoizer_data)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def memoizer_data
|
|
96
|
+
memoizer = memoizer_stats
|
|
97
|
+
|
|
98
|
+
{ memoizer_size: memoizer[:size] || STR_DASH,
|
|
99
|
+
memoizer_count: memoizer[:count] || STR_DASH,
|
|
100
|
+
memoizer_hits: memoizer[:hits] || STR_DASH }
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def error_specific_data(error)
|
|
104
|
+
{ error: error }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def extract_query_string(env)
|
|
108
|
+
qs = env[QUERY_STRING]
|
|
109
|
+
if env[REQUEST_METHOD].to_s.upcase == STR_POST
|
|
110
|
+
provider_key = begin
|
|
111
|
+
::Rack::Request.new(env).params[STR_PROVIDER_KEY]
|
|
112
|
+
rescue IOError
|
|
113
|
+
# happens when body does not parse
|
|
114
|
+
nil
|
|
115
|
+
end
|
|
116
|
+
unless provider_key.nil?
|
|
117
|
+
qs = qs.dup
|
|
118
|
+
qs << STR_AMPERSAND unless qs.empty?
|
|
119
|
+
qs << STR_PROVIDER_KEY + STR_EQUAL + provider_key.to_s
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
qs.empty? ? STR_EMPTY : STR_QUESTION_MARK + qs.tr(STR_NEWLINE, STR_EMPTY)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def extract_content_length(headers)
|
|
127
|
+
value = headers[STR_CONTENT_LENGTH] or return STR_DASH
|
|
128
|
+
value.to_s == STR_ZERO ? STR_DASH : value
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def extensions(env)
|
|
132
|
+
ext = env[HTTP_3SCALE_OPTIONS]
|
|
133
|
+
ext ? "\"#{ext.gsub(STR_DQUOTE, STR_ESCAPED_DQUOTE)}\"" : STR_DASH
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def memoizer_stats
|
|
137
|
+
ThreeScale::Backend::Memoizer.stats
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
module ThreeScale
|
|
2
|
+
module Backend
|
|
3
|
+
module Logging
|
|
4
|
+
class Worker
|
|
5
|
+
include Configurable
|
|
6
|
+
|
|
7
|
+
module PlainText
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def logger_formatter
|
|
11
|
+
proc do |severity, datetime, _progname, msg|
|
|
12
|
+
"#{severity} #{Process.pid} #{formatted_datetime(datetime)} #{msg}\n"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def formatted_datetime(datetime)
|
|
17
|
+
datetime.getutc.strftime("[%d/%b/%Y %H:%M:%S %Z]".freeze)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
private_constant :PlainText
|
|
21
|
+
|
|
22
|
+
module Json
|
|
23
|
+
STRING_COMMON_FIELDS = [:job_class].freeze
|
|
24
|
+
private_constant :STRING_COMMON_FIELDS
|
|
25
|
+
|
|
26
|
+
FLOAT_COMMON_FIELDS = [:runtime, :run_plus_queued_time].freeze
|
|
27
|
+
private_constant :FLOAT_COMMON_FIELDS
|
|
28
|
+
|
|
29
|
+
INT_COMMON_FIELDS = [:memoizer_size, :memoizer_count, :memoizer_hits].freeze
|
|
30
|
+
private_constant :INT_COMMON_FIELDS
|
|
31
|
+
|
|
32
|
+
COMMON_LOG_FIELDS = (STRING_COMMON_FIELDS +
|
|
33
|
+
FLOAT_COMMON_FIELDS +
|
|
34
|
+
INT_COMMON_FIELDS).freeze
|
|
35
|
+
private_constant :COMMON_LOG_FIELDS
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def logger_formatter
|
|
40
|
+
proc do |severity, datetime, _progname, msg|
|
|
41
|
+
common_fields = { severity: severity,
|
|
42
|
+
pid: Process.pid,
|
|
43
|
+
time: datetime.getutc.to_s }
|
|
44
|
+
|
|
45
|
+
# When there is an error, the msg does not contain run times and
|
|
46
|
+
# memoizer stats.
|
|
47
|
+
msg_fields = if severity == 'INFO'.freeze
|
|
48
|
+
formatted_msg(msg)
|
|
49
|
+
else
|
|
50
|
+
{ msg: msg }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
common_fields.merge(msg_fields).to_json + "\n".freeze
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def formatted_msg(msg)
|
|
58
|
+
# The format of the message depends on the kind of background job
|
|
59
|
+
# that sends it:
|
|
60
|
+
# job_class -variable_part- run_time run_time+queued_time
|
|
61
|
+
# memoizer_size memoizer_count memoizer_hits.
|
|
62
|
+
# -variable_part- depends on the kind of job. It might contain app
|
|
63
|
+
# ids, a message (with spaces), etc. The rest of the message is
|
|
64
|
+
# common for all the jobs. For now, we discard the variable part.
|
|
65
|
+
fields = msg.split(' '.freeze)
|
|
66
|
+
common_field_values = [fields.first] + fields.last(5)
|
|
67
|
+
res = Hash[COMMON_LOG_FIELDS.zip(common_field_values)]
|
|
68
|
+
|
|
69
|
+
FLOAT_COMMON_FIELDS.each do |field|
|
|
70
|
+
res[field] = res[field].to_f
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
INT_COMMON_FIELDS.each do |field|
|
|
74
|
+
res[field] = res[field].to_i
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
res
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
private_constant :Json
|
|
81
|
+
|
|
82
|
+
extend(configuration.workers_logger_formatter == :json ? Json : PlainText)
|
|
83
|
+
|
|
84
|
+
class << self
|
|
85
|
+
def configure_logging(worker_class, workers_log_file)
|
|
86
|
+
log_file = workers_log_file || configuration.workers_log_file || '/dev/null'
|
|
87
|
+
|
|
88
|
+
Logging.enable! on: worker_class.singleton_class, with: log_file do |logger|
|
|
89
|
+
logger.formatter = logger_formatter
|
|
90
|
+
|
|
91
|
+
# At this point, we've already configured the logger for Backend
|
|
92
|
+
# (used in Listeners and rake tasks). We can reuse the notify proc
|
|
93
|
+
# defined there.
|
|
94
|
+
logger.define_singleton_method(:notify, backend_logger_notify_proc)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def backend_logger_notify_proc
|
|
101
|
+
Backend.logger.method(:notify).to_proc
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require '3scale/backend/version'
|
|
2
|
+
require '3scale/backend/util'
|
|
3
|
+
require '3scale/backend/server'
|
|
4
|
+
|
|
5
|
+
module ThreeScale
|
|
6
|
+
module Backend
|
|
7
|
+
module Manifest
|
|
8
|
+
class << self
|
|
9
|
+
LISTENER_WORKERS = 'LISTENER_WORKERS'.freeze
|
|
10
|
+
private_constant :LISTENER_WORKERS
|
|
11
|
+
PUMA_WORKERS = 'PUMA_WORKERS'.freeze
|
|
12
|
+
private_constant :PUMA_WORKERS
|
|
13
|
+
PUMA_WORKERS_CPUMULT = 8
|
|
14
|
+
private_constant :PUMA_WORKERS_CPUMULT
|
|
15
|
+
|
|
16
|
+
# Thread safety of our application. Turn this on if we ever are MT safe.
|
|
17
|
+
def thread_safe?
|
|
18
|
+
false
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Compute workers based on LISTENER_WORKERS and PUMA_WORKERS env
|
|
22
|
+
# variables. The former takes precedence.
|
|
23
|
+
# If those envs do not exist or are empty, use number of cpus
|
|
24
|
+
def compute_workers(ncpus)
|
|
25
|
+
return 0 unless Process.respond_to?(:fork)
|
|
26
|
+
|
|
27
|
+
compute_workers_from_env(LISTENER_WORKERS) ||
|
|
28
|
+
compute_workers_from_env(PUMA_WORKERS) ||
|
|
29
|
+
ncpus * PUMA_WORKERS_CPUMULT
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def server_model
|
|
33
|
+
# Serving model settings here
|
|
34
|
+
#
|
|
35
|
+
# compute default workers and threads values
|
|
36
|
+
# We want to adapt workers and threads to our characteristics.
|
|
37
|
+
# Note that these values will likely need to be tweaked depending on
|
|
38
|
+
# the Ruby implementation and how our app behaves!
|
|
39
|
+
ncpus = ThreeScale::Backend::Util.number_of_cpus
|
|
40
|
+
workers = compute_workers ncpus
|
|
41
|
+
# if no workers but mt-safe, we spawn more threads.
|
|
42
|
+
min_threads, max_threads = if thread_safe?
|
|
43
|
+
shift = workers.zero? ? 2 : 0
|
|
44
|
+
[ncpus << shift, ncpus << 1 + shift]
|
|
45
|
+
else
|
|
46
|
+
[1, 1]
|
|
47
|
+
end
|
|
48
|
+
{
|
|
49
|
+
ncpus: ncpus,
|
|
50
|
+
workers: workers,
|
|
51
|
+
min_threads: min_threads,
|
|
52
|
+
max_threads: max_threads
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def report
|
|
57
|
+
{
|
|
58
|
+
version: ThreeScale::Backend::VERSION,
|
|
59
|
+
root_dir: ThreeScale::Backend::Util.root_dir,
|
|
60
|
+
servers: ThreeScale::Backend::Server.list,
|
|
61
|
+
thread_safe: thread_safe?,
|
|
62
|
+
server_model: server_model,
|
|
63
|
+
}
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def compute_workers_from_env(env_name)
|
|
69
|
+
if ENV[env_name] && !ENV[env_name].empty?
|
|
70
|
+
begin
|
|
71
|
+
Integer(ENV[env_name])
|
|
72
|
+
rescue => e
|
|
73
|
+
raise e, "#{env_name} environment var cannot be parsed: #{e.message}"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|