hanami 2.0.0.alpha4 → 2.0.0.alpha7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +256 -0
- data/README.md +3 -7
- data/hanami.gemspec +5 -4
- data/lib/hanami/application/container/{boot → providers}/inflector.rb +1 -1
- data/lib/hanami/application/container/{boot → providers}/logger.rb +1 -1
- data/lib/hanami/application/container/providers/rack_logger.rb +15 -0
- data/lib/hanami/application/container/{boot → providers}/rack_monitor.rb +2 -2
- data/lib/hanami/application/container/{boot → providers}/routes_helper.rb +1 -1
- data/lib/hanami/application/container/{boot → providers}/settings.rb +1 -1
- data/lib/hanami/application/router.rb +7 -7
- data/lib/hanami/application/routing/router.rb +36 -0
- data/lib/hanami/application/slice_registrar.rb +107 -0
- data/lib/hanami/application.rb +124 -202
- data/lib/hanami/boot/source_dirs.rb +44 -0
- data/lib/hanami/cli/application/cli.rb +1 -1
- data/lib/hanami/configuration/actions.rb +90 -0
- data/lib/hanami/configuration/logger.rb +49 -5
- data/lib/hanami/configuration/source_dirs.rb +42 -0
- data/lib/hanami/configuration.rb +19 -24
- data/lib/hanami/constants.rb +23 -0
- data/lib/hanami/errors.rb +12 -0
- data/lib/hanami/{init.rb → prepare.rb} +1 -1
- data/lib/hanami/slice.rb +198 -112
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +27 -51
- data/lib/hanami.rb +19 -29
- metadata +23 -16
- data/lib/hanami/application/autoloader/inflector_adapter.rb +0 -22
- data/lib/hanami/application/container/boot/rack_logger.rb +0 -19
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/configurable"
|
4
|
+
require "dry/system/config/component_dirs"
|
5
|
+
|
6
|
+
module Hanami
|
7
|
+
class Configuration
|
8
|
+
# Configuration for slice source dirs
|
9
|
+
#
|
10
|
+
# @since 2.0.0
|
11
|
+
class SourceDirs
|
12
|
+
DEFAULT_COMPONENT_DIR_PATHS = %w[lib actions repositories views].freeze
|
13
|
+
private_constant :DEFAULT_COMPONENT_DIR_PATHS
|
14
|
+
|
15
|
+
include Dry::Configurable
|
16
|
+
|
17
|
+
setting :component_dirs,
|
18
|
+
default: Dry::System::Config::ComponentDirs.new.tap { |dirs|
|
19
|
+
DEFAULT_COMPONENT_DIR_PATHS.each do |path|
|
20
|
+
dirs.add path
|
21
|
+
end
|
22
|
+
},
|
23
|
+
cloneable: true
|
24
|
+
|
25
|
+
setting :autoload_paths, default: %w[entities]
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def method_missing(name, *args, &block)
|
30
|
+
if config.respond_to?(name)
|
31
|
+
config.public_send(name, *args, &block)
|
32
|
+
else
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def respond_to_missing?(name, _include_all = false)
|
38
|
+
config.respond_to?(name) || super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/hanami/configuration.rb
CHANGED
@@ -12,6 +12,8 @@ require_relative "configuration/logger"
|
|
12
12
|
require_relative "configuration/middleware"
|
13
13
|
require_relative "configuration/router"
|
14
14
|
require_relative "configuration/sessions"
|
15
|
+
require_relative "configuration/source_dirs"
|
16
|
+
require_relative "constants"
|
15
17
|
|
16
18
|
module Hanami
|
17
19
|
# Hanami application configuration
|
@@ -25,6 +27,8 @@ module Hanami
|
|
25
27
|
DEFAULT_ENVIRONMENTS = Concurrent::Hash.new { |h, k| h[k] = Concurrent::Array.new }
|
26
28
|
private_constant :DEFAULT_ENVIRONMENTS
|
27
29
|
|
30
|
+
attr_reader :env
|
31
|
+
|
28
32
|
attr_reader :actions
|
29
33
|
attr_reader :middleware
|
30
34
|
attr_reader :router
|
@@ -33,15 +37,19 @@ module Hanami
|
|
33
37
|
attr_reader :environments
|
34
38
|
private :environments
|
35
39
|
|
36
|
-
def initialize(env:)
|
40
|
+
def initialize(application_name:, env:)
|
41
|
+
@namespace = application_name.split(MODULE_DELIMITER)[0..-2].join(MODULE_DELIMITER)
|
42
|
+
|
37
43
|
@environments = DEFAULT_ENVIRONMENTS.clone
|
38
|
-
|
44
|
+
@env = env
|
39
45
|
|
40
46
|
# Some default setting values must be assigned at initialize-time to ensure they
|
41
47
|
# have appropriate values for the current application
|
42
48
|
self.root = Dir.pwd
|
43
49
|
self.settings_store = Application::Settings::DotenvStore.new.with_dotenv_loaded
|
44
50
|
|
51
|
+
config.logger = Configuration::Logger.new(env: env, application_name: method(:application_name))
|
52
|
+
|
45
53
|
@assets = begin
|
46
54
|
require_path = "hanami/assets/application_configuration"
|
47
55
|
require require_path
|
@@ -101,29 +109,30 @@ module Hanami
|
|
101
109
|
super
|
102
110
|
end
|
103
111
|
|
104
|
-
|
112
|
+
def namespace
|
113
|
+
inflector.constantize(@namespace)
|
114
|
+
end
|
105
115
|
|
106
|
-
def
|
107
|
-
|
108
|
-
apply_env_config(new_env)
|
116
|
+
def application_name
|
117
|
+
inflector.underscore(@namespace).to_sym
|
109
118
|
end
|
110
119
|
|
111
120
|
setting :root, constructor: -> path { Pathname(path) }
|
112
121
|
|
113
|
-
setting :inflector, default: Dry::Inflector.new
|
122
|
+
setting :inflector, default: Dry::Inflector.new
|
114
123
|
|
115
124
|
def inflections(&block)
|
116
125
|
self.inflector = Dry::Inflector.new(&block)
|
117
126
|
end
|
118
127
|
|
119
|
-
setting :logger,
|
128
|
+
setting :logger, cloneable: true
|
120
129
|
|
121
130
|
def logger=(logger_instance)
|
122
131
|
@logger_instance = logger_instance
|
123
132
|
end
|
124
133
|
|
125
134
|
def logger_instance
|
126
|
-
@logger_instance || logger.
|
135
|
+
@logger_instance || logger.instance
|
127
136
|
end
|
128
137
|
|
129
138
|
setting :settings_path, default: File.join("config", "settings")
|
@@ -132,21 +141,7 @@ module Hanami
|
|
132
141
|
|
133
142
|
setting :settings_store, default: Application::Settings::DotenvStore
|
134
143
|
|
135
|
-
setting :
|
136
|
-
|
137
|
-
setting :slices_namespace, default: Object
|
138
|
-
|
139
|
-
# TODO: convert into a dedicated object with explicit behaviour around blocks per
|
140
|
-
# slice, etc.
|
141
|
-
setting :slices, default: {}, constructor: :dup.to_proc
|
142
|
-
|
143
|
-
# TODO: turn this into a richer "source dirs" setting that can support enabling
|
144
|
-
# of container component loading as an opt in behvior
|
145
|
-
setting :component_dir_paths, default: %w[actions repositories views]
|
146
|
-
|
147
|
-
def slice(slice_name, &block)
|
148
|
-
slices[slice_name] = block
|
149
|
-
end
|
144
|
+
setting :source_dirs, default: Configuration::SourceDirs.new, cloneable: true
|
150
145
|
|
151
146
|
setting :base_url, default: "http://0.0.0.0:2300", constructor: -> url { URI(url) }
|
152
147
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
# @api private
|
5
|
+
MODULE_DELIMITER = "::"
|
6
|
+
private_constant :MODULE_DELIMITER
|
7
|
+
|
8
|
+
# @api private
|
9
|
+
CONFIG_DIR = "config"
|
10
|
+
private_constant :CONFIG_DIR
|
11
|
+
|
12
|
+
# @api private
|
13
|
+
SLICES_DIR = "slices"
|
14
|
+
private_constant :SLICES_DIR
|
15
|
+
|
16
|
+
# @api private
|
17
|
+
LIB_DIR = "lib"
|
18
|
+
private_constant :LIB_DIR
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
RB_EXT = ".rb"
|
22
|
+
private_constant :RB_EXT
|
23
|
+
end
|
data/lib/hanami/slice.rb
CHANGED
@@ -1,167 +1,253 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "dry/system/container"
|
4
|
-
require "
|
4
|
+
require "hanami/errors"
|
5
5
|
require "pathname"
|
6
|
+
require_relative "constants"
|
6
7
|
|
7
8
|
module Hanami
|
8
9
|
# Distinct area of concern within an Hanami application
|
9
10
|
#
|
10
11
|
# @since 2.0.0
|
11
12
|
class Slice
|
12
|
-
|
13
|
-
|
14
|
-
def initialize(application, name:, namespace: nil, root: nil, container: nil)
|
15
|
-
@application = application
|
16
|
-
@name = name.to_sym
|
17
|
-
@namespace = namespace
|
18
|
-
@root = root ? Pathname(root) : root
|
19
|
-
@container = container || define_container
|
20
|
-
end
|
13
|
+
def self.inherited(klass)
|
14
|
+
super
|
21
15
|
|
22
|
-
|
23
|
-
application.inflector
|
24
|
-
end
|
16
|
+
klass.extend(ClassMethods)
|
25
17
|
|
26
|
-
|
27
|
-
|
18
|
+
# Eagerly initialize any variables that may be accessed inside the subclass body
|
19
|
+
klass.instance_variable_set(:@application, Hanami.application)
|
20
|
+
klass.instance_variable_set(:@container, Class.new(Dry::System::Container))
|
28
21
|
end
|
29
22
|
|
30
|
-
|
31
|
-
|
23
|
+
# rubocop:disable Metrics/ModuleLength
|
24
|
+
module ClassMethods
|
25
|
+
attr_reader :application, :container
|
32
26
|
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
def slice_name
|
28
|
+
inflector.underscore(name.split(MODULE_DELIMITER)[-2]).to_sym
|
29
|
+
end
|
36
30
|
|
37
|
-
|
38
|
-
|
39
|
-
container.config.env = application.container.config.env
|
31
|
+
def namespace
|
32
|
+
inflector.constantize(name.split(MODULE_DELIMITER)[0..-2].join(MODULE_DELIMITER))
|
40
33
|
end
|
41
34
|
|
42
|
-
|
43
|
-
|
44
|
-
|
35
|
+
def namespace_path
|
36
|
+
inflector.underscore(namespace)
|
37
|
+
end
|
45
38
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
# rubocop:enable Style/DoubleNegation
|
39
|
+
def root
|
40
|
+
application.root.join(SLICES_DIR, slice_name.to_s)
|
41
|
+
end
|
51
42
|
|
52
|
-
|
53
|
-
|
54
|
-
|
43
|
+
def inflector
|
44
|
+
application.inflector
|
45
|
+
end
|
46
|
+
|
47
|
+
def prepare(provider_name = nil)
|
48
|
+
container.prepare(provider_name) and return self if provider_name
|
49
|
+
|
50
|
+
return self if prepared?
|
51
|
+
|
52
|
+
ensure_slice_name
|
53
|
+
ensure_slice_consts
|
55
54
|
|
56
|
-
|
57
|
-
raise "Cannot import after booting" if booted?
|
55
|
+
prepare_all
|
58
56
|
|
59
|
-
|
60
|
-
|
57
|
+
@prepared = true
|
58
|
+
self
|
61
59
|
end
|
62
|
-
end
|
63
60
|
|
64
|
-
|
65
|
-
|
66
|
-
|
61
|
+
def prepare_container(&block)
|
62
|
+
@prepare_container_block = block
|
63
|
+
end
|
67
64
|
|
68
|
-
|
69
|
-
|
70
|
-
end
|
65
|
+
def boot
|
66
|
+
return self if booted?
|
71
67
|
|
72
|
-
|
73
|
-
container.init(*args)
|
74
|
-
end
|
68
|
+
container.finalize!
|
75
69
|
|
76
|
-
|
77
|
-
container.start(*args)
|
78
|
-
end
|
70
|
+
@booted = true
|
79
71
|
|
80
|
-
|
81
|
-
|
82
|
-
end
|
72
|
+
self
|
73
|
+
end
|
83
74
|
|
84
|
-
|
85
|
-
|
86
|
-
|
75
|
+
def shutdown
|
76
|
+
container.shutdown!
|
77
|
+
self
|
78
|
+
end
|
87
79
|
|
88
|
-
|
89
|
-
|
90
|
-
|
80
|
+
def prepared?
|
81
|
+
!!@prepared
|
82
|
+
end
|
91
83
|
|
92
|
-
|
93
|
-
|
94
|
-
|
84
|
+
def booted?
|
85
|
+
!!@booted
|
86
|
+
end
|
95
87
|
|
96
|
-
|
88
|
+
def register(...)
|
89
|
+
container.register(...)
|
90
|
+
end
|
97
91
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
container.use :env
|
92
|
+
def register_provider(...)
|
93
|
+
container.register_provider(...)
|
94
|
+
end
|
102
95
|
|
103
|
-
|
104
|
-
|
105
|
-
|
96
|
+
def start(...)
|
97
|
+
container.start(...)
|
98
|
+
end
|
106
99
|
|
107
|
-
|
108
|
-
|
100
|
+
def key?(...)
|
101
|
+
container.key?(...)
|
102
|
+
end
|
109
103
|
|
110
|
-
|
111
|
-
|
112
|
-
|
104
|
+
def keys
|
105
|
+
container.keys
|
106
|
+
end
|
113
107
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
# Expect component files in the root of the lib
|
118
|
-
# component dir to define classes inside the slice's namespace.
|
119
|
-
#
|
120
|
-
# e.g. "lib/foo.rb" should define SliceNamespace::Foo, and will be
|
121
|
-
# registered as "foo"
|
122
|
-
component_dir.namespaces.root(key: nil, const: namespace_path)
|
108
|
+
def [](...)
|
109
|
+
container.[](...)
|
110
|
+
end
|
123
111
|
|
124
|
-
|
125
|
-
|
112
|
+
def resolve(...)
|
113
|
+
container.resolve(...)
|
114
|
+
end
|
115
|
+
|
116
|
+
def export(keys)
|
117
|
+
container.config.exports = keys
|
118
|
+
end
|
119
|
+
|
120
|
+
def import(from:, **kwargs)
|
121
|
+
# TODO: This should be handled via dry-system (see dry-rb/dry-system#228)
|
122
|
+
raise "Cannot import after booting" if booted?
|
123
|
+
|
124
|
+
application = self.application
|
125
|
+
|
126
|
+
container.after(:configure) do
|
127
|
+
if from.is_a?(Symbol) || from.is_a?(String)
|
128
|
+
slice_name = from
|
129
|
+
from = application.slices[from.to_sym].container
|
126
130
|
end
|
127
131
|
|
128
|
-
|
129
|
-
|
130
|
-
|
132
|
+
as = kwargs[:as] || slice_name
|
133
|
+
|
134
|
+
import(from: from, as: as, **kwargs)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def ensure_slice_name
|
141
|
+
unless name
|
142
|
+
raise SliceLoadError, "Slice must have a class name before it can be prepared"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def ensure_slice_consts
|
147
|
+
if namespace.const_defined?(:Container) || namespace.const_defined?(:Deps)
|
148
|
+
raise(
|
149
|
+
SliceLoadError,
|
150
|
+
"#{namespace}::Container and #{namespace}::Deps constants must not already be defined"
|
151
|
+
)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def prepare_all
|
156
|
+
prepare_container_plugins
|
157
|
+
prepare_container_base_config
|
158
|
+
prepare_container_component_dirs
|
159
|
+
prepare_autoloader
|
160
|
+
prepare_container_imports
|
161
|
+
prepare_container_consts
|
162
|
+
instance_exec(container, &@prepare_container_block) if @prepare_container_block
|
163
|
+
container.configured!
|
164
|
+
end
|
165
|
+
|
166
|
+
def prepare_container_plugins
|
167
|
+
container.use(:env, inferrer: -> { Hanami.env })
|
168
|
+
|
169
|
+
container.use(
|
170
|
+
:zeitwerk,
|
171
|
+
loader: application.autoloader,
|
172
|
+
run_setup: false,
|
173
|
+
eager_load: false
|
174
|
+
)
|
175
|
+
end
|
176
|
+
|
177
|
+
def prepare_container_base_config
|
178
|
+
container.config.name = slice_name
|
179
|
+
container.config.root = root
|
180
|
+
container.config.provider_dirs = [File.join("config", "providers")]
|
181
|
+
|
182
|
+
container.config.env = application.configuration.env
|
183
|
+
container.config.inflector = application.configuration.inflector
|
184
|
+
end
|
185
|
+
|
186
|
+
def prepare_container_component_dirs # rubocop:disable Metrics/AbcSize
|
187
|
+
return unless root&.directory?
|
188
|
+
|
189
|
+
# Add component dirs for each configured component path
|
190
|
+
application.configuration.source_dirs.component_dirs.each do |component_dir|
|
191
|
+
next unless root.join(component_dir.path).directory?
|
192
|
+
|
193
|
+
component_dir = component_dir.dup
|
194
|
+
|
195
|
+
if component_dir.path == LIB_DIR
|
196
|
+
# Expect component files in the root of the lib/ component dir to define
|
197
|
+
# classes inside the slice's namespace.
|
198
|
+
#
|
199
|
+
# e.g. "lib/foo.rb" should define SliceNamespace::Foo, to be registered as
|
200
|
+
# "foo"
|
201
|
+
component_dir.namespaces.delete_root
|
202
|
+
component_dir.namespaces.add_root(key: nil, const: namespace_path)
|
203
|
+
else
|
204
|
+
# Expect component files in the root of non-lib/ component dirs to define
|
205
|
+
# classes inside a namespace matching that dir.
|
206
|
+
#
|
207
|
+
# e.g. "actions/foo.rb" should define SliceNamespace::Actions::Foo, to be
|
208
|
+
# registered as "actions.foo"
|
209
|
+
|
210
|
+
dir_namespace_path = File.join(namespace_path, component_dir.path)
|
211
|
+
|
212
|
+
component_dir.namespaces.delete_root
|
213
|
+
component_dir.namespaces.add_root(const: dir_namespace_path, key: component_dir.path)
|
214
|
+
end
|
131
215
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
#
|
136
|
-
# e.g. "actions/foo.rb" should define SliceNamespace::Actions::Foo, and
|
137
|
-
# will be registered as "actions.foo"
|
216
|
+
container.config.component_dirs.add(component_dir)
|
217
|
+
end
|
218
|
+
end
|
138
219
|
|
139
|
-
|
220
|
+
def prepare_autoloader # rubocop:disable Metrics/AbcSize
|
221
|
+
return unless root&.directory?
|
140
222
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
namespace.const_set(inflector.camelize(slice_dir), Module.new)
|
145
|
-
end
|
223
|
+
# Pass configured autoload dirs to the autoloader
|
224
|
+
application.configuration.source_dirs.autoload_paths.each do |autoload_path|
|
225
|
+
next unless root.join(autoload_path).directory?
|
146
226
|
|
147
|
-
|
227
|
+
dir_namespace_path = File.join(namespace_path, autoload_path)
|
148
228
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
end
|
229
|
+
autoloader_namespace = begin
|
230
|
+
inflector.constantize(inflector.camelize(dir_namespace_path))
|
231
|
+
rescue NameError
|
232
|
+
namespace.const_set(inflector.camelize(autoload_path), Module.new)
|
154
233
|
end
|
234
|
+
|
235
|
+
container.config.autoloader.push_dir(
|
236
|
+
container.root.join(autoload_path),
|
237
|
+
namespace: autoloader_namespace
|
238
|
+
)
|
155
239
|
end
|
156
240
|
end
|
157
241
|
|
158
|
-
|
242
|
+
def prepare_container_imports
|
243
|
+
container.import from: application.container, as: :application
|
244
|
+
end
|
245
|
+
|
246
|
+
def prepare_container_consts
|
159
247
|
namespace.const_set :Container, container
|
160
248
|
namespace.const_set :Deps, container.injector
|
161
249
|
end
|
162
|
-
|
163
|
-
container
|
164
250
|
end
|
165
|
-
# rubocop:enable Metrics/
|
251
|
+
# rubocop:enable Metrics/ModuleLength
|
166
252
|
end
|
167
253
|
end
|
data/lib/hanami/version.rb
CHANGED
@@ -1,19 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "json"
|
4
|
-
require "rack/request"
|
5
|
-
require "hanami/utils/hash"
|
6
|
-
|
7
3
|
module Hanami
|
8
4
|
module Web
|
9
5
|
# Rack logger for Hanami applications
|
10
6
|
class RackLogger
|
11
|
-
|
12
|
-
|
7
|
+
REQUEST_METHOD = "REQUEST_METHOD"
|
8
|
+
private_constant :REQUEST_METHOD
|
9
|
+
|
10
|
+
HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
|
11
|
+
private_constant :HTTP_X_FORWARDED_FOR
|
12
|
+
|
13
|
+
REMOTE_ADDR = "REMOTE_ADDR"
|
14
|
+
private_constant :REMOTE_ADDR
|
15
|
+
|
16
|
+
SCRIPT_NAME = "SCRIPT_NAME"
|
17
|
+
private_constant :SCRIPT_NAME
|
18
|
+
|
19
|
+
PATH_INFO = "PATH_INFO"
|
20
|
+
private_constant :PATH_INFO
|
21
|
+
|
22
|
+
ROUTER_PARAMS = "router.params"
|
23
|
+
private_constant :ROUTER_PARAMS
|
24
|
+
|
25
|
+
CONTENT_LENGTH = "Content-Length"
|
26
|
+
private_constant :CONTENT_LENGTH
|
13
27
|
|
14
|
-
def initialize(logger
|
28
|
+
def initialize(logger)
|
15
29
|
@logger = logger
|
16
|
-
@filter_params = filter_params
|
17
30
|
end
|
18
31
|
|
19
32
|
def attach(rack_monitor)
|
@@ -26,22 +39,20 @@ module Hanami
|
|
26
39
|
end
|
27
40
|
end
|
28
41
|
|
29
|
-
|
30
|
-
def log_request(env, status, time)
|
42
|
+
def log_request(env, status, elapsed)
|
31
43
|
data = {
|
32
|
-
http: env[HTTP_VERSION],
|
33
44
|
verb: env[REQUEST_METHOD],
|
34
45
|
status: status,
|
46
|
+
elapsed: "#{elapsed}ms",
|
35
47
|
ip: env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR],
|
36
48
|
path: env[SCRIPT_NAME] + env[PATH_INFO].to_s,
|
37
49
|
length: extract_content_length(env),
|
38
|
-
params:
|
39
|
-
|
50
|
+
params: env[ROUTER_PARAMS],
|
51
|
+
time: Time.now,
|
40
52
|
}
|
41
53
|
|
42
|
-
logger.info
|
54
|
+
logger.info(data)
|
43
55
|
end
|
44
|
-
# rubocop:enable Metrics/MethodLength
|
45
56
|
|
46
57
|
def log_exception(exception)
|
47
58
|
logger.error exception.message
|
@@ -50,47 +61,12 @@ module Hanami
|
|
50
61
|
|
51
62
|
private
|
52
63
|
|
53
|
-
|
54
|
-
REQUEST_METHOD = "REQUEST_METHOD"
|
55
|
-
HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
|
56
|
-
REMOTE_ADDR = "REMOTE_ADDR"
|
57
|
-
SCRIPT_NAME = "SCRIPT_NAME"
|
58
|
-
PATH_INFO = "PATH_INFO"
|
59
|
-
RACK_ERRORS = "rack.errors"
|
60
|
-
QUERY_HASH = "rack.request.query_hash"
|
61
|
-
FORM_HASH = "rack.request.form_hash"
|
62
|
-
ROUTER_PARAMS = "router.params"
|
63
|
-
CONTENT_LENGTH = "Content-Length"
|
64
|
+
attr_reader :logger
|
64
65
|
|
65
66
|
def extract_content_length(env)
|
66
67
|
value = env[CONTENT_LENGTH]
|
67
68
|
!value || value.to_s == "0" ? "-" : value
|
68
69
|
end
|
69
|
-
|
70
|
-
def extract_params(env)
|
71
|
-
result = env.fetch(QUERY_HASH, {})
|
72
|
-
result.merge!(env.fetch(FORM_HASH, {}))
|
73
|
-
result.merge!(Hanami::Utils::Hash.deep_stringify(env.fetch(ROUTER_PARAMS, {})))
|
74
|
-
result
|
75
|
-
end
|
76
|
-
|
77
|
-
FILTERED = "[FILTERED]"
|
78
|
-
|
79
|
-
# rubocop:disable Metrics/MethodLength
|
80
|
-
def filter(params)
|
81
|
-
params.each_with_object({}) do |(k, v), h|
|
82
|
-
if filter_params.include?(k)
|
83
|
-
h.update(k => FILTERED)
|
84
|
-
elsif v.is_a?(Hash)
|
85
|
-
h.update(k => filter(v))
|
86
|
-
elsif v.is_a?(Array)
|
87
|
-
h.update(k => v.map { |m| m.is_a?(Hash) ? filter(m) : m })
|
88
|
-
else
|
89
|
-
h[k] = v
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
# rubocop:enable Metrics/MethodLength
|
94
70
|
end
|
95
71
|
end
|
96
72
|
end
|