apisonator 2.100.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|