pliny 1.2.0 → 2.0.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 +4 -4
- data/bin/pliny-generate +2 -1
- data/bin/pliny-new +2 -1
- data/bin/pliny-update +2 -1
- data/lib/pliny/canonical_log_line_helpers.rb +2 -0
- data/lib/pliny/commands/creator.rb +13 -12
- data/lib/pliny/commands/generator/base.rb +11 -9
- data/lib/pliny/commands/generator/endpoint.rb +19 -17
- data/lib/pliny/commands/generator/mediator.rb +7 -5
- data/lib/pliny/commands/generator/migration.rb +4 -2
- data/lib/pliny/commands/generator/model.rb +11 -9
- data/lib/pliny/commands/generator/schema.rb +4 -2
- data/lib/pliny/commands/generator/serializer.rb +7 -5
- data/lib/pliny/commands/generator.rb +19 -17
- data/lib/pliny/commands/updater.rb +5 -3
- data/lib/pliny/config_helpers.rb +10 -35
- data/lib/pliny/db_support.rb +21 -21
- data/lib/pliny/error_reporters/rollbar.rb +5 -3
- data/lib/pliny/error_reporters/sentry.rb +40 -0
- data/lib/pliny/error_reporters.rb +5 -5
- data/lib/pliny/errors.rb +46 -44
- data/lib/pliny/helpers/encode.rb +4 -2
- data/lib/pliny/helpers/params.rb +2 -0
- data/lib/pliny/helpers/serialize.rb +6 -4
- data/lib/pliny/helpers/zulu_time.rb +3 -1
- data/lib/pliny/log.rb +26 -25
- data/lib/pliny/metrics/backends/logger.rb +5 -3
- data/lib/pliny/metrics.rb +4 -2
- data/lib/pliny/middleware/canonical_log_line.rb +5 -3
- data/lib/pliny/middleware/cors.rb +13 -12
- data/lib/pliny/middleware/instruments.rb +9 -7
- data/lib/pliny/middleware/metrics.rb +3 -1
- data/lib/pliny/middleware/request_id.rb +4 -2
- data/lib/pliny/middleware/request_store/clear.rb +3 -1
- data/lib/pliny/middleware/request_store/seed.rb +3 -1
- data/lib/pliny/middleware/rescue_errors.rb +2 -0
- data/lib/pliny/middleware/versioning.rb +11 -11
- data/lib/pliny/request_store.rb +4 -2
- data/lib/pliny/rollbar_logger.rb +6 -4
- data/lib/pliny/router.rb +3 -2
- data/lib/pliny/tasks/db.rake +3 -1
- data/lib/pliny/tasks/schema.rake +3 -1
- data/lib/pliny/tasks.rb +2 -0
- data/lib/pliny/utils.rb +4 -2
- data/lib/pliny/version.rb +3 -1
- data/lib/pliny.rb +2 -0
- data/lib/template/{.rubocop.yml → .rubocop_template.yml} +1 -5
- data/lib/template/Gemfile +7 -4
- data/lib/template/Rakefile +1 -0
- data/lib/template/bin/console +2 -1
- data/lib/template/bin/run +4 -1
- data/lib/template/config/config.rb +18 -16
- data/lib/template/config/initializers/database.rb +4 -2
- data/lib/template/config/initializers/log.rb +2 -0
- data/lib/template/config/initializers/metrics.rb +2 -0
- data/lib/template/config/initializers/sentry.rb +14 -0
- data/lib/template/config/puma.rb +3 -1
- data/lib/template/config.ru +2 -0
- data/lib/template/db/seeds.rb +2 -0
- data/lib/template/lib/application.rb +2 -0
- data/lib/template/lib/endpoints/base.rb +2 -0
- data/lib/template/lib/endpoints/health.rb +2 -0
- data/lib/template/lib/endpoints/root.rb +2 -0
- data/lib/template/lib/endpoints/schema.rb +2 -0
- data/lib/template/lib/initializer.rb +6 -4
- data/lib/template/lib/mediators/base.rb +2 -0
- data/lib/template/lib/routes.rb +8 -6
- data/lib/template/lib/serializers/base.rb +2 -0
- data/lib/template/lib/tasks/rubocop.rake +2 -0
- data/lib/template/lib/tasks/spec.rake +2 -1
- data/lib/template/spec/endpoints/health_spec.rb +2 -0
- data/lib/template/spec/endpoints/schema_spec.rb +2 -0
- data/lib/template/spec/spec_helper.rb +2 -0
- data/lib/template/spec/spec_support/auto_define_rack_app.rb +2 -0
- data/lib/template/spec/spec_support/coverage.rb +2 -0
- data/lib/template/spec/spec_support/log.rb +2 -0
- data/spec/canonical_log_line_helpers_spec.rb +10 -8
- data/spec/commands/creator_spec.rb +3 -0
- data/spec/commands/generator/base_spec.rb +61 -59
- data/spec/commands/generator/endpoint_spec.rb +16 -15
- data/spec/commands/generator/mediator_spec.rb +11 -9
- data/spec/commands/generator/migration_spec.rb +7 -5
- data/spec/commands/generator/model_spec.rb +13 -11
- data/spec/commands/generator/schema_spec.rb +29 -28
- data/spec/commands/generator/serializer_spec.rb +11 -9
- data/spec/commands/generator_spec.rb +64 -62
- data/spec/commands/updater_spec.rb +2 -0
- data/spec/config_helpers_spec.rb +7 -85
- data/spec/db_support_spec.rb +46 -44
- data/spec/error_reporters/rollbar_spec.rb +8 -6
- data/spec/error_reporters/sentry_spec.rb +83 -0
- data/spec/error_reporters_spec.rb +4 -2
- data/spec/errors_spec.rb +4 -1
- data/spec/helpers/encode_spec.rb +2 -0
- data/spec/helpers/params_spec.rb +9 -7
- data/spec/helpers/serialize_spec.rb +11 -7
- data/spec/helpers/zulu_time_spec.rb +6 -4
- data/spec/integration_spec.rb +14 -12
- data/spec/log_spec.rb +8 -6
- data/spec/metrics/backends/logger_spec.rb +10 -6
- data/spec/metrics_spec.rb +15 -13
- data/spec/middleware/canonical_log_line_spec.rb +5 -2
- data/spec/middleware/cors_spec.rb +2 -0
- data/spec/middleware/instruments_spec.rb +10 -8
- data/spec/middleware/metrics_spec.rb +3 -1
- data/spec/middleware/request_id_spec.rb +2 -0
- data/spec/middleware/request_store/clear_spec.rb +2 -0
- data/spec/middleware/request_store/seed_spec.rb +2 -0
- data/spec/middleware/rescue_errors_spec.rb +13 -13
- data/spec/middleware/versioning_spec.rb +22 -20
- data/spec/request_store_spec.rb +3 -1
- data/spec/rollbar_logger_spec.rb +11 -9
- data/spec/router_spec.rb +9 -7
- data/spec/spec_helper.rb +3 -1
- data/spec/support/config.rb +2 -0
- data/spec/support/endpoints.rb +2 -0
- metadata +91 -100
- data/lib/template/config/initializers/rollbar.rb +0 -12
data/lib/pliny/db_support.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "logger"
|
|
2
4
|
require "sequel"
|
|
3
5
|
require "sequel/extensions/migration"
|
|
@@ -15,12 +17,12 @@ module Pliny
|
|
|
15
17
|
@db = Sequel.connect(database_url)
|
|
16
18
|
@db.test_connection
|
|
17
19
|
@db.disconnect
|
|
18
|
-
|
|
20
|
+
true
|
|
19
21
|
rescue Sequel::DatabaseConnectionError
|
|
20
|
-
|
|
22
|
+
false
|
|
21
23
|
end
|
|
22
24
|
|
|
23
|
-
def self.run(url, sequel_log_io=StringIO.new)
|
|
25
|
+
def self.run(url, sequel_log_io = StringIO.new)
|
|
24
26
|
logger = Logger.new(sequel_log_io)
|
|
25
27
|
instance = new(url, logger)
|
|
26
28
|
yield instance
|
|
@@ -39,11 +41,11 @@ module Pliny
|
|
|
39
41
|
|
|
40
42
|
def exists?(name)
|
|
41
43
|
res = db.fetch("SELECT 1 FROM pg_database WHERE datname = ?", name)
|
|
42
|
-
|
|
44
|
+
res.count > 0
|
|
43
45
|
end
|
|
44
46
|
|
|
45
47
|
def create(name)
|
|
46
|
-
db.run(%
|
|
48
|
+
db.run(%(CREATE DATABASE "#{name}"))
|
|
47
49
|
end
|
|
48
50
|
|
|
49
51
|
def migrate(target = nil)
|
|
@@ -79,32 +81,30 @@ module Pliny
|
|
|
79
81
|
else
|
|
80
82
|
:down
|
|
81
83
|
end
|
|
84
|
+
elsif present_in_database
|
|
85
|
+
:file_missing
|
|
82
86
|
else
|
|
83
|
-
|
|
84
|
-
:file_missing
|
|
85
|
-
else
|
|
86
|
-
raise "error" # FIXME: better message
|
|
87
|
-
end
|
|
87
|
+
raise "error" # FIXME: better message
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
class MigrationStatusPresenter
|
|
93
93
|
PADDING = 2
|
|
94
|
-
UP = "UP"
|
|
95
|
-
DOWN = "DOWN"
|
|
96
|
-
FILE_MISSING = "FILE MISSING"
|
|
94
|
+
UP = "UP"
|
|
95
|
+
DOWN = "DOWN"
|
|
96
|
+
FILE_MISSING = "FILE MISSING"
|
|
97
97
|
|
|
98
98
|
STATUS_MAP = {
|
|
99
99
|
up: UP,
|
|
100
100
|
down: DOWN,
|
|
101
|
-
file_missing: FILE_MISSING
|
|
101
|
+
file_missing: FILE_MISSING,
|
|
102
102
|
}.freeze
|
|
103
103
|
|
|
104
104
|
STATUS_OPTIONS = [
|
|
105
105
|
UP,
|
|
106
106
|
DOWN,
|
|
107
|
-
FILE_MISSING
|
|
107
|
+
FILE_MISSING,
|
|
108
108
|
].freeze
|
|
109
109
|
|
|
110
110
|
attr_reader :migration_statuses
|
|
@@ -125,7 +125,7 @@ module Pliny
|
|
|
125
125
|
[
|
|
126
126
|
barrier_row,
|
|
127
127
|
header_row,
|
|
128
|
-
barrier_row
|
|
128
|
+
barrier_row,
|
|
129
129
|
]
|
|
130
130
|
end
|
|
131
131
|
|
|
@@ -137,20 +137,20 @@ module Pliny
|
|
|
137
137
|
|
|
138
138
|
def footer
|
|
139
139
|
[
|
|
140
|
-
barrier_row
|
|
140
|
+
barrier_row,
|
|
141
141
|
]
|
|
142
142
|
end
|
|
143
143
|
|
|
144
144
|
def barrier_row
|
|
145
|
-
"+#{
|
|
145
|
+
"+#{"-" * (longest_status + PADDING)}+#{"-" * (longest_migration_name + PADDING)}+"
|
|
146
146
|
end
|
|
147
147
|
|
|
148
148
|
def header_row
|
|
149
|
-
"|#{
|
|
149
|
+
"|#{"STATUS".center(longest_status + PADDING)}|#{"MIGRATION".center(longest_migration_name + PADDING)}|"
|
|
150
150
|
end
|
|
151
151
|
|
|
152
152
|
def status_row(migration_status)
|
|
153
|
-
"|#{STATUS_MAP[migration_status.status].center(longest_status + PADDING)}|#{
|
|
153
|
+
"|#{STATUS_MAP[migration_status.status].center(longest_status + PADDING)}|#{" " * (PADDING / 2)}#{migration_status.filename.ljust(longest_migration_name)}#{" " * (PADDING / 2)}|"
|
|
154
154
|
end
|
|
155
155
|
|
|
156
156
|
private
|
|
@@ -210,7 +210,7 @@ module Pliny
|
|
|
210
210
|
|
|
211
211
|
private
|
|
212
212
|
|
|
213
|
-
MIGRATION_DIR = "./db/migrate"
|
|
213
|
+
MIGRATION_DIR = "./db/migrate"
|
|
214
214
|
private_constant :MIGRATION_DIR
|
|
215
215
|
end
|
|
216
216
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rollbar/exception_reporter"
|
|
4
|
+
require "rollbar/request_data_extractor"
|
|
3
5
|
|
|
4
6
|
module Pliny
|
|
5
7
|
module ErrorReporters
|
|
@@ -24,7 +26,7 @@ module Pliny
|
|
|
24
26
|
scope[:person] = proc { extract_person_data_from_controller(rack_env) }
|
|
25
27
|
end
|
|
26
28
|
scope
|
|
27
|
-
rescue Exception => e
|
|
29
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
28
30
|
report_exception_to_rollbar(rack_env, e)
|
|
29
31
|
raise
|
|
30
32
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pliny
|
|
4
|
+
module ErrorReporters
|
|
5
|
+
class Sentry
|
|
6
|
+
def notify(exception, context:, rack_env:)
|
|
7
|
+
::Sentry.with_scope do |scope|
|
|
8
|
+
configure_scope(scope, context: context, rack_env: rack_env)
|
|
9
|
+
::Sentry.capture_exception(exception)
|
|
10
|
+
end
|
|
11
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
12
|
+
::Sentry.capture_exception(e)
|
|
13
|
+
raise
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def configure_scope(scope, context:, rack_env:)
|
|
19
|
+
scope.set_context("custom", context)
|
|
20
|
+
|
|
21
|
+
begin
|
|
22
|
+
person_data = extract_person_data_from_controller(rack_env)
|
|
23
|
+
if person_data && !person_data.empty?
|
|
24
|
+
scope.set_user(
|
|
25
|
+
id: person_data[:id],
|
|
26
|
+
email: person_data[:email],
|
|
27
|
+
username: person_data[:username],
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
rescue => e
|
|
31
|
+
::Sentry.capture_exception(e)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def extract_person_data_from_controller(env)
|
|
36
|
+
env["sentry.person_data"] || {}
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Pliny::ErrorReporters
|
|
2
4
|
extend self
|
|
3
5
|
|
|
@@ -9,11 +11,9 @@ module Pliny::ErrorReporters
|
|
|
9
11
|
Pliny.log_exception(exception)
|
|
10
12
|
|
|
11
13
|
error_reporters.each do |reporter|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Pliny.log_exception($!)
|
|
16
|
-
end
|
|
14
|
+
reporter.new.notify(exception, context: context, rack_env: rack_env)
|
|
15
|
+
rescue
|
|
16
|
+
Pliny.log_exception($!)
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
end
|
data/lib/pliny/errors.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Pliny
|
|
2
4
|
module Errors
|
|
3
5
|
class Error < StandardError
|
|
@@ -19,9 +21,9 @@ module Pliny
|
|
|
19
21
|
attr_accessor :status
|
|
20
22
|
|
|
21
23
|
def initialize(message = nil, id = nil, status = nil)
|
|
22
|
-
meta
|
|
23
|
-
message
|
|
24
|
-
id
|
|
24
|
+
meta = Pliny::Errors::META[self.class]
|
|
25
|
+
message ||= meta[1] + "."
|
|
26
|
+
id ||= meta[1].downcase.tr(" ", "_").to_sym
|
|
25
27
|
@status = status || meta[0]
|
|
26
28
|
super(message, id)
|
|
27
29
|
end
|
|
@@ -71,47 +73,47 @@ module Pliny
|
|
|
71
73
|
|
|
72
74
|
# Messages for nicer exceptions, from rfc2616
|
|
73
75
|
META = {
|
|
74
|
-
Continue
|
|
75
|
-
SwitchingProtocols
|
|
76
|
-
OK
|
|
77
|
-
Created
|
|
78
|
-
Accepted
|
|
79
|
-
NonAuthoritativeInformation
|
|
80
|
-
NoContent
|
|
81
|
-
ResetContent
|
|
82
|
-
PartialContent
|
|
83
|
-
MultipleChoices
|
|
84
|
-
MovedPermanently
|
|
85
|
-
Found
|
|
86
|
-
SeeOther
|
|
87
|
-
NotModified
|
|
88
|
-
UseProxy
|
|
89
|
-
TemporaryRedirect
|
|
90
|
-
BadRequest
|
|
91
|
-
Unauthorized
|
|
92
|
-
PaymentRequired
|
|
93
|
-
Forbidden
|
|
94
|
-
NotFound
|
|
95
|
-
MethodNotAllowed
|
|
96
|
-
NotAcceptable
|
|
97
|
-
ProxyAuthenticationRequired
|
|
98
|
-
RequestTimeout
|
|
99
|
-
Conflict
|
|
100
|
-
Gone
|
|
101
|
-
LengthRequired
|
|
102
|
-
PreconditionFailed
|
|
103
|
-
RequestEntityTooLarge
|
|
104
|
-
RequestURITooLong
|
|
105
|
-
UnsupportedMediaType
|
|
106
|
-
RequestedRangeNotSatisfiable => [416,
|
|
107
|
-
ExpectationFailed
|
|
108
|
-
UnprocessableEntity
|
|
109
|
-
TooManyRequests
|
|
110
|
-
InternalServerError
|
|
111
|
-
NotImplemented
|
|
112
|
-
BadGateway
|
|
113
|
-
ServiceUnavailable
|
|
114
|
-
GatewayTimeout
|
|
76
|
+
Continue => [100, "Continue"],
|
|
77
|
+
SwitchingProtocols => [101, "Switching protocols"],
|
|
78
|
+
OK => [200, "OK"],
|
|
79
|
+
Created => [201, "Created"],
|
|
80
|
+
Accepted => [202, "Accepted"],
|
|
81
|
+
NonAuthoritativeInformation => [203, "Non-authoritative information"],
|
|
82
|
+
NoContent => [204, "No content"],
|
|
83
|
+
ResetContent => [205, "Reset content"],
|
|
84
|
+
PartialContent => [206, "Partial content"],
|
|
85
|
+
MultipleChoices => [300, "Multiple choices"],
|
|
86
|
+
MovedPermanently => [301, "Moved permanently"],
|
|
87
|
+
Found => [302, "Found"],
|
|
88
|
+
SeeOther => [303, "See other"],
|
|
89
|
+
NotModified => [304, "Not modified"],
|
|
90
|
+
UseProxy => [305, "Use proxy"],
|
|
91
|
+
TemporaryRedirect => [307, "Temporary redirect"],
|
|
92
|
+
BadRequest => [400, "Bad request"],
|
|
93
|
+
Unauthorized => [401, "Unauthorized"],
|
|
94
|
+
PaymentRequired => [402, "Payment required"],
|
|
95
|
+
Forbidden => [403, "Forbidden"],
|
|
96
|
+
NotFound => [404, "Not found"],
|
|
97
|
+
MethodNotAllowed => [405, "Method not allowed"],
|
|
98
|
+
NotAcceptable => [406, "Not acceptable"],
|
|
99
|
+
ProxyAuthenticationRequired => [407, "Proxy authentication required"],
|
|
100
|
+
RequestTimeout => [408, "Request timeout"],
|
|
101
|
+
Conflict => [409, "Conflict"],
|
|
102
|
+
Gone => [410, "Gone"],
|
|
103
|
+
LengthRequired => [411, "Length required"],
|
|
104
|
+
PreconditionFailed => [412, "Precondition failed"],
|
|
105
|
+
RequestEntityTooLarge => [413, "Request entity too large"],
|
|
106
|
+
RequestURITooLong => [414, "Request-URI too long"],
|
|
107
|
+
UnsupportedMediaType => [415, "Unsupported media type"],
|
|
108
|
+
RequestedRangeNotSatisfiable => [416, "Requested range not satisfiable"],
|
|
109
|
+
ExpectationFailed => [417, "Expectation failed"],
|
|
110
|
+
UnprocessableEntity => [422, "Unprocessable entity"],
|
|
111
|
+
TooManyRequests => [429, "Too many requests"],
|
|
112
|
+
InternalServerError => [500, "Internal server error"],
|
|
113
|
+
NotImplemented => [501, "Not implemented"],
|
|
114
|
+
BadGateway => [502, "Bad gateway"],
|
|
115
|
+
ServiceUnavailable => [503, "Service unavailable"],
|
|
116
|
+
GatewayTimeout => [504, "Gateway timeout"],
|
|
115
117
|
}.freeze
|
|
116
118
|
end
|
|
117
119
|
end
|
data/lib/pliny/helpers/encode.rb
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Pliny::Helpers
|
|
2
4
|
module Encode
|
|
3
5
|
def encode(object)
|
|
4
|
-
content_type :json, charset:
|
|
5
|
-
if params[:pretty] ==
|
|
6
|
+
content_type :json, charset: "utf-8"
|
|
7
|
+
if params[:pretty] == "true" || Config.pretty_json
|
|
6
8
|
JSON.pretty_generate(object)
|
|
7
9
|
else
|
|
8
10
|
JSON.generate(object)
|
data/lib/pliny/helpers/params.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Pliny::Helpers
|
|
2
4
|
module Serialize
|
|
3
5
|
def self.registered(base)
|
|
@@ -10,17 +12,17 @@ module Pliny::Helpers
|
|
|
10
12
|
serializer_class = settings.serializer_class
|
|
11
13
|
|
|
12
14
|
if serializer_class.nil?
|
|
13
|
-
raise <<~
|
|
15
|
+
raise <<~EOS.strip
|
|
14
16
|
No serializer has been specified for this endpoint. Please specify one with
|
|
15
17
|
`serializer Serializers::ModelName` in the endpoint.
|
|
16
|
-
|
|
18
|
+
EOS
|
|
17
19
|
end
|
|
18
20
|
|
|
19
|
-
env[
|
|
21
|
+
env["pliny.serializer_arity"] = data.respond_to?(:size) ? data.size : 1
|
|
20
22
|
|
|
21
23
|
start = Time.now
|
|
22
24
|
serializer_class.new(structure).serialize(data).tap do
|
|
23
|
-
env[
|
|
25
|
+
env["pliny.serializer_timing"] = (Time.now - start).to_f
|
|
24
26
|
end
|
|
25
27
|
end
|
|
26
28
|
end
|
data/lib/pliny/log.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Pliny
|
|
2
4
|
module Log
|
|
3
5
|
def log(data, &block)
|
|
@@ -16,22 +18,20 @@ module Pliny
|
|
|
16
18
|
exception_id = e.object_id
|
|
17
19
|
|
|
18
20
|
# Log backtrace in reverse order for easier digestion.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
))
|
|
25
|
-
end
|
|
21
|
+
e.backtrace&.reverse&.each do |backtrace|
|
|
22
|
+
log_to_stream(stderr || $stderr, merge_log_contexts(
|
|
23
|
+
exception_id: exception_id,
|
|
24
|
+
backtrace: backtrace,
|
|
25
|
+
),)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
# then log the exception message last so that it's as close to the end of
|
|
29
29
|
# a log trace as possible
|
|
30
30
|
data.merge!(
|
|
31
|
-
exception:
|
|
32
|
-
class:
|
|
33
|
-
message:
|
|
34
|
-
exception_id: exception_id
|
|
31
|
+
exception: true,
|
|
32
|
+
class: e.class.name,
|
|
33
|
+
message: e.message,
|
|
34
|
+
exception_id: exception_id,
|
|
35
35
|
)
|
|
36
36
|
|
|
37
37
|
data[:status] = e.status if e.respond_to?(:status)
|
|
@@ -42,10 +42,9 @@ module Pliny
|
|
|
42
42
|
def context(data, &block)
|
|
43
43
|
old = local_context
|
|
44
44
|
self.local_context = old.merge(data)
|
|
45
|
-
|
|
45
|
+
block.call
|
|
46
46
|
ensure
|
|
47
47
|
self.local_context = old
|
|
48
|
-
res
|
|
49
48
|
end
|
|
50
49
|
|
|
51
50
|
def default_context=(default_context)
|
|
@@ -102,24 +101,26 @@ module Pliny
|
|
|
102
101
|
end
|
|
103
102
|
|
|
104
103
|
def log_to_stream(stream, data, &block)
|
|
105
|
-
|
|
106
|
-
data = log_scrubber.call(data) if log_scrubber
|
|
107
|
-
str = unparse(data)
|
|
108
|
-
stream.print(str + "\n")
|
|
109
|
-
else
|
|
104
|
+
if block
|
|
110
105
|
data = data.dup
|
|
111
106
|
start = Time.now
|
|
112
107
|
log_to_stream(stream, data.merge(at: "start"))
|
|
113
108
|
begin
|
|
114
109
|
res = yield
|
|
115
110
|
log_to_stream(stream, data.merge(
|
|
116
|
-
at: "finish", elapsed: (Time.now - start).to_f
|
|
111
|
+
at: "finish", elapsed: (Time.now - start).to_f,
|
|
112
|
+
),)
|
|
117
113
|
res
|
|
118
114
|
rescue
|
|
119
115
|
log_to_stream(stream, data.merge(
|
|
120
|
-
at: "exception", elapsed: (Time.now - start).to_f
|
|
116
|
+
at: "exception", elapsed: (Time.now - start).to_f,
|
|
117
|
+
),)
|
|
121
118
|
raise $!
|
|
122
119
|
end
|
|
120
|
+
else
|
|
121
|
+
data = log_scrubber.call(data) if log_scrubber
|
|
122
|
+
str = unparse(data)
|
|
123
|
+
stream.print(str + "\n")
|
|
123
124
|
end
|
|
124
125
|
end
|
|
125
126
|
|
|
@@ -129,11 +130,11 @@ module Pliny
|
|
|
129
130
|
|
|
130
131
|
def quote_string(v)
|
|
131
132
|
if !v.include?('"')
|
|
132
|
-
%
|
|
133
|
+
%("#{v}")
|
|
133
134
|
elsif !v.include?("'")
|
|
134
|
-
%
|
|
135
|
+
%('#{v}')
|
|
135
136
|
else
|
|
136
|
-
%
|
|
137
|
+
%("#{v.gsub('"', '\\"')}")
|
|
137
138
|
end
|
|
138
139
|
end
|
|
139
140
|
|
|
@@ -144,7 +145,7 @@ module Pliny
|
|
|
144
145
|
def unparse_pair(k, v)
|
|
145
146
|
v = v.call if v.is_a?(Proc)
|
|
146
147
|
|
|
147
|
-
if v
|
|
148
|
+
if v.nil?
|
|
148
149
|
nil
|
|
149
150
|
elsif v == true
|
|
150
151
|
k
|
|
@@ -153,7 +154,7 @@ module Pliny
|
|
|
153
154
|
elsif v.is_a?(Time)
|
|
154
155
|
"#{k}=#{v.iso8601}"
|
|
155
156
|
else
|
|
156
|
-
v =
|
|
157
|
+
v = v.to_s
|
|
157
158
|
v = replace_newlines(v)
|
|
158
159
|
v = quote_string(v) if v =~ /\s/
|
|
159
160
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Pliny
|
|
2
4
|
module Metrics
|
|
3
5
|
module Backends
|
|
@@ -10,11 +12,11 @@ module Pliny
|
|
|
10
12
|
Pliny.log(add_prefix(:measure, measures))
|
|
11
13
|
end
|
|
12
14
|
|
|
13
|
-
private
|
|
14
|
-
|
|
15
15
|
def self.add_prefix(type, metrics)
|
|
16
|
-
metrics.map { |k, v| [
|
|
16
|
+
metrics.map { |k, v| ["#{type}##{k}", v] }.to_h
|
|
17
17
|
end
|
|
18
|
+
|
|
19
|
+
private_class_method :add_prefix
|
|
18
20
|
end
|
|
19
21
|
end
|
|
20
22
|
end
|
data/lib/pliny/metrics.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Pliny
|
|
2
4
|
module Metrics
|
|
3
5
|
extend self
|
|
@@ -7,7 +9,7 @@ module Pliny
|
|
|
7
9
|
@backends = [Backends::Logger]
|
|
8
10
|
|
|
9
11
|
def count(*names, value: 1)
|
|
10
|
-
counts =
|
|
12
|
+
counts = names.map { |n| ["#{Config.app_name}.#{n}", value] }.to_h
|
|
11
13
|
|
|
12
14
|
backends.each do |backend|
|
|
13
15
|
report_and_catch { backend.report_counts(counts) }
|
|
@@ -32,7 +34,7 @@ module Pliny
|
|
|
32
34
|
0
|
|
33
35
|
end
|
|
34
36
|
|
|
35
|
-
measures =
|
|
37
|
+
measures = inputs.map { |n| ["#{Config.app_name}.#{n}", measurement] }.to_h
|
|
36
38
|
|
|
37
39
|
backends.each do |backend|
|
|
38
40
|
report_and_catch { backend.report_measures(measures) }
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Pliny::Middleware
|
|
2
4
|
# Emits a "canonical log line", i.e. a single log line that contains as much
|
|
3
5
|
# relevant information about a request as possible and which makes for a
|
|
@@ -75,7 +77,7 @@ module Pliny::Middleware
|
|
|
75
77
|
# error
|
|
76
78
|
#
|
|
77
79
|
|
|
78
|
-
if error = env["pliny.error"]
|
|
80
|
+
if (error = env["pliny.error"])
|
|
79
81
|
line.error_class = error.class.name
|
|
80
82
|
line.error_message = error.message
|
|
81
83
|
if error.is_a?(Pliny::Errors::Error)
|
|
@@ -93,7 +95,7 @@ module Pliny::Middleware
|
|
|
93
95
|
line.request_method = request.request_method
|
|
94
96
|
line.request_path = request.path_info
|
|
95
97
|
line.request_user_agent = request.user_agent
|
|
96
|
-
if route = env["sinatra.route"]
|
|
98
|
+
if (route = env["sinatra.route"])
|
|
97
99
|
line.request_route_signature = route.split(" ").last
|
|
98
100
|
end
|
|
99
101
|
|
|
@@ -101,7 +103,7 @@ module Pliny::Middleware
|
|
|
101
103
|
# response
|
|
102
104
|
#
|
|
103
105
|
|
|
104
|
-
if length = headers["Content-Length"]
|
|
106
|
+
if (length = headers["Content-Length"])
|
|
105
107
|
line.response_length = length.to_i
|
|
106
108
|
end
|
|
107
109
|
line.response_status = status
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Pliny::Middleware
|
|
2
4
|
class CORS
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
%w( Content-Type Accept Authorization Cache-Control If-None-Match If-Modified-Since Origin).freeze
|
|
5
|
+
ALLOW_METHODS =
|
|
6
|
+
%w[GET POST PUT PATCH DELETE OPTIONS].freeze
|
|
7
|
+
ALLOW_HEADERS =
|
|
8
|
+
%w[Content-Type Accept Authorization Cache-Control If-None-Match If-Modified-Since Origin].freeze
|
|
8
9
|
EXPOSE_HEADERS =
|
|
9
|
-
%w
|
|
10
|
+
%w[Cache-Control Content-Language Content-Type Expires Last-Modified Pragma].freeze
|
|
10
11
|
|
|
11
12
|
@@additional_headers = []
|
|
12
13
|
|
|
@@ -44,12 +45,12 @@ module Pliny::Middleware
|
|
|
44
45
|
|
|
45
46
|
def cors_headers(env)
|
|
46
47
|
{
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
"access-control-allow-origin" => env["HTTP_ORIGIN"],
|
|
49
|
+
"access-control-allow-methods" => ALLOW_METHODS.join(", "),
|
|
50
|
+
"access-control-allow-headers" => allow_headers.join(", "),
|
|
51
|
+
"access-control-allow-credentials" => "true",
|
|
52
|
+
"access-control-max-age" => "1728000",
|
|
53
|
+
"access-control-expose-headers" => EXPOSE_HEADERS.join(", "),
|
|
53
54
|
}
|
|
54
55
|
end
|
|
55
56
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Pliny::Middleware
|
|
2
4
|
class Instruments
|
|
3
5
|
def initialize(app)
|
|
@@ -9,24 +11,24 @@ module Pliny::Middleware
|
|
|
9
11
|
|
|
10
12
|
data = {
|
|
11
13
|
instrumentation: true,
|
|
12
|
-
method:
|
|
13
|
-
path:
|
|
14
|
+
method: env["REQUEST_METHOD"],
|
|
15
|
+
path: env["PATH_INFO"],
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
Pliny.log(data.merge(at: "start"))
|
|
17
19
|
|
|
18
20
|
status, headers, response = @app.call(env)
|
|
19
21
|
|
|
20
|
-
if route = env["sinatra.route"]
|
|
22
|
+
if (route = env["sinatra.route"])
|
|
21
23
|
data.merge!(route_signature: route.split(" ").last)
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
elapsed = (Time.now - start).to_f
|
|
25
27
|
Pliny.log(data.merge(
|
|
26
|
-
at:
|
|
27
|
-
status:
|
|
28
|
-
length:
|
|
29
|
-
elapsed:
|
|
28
|
+
at: "finish",
|
|
29
|
+
status: status,
|
|
30
|
+
length: headers["Content-Length"],
|
|
31
|
+
elapsed: elapsed,
|
|
30
32
|
))
|
|
31
33
|
|
|
32
34
|
[status, headers, response]
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Pliny::Middleware
|
|
2
4
|
class Metrics
|
|
3
5
|
def initialize(app)
|
|
@@ -18,7 +20,7 @@ module Pliny::Middleware
|
|
|
18
20
|
elapsed = (Time.now - start).to_f
|
|
19
21
|
Pliny::Metrics.measure("requests.latency", value: elapsed)
|
|
20
22
|
|
|
21
|
-
status_level = "#{status/100}xx"
|
|
23
|
+
status_level = "#{status / 100}xx"
|
|
22
24
|
Pliny::Metrics.count("requests.status.#{status_level}")
|
|
23
25
|
end
|
|
24
26
|
|