cloudtasker 0.1.0 → 0.6.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/.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
|