cem_acpt 0.2.5 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/spec.yml +30 -0
  3. data/Gemfile +4 -3
  4. data/Gemfile.lock +95 -43
  5. data/README.md +144 -83
  6. data/cem_acpt.gemspec +12 -7
  7. data/exe/cem_acpt +41 -7
  8. data/lib/cem_acpt/config.rb +340 -0
  9. data/lib/cem_acpt/core_extensions.rb +17 -61
  10. data/lib/cem_acpt/goss/api/action_response.rb +175 -0
  11. data/lib/cem_acpt/goss/api.rb +83 -0
  12. data/lib/cem_acpt/goss.rb +8 -0
  13. data/lib/cem_acpt/image_name_builder.rb +0 -9
  14. data/lib/cem_acpt/logging/formatter.rb +97 -0
  15. data/lib/cem_acpt/logging.rb +168 -142
  16. data/lib/cem_acpt/platform/base.rb +26 -37
  17. data/lib/cem_acpt/platform/gcp.rb +48 -62
  18. data/lib/cem_acpt/platform.rb +30 -28
  19. data/lib/cem_acpt/provision/terraform/linux.rb +47 -0
  20. data/lib/cem_acpt/provision/terraform/os_data.rb +72 -0
  21. data/lib/cem_acpt/provision/terraform/windows.rb +22 -0
  22. data/lib/cem_acpt/provision/terraform.rb +193 -0
  23. data/lib/cem_acpt/provision.rb +20 -0
  24. data/lib/cem_acpt/puppet_helpers.rb +0 -1
  25. data/lib/cem_acpt/test_data.rb +23 -13
  26. data/lib/cem_acpt/test_runner/log_formatter/goss_action_response.rb +104 -0
  27. data/lib/cem_acpt/test_runner/log_formatter.rb +10 -0
  28. data/lib/cem_acpt/test_runner.rb +170 -3
  29. data/lib/cem_acpt/utils/puppet.rb +29 -0
  30. data/lib/cem_acpt/utils/ssh.rb +197 -0
  31. data/lib/cem_acpt/utils/terminal.rb +27 -0
  32. data/lib/cem_acpt/utils.rb +4 -138
  33. data/lib/cem_acpt/version.rb +1 -1
  34. data/lib/cem_acpt.rb +73 -23
  35. data/lib/terraform/gcp/linux/goss/puppet_idempotent.yaml +10 -0
  36. data/lib/terraform/gcp/linux/goss/puppet_noop.yaml +12 -0
  37. data/lib/terraform/gcp/linux/main.tf +191 -0
  38. data/lib/terraform/gcp/linux/systemd/goss-acpt.service +8 -0
  39. data/lib/terraform/gcp/linux/systemd/goss-idempotent.service +8 -0
  40. data/lib/terraform/gcp/linux/systemd/goss-noop.service +8 -0
  41. data/lib/terraform/gcp/windows/.keep +0 -0
  42. data/sample_config.yaml +22 -21
  43. metadata +151 -51
  44. data/lib/cem_acpt/bootstrap/bootstrapper.rb +0 -206
  45. data/lib/cem_acpt/bootstrap/operating_system/rhel_family.rb +0 -129
  46. data/lib/cem_acpt/bootstrap/operating_system.rb +0 -17
  47. data/lib/cem_acpt/bootstrap.rb +0 -12
  48. data/lib/cem_acpt/context.rb +0 -153
  49. data/lib/cem_acpt/platform/base/cmd.rb +0 -71
  50. data/lib/cem_acpt/platform/gcp/cmd.rb +0 -345
  51. data/lib/cem_acpt/platform/gcp/compute.rb +0 -332
  52. data/lib/cem_acpt/platform/vmpooler.rb +0 -24
  53. data/lib/cem_acpt/rspec_utils.rb +0 -242
  54. data/lib/cem_acpt/shared_objects.rb +0 -537
  55. data/lib/cem_acpt/spec_helper_acceptance.rb +0 -184
  56. data/lib/cem_acpt/test_runner/run_handler.rb +0 -187
  57. data/lib/cem_acpt/test_runner/runner.rb +0 -210
  58. data/lib/cem_acpt/test_runner/runner_result.rb +0 -103
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'async'
4
+ require 'async/barrier'
5
+ require 'async/http/internet'
6
+ require 'json'
7
+ require_relative 'api/action_response'
8
+
9
+ module CemAcpt
10
+ module Goss
11
+ # Holds methods for interacting with the Goss API running on a test node.
12
+ module Api
13
+ class << self
14
+ # The actions that can be run against the Goss API. The key is the action
15
+ # name and the value is the port/endpoint of the action.
16
+ ACTIONS = {
17
+ acpt: '8080/acpt',
18
+ idempotent: '8081/idempotent',
19
+ noop: '8082/noop',
20
+ }.freeze
21
+
22
+ # Create a URI for the specified action against the specified host.
23
+ # @param host [String] The host to run the action against. This should be
24
+ # a public IP address or a DNS-resolvable name.
25
+ # @param action [Symbol] The action to run.
26
+ # @return [URI] The URI for the action.
27
+ def action_uri(host, action)
28
+ URI("http://#{host}:#{ACTIONS[action.to_sym]}")
29
+ end
30
+
31
+ # Run the specified actions against the specified hosts asynchronously.
32
+ # @param hosts [Array<String>] The hosts to run the actions against. Each
33
+ # host should be a public IP address or a DNS-resolvable name.
34
+ # @param results [Queue] The queue to push the results to.
35
+ # @param only [Array<Symbol>] The actions to run.
36
+ # @param except [Array<Symbol>] The actions to skip.
37
+ # @return [Queue] The queue of results.
38
+ def run_actions_async(hosts, results: Queue.new, only: [], except: [])
39
+ raise ArgumentError, 'hosts must be an Array' unless hosts.is_a?(Array)
40
+ raise ArgumentError, 'results must be a Queue-like object implementing #<<' unless results.respond_to?(:<<)
41
+ raise ArgumentError, 'only must be an Array' unless except.is_a?(Array)
42
+ raise ArgumentError, 'except must be an Array' unless except.is_a?(Array)
43
+ only.map!(&:to_sym)
44
+ except.map!(&:to_sym)
45
+ only_specified = !only.empty?
46
+ except_specified = !except.empty?
47
+ Async do
48
+ internet = Async::HTTP::Internet.new
49
+ barrier = Async::Barrier.new
50
+ barrier.async do
51
+ hosts.each do |host|
52
+ ACTIONS.keys.each do |action, _|
53
+ next if only_specified && !only.include?(action)
54
+ next if except_specified && except.include?(action)
55
+
56
+ results << run_action(internet, host, action)
57
+ end
58
+ end
59
+ end
60
+ barrier.wait
61
+ ensure
62
+ internet&.close
63
+ results.close if results.respond_to?(:close)
64
+ end
65
+ results
66
+ end
67
+
68
+ # Run the specified action against the specified host.
69
+ # @param internet [Async::HTTP::Internet] The Async::HTTP::Internet object to use for the request.
70
+ # @param host [String] The host to run the action against. This should be
71
+ # a public IP address or a DNS-resolvable name.
72
+ # @param action [Symbol] The action to run.
73
+ # @return [ActionResponse] The response from the action.
74
+ def run_action(internet, host, action)
75
+ uri = action_uri(host, action)
76
+ response = internet.get(uri.to_s)
77
+ body = JSON.parse(response.read)
78
+ ActionResponse.new(host, action, response.status, body)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'goss/api'
4
+
5
+ module CemAcpt
6
+ # Holds all the Goss related code
7
+ module Goss; end
8
+ end
@@ -41,13 +41,8 @@ module CemAcpt
41
41
  # @param test_data [Hash] The test data to use to build the image name.
42
42
  # @return [String] The image name.
43
43
  def build(test_data)
44
- logger.debug 'Building image name...'
45
- logger.debug "Using config: #{@config.to_h}"
46
- logger.debug "Test data: #{test_data}"
47
44
  parts = resolve_parts(test_data)
48
- logger.debug "Resolved parts: #{parts}"
49
45
  image_name = create_image_name(parts)
50
- logger.debug "Created image name: #{image_name}"
51
46
  final_image_name = character_substitutions(image_name)
52
47
  logger.debug "Final image name: #{final_image_name}"
53
48
  final_image_name
@@ -61,10 +56,8 @@ module CemAcpt
61
56
  # @return [Array] The parts array with variables resolved.
62
57
  def resolve_parts(test_data)
63
58
  @config[:parts].each_with_object([]) do |part, ary|
64
- logger.debug "Resolving part: #{part}"
65
59
  if part.start_with?('$')
66
60
  var_path = part[1..-1]
67
- logger.debug "Resolving variable path: #{var_path}"
68
61
  ary << test_data.dot_dig(var_path)
69
62
  else
70
63
  ary << part
@@ -77,10 +70,8 @@ module CemAcpt
77
70
  # @return [String] The image name.
78
71
  def create_image_name(parts)
79
72
  image_name = @config[:join_with] ? parts.join(@config[:join_with]) : parts.join
80
- logger.debug("Final image name: #{image_name}")
81
73
 
82
74
  if @config[:validation_pattern]
83
- logger.debug "Validating image name: #{image_name}..."
84
75
  return image_name if image_name.match?(@config[:validation_pattern])
85
76
 
86
77
  raise "Image name #{image_name} does not match validation pattern #{@config[:validation_pattern]}"
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CemAcpt
4
+ module Logging
5
+ module Formatter
6
+ class << self
7
+ def valid_format?(log_format)
8
+ all.any? { |f| f.log_format == log_format.downcase.to_sym }
9
+ end
10
+
11
+ def for(log_format)
12
+ formatter = all.find { |f| f.log_format == log_format.downcase.to_sym }
13
+ raise "Unknown log format: #{log_format}" unless formatter
14
+
15
+ formatter.get
16
+ end
17
+
18
+ def all
19
+ @all ||= [FileFormatter.new, JSONFormatter.new, TextFormatter.new, GithubActionFormatter.new]
20
+ end
21
+ end
22
+
23
+ class FileFormatter
24
+ attr_reader :log_format
25
+
26
+ def initialize
27
+ @log_format = :file
28
+ end
29
+
30
+ def get
31
+ proc do |severity, datetime, progname, msg|
32
+ format(severity, datetime, progname, msg)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def format(severity, datetime, progname, msg)
39
+ "[#{datetime}] #{severity}: #{progname}: #{msg}\n"
40
+ end
41
+ end
42
+
43
+ class JSONFormatter < FileFormatter
44
+ def initialize
45
+ super
46
+ @log_format = :json
47
+ end
48
+
49
+ private
50
+
51
+ def format(severity, datetime, progname, msg)
52
+ require 'json'
53
+ {
54
+ timestamp: datetime,
55
+ progname: progname,
56
+ severity: severity,
57
+ message: msg,
58
+ }.to_json + "\n"
59
+ end
60
+ end
61
+
62
+ class TextFormatter < FileFormatter
63
+ def initialize
64
+ super
65
+ @log_format = :text
66
+ end
67
+
68
+ private
69
+
70
+ def format(severity, _datetime, progname, msg)
71
+ "#{severity}: #{progname}: #{msg}\n"
72
+ end
73
+ end
74
+
75
+ class GithubActionFormatter < FileFormatter
76
+ SEV_MAP = {
77
+ 'DEBUG' => '::debug::',
78
+ 'INFO' => '::notice::',
79
+ 'WARN' => '::warning::',
80
+ 'ERROR' => '::error::',
81
+ 'FATAL' => '::error::',
82
+ }.freeze
83
+
84
+ def initialize
85
+ super
86
+ @log_format = :github_action
87
+ end
88
+
89
+ private
90
+
91
+ def format(severity, _datetime, progname, msg)
92
+ "#{SEV_MAP[severity]}[#{progname}] #{msg}\n"
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -1,27 +1,50 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'logger'
4
+ require 'cem_acpt/logging/formatter'
4
5
 
5
6
  module CemAcpt
6
7
  # Logging for CemAcpt
7
8
  module Logging
8
9
  LEVEL_MAP = {
9
- 'debug' => Logger::DEBUG,
10
- 'info' => Logger::INFO,
11
- 'warn' => Logger::WARN,
12
- 'error' => Logger::ERROR,
13
- 'fatal' => Logger::FATAL,
14
- 'unknown' => Logger::UNKNOWN,
10
+ 'debug' => ::Logger::DEBUG,
11
+ 'info' => ::Logger::INFO,
12
+ 'warn' => ::Logger::WARN,
13
+ 'error' => ::Logger::ERROR,
14
+ 'fatal' => ::Logger::FATAL,
15
+ 'unknown' => ::Logger::UNKNOWN,
15
16
  }
16
17
 
17
18
  # Delegator class for when you want to log to multiple devices
18
19
  # at the same time, such as STDOUT and a file.
19
- # @param loggers [::Logger] one or more instances of Logger
20
+ # @param loggers [Logger] one or more instances of CemAcpt::Logging::Logger
20
21
  class MultiLogger
22
+ # @param configs [Array<Hash>] an array of hashes containing the
23
+ # configuration for each logger. Each hash must contain the keys
24
+ # :logdev, :shift_age, and :shift_size. The values for these keys
25
+ # are passed to the Logger.new method. Any other keys and values
26
+ # are passed to the Logger.new method as keyword arguments.
27
+ # @return [MultiLogger] a new instance of MultiLogger
28
+ def self.from_logger_configs(configs)
29
+ return if configs.nil? || configs.empty?
30
+
31
+ loggers = configs.map do |config|
32
+ CemAcpt::Logging::Logger.new(config[:logdev],
33
+ config[:shift_age],
34
+ config[:shift_size],
35
+ **config.except(:logdev, :shift_age, :shift_size))
36
+ end
37
+ new(*loggers)
38
+ end
39
+
21
40
  def initialize(*loggers)
22
41
  @loggers = loggers
23
42
  end
24
43
 
44
+ def logger_configs
45
+ @loggers.map(&:config_hash)
46
+ end
47
+
25
48
  def method_missing(m, *args, &block)
26
49
  if @loggers.all? { |l| l.respond_to?(m) }
27
50
  @loggers.map { |l| l.send(m, *args, &block) }
@@ -35,6 +58,137 @@ module CemAcpt
35
58
  end
36
59
  end
37
60
 
61
+ # Delagator class for the standard Ruby Logger class.
62
+ # This class is used to ensure the Github Actions formatter
63
+ # correctly formats the log output when using the standard
64
+ # Ruby Logger class methods such as #info, #debug, etc.
65
+ class Logger < ::Logger
66
+ attr_reader :config_hash
67
+ attr_accessor :trap_context
68
+
69
+ def initialize(logdev, shift_age = 0, shift_size = 1_048_576, **kwargs)
70
+ @config_hash = { logdev: logdev, shift_age: shift_age, shift_size: shift_size, **kwargs }
71
+ @ci_mode = (kwargs[:formatter].downcase.to_sym == :github_action || !ENV['GITHUB_ACTIONS'].nil? || !ENV['CI'].nil?)
72
+ kwargs[:formatter] = CemAcpt::Logging::Formatter.for(kwargs[:formatter]) if kwargs[:formatter]
73
+ super(logdev, shift_age, shift_size, **kwargs)
74
+ @raw_logdev = logdev # Used for logging from trap context
75
+ @trap_context = false # If true, will not use the standard Logger methods and will write directly to the logdev
76
+ @verbose = false
77
+ end
78
+
79
+ def set_verbose(value)
80
+ raise ArgumentError, 'value must be a boolean' unless [true, false].include?(value)
81
+
82
+ @verbose = value
83
+ end
84
+
85
+ def verbose(progname = nil, &block)
86
+ return unless @verbose
87
+
88
+ debug(progname, &block)
89
+ end
90
+
91
+ def debug(progname = nil, &block)
92
+ return if log_trap_context('debug', progname, &block)
93
+ return if log_ci_mode('debug', progname, &block)
94
+
95
+ super
96
+ end
97
+
98
+ def info(progname = nil, &block)
99
+ return if log_trap_context('info', progname, &block)
100
+ return if log_ci_mode('info', progname, &block)
101
+
102
+ super
103
+ end
104
+
105
+ def warn(progname = nil, &block)
106
+ return if log_trap_context('warn', progname, &block)
107
+ return if log_ci_mode('warn', progname, &block)
108
+
109
+ super
110
+ end
111
+
112
+ def error(progname = nil, &block)
113
+ return if log_trap_context('error', progname, &block)
114
+ return if log_ci_mode('error', progname, &block)
115
+
116
+ super
117
+ end
118
+
119
+ def fatal(progname = nil, &block)
120
+ return if log_trap_context('fatal', progname, &block)
121
+ return if log_ci_mode('fatal', progname, &block)
122
+
123
+ super
124
+ end
125
+
126
+ # Wraps the given block in a Github Actions group if in CI mode
127
+ # @param name [String] the name of the group
128
+ def with_ci_group(name)
129
+ return yield unless @ci_mode
130
+
131
+ self.<< "::group::#{name}\n"
132
+ yield
133
+ ensure
134
+ self.<< "::endgroup::\n" if @ci_mode
135
+ end
136
+
137
+ private
138
+
139
+ # Can't use the standard Logger methods when in trap context
140
+ # because they don't work. So we have to write directly to the
141
+ # raw logdev. Unlike the standard Logger methods, there is no
142
+ # Mutex lock, so messages are not guaranteed to be in order.
143
+ # This is necessary in the trap context because using a Mutex
144
+ # lock in a trap context will cause a deadlock.
145
+ def log_trap_context(severity, progname = nil, &block)
146
+ return false unless @trap_context && level <= LEVEL_MAP[severity]
147
+
148
+ if @raw_logdev.respond_to?(:puts)
149
+ @raw_logdev.puts(ci_format(severity, false, progname, &block))
150
+ elsif @raw_logdev.respond_to?(:write)
151
+ @raw_logdev.write(ci_format(severity, true, progname, &block))
152
+ else
153
+ # Default to logging to STDERR
154
+ $stderr.puts(ci_format(severity, false, progname, &block))
155
+ end
156
+ true
157
+ end
158
+
159
+ # CI mode uses << instead of the standard Logger methods
160
+ # because Github Actions wants messages to be echoed. This
161
+ # is a way to ensure that, in the event of using a multi-logger
162
+ # with a standard Logger, the CI mode messages are still
163
+ # formatted correctly.
164
+ def log_ci_mode(severity, progname = nil, &block)
165
+ return false unless @ci_mode && level <= LEVEL_MAP[severity]
166
+
167
+ self.<<(ci_format(severity, true, progname, &block))
168
+ true
169
+ end
170
+
171
+ # Formats the log message for CI mode, translating the severity
172
+ # level to the correct format for Github Actions and adding
173
+ # the colon separators.
174
+ def ci_format(severity, newline = true, progname = nil, &block)
175
+ sev = if severity == 'fatal'
176
+ 'error'
177
+ elsif severity == 'warn'
178
+ 'warning'
179
+ elsif severity == 'info'
180
+ 'notice'
181
+ else
182
+ severity
183
+ end
184
+ block_message = block_given? ? block.call : nil
185
+ base = [progname, block_message].compact.join(': ')
186
+ return if base.empty?
187
+
188
+ newline ? "::#{sev}::#{base}\n" : "::#{sev}::#{base}"
189
+ end
190
+ end
191
+
38
192
  class << self
39
193
  def new_logger(*logdevs, **configs)
40
194
  new_configs = current_log_config.merge(configs.reject { |_, v| v.nil? })
@@ -57,14 +211,9 @@ module CemAcpt
57
211
 
58
212
  # Exposes a logger instance. Will either use the currently set logger or
59
213
  # create a new one.
60
- # @return [Logger]
214
+ # @return [MultiLogger]
61
215
  def logger
62
- @logger ||= Logger.new(
63
- current_log_config[:logdev],
64
- current_log_config[:shift_age],
65
- current_log_config[:shift_size],
66
- **current_log_config.reject { |k, _| %i[logdev shift_age shift_size].include?(k) }
67
- )
216
+ @logger ||= new_logger($stdout)
68
217
  end
69
218
 
70
219
  # Shortcut method for logger.level
@@ -92,41 +241,7 @@ module CemAcpt
92
241
  # @param f [Symbol] the log format style to set
93
242
  # @return [Proc] the proc to be passed to Logger#formatter=
94
243
  def new_log_formatter(f)
95
- case f.downcase.to_sym
96
- when :json
97
- require 'json'
98
- @current_log_format = :json
99
- proc do |severity, datetime, progname, msg|
100
- {
101
- timestamp: datetime,
102
- progname: progname,
103
- severity: severity,
104
- message: msg,
105
- }.to_json + "\n"
106
- end
107
- when :text
108
- @current_log_format = :text
109
- proc do |severity, _datetime, _progname, msg|
110
- "#{severity} - #{msg}\n"
111
- end
112
- when :github_action
113
- @current_log_format = :github_action
114
- sev_map = {
115
- 'DEBUG' => '::debug::',
116
- 'INFO' => '::notice::',
117
- 'WARN' => '::warning::',
118
- 'ERROR' => '::error::',
119
- 'FATAL' => '::error::',
120
- }
121
- proc do |severity, _datetime, _progname, msg|
122
- "#{sev_map[severity]}{#{msg}}\n"
123
- end
124
- else
125
- @current_log_format = :file
126
- proc do |severity, datetime, _progname, msg|
127
- "[#{datetime}] #{severity}: #{msg}\n"
128
- end
129
- end
244
+ CemAcpt::Logging::Formatter.for(f)
130
245
  end
131
246
 
132
247
  # Returns the current log config if set, or the default if not.
@@ -134,15 +249,14 @@ module CemAcpt
134
249
  def current_log_config
135
250
  return @log_config if @log_config
136
251
 
137
- formatter = new_log_formatter(current_log_format)
138
252
  @log_config = {
139
253
  logdev: $stdout,
140
254
  shift_age: 'o',
141
255
  shift_size: 1_048_576,
142
- level: Logger::INFO,
256
+ level: ::Logger::INFO,
143
257
  progname: 'CemAcpt',
144
258
  datetime_format: '%Y%m%dT%H%M%S%z',
145
- formatter: formatter,
259
+ formatter: current_log_format,
146
260
  }
147
261
  @log_config
148
262
  end
@@ -177,12 +291,12 @@ module CemAcpt
177
291
  @log_config[:logdev] = $stdout
178
292
  logger.warn("Unknown log target: #{logdev.inspect}, using STDOUT")
179
293
  end
180
- @logger = Logger.new(
294
+ @logger = MultiLogger.new(Logger.new(
181
295
  @log_config[:logdev],
182
296
  @log_config[:shift_age],
183
297
  @log_config[:shift_size],
184
298
  **@log_config.reject { |k, _| %i[logdev shift_age shift_size].include?(k) },
185
- )
299
+ ))
186
300
  end
187
301
  end
188
302
 
@@ -260,92 +374,4 @@ module CemAcpt
260
374
  CemAcpt::Logging.new_log_config(logdev: logdev, shift_age: shift_age, shift_size: shift_size, level: level, formatter: formatter, datetime_format: datetime_format)
261
375
  end
262
376
  end
263
-
264
- module LoggingAsync
265
- require 'concurrent-ruby'
266
-
267
- class << self
268
- def log_write_thread
269
- @log_write_thread ||= Concurrent::SingleThreadExecutor.new
270
- end
271
-
272
- def async_debug(message, prefix = nil)
273
- msg = prefix.nil? || prefix.empty? ? message : "#{prefix} #{message}"
274
- CemAcpt::Logging.logger.debug(msg)
275
- end
276
-
277
- def async_info(message, prefix = nil)
278
- msg = prefix.nil? || prefix.empty? ? message : "#{prefix} #{message}"
279
- CemAcpt::Logging.logger.info(msg)
280
- end
281
-
282
- def async_warn(message, prefix = nil)
283
- msg = prefix.nil? || prefix.empty? ? message : "#{prefix} #{message}"
284
- CemAcpt::Logging.logger.warn(msg)
285
- end
286
-
287
- def async_error(message, prefix = nil)
288
- msg = prefix.nil? || prefix.empty? ? message : "#{prefix} #{message}"
289
- CemAcpt::Logging.logger.error(msg)
290
- end
291
-
292
- def async_fatal(message, prefix = nil)
293
- msg = prefix.nil? || prefix.empty? ? message : "#{prefix} #{message}"
294
- CemAcpt::Logging.logger.fatal(msg)
295
- end
296
- end
297
-
298
- # Provides class method wrappers for logging methods
299
- def self.included(base)
300
- class << base
301
- def log_write_thread
302
- CemAcpt::LoggingAsync.log_write_thread
303
- end
304
-
305
- def async_debug(message, prefix = nil)
306
- CemAcpt::LoggingAsync.async_debug(message, prefix)
307
- end
308
-
309
- def async_info(message, prefix = nil)
310
- CemAcpt::LoggingAsync.async_info(message, prefix)
311
- end
312
-
313
- def async_warn(message, prefix = nil)
314
- CemAcpt::LoggingAsync.async_warn(message, prefix)
315
- end
316
-
317
- def async_error(message, prefix = nil)
318
- CemAcpt::LoggingAsync.async_error(message, prefix)
319
- end
320
-
321
- def async_fatal(message, prefix = nil)
322
- CemAcpt::LoggingAsync.async_fatal(message, prefix)
323
- end
324
- end
325
- end
326
-
327
- def log_write_thread
328
- CemAcpt::LoggingAsync.log_write_thread
329
- end
330
-
331
- def async_debug(message, prefix = nil)
332
- CemAcpt::LoggingAsync.async_debug(message, prefix)
333
- end
334
-
335
- def async_info(message, prefix = nil)
336
- CemAcpt::LoggingAsync.async_info(message, prefix)
337
- end
338
-
339
- def async_warn(message, prefix = nil)
340
- CemAcpt::LoggingAsync.async_warn(message, prefix)
341
- end
342
-
343
- def async_error(message, prefix = nil)
344
- CemAcpt::LoggingAsync.async_error(message, prefix)
345
- end
346
-
347
- def async_fatal(message, prefix = nil)
348
- CemAcpt::LoggingAsync.async_fatal(message, prefix)
349
- end
350
- end
351
377
  end