bbk-app 1.0.0.72899
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|