bbk-app 1.0.0.72899
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/Gemfile +7 -0
- data/Gemfile.lock +177 -0
- data/README.md +38 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/bbk/app/dispatcher/message.rb +47 -0
- data/lib/bbk/app/dispatcher/message_stream.rb +42 -0
- data/lib/bbk/app/dispatcher/queue_stream_strategy.rb +54 -0
- data/lib/bbk/app/dispatcher/result.rb +20 -0
- data/lib/bbk/app/dispatcher/route.rb +37 -0
- data/lib/bbk/app/dispatcher.rb +210 -0
- data/lib/bbk/app/factory.rb +26 -0
- data/lib/bbk/app/handler.rb +69 -0
- data/lib/bbk/app/matchers/base.rb +50 -0
- data/lib/bbk/app/matchers/delivery_info.rb +35 -0
- data/lib/bbk/app/matchers/full.rb +41 -0
- data/lib/bbk/app/matchers/headers.rb +23 -0
- data/lib/bbk/app/matchers/payload.rb +23 -0
- data/lib/bbk/app/matchers.rb +28 -0
- data/lib/bbk/app/middlewares/active_record_pool.rb +21 -0
- data/lib/bbk/app/middlewares/base.rb +20 -0
- data/lib/bbk/app/middlewares/from_block.rb +26 -0
- data/lib/bbk/app/middlewares/self_killer.rb +66 -0
- data/lib/bbk/app/middlewares/watchdog.rb +78 -0
- data/lib/bbk/app/middlewares.rb +12 -0
- data/lib/bbk/app/processors/base.rb +46 -0
- data/lib/bbk/app/processors/ping.rb +26 -0
- data/lib/bbk/app/processors/pong.rb +16 -0
- data/lib/bbk/app/processors.rb +3 -0
- data/lib/bbk/app/proxy_logger.rb +42 -0
- data/lib/bbk/app/thread_pool.rb +75 -0
- data/lib/bbk/app/version.rb +8 -0
- data/lib/bbk/app.rb +23 -0
- data/sig/bbk/app/callable.rbs +3 -0
- data/sig/bbk/app/dispatcher/message.rbs +33 -0
- data/sig/bbk/app/dispatcher/message_stream.rbs +15 -0
- data/sig/bbk/app/dispatcher/queue_stream_strategy.rbs +12 -0
- data/sig/bbk/app/dispatcher/result.rbs +12 -0
- data/sig/bbk/app/dispatcher/route.rbs +18 -0
- data/sig/bbk/app/dispatcher/stream_strategy.rbs +13 -0
- data/sig/bbk/app/dispatcher.rbs +62 -0
- data/sig/bbk/app/factory.rbs +21 -0
- data/sig/bbk/app/handler.rbs +19 -0
- data/sig/bbk/app/matchers.rbs +12 -0
- data/sig/bbk/app/middlewares/self_killer.rbs +26 -0
- data/sig/bbk/app/middlewares/watchdog.rbs +40 -0
- data/sig/bbk/app/processors/base.rbs +21 -0
- metadata +327 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
module BBK
|
2
|
+
module App
|
3
|
+
class Handler
|
4
|
+
|
5
|
+
def initialize(&block)
|
6
|
+
@handlers = {}
|
7
|
+
@default = if block_given?
|
8
|
+
block
|
9
|
+
else
|
10
|
+
lambda do |*_args|
|
11
|
+
# delivery_info, properties, body = message
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# регистрация обработчика
|
17
|
+
# тип матчера, парметры матчера, Обработчик | Класс обработчика, [аргументы обработчика]
|
18
|
+
def register(*args, **kwargs, &block)
|
19
|
+
type, rule, callable = nil
|
20
|
+
|
21
|
+
if args.first.respond_to?(:rule)
|
22
|
+
type, *rule = args.first.rule
|
23
|
+
elsif args.first.is_a?(Symbol) || args.first.is_a?(String)
|
24
|
+
type = args.shift.to_sym
|
25
|
+
rule = args.shift
|
26
|
+
if rule.nil?
|
27
|
+
$logger&.warn("Not found processor rule in positional arguments. Use keyword arguments #{kwargs} as rule")
|
28
|
+
rule = kwargs
|
29
|
+
kwargs = {}
|
30
|
+
end
|
31
|
+
raise "rule is not a Hash: #{args.inspect}" unless rule.is_a?(Hash)
|
32
|
+
else
|
33
|
+
raise "type and rule or method :rule missing: #{args.inspect}"
|
34
|
+
end
|
35
|
+
args.push block if block_given?
|
36
|
+
|
37
|
+
callable = if args.first.is_a?(Class)
|
38
|
+
BBK::App::Factory.new(*args, **kwargs)
|
39
|
+
elsif args.first.respond_to?(:call)
|
40
|
+
args.first
|
41
|
+
else
|
42
|
+
raise "callable object or class missing: #{args.inspect}"
|
43
|
+
end
|
44
|
+
|
45
|
+
matcher = BBK::App::Matchers.create(type, *[rule].flatten)
|
46
|
+
@handlers.each do |m, _c|
|
47
|
+
$logger&.warn("Handler with same matcher already registered: #{m.inspect}") if m == matcher
|
48
|
+
end
|
49
|
+
|
50
|
+
@handlers[BBK::App::Matchers.create(type, *[rule].flatten)] = callable
|
51
|
+
end
|
52
|
+
|
53
|
+
def default(&block)
|
54
|
+
@default = block
|
55
|
+
end
|
56
|
+
|
57
|
+
def match(metadata, payload, delivery_info)
|
58
|
+
@handlers.each_with_object([nil, @default]) do |p, _res|
|
59
|
+
m, h = p
|
60
|
+
if (match = m.match(metadata, payload, delivery_info))
|
61
|
+
return [match, h]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module BBK
|
2
|
+
module App
|
3
|
+
module Matchers
|
4
|
+
class Base
|
5
|
+
|
6
|
+
attr_reader :rule
|
7
|
+
|
8
|
+
def hash
|
9
|
+
(self.class.to_s + rule.to_s).hash
|
10
|
+
end
|
11
|
+
|
12
|
+
def ==(other)
|
13
|
+
self.class == other.class && rule == other.rule
|
14
|
+
end
|
15
|
+
|
16
|
+
def eql?(other)
|
17
|
+
self == other
|
18
|
+
end
|
19
|
+
|
20
|
+
def keys_deep(data)
|
21
|
+
data.inject([]) do |res, p|
|
22
|
+
k, _v = p
|
23
|
+
res.push k
|
24
|
+
res += keys_deep(data[k]) if data[k].is_a? Hash
|
25
|
+
res
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def match_impl(rule, data)
|
30
|
+
result = rule.each_with_object({}.with_indifferent_access) do |p, res|
|
31
|
+
k, v = p
|
32
|
+
|
33
|
+
if v == :any && data.key?(k.to_sym)
|
34
|
+
res[k.to_sym] = data[k.to_sym]
|
35
|
+
elsif v.is_a? Hash
|
36
|
+
res[k.to_sym] = match_impl(v, data[k.to_sym] || {})
|
37
|
+
elsif v == data[k.to_sym]
|
38
|
+
res[k.to_sym] = data[k.to_sym]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
result.keys.size == rule.keys.size && keys_deep(result).count >= keys_deep(rule).count ? result : nil
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'bbk/app/matchers/base'
|
2
|
+
|
3
|
+
module BBK
|
4
|
+
module App
|
5
|
+
module Matchers
|
6
|
+
class DeliveryInfo < Base
|
7
|
+
|
8
|
+
|
9
|
+
def initialize(rule)
|
10
|
+
@rule = rule.with_indifferent_access
|
11
|
+
end
|
12
|
+
|
13
|
+
def match(_headers, _payload, delivery_info, *_args)
|
14
|
+
delivery_info = delivery_info.to_hash unless delivery_info.is_a? Hash
|
15
|
+
match_impl(@rule, delivery_info.with_indifferent_access)
|
16
|
+
rescue StandardError
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def match_impl(rule, data)
|
21
|
+
result = super
|
22
|
+
if !result && (key_rule = rule[:routing_key])
|
23
|
+
regexp_rule = Regexp.new("\\A#{key_rule.gsub('.', '\.').gsub('*', '\S+').gsub('#',
|
24
|
+
'.*')}\\Z")
|
25
|
+
check = regexp_rule.match?(data[:routing_key])
|
26
|
+
result = ({ 'routing_key' => data[:routing_key] } if check)
|
27
|
+
end
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'bbk/app/matchers/headers'
|
2
|
+
require 'bbk/app/matchers/payload'
|
3
|
+
require 'bbk/app/matchers/delivery_info'
|
4
|
+
|
5
|
+
module BBK
|
6
|
+
module App
|
7
|
+
module Matchers
|
8
|
+
class Full < Base
|
9
|
+
|
10
|
+
def initialize(*args)
|
11
|
+
if args.size == 1
|
12
|
+
arg = args[0]
|
13
|
+
hrule = arg.fetch(:headers, {})
|
14
|
+
prule = arg.fetch(:payload, {})
|
15
|
+
drule = arg.fetch(:delivery_info, {})
|
16
|
+
else
|
17
|
+
hrule, prule, drule = *args
|
18
|
+
end
|
19
|
+
|
20
|
+
@hm = Headers.new(hrule)
|
21
|
+
@pm = Payload.new(prule)
|
22
|
+
@dm = DeliveryInfo.new(drule)
|
23
|
+
@rule = [hrule, prule, drule]
|
24
|
+
end
|
25
|
+
|
26
|
+
def match(headers, payload, delivery_info, *_args)
|
27
|
+
return unless (hr = @hm.match(headers, payload, delivery_info))
|
28
|
+
return unless (pr = @pm.match(headers, payload, delivery_info))
|
29
|
+
return unless (dr = @dm.match(headers, payload, delivery_info))
|
30
|
+
|
31
|
+
[hr, pr, dr]
|
32
|
+
rescue StandardError
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'bbk/app/matchers/base'
|
2
|
+
|
3
|
+
module BBK
|
4
|
+
module App
|
5
|
+
module Matchers
|
6
|
+
class Headers < Base
|
7
|
+
|
8
|
+
def initialize(rule)
|
9
|
+
@rule = rule.with_indifferent_access
|
10
|
+
end
|
11
|
+
|
12
|
+
def match(headers, _payload = nil, _delivery_info = nil, *_args)
|
13
|
+
match_impl(@rule, headers.with_indifferent_access)
|
14
|
+
rescue StandardError
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'bbk/app/matchers/base'
|
2
|
+
|
3
|
+
module BBK
|
4
|
+
module App
|
5
|
+
module Matchers
|
6
|
+
class Payload < Base
|
7
|
+
|
8
|
+
def initialize(rule)
|
9
|
+
@rule = rule.with_indifferent_access
|
10
|
+
end
|
11
|
+
|
12
|
+
def match(_headers, payload, _delivery_info = nil, *_args)
|
13
|
+
payload = JSON(payload) if payload&.is_a?(String)
|
14
|
+
match_impl(@rule, payload.with_indifferent_access)
|
15
|
+
rescue StandardError
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'bbk/app/matchers/headers'
|
2
|
+
require 'bbk/app/matchers/payload'
|
3
|
+
require 'bbk/app/matchers/delivery_info'
|
4
|
+
require 'bbk/app/matchers/full'
|
5
|
+
|
6
|
+
module BBK
|
7
|
+
module App
|
8
|
+
module Matchers
|
9
|
+
|
10
|
+
def self.create(type, *args)
|
11
|
+
case type
|
12
|
+
when :meta, :headers
|
13
|
+
Headers.new(args.first)
|
14
|
+
when :payload
|
15
|
+
Payload.new(args.first)
|
16
|
+
when :delivery, :delivery_info
|
17
|
+
DeliveryInfo.new(args.first)
|
18
|
+
when :full
|
19
|
+
Full.new(*args)
|
20
|
+
else
|
21
|
+
raise "there is no such matcher: #{type}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'bbk/app/middlewares/base'
|
3
|
+
|
4
|
+
module BBK
|
5
|
+
module App
|
6
|
+
module Middlewares
|
7
|
+
class ActiveRecordPool < Base
|
8
|
+
|
9
|
+
|
10
|
+
def call(msg)
|
11
|
+
::ActiveRecord::Base.connection_pool.with_connection do
|
12
|
+
app.call(msg)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module BBK
|
2
|
+
module App
|
3
|
+
module Middlewares
|
4
|
+
class FromBlock < Base
|
5
|
+
|
6
|
+
def initialize(&block)
|
7
|
+
raise ArgumentError.new('Not passed block') unless block_given?
|
8
|
+
|
9
|
+
@block = block
|
10
|
+
end
|
11
|
+
|
12
|
+
def build(app)
|
13
|
+
@app = app
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(msg)
|
18
|
+
@block.call(app, msg)
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module BBK
|
2
|
+
module App
|
3
|
+
module Middlewares
|
4
|
+
class SelfKiller
|
5
|
+
|
6
|
+
|
7
|
+
SELF_KILLER_LOG_INTERVAL = 300
|
8
|
+
|
9
|
+
attr_reader :dispatcher, :count, :threshold, :stop_time
|
10
|
+
|
11
|
+
def initialize(dispatcher, delay: 10 * 60, threshold: 10_000, logger: ::Logger.new(STDOUT))
|
12
|
+
@dispatcher = dispatcher
|
13
|
+
@threshold = threshold
|
14
|
+
@count = 0
|
15
|
+
@stop_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) + delay
|
16
|
+
@stopping = false
|
17
|
+
@logger = logger
|
18
|
+
@logger.info "[SelfKiller] Initializing: #{@count}/#{@threshold}"
|
19
|
+
reset_log_timer
|
20
|
+
end
|
21
|
+
|
22
|
+
def build(app)
|
23
|
+
@app = app
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def call(msg)
|
28
|
+
@count += 1
|
29
|
+
if time_exceed?(@log_timer)
|
30
|
+
@logger.info "[SelfKiller] Threshold status: #{@count}/#{@threshold}, delayed: #{!time_exceed?}"
|
31
|
+
reset_log_timer
|
32
|
+
end
|
33
|
+
close_dispatcher if stop?
|
34
|
+
|
35
|
+
@app.call(msg)
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def reset_log_timer
|
41
|
+
@log_timer = Process.clock_gettime(Process::CLOCK_MONOTONIC) + SELF_KILLER_LOG_INTERVAL
|
42
|
+
end
|
43
|
+
|
44
|
+
def stop?
|
45
|
+
!@stopping && threshold_exceed? && time_exceed?
|
46
|
+
end
|
47
|
+
|
48
|
+
def threshold_exceed?
|
49
|
+
@count > @threshold
|
50
|
+
end
|
51
|
+
|
52
|
+
def time_exceed?(time = @stop_time)
|
53
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) > time
|
54
|
+
end
|
55
|
+
|
56
|
+
def close_dispatcher
|
57
|
+
@stopping = true
|
58
|
+
@logger.warn '[SelfKiller] Threshold exceeded, closing dispatcher...'
|
59
|
+
Thread.new { @dispatcher.close } # Don't block current call
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module BBK
|
2
|
+
module App
|
3
|
+
module Middlewares
|
4
|
+
class Watchdog < Base
|
5
|
+
|
6
|
+
attr_reader :publisher, :route, :message_factory, :reply_to, :delay, :timeout,
|
7
|
+
:watcher_delay, :pinger_thread, :watcher_thread
|
8
|
+
|
9
|
+
def initialize(publisher, route, message_factory, reply_to, delay: 20, timeout: 60, watcher_delay: 40)
|
10
|
+
@publisher = publisher
|
11
|
+
@route = route
|
12
|
+
@message_factory = message_factory
|
13
|
+
@reply_to = reply_to
|
14
|
+
@delay = delay
|
15
|
+
@timeout = timeout
|
16
|
+
@timestamp = Time.now.to_i
|
17
|
+
@watcher_delay = watcher_delay
|
18
|
+
end
|
19
|
+
|
20
|
+
def build(app)
|
21
|
+
@app = app
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def call(msg)
|
26
|
+
touch
|
27
|
+
@app.call(msg)
|
28
|
+
end
|
29
|
+
|
30
|
+
def start
|
31
|
+
touch
|
32
|
+
start_ping
|
33
|
+
start_watch
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def stop
|
38
|
+
@pinger_thread&.kill
|
39
|
+
@watcher_thread&.kill
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def start_ping
|
45
|
+
@pinger_thread = Thread.new(publisher, delay, route) do |publisher, delay, route|
|
46
|
+
Thread.current.name = 'WatchDog::Pinger'
|
47
|
+
loop do
|
48
|
+
publisher.publish BBK::App::Dispatcher::Result.new(
|
49
|
+
route,
|
50
|
+
message_factory.build(reply_to)
|
51
|
+
)
|
52
|
+
sleep delay
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def start_watch
|
58
|
+
@watcher_thread = Thread.new(timeout, watcher_delay) do |timeout, watcher_delay|
|
59
|
+
Thread.current.name = 'WatchDog::Watcher'
|
60
|
+
msg = "[CRITICAL] watchdog: last ping is more than #{timeout} seconds ago"
|
61
|
+
|
62
|
+
sleep watcher_delay while (Time.now.to_i - @timestamp) < timeout
|
63
|
+
warn msg
|
64
|
+
exit!(8)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def touch
|
69
|
+
@timestamp = Time.now.to_i
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'bbk/utils/proxy_logger'
|
2
|
+
|
3
|
+
module BBK
|
4
|
+
module App
|
5
|
+
module Processors
|
6
|
+
class Base
|
7
|
+
|
8
|
+
attr_reader :logger
|
9
|
+
|
10
|
+
def initialize(*untyped, logger: BBK::App.logger, **)
|
11
|
+
logger = logger.respond_to?(:tagged) ? logger : ActiveSupport::TaggedLogging.new(logger)
|
12
|
+
@logger = BBK::Utils::ProxyLogger.new(logger, tags: self.class.to_s)
|
13
|
+
end
|
14
|
+
|
15
|
+
def rule
|
16
|
+
unless self.class.respond_to?(:rule)
|
17
|
+
raise NotImplementedError.new("Not implemented class method rule in #{self.class.name}")
|
18
|
+
end
|
19
|
+
|
20
|
+
self.class.rule
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(message, results: [])
|
24
|
+
debug 'processing message...'
|
25
|
+
|
26
|
+
process(message, results: results)
|
27
|
+
|
28
|
+
results
|
29
|
+
end
|
30
|
+
|
31
|
+
def process(_message, results: [])
|
32
|
+
raise NotImplementedError.new("process method abstract in Processor class. Results count: #{results.count}")
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
%i[debug info warn error fatal unknown].each do |severity|
|
37
|
+
define_method(severity) do |*args|
|
38
|
+
logger.public_send(severity, *args)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'bbk/app/processors/base'
|
2
|
+
|
3
|
+
module BBK
|
4
|
+
module App
|
5
|
+
module Processors
|
6
|
+
class Ping < Base
|
7
|
+
|
8
|
+
def initialize(pong_message_factory, pong_route, *args, **kwargs)
|
9
|
+
super
|
10
|
+
@pong_message_factory = pong_message_factory
|
11
|
+
@pong_route = pong_route
|
12
|
+
end
|
13
|
+
|
14
|
+
def process(message, results: [])
|
15
|
+
results << BBK::App::Dispatcher::Result.new(
|
16
|
+
@pong_route,
|
17
|
+
@pong_message_factory.build(message)
|
18
|
+
)
|
19
|
+
results
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BBK
|
4
|
+
module App
|
5
|
+
class ProxyLogger
|
6
|
+
|
7
|
+
attr_reader :tags, :logger
|
8
|
+
|
9
|
+
def initialize(logger, tags:)
|
10
|
+
@logger = logger
|
11
|
+
@tagged = @logger.respond_to?(:tagged)
|
12
|
+
@tags = [tags].flatten
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_tags(*tags)
|
16
|
+
@tags += tags.flatten
|
17
|
+
@tags = @tags.uniq
|
18
|
+
end
|
19
|
+
|
20
|
+
def method_missing(method, *args, &block)
|
21
|
+
super unless logger.respond_to?(method)
|
22
|
+
|
23
|
+
if @tagged
|
24
|
+
current_tags = tags - logger.formatter.current_tags
|
25
|
+
logger.tagged(current_tags) { logger.send(method, *args, &block) }
|
26
|
+
else
|
27
|
+
logger.send(method, *args, &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def respond_to?(*args)
|
32
|
+
logger.send(:respond_to?, *args) || super
|
33
|
+
end
|
34
|
+
|
35
|
+
def respond_to_missing?(method_name, include_private = false)
|
36
|
+
logger.send(:respond_to_missing?, method_name, include_private) || super
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|