Module: HybridPlatformsConductor::LoggerHelpers

Overview

Gives easy logging methods to any class including this module, such as log_error, log_debug… Also define methods for UI (meaning text that should be displayed as interface, and not as logging).

Defined Under Namespace

Classes: ProgressBarLogDevice

Constant Summary collapse

LEVELS_MODIFIERS =

Sorted list of levels and their corresponding modifiers.

{
  fatal: [:red, :bold],
  error: [:red, :bold],
  warn: [:yellow, :bold],
  info: [:white],
  debug: [:white],
  unknown: [:white]
}
LEVELS_TO_STDERR =

List of levels that will output on stderr

%i[warn error fatal]

Class Attribute Summary collapse

Instance Method Summary collapse

Class Attribute Details

.progress_bar_semaphoreObject (readonly)

Returns the value of attribute progress_bar_semaphore.



67
68
69
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 67

def progress_bar_semaphore
  @progress_bar_semaphore
end

Instance Method Details

#err(message = '') ⇒ Object

Print an error string to the command-line UI. This is different from logging because this is the UI of the CLI. Use sections indentation for better clarity.

Parameters
  • message (String): Message to be printed out [default = ”]



167
168
169
170
171
172
173
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 167

def err(message = '')
  @out_sections = [] unless defined?(@out_sections)
  message = "#{'  ' * @out_sections.size}#{message}"
  # log_debug "<Output> - #{message}"
  message = "#{message}\n" unless message.end_with?("\n")
  @logger_stderr << message
end

#init_loggers(logger, logger_stderr) ⇒ Object

Initialize loggers

Parameters
  • logger (Logger): Logger used for stdout

  • logger_stderr (Logger): Logger used for stderr



99
100
101
102
103
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 99

def init_loggers(logger, logger_stderr)
  @logger = logger
  @logger_stderr = logger_stderr
  set_loggers_format
end

#log_component=(component) ⇒ Object

Set the logging component name, to be prepend in any log message, or nil if none. By default the component is the class name.

Parameters
  • component (String or nil): Logging component, or nil for none



143
144
145
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 143

def log_component=(component)
  @log_component = component
end

#log_debug?Boolean

Are we in debug level?

Result
  • Boolean: Are we in debug level?

Returns:

  • (Boolean)


134
135
136
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 134

def log_debug?
  @logger.debug?
end

#log_level=(level) ⇒ Object

Set log level

Parameters
  • level (Symbol): Log level (used directly with the logger)



126
127
128
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 126

def log_level=(level)
  @logger.level = level
end

#out(message = '') ⇒ Object

Print a string to the command-line UI. This is different from logging because this is the UI of the CLI. Use sections indentation for better clarity.

Parameters
  • message (String): Message to be printed out [default = ”]



153
154
155
156
157
158
159
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 153

def out(message = '')
  @out_sections = [] unless defined?(@out_sections)
  message = "#{'  ' * @out_sections.size}#{message}"
  # log_debug "<Output> - #{message}"
  message = "#{message}\n" unless message.end_with?("\n")
  @logger << message
end

#section(name) ⇒ Object

Display a new section in the UI, used to group a set of operations

Parameters
  • name (String): Section name

  • Proc: Code called in the section



180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 180

def section(name)
  out "===== #{name} ==== Begin..."
  @out_sections = [] unless defined?(@out_sections)
  @out_sections << name
  begin
    yield
  ensure
    @out_sections.pop
    out "===== #{name} ==== ...End"
    out
  end
end

#set_loggers_formatObject

Set loggers to the desired format



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 106

def set_loggers_format
  [@logger, @logger_stderr].each do |logger|
    logger.formatter = proc do |severity, datetime, progname, msg|
      # If the message already has control characters, don't colorize it
      keep_original_color = msg.include? "\u001b"
      message = "[#{Time.now.utc.strftime('%F %T')} (PID #{$$} / TID #{Thread.current.object_id})] #{severity.rjust(5)} - [ #{progname} ] - "
      message << "#{msg}\n" unless keep_original_color
      LEVELS_MODIFIERS[severity.downcase.to_sym].each do |modifier|
        message = message.send(modifier)
      end
      message << "#{msg}\n" if keep_original_color
      message
    end
  end
end

#stderr_deviceObject

Get the stderr device

Result
  • IO or String: The stdout IO or file name



215
216
217
218
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 215

def stderr_device
  # TODO: Find a more elegant way to access the internal log device
  @logger_stderr.instance_variable_get(:@logdev).dev
end

#stderr_device=(log_device) ⇒ Object

Set the stderr device

Parameters
  • log_device (Object): The stdout log device to set



224
225
226
227
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 224

def stderr_device=(log_device)
  # TODO: Find a more elegant way to access the internal log device
  @logger_stderr.instance_variable_get(:@logdev).send(:set_dev, log_device)
end

#stderr_displayed?Boolean

Is stderr really getting to the terminal display?

Result
  • Boolean: Is stderr really getting to the terminal stdout?

Returns:

  • (Boolean)


242
243
244
245
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 242

def stderr_displayed?
  log_device = stderr_device
  log_device == $stderr || log_device == $stdout || log_device.is_a?(ProgressBarLogDevice)
end

#stdout_deviceObject

Get the stdout device

Result
  • Object: The stdout log device



197
198
199
200
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 197

def stdout_device
  # TODO: Find a more elegant way to access the internal log device
  @logger.instance_variable_get(:@logdev).dev
end

#stdout_device=(log_device) ⇒ Object

Set the stdout device

Parameters
  • log_device (Object): The stdout log device to set



206
207
208
209
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 206

def stdout_device=(log_device)
  # TODO: Find a more elegant way to access the internal log device
  @logger.instance_variable_get(:@logdev).send(:set_dev, log_device)
end

#stdout_displayed?Boolean

Is stdout really getting to the terminal display?

Result
  • Boolean: Is stdout really getting to the terminal stdout?

Returns:

  • (Boolean)


233
234
235
236
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 233

def stdout_displayed?
  log_device = stdout_device
  log_device == $stdout || log_device == $stderr || log_device.is_a?(ProgressBarLogDevice)
end

#stdouts_to_sObject

Return a string describing the stdout and stderr if they were logged into files or StringIO. Useful for debugging.

Result
  • String: The corresponding stdout and stderr info, or nil if none



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 298

def stdouts_to_s
  messages = []
  {
    'STDOUT' => self.stdout_device,
    'STDERR' => self.stderr_device
  }.each do |name, device|
    if device.is_a?(File)
      if File.exist?(device.path)
        content = File.read(device.path).strip
        messages << "----- #{name} BEGIN - #{device.path} -----\n#{content}\n----- #{name} END - #{device.path} -----" unless content.empty?
      end
    elsif device.is_a?(StringIO)
      content = device.string
      messages << "----- #{name} BEGIN -----\n#{content}\n----- #{name} END -----" unless content.empty?
    end
  end
  messages.empty? ? nil : messages.join("\n")
end

#with_progress_bar(nbr_total, name: nil) ⇒ Object

Create a UI progress bar and call some code with it. Ensure logging done with the progress bar does not conflict in stdout.

Parameters
  • nbr_total (Integer): Total value of the progress bar

  • name (String or nil): Name to put on the progress bar, or nil for no name [default: nil]

  • Proc: Code block called with the progress bar

    • Parameters
      • progress_bar (ProgressBar): The progress bar



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/hybrid_platforms_conductor/logger_helpers.rb', line 256

def with_progress_bar(nbr_total, name: nil)
  previous_stdout_device = nil
  previous_stderr_device = nil
  progress_bar = nil
  LoggerHelpers.progress_bar_semaphore.synchronize do
    stdout_log_device = stdout_device
    progress_bar = ProgressBar.create(
      output: stdout_log_device.is_a?(ProgressBarLogDevice) ? $stdout : stdout_log_device,
      title: 'Initializing...',
      total: nbr_total,
      format: "#{name ? "#{name} " : ''}[%j%%] - |%bC%i| - [ %t ]",
      progress_mark: ' ',
      remainder_mark: '-'
    )
    if stdout_displayed? && !stdout_log_device.is_a?(ProgressBarLogDevice)
      # Change the current logger so that when its logdev calls write it redirects to our ProgressBar#log
      previous_stdout_device = stdout_device
      self.stdout_device = ProgressBarLogDevice.new(progress_bar, previous_stdout_device)
    end
    if stderr_displayed? && !stderr_device.is_a?(ProgressBarLogDevice)
      # Change the current logger so that when its logdev calls write it redirects to our ProgressBar#log
      previous_stderr_device = stderr_device
      self.stderr_device = ProgressBarLogDevice.new(progress_bar, previous_stderr_device)
    end
  end
  begin
    yield progress_bar
  ensure
    LoggerHelpers.progress_bar_semaphore.synchronize do
      self.stdout_device.flush
      self.stderr_device.flush
      self.stdout_device = previous_stdout_device unless previous_stdout_device.nil?
      self.stderr_device = previous_stderr_device unless previous_stderr_device.nil?
    end
  end
end