cloudtasker 0.1.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +10 -1
- data/Appraisals +25 -0
- data/CHANGELOG.md +25 -0
- data/Gemfile.lock +37 -4
- data/README.md +573 -6
- data/Rakefile +6 -0
- data/app/controllers/cloudtasker/application_controller.rb +2 -0
- data/app/controllers/cloudtasker/worker_controller.rb +24 -2
- data/cloudtasker.gemspec +7 -3
- data/docs/BATCH_JOBS.md +66 -0
- data/docs/CRON_JOBS.md +63 -0
- data/docs/UNIQUE_JOBS.md +127 -0
- data/exe/cloudtasker +15 -0
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/google_cloud_tasks_1.0.gemfile +9 -0
- data/gemfiles/google_cloud_tasks_1.0.gemfile.lock +263 -0
- data/gemfiles/google_cloud_tasks_1.1.gemfile +9 -0
- data/gemfiles/google_cloud_tasks_1.1.gemfile.lock +263 -0
- data/gemfiles/google_cloud_tasks_1.2.gemfile +9 -0
- data/gemfiles/google_cloud_tasks_1.2.gemfile.lock +263 -0
- data/gemfiles/google_cloud_tasks_1.3.gemfile +9 -0
- data/gemfiles/google_cloud_tasks_1.3.gemfile.lock +264 -0
- data/gemfiles/rails_4.0.gemfile +10 -0
- data/gemfiles/rails_4.1.gemfile +9 -0
- data/gemfiles/rails_4.2.gemfile +9 -0
- data/gemfiles/rails_5.0.gemfile +9 -0
- data/gemfiles/rails_5.1.gemfile +9 -0
- data/gemfiles/rails_5.2.gemfile +9 -0
- data/gemfiles/rails_5.2.gemfile.lock +247 -0
- data/gemfiles/rails_6.0.gemfile +9 -0
- data/gemfiles/rails_6.0.gemfile.lock +263 -0
- data/lib/cloudtasker.rb +21 -1
- data/lib/cloudtasker/backend/google_cloud_task.rb +139 -0
- data/lib/cloudtasker/backend/memory_task.rb +190 -0
- data/lib/cloudtasker/backend/redis_task.rb +249 -0
- data/lib/cloudtasker/batch/batch_progress.rb +19 -1
- data/lib/cloudtasker/batch/job.rb +88 -23
- data/lib/cloudtasker/batch/middleware.rb +0 -1
- data/lib/cloudtasker/cli.rb +194 -0
- data/lib/cloudtasker/cloud_task.rb +91 -0
- data/lib/cloudtasker/config.rb +64 -2
- data/lib/cloudtasker/cron/job.rb +6 -3
- data/lib/cloudtasker/cron/middleware.rb +0 -1
- data/lib/cloudtasker/cron/schedule.rb +73 -13
- data/lib/cloudtasker/dead_worker_error.rb +6 -0
- data/lib/cloudtasker/local_server.rb +74 -0
- data/lib/cloudtasker/railtie.rb +10 -0
- data/lib/cloudtasker/redis_client.rb +24 -2
- data/lib/cloudtasker/testing.rb +133 -0
- data/lib/cloudtasker/unique_job/job.rb +5 -2
- data/lib/cloudtasker/unique_job/lock/base_lock.rb +1 -1
- data/lib/cloudtasker/unique_job/lock/until_executed.rb +3 -1
- data/lib/cloudtasker/unique_job/lock/while_executing.rb +3 -1
- data/lib/cloudtasker/unique_job/middleware.rb +0 -1
- data/lib/cloudtasker/version.rb +1 -1
- data/lib/cloudtasker/worker.rb +59 -16
- data/lib/cloudtasker/{task.rb → worker_handler.rb} +10 -77
- data/lib/cloudtasker/worker_logger.rb +155 -0
- data/lib/tasks/setup_queue.rake +10 -0
- metadata +98 -9
- data/lib/cloudtasker/batch/config.rb +0 -11
- data/lib/cloudtasker/cron/config.rb +0 -11
- data/lib/cloudtasker/unique_job/config.rb +0 -10
@@ -10,6 +10,9 @@ module Cloudtasker
|
|
10
10
|
# The default lock strategy to use. Defaults to "no lock".
|
11
11
|
DEFAULT_LOCK = UniqueJob::Lock::NoOp
|
12
12
|
|
13
|
+
# Key Namespace used for object saved under this class
|
14
|
+
SUB_NAMESPACE = 'job'
|
15
|
+
|
13
16
|
#
|
14
17
|
# Build a new instance of the class.
|
15
18
|
#
|
@@ -37,7 +40,7 @@ module Cloudtasker
|
|
37
40
|
@lock_instance ||=
|
38
41
|
begin
|
39
42
|
# Infer lock class and get instance
|
40
|
-
lock_name = options[:lock]
|
43
|
+
lock_name = options[:lock]
|
41
44
|
lock_klass = Lock.const_get(lock_name.to_s.split('_').collect(&:capitalize).join)
|
42
45
|
lock_klass.new(self)
|
43
46
|
rescue NameError
|
@@ -91,7 +94,7 @@ module Cloudtasker
|
|
91
94
|
# @return [String] The global ID of the job
|
92
95
|
#
|
93
96
|
def unique_gid
|
94
|
-
[
|
97
|
+
[self.class.to_s.underscore, unique_id].join('/')
|
95
98
|
end
|
96
99
|
|
97
100
|
#
|
@@ -43,7 +43,7 @@ module Cloudtasker
|
|
43
43
|
@conflict_instance ||=
|
44
44
|
begin
|
45
45
|
# Infer lock class and get instance
|
46
|
-
strategy_name = options[:on_conflict]
|
46
|
+
strategy_name = options[:on_conflict]
|
47
47
|
strategy_klass = ConflictStrategy.const_get(strategy_name.to_s.split('_').collect(&:capitalize).join)
|
48
48
|
strategy_klass.new(job)
|
49
49
|
rescue NameError
|
data/lib/cloudtasker/version.rb
CHANGED
data/lib/cloudtasker/worker.rb
CHANGED
@@ -6,7 +6,7 @@ module Cloudtasker
|
|
6
6
|
# Add class method to including class
|
7
7
|
def self.included(base)
|
8
8
|
base.extend(ClassMethods)
|
9
|
-
base.attr_accessor :job_args, :job_id, :job_meta, :job_reenqueued
|
9
|
+
base.attr_accessor :job_args, :job_id, :job_meta, :job_reenqueued, :job_retries
|
10
10
|
end
|
11
11
|
|
12
12
|
#
|
@@ -44,7 +44,7 @@ module Cloudtasker
|
|
44
44
|
return nil unless worker_klass.include?(self)
|
45
45
|
|
46
46
|
# Return instantiated worker
|
47
|
-
worker_klass.new(payload.slice(:job_args, :job_id, :job_meta))
|
47
|
+
worker_klass.new(payload.slice(:job_args, :job_id, :job_meta, :job_retries))
|
48
48
|
rescue NameError
|
49
49
|
nil
|
50
50
|
end
|
@@ -54,12 +54,12 @@ module Cloudtasker
|
|
54
54
|
#
|
55
55
|
# Set the worker runtime options.
|
56
56
|
#
|
57
|
-
# @param [Hash] opts The worker options
|
57
|
+
# @param [Hash] opts The worker options.
|
58
58
|
#
|
59
|
-
# @return [
|
59
|
+
# @return [Hash] The options set.
|
60
60
|
#
|
61
61
|
def cloudtasker_options(opts = {})
|
62
|
-
opt_list = opts&.map { |k, v| [k.
|
62
|
+
opt_list = opts&.map { |k, v| [k.to_sym, v] } || [] # symbolize
|
63
63
|
@cloudtasker_options_hash = Hash[opt_list]
|
64
64
|
end
|
65
65
|
|
@@ -69,7 +69,7 @@ module Cloudtasker
|
|
69
69
|
# @return [Hash] The worker runtime options.
|
70
70
|
#
|
71
71
|
def cloudtasker_options_hash
|
72
|
-
@cloudtasker_options_hash
|
72
|
+
@cloudtasker_options_hash || {}
|
73
73
|
end
|
74
74
|
|
75
75
|
#
|
@@ -77,7 +77,7 @@ module Cloudtasker
|
|
77
77
|
#
|
78
78
|
# @param [Array<any>] *args List of worker arguments
|
79
79
|
#
|
80
|
-
# @return [
|
80
|
+
# @return [Cloudtasker::CloudTask] The Google Task response
|
81
81
|
#
|
82
82
|
def perform_async(*args)
|
83
83
|
perform_in(nil, *args)
|
@@ -89,7 +89,7 @@ module Cloudtasker
|
|
89
89
|
# @param [Integer, nil] interval The delay in seconds.
|
90
90
|
# @param [Array<any>] *args List of worker arguments.
|
91
91
|
#
|
92
|
-
# @return [
|
92
|
+
# @return [Cloudtasker::CloudTask] The Google Task response
|
93
93
|
#
|
94
94
|
def perform_in(interval, *args)
|
95
95
|
new(job_args: args).schedule(interval: interval)
|
@@ -101,11 +101,20 @@ module Cloudtasker
|
|
101
101
|
# @param [Time, Integer] time_at The time at which the job should run.
|
102
102
|
# @param [Array<any>] *args List of worker arguments
|
103
103
|
#
|
104
|
-
# @return [
|
104
|
+
# @return [Cloudtasker::CloudTask] The Google Task response
|
105
105
|
#
|
106
106
|
def perform_at(time_at, *args)
|
107
107
|
new(job_args: args).schedule(time_at: time_at)
|
108
108
|
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# Return the numbeer of times this worker will be retried.
|
112
|
+
#
|
113
|
+
# @return [Integer] The number of retries.
|
114
|
+
#
|
115
|
+
def max_retries
|
116
|
+
cloudtasker_options_hash[:max_retries] || Cloudtasker.config.max_retries
|
117
|
+
end
|
109
118
|
end
|
110
119
|
|
111
120
|
#
|
@@ -114,10 +123,20 @@ module Cloudtasker
|
|
114
123
|
# @param [Array<any>] job_args The list of perform args.
|
115
124
|
# @param [String] job_id A unique ID identifying this job.
|
116
125
|
#
|
117
|
-
def initialize(job_args: [], job_id: nil, job_meta: {})
|
126
|
+
def initialize(job_args: [], job_id: nil, job_meta: {}, job_retries: 0)
|
118
127
|
@job_args = job_args
|
119
128
|
@job_id = job_id || SecureRandom.uuid
|
120
129
|
@job_meta = MetaStore.new(job_meta)
|
130
|
+
@job_retries = job_retries || 0
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# Return the Cloudtasker logger instance.
|
135
|
+
#
|
136
|
+
# @return [Logger, any] The cloudtasker logger.
|
137
|
+
#
|
138
|
+
def logger
|
139
|
+
@logger ||= WorkerLogger.new(self)
|
121
140
|
end
|
122
141
|
|
123
142
|
#
|
@@ -126,9 +145,22 @@ module Cloudtasker
|
|
126
145
|
# @return [Any] The result of the perform.
|
127
146
|
#
|
128
147
|
def execute
|
129
|
-
|
130
|
-
|
148
|
+
logger.info('Starting job...')
|
149
|
+
resp = Cloudtasker.config.server_middleware.invoke(self) do
|
150
|
+
begin
|
151
|
+
perform(*job_args)
|
152
|
+
rescue StandardError => e
|
153
|
+
try(:on_error, e)
|
154
|
+
return raise(e) unless job_dead?
|
155
|
+
|
156
|
+
# Flag job as dead
|
157
|
+
logger.info('Job dead')
|
158
|
+
try(:on_dead, e)
|
159
|
+
raise(DeadWorkerError, e)
|
160
|
+
end
|
131
161
|
end
|
162
|
+
logger.info('Job done')
|
163
|
+
resp
|
132
164
|
end
|
133
165
|
|
134
166
|
#
|
@@ -138,11 +170,11 @@ module Cloudtasker
|
|
138
170
|
#
|
139
171
|
# @param [Time, Integer] interval The time at which the job should run
|
140
172
|
#
|
141
|
-
# @return [
|
173
|
+
# @return [Cloudtasker::CloudTask] The Google Task response
|
142
174
|
#
|
143
175
|
def schedule(interval: nil, time_at: nil)
|
144
176
|
Cloudtasker.config.client_middleware.invoke(self) do
|
145
|
-
|
177
|
+
WorkerHandler.new(self).schedule(interval: interval, time_at: time_at)
|
146
178
|
end
|
147
179
|
end
|
148
180
|
|
@@ -155,7 +187,7 @@ module Cloudtasker
|
|
155
187
|
#
|
156
188
|
# @param [Integer] interval Delay to wait before processing the job again (in seconds).
|
157
189
|
#
|
158
|
-
# @return [
|
190
|
+
# @return [Cloudtasker::CloudTask] The Google Task response
|
159
191
|
#
|
160
192
|
def reenqueue(interval)
|
161
193
|
@job_reenqueued = true
|
@@ -182,7 +214,8 @@ module Cloudtasker
|
|
182
214
|
worker: self.class.to_s,
|
183
215
|
job_id: job_id,
|
184
216
|
job_args: job_args,
|
185
|
-
job_meta: job_meta.to_h
|
217
|
+
job_meta: job_meta.to_h,
|
218
|
+
job_retries: job_retries
|
186
219
|
}
|
187
220
|
end
|
188
221
|
|
@@ -207,5 +240,15 @@ module Cloudtasker
|
|
207
240
|
def ==(other)
|
208
241
|
other.is_a?(self.class) && other.job_id == job_id
|
209
242
|
end
|
243
|
+
|
244
|
+
#
|
245
|
+
# Return true if the job has excceeded its maximum number
|
246
|
+
# of retries
|
247
|
+
#
|
248
|
+
# @return [Boolean] True if the job is dead
|
249
|
+
#
|
250
|
+
def job_dead?
|
251
|
+
job_retries >= Cloudtasker.config.max_retries
|
252
|
+
end
|
210
253
|
end
|
211
254
|
end
|
@@ -3,39 +3,13 @@
|
|
3
3
|
require 'google/cloud/tasks'
|
4
4
|
|
5
5
|
module Cloudtasker
|
6
|
-
# Build, serialize and schedule tasks on
|
7
|
-
class
|
6
|
+
# Build, serialize and schedule tasks on the processing backend.
|
7
|
+
class WorkerHandler
|
8
8
|
attr_reader :worker, :job_args
|
9
9
|
|
10
10
|
# Alrogith used to sign the verification token
|
11
11
|
JWT_ALG = 'HS256'
|
12
12
|
|
13
|
-
# TODO: Move to a dedicated CloudTask class
|
14
|
-
#
|
15
|
-
# Find a Cloud task
|
16
|
-
#
|
17
|
-
# @param [String] id The ID of the task.
|
18
|
-
#
|
19
|
-
# @return [Google::Cloud::Tasks::V2beta3::Task] The cloud task.
|
20
|
-
#
|
21
|
-
def self.find(id)
|
22
|
-
client.get_task(id)
|
23
|
-
rescue Google::Gax::RetryError
|
24
|
-
nil
|
25
|
-
end
|
26
|
-
|
27
|
-
# TODO: Move to a dedicated CloudTask class
|
28
|
-
#
|
29
|
-
# Delete a Cloud task
|
30
|
-
#
|
31
|
-
# @param [String] id The ID of the task.
|
32
|
-
#
|
33
|
-
def self.delete(id)
|
34
|
-
client.delete_task(id)
|
35
|
-
rescue Google::Gax::RetryError
|
36
|
-
nil
|
37
|
-
end
|
38
|
-
|
39
13
|
#
|
40
14
|
# Execute a task worker from a task payload
|
41
15
|
#
|
@@ -48,15 +22,6 @@ module Cloudtasker
|
|
48
22
|
worker.execute
|
49
23
|
end
|
50
24
|
|
51
|
-
#
|
52
|
-
# Return the Google Cloud Task client.
|
53
|
-
#
|
54
|
-
# @return [Google::Cloud::Tasks] The Google Cloud Task client.
|
55
|
-
#
|
56
|
-
def self.client
|
57
|
-
@client ||= ::Google::Cloud::Tasks.new(version: :v2beta3)
|
58
|
-
end
|
59
|
-
|
60
25
|
#
|
61
26
|
# Prepare a new cloud task.
|
62
27
|
#
|
@@ -66,37 +31,6 @@ module Cloudtasker
|
|
66
31
|
@worker = worker
|
67
32
|
end
|
68
33
|
|
69
|
-
#
|
70
|
-
# Return the Google Cloud Task client.
|
71
|
-
#
|
72
|
-
# @return [Google::Cloud::Tasks] The Google Cloud Task client.
|
73
|
-
#
|
74
|
-
def client
|
75
|
-
self.class.client
|
76
|
-
end
|
77
|
-
|
78
|
-
#
|
79
|
-
# Return the cloudtasker configuration. See Cloudtasker#configure.
|
80
|
-
#
|
81
|
-
# @return [Cloudtasker::Config] The library configuration.
|
82
|
-
#
|
83
|
-
def config
|
84
|
-
Cloudtasker.config
|
85
|
-
end
|
86
|
-
|
87
|
-
#
|
88
|
-
# Return the fully qualified path for the Cloud Task queue.
|
89
|
-
#
|
90
|
-
# @return [String] The queue path.
|
91
|
-
#
|
92
|
-
def queue_path
|
93
|
-
client.queue_path(
|
94
|
-
config.gcp_project_id,
|
95
|
-
config.gcp_location_id,
|
96
|
-
config.gcp_queue_id
|
97
|
-
)
|
98
|
-
end
|
99
|
-
|
100
34
|
#
|
101
35
|
# Return the full task configuration sent to Cloud Task
|
102
36
|
#
|
@@ -106,7 +40,7 @@ module Cloudtasker
|
|
106
40
|
{
|
107
41
|
http_request: {
|
108
42
|
http_method: 'POST',
|
109
|
-
url: config.processor_url,
|
43
|
+
url: Cloudtasker.config.processor_url,
|
110
44
|
headers: {
|
111
45
|
'Content-Type' => 'application/json',
|
112
46
|
'Authorization' => "Bearer #{Authenticator.verification_token}"
|
@@ -133,7 +67,7 @@ module Cloudtasker
|
|
133
67
|
worker: worker.class.to_s,
|
134
68
|
job_id: worker.job_id,
|
135
69
|
job_args: worker.job_args,
|
136
|
-
job_meta: worker.job_meta
|
70
|
+
job_meta: worker.job_meta.to_h
|
137
71
|
}
|
138
72
|
end
|
139
73
|
|
@@ -142,16 +76,15 @@ module Cloudtasker
|
|
142
76
|
# before running a task.
|
143
77
|
#
|
144
78
|
# @param [Integer, nil] interval The time to wait.
|
79
|
+
# @param [Integer, nil] time_at The time at which the job should run.
|
145
80
|
#
|
146
|
-
# @return [
|
81
|
+
# @return [Integer, nil] The Unix timestamp.
|
147
82
|
#
|
148
83
|
def schedule_time(interval: nil, time_at: nil)
|
149
84
|
return nil unless interval || time_at
|
150
85
|
|
151
|
-
# Generate
|
152
|
-
|
153
|
-
timestamp.seconds = (time_at || Time.now).to_i + interval.to_i
|
154
|
-
timestamp
|
86
|
+
# Generate the complete Unix timestamp
|
87
|
+
(time_at || Time.now).to_i + interval.to_i
|
155
88
|
end
|
156
89
|
|
157
90
|
#
|
@@ -160,7 +93,7 @@ module Cloudtasker
|
|
160
93
|
# @param [Integer, nil] interval How to wait before running the task.
|
161
94
|
# Leave to `nil` to run now.
|
162
95
|
#
|
163
|
-
# @return [
|
96
|
+
# @return [Cloudtasker::CloudTask] The Google Task response
|
164
97
|
#
|
165
98
|
def schedule(interval: nil, time_at: nil)
|
166
99
|
# Generate task payload
|
@@ -169,7 +102,7 @@ module Cloudtasker
|
|
169
102
|
).compact
|
170
103
|
|
171
104
|
# Create and return remote task
|
172
|
-
|
105
|
+
CloudTask.create(task)
|
173
106
|
end
|
174
107
|
end
|
175
108
|
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cloudtasker
|
4
|
+
# Add contextual information to logs generated
|
5
|
+
# by workers
|
6
|
+
class WorkerLogger
|
7
|
+
attr_accessor :worker
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_accessor :log_context_processor
|
11
|
+
end
|
12
|
+
|
13
|
+
# Only log the job meta information by default (exclude arguments)
|
14
|
+
DEFAULT_CONTEXT_PROCESSOR = ->(worker) { worker.to_h.slice(:worker, :job_id, :job_meta) }
|
15
|
+
|
16
|
+
#
|
17
|
+
# Build a new instance of the class.
|
18
|
+
#
|
19
|
+
# @param [Cloudtasker::Worker] worker The worker.
|
20
|
+
#
|
21
|
+
def initialize(worker)
|
22
|
+
@worker = worker
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Return the Proc responsible for formatting the log payload.
|
27
|
+
#
|
28
|
+
# @return [Proc] The context processor.
|
29
|
+
#
|
30
|
+
def context_processor
|
31
|
+
@context_processor ||= worker.class.cloudtasker_options_hash[:log_context_processor] ||
|
32
|
+
self.class.log_context_processor ||
|
33
|
+
DEFAULT_CONTEXT_PROCESSOR
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# The block to pass to log messages.
|
38
|
+
#
|
39
|
+
# @return [Proc] The log block.
|
40
|
+
#
|
41
|
+
def log_block
|
42
|
+
@log_block ||= proc { context_processor.call(worker) }
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Return the Cloudtasker logger.
|
47
|
+
#
|
48
|
+
# @return [Logger, any] The cloudtasker logger.
|
49
|
+
#
|
50
|
+
def logger
|
51
|
+
Cloudtasker.logger
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Format main log message.
|
56
|
+
#
|
57
|
+
# @param [String] msg The message to log.
|
58
|
+
#
|
59
|
+
# @return [String] The formatted log message
|
60
|
+
#
|
61
|
+
def formatted_message(msg)
|
62
|
+
"[Cloudtasker][#{worker.job_id}] #{msg}"
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Log an info message.
|
67
|
+
#
|
68
|
+
# @param [String] msg The message to log.
|
69
|
+
# @param [Proc] &block Optional context block.
|
70
|
+
#
|
71
|
+
def info(msg, &block)
|
72
|
+
log_message(:info, msg, &block)
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Log an error message.
|
77
|
+
#
|
78
|
+
# @param [String] msg The message to log.
|
79
|
+
# @param [Proc] &block Optional context block.
|
80
|
+
#
|
81
|
+
def error(msg, &block)
|
82
|
+
log_message(:error, msg, &block)
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Log an fatal message.
|
87
|
+
#
|
88
|
+
# @param [String] msg The message to log.
|
89
|
+
# @param [Proc] &block Optional context block.
|
90
|
+
#
|
91
|
+
def fatal(msg, &block)
|
92
|
+
log_message(:fatal, msg, &block)
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# Log an debut message.
|
97
|
+
#
|
98
|
+
# @param [String] msg The message to log.
|
99
|
+
# @param [Proc] &block Optional context block.
|
100
|
+
#
|
101
|
+
def debug(msg, &block)
|
102
|
+
log_message(:debug, msg, &block)
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Delegate all methods to the underlying logger.
|
107
|
+
#
|
108
|
+
# @param [String, Symbol] name The method to delegate.
|
109
|
+
# @param [Array<any>] *args The list of method arguments.
|
110
|
+
# @param [Proc] &block Block passed to the method.
|
111
|
+
#
|
112
|
+
# @return [Any] The method return value
|
113
|
+
#
|
114
|
+
def method_missing(name, *args, &block)
|
115
|
+
if logger.respond_to?(name)
|
116
|
+
logger.send(name, *args, &block)
|
117
|
+
else
|
118
|
+
super
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
#
|
123
|
+
# Check if the class respond to a certain method.
|
124
|
+
#
|
125
|
+
# @param [String, Symbol] name The name of the method.
|
126
|
+
# @param [Boolean] include_private Whether to check private methods or not. Default to false.
|
127
|
+
#
|
128
|
+
# @return [Boolean] Return true if the class respond to this method.
|
129
|
+
#
|
130
|
+
def respond_to_missing?(name, include_private = false)
|
131
|
+
logger.respond_to?(name) || super
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
#
|
137
|
+
# Log a message for the provided log level.
|
138
|
+
#
|
139
|
+
# @param [String, Symbol] level The log level
|
140
|
+
# @param [String] msg The message to log.
|
141
|
+
# @param [Proc] &block Optional context block.
|
142
|
+
#
|
143
|
+
def log_message(level, msg, &block)
|
144
|
+
payload_block = block || log_block
|
145
|
+
|
146
|
+
# ActiveSupport::Logger does not support passing a payload through a block on top
|
147
|
+
# of a message.
|
148
|
+
if defined?(ActiveSupport::Logger) && logger.is_a?(ActiveSupport::Logger)
|
149
|
+
logger.send(level) { "#{formatted_message(msg)} -- #{payload_block.call}" }
|
150
|
+
else
|
151
|
+
logger.send(level, formatted_message(msg), &payload_block)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|