Common Ruby Logger
The ‘mintpress-logger’ ruby gem provides the MintLogger module to include into any ruby class that requires logging. By default it creates a STDOUT/STDERR logger, with logging enabled at Logger::INFO level.
Setting Up the Logger
set_log_level
The set_log_level method should only be called from an entry point into the ruby code. Common utilities / gems should refrain from calling it is preferrable that they inherit the current log settings from the code that is calling them.
The first parameter can be * a String (debug/info/warn/error/fatal) * a Symbol (:debug/:info/:warn/:error/:fatal) * an Integer (Logger::DEBUG/Logger::INFO/Logger::WARN/Logger::ERROR/Logger::FATAL)
The second parameter can be * nil (if changing the default log level), or * the file name of the entry point into the code (if changing the default log level for all code called from this entry point).
set_log_prefix
The set_log_prefix method allows control over the text that prefixes the log messages produced by the logger. It accepts a LogPrefixElements object, that describes the required format. The message prefix can contain zero or more of the following elements:
element | description |
---|---|
:date | log date and time |
:severity | log message severity (DEBUG/INFO/WARN/ERROR/FATAL) |
:progname | the name of the class & method that generated the log message |
:other | allows text constants to be included in the prefix |
The order the elements appear in the elements: array passed to the LogPrefixElements object determines the order they appear in the prefix. The date_format: string passed to the LogPrefixElements object determines the format of the :date element. The DateTime documentation describes the values that can be used to format the date. The default date format is "%Y-%m-%d %H:%M:%S"
.
The log prefix call below is the default used by MintLogger
set_log_prefix(
LogPrefixElements.new(
elements: [
LogPrefix.new(
prefix: "[",
suffix: "] ",
element: :date
),
LogPrefix.new(
prefix: nil,
suffix: nil,
element: :severity
),
LogPrefix.new(
prefix: " (",
suffix: ") ",
element: :progname
)
],
date_format: "%Y-%m-%d %H:%M:%S"
)
)
This generates log messages with a prefix: [2018-11-21 18:00:08] DEBUG (MintPress::OracleEBS::DBHost.get_patch_level)
enable_debug_file_log
Calling the enable_debug_file_log method will cause the MintLogger to log all messages (regardless of level) into a local debug log file. Logging into the debug log file is independent of the STDOUT/STDERR logger controlled by the set_log_level and set_log_prefix methods. Eg the STDOUT/STDERR logger can be configured to log Logger::ERROR -> Logger::FATAL messages, whilst the debug log file will receive Logger::DEBUG -> Logger::FATAL messages.
The enable_debug_file_log method accepts three parameters:
parameter | description |
---|---|
file_name | The name of the file to create on the local file system. The default file is /tmp/mp_debug.log |
mode | Valid values are (w)rite and (a)ppend. In write mode, the file is replaced each time the enable_debug_file_log is called. In append mode it appends to the existing file (or creates a new one) |
debug_log_prefix | LogPrefixElements object describing the prefix to use in the log file. If not provided, the default described above is used. |
disable_debug_file_log
Calling the disable_debug_file_log method will cause the MintLogger to no logger log messages into the debug log file. This has no affect on the STDOUT/STDERR logger.
For further details on the CLI, please refer to docs.oracle.com/en/database/oracle/oracle-database/12.2/dgbkr/oracle-data-guard-broker-commands.html
Utilities - Common
check_result
The check_result method is used with the LASRpcUtils::ConsoleTuple result values returned from the las_rpc_utils execute command. It accepts the following parameters
Parameter | Default | Description |
---|---|---|
command: | The command that was passed to las-rpc-utils execute. | |
result: | The LASRpcUtils::ConsoleTuple returned from las-rpc-utils execute. | |
success_msg: | A message to print if the result.exit_status = 0. nil if no success message required. | |
failure_msg: | A message to print if the result.exit_status != 0. nil if no failure message required. | |
success_out: | :debug | Logger target for the success messages (anything that translate_log_level can translate). |
failure_out: | :error | Logger target for the failure messages (anything that translate_log_level can translate). |
abort_on_failure: | false | true/false value, if set to true check_result will raise the failure_msg if result.exit_status != 0. |
print_command: | false | true/false value, if true, prints the command that was successful prior to printing the success_msg. (applies to exit_status = 0 only). |
With the default parameters: * if the result.exit_status passed in is 0, it will print the success_msg passed in as a debug message * if the result.exit_status passed in is not 0, it will print the failure_msg passed in as an error message along with the exit status, stdout and stderr.
fmt_variable
The fmt_variable returns a string based on the following parameters:
Parameter | Default | Description |
---|---|---|
prompt | Text to print prior to the variable’s contents | |
variable | Variable to print the contents of (must be a String) | |
dont_pad | false | true/false, whether to right pad the prompt text to prompt_length or not. |
prompt_length: | PROMPT_LENGTH | The width to pad the prompt string with (PROMPT_LENGTH=20) |
A sample output from fmt_variable("surname",surname_var,true)
is surname: Anderson
fmt_hash
The fmt_hash method loops through the elements in a hash (or array) and, using fmt_variable builds a debug string of the hash/array’s contents. It derives the prompt_length to call fmt_variable with as the longest hash key + 4 or the array length + 3.
Utilities - Logging
translate_log_level
The translate_log_level method translates the log_level passed in into an integer that reflects the Logger constants for the various log levels. The parameter value can be:
Object Type | Debug | Info | Warn | Error | Fatal |
---|---|---|---|---|---|
a string | “debug” | “info” | “warn” | “error” | “fatal” |
a symbol | :debug | :info | :warn | :error | :fatal |
an integer | Logger::DEBUG | Logger::INFO | Logger::WARN | Logger::ERROR | Logger::FATAL |
If the log_level passed is a String, translate_log_level will downcase the value passed.
current_log_level
The current_log_level method returns the log level configured for the current call stack. (as one of the Logger::XXX constants)
logging_at?
The logging_at? method returns true if the log level passed in is greater than or equal to the current log level, false otherwise
debug_logging_enabled?
The debug_logging_enabled? method returns true if the current log level is Logger::DEBUG, false otherwise
info_logging_enabled?
The debug_logging_enabled? method returns true if the current log level is Logger::DEBUG or Logger::INFO, false otherwise
Logging Messages
debug, info, warn, error, fatal
The debug, info, warn, error and fatal methods all accept either * a bracketed string (eg. info("Here is a test message")
or * a lambda/proc info { "here is a test message" }
.
The proc will only be executed if logging is enabled at the level requested. It is recommended that all calls to debug use the proc call method to reduce processing overhead.
def my_test
debug { "here is a debug message" }
info { "here is an information message" }
warn { "here is a warning message" }
error { "here is an error message" }
fatal { "here is a fatal message" }
end
throw_error
Similar to the methods above, abort will accept a string or lambda/proc as a parameter. As abort messages eventually get ‘raise’d, the proc will always be processed so there is little benefit in using a proc to pass the message content. It is provided more for compatibility with the other methods above.
The throw_error method accepts an optional second parameter use_fail:. By default, abort will use raise to produce the message. If the use_fail: parameter is set to true, abort will use fail to produce the message.
NB. As raise and fail are aliases of each other, this has zero effect AFAIK)
def my_test
throw_error("Major exception occurred")
end
log_exception
The log_exception method accepts a StandardError exception and builds a backtrace stack (like the one that ruby generates when an un-rescued raise is encountered) then logs it to the Logger::ERROR output. If the optional raise_error: parameter is set to true, log_exception will use throw_error to output the backtrace.
start_method
Logs the string --> ENTER <--
as a debug message
end_method
Logs the string --> EXIT <--
as a debug message
Configuration File
If, when the MintLogger is first activated, the current user’s home directory includes a .limepoint
subdirectory, MintLogger will listen for changes in that directory. If a MintLogger configuration file (mlConfig.toml
) is created, modified or deleted from the directory this will impact the current run-time logging environment.
The configuration file has the following structure:
[levelOverrides]
DifferentClass = "info"
SampleClass = "debug"
[excludeMethods]
DifferentClass = []
SampleClass = ["differentTest"]
[includeMethods]
DifferentClass = []
SampleClass = ["/.*Test/", "testDebug"]
Configuration File Sections
levelOverrides
This section allows the log level assigned to each class to be dynamically overridden. Each key value is a ruby class (case sensitive) and the value for each key is the debug log level to use when checking if messages should be output from that class. Valid values are “debug”, “info”, “warn”, “error” or “fatal”.
excludeMethods
This section allows configuration of methods that should not produce log output. Each key value is a ruby class (case sensitive) and the value for each key is an array of method names or regex’s to “match” methods to exclude from logging. NB. toml does not allow a native ruby regex as an array value so it must be enclosed in double quotes per the SampleClass example in the includeMethods above.
includeMethods
This section allows configuration of methods that should produce log output. Each key value is a ruby class (case sensitive) and the value for each key is an array of method names or regex’s to “match” methods to include in the logging. NB. toml does not allow a native ruby regex as an array value so it must be enclosed in double quotes per the SampleClass example in the includeMethods above.
Configuration File Processing
When deciding to log (or not log) a message from a class, the configuration file’s contents are processed in the following sequence outlined below. Each step in the sequence is only performed if the previous steps are successful. 1. levelOverrides - the message must be being logged from the class at a level greater than or equal to the override level for that class (Logger::DEBUG = 0, Logger::INFO = 1, Logger::WARN = 2, Logger::ERROR = 3, Logger::FATAL = 4). If no override level exists in the toml file, then the message log level will be compared to the default level provided by the class itself (or one of its parents) 2. includeMethods - the message must be one of the following : * logged from a class that is not listed in the includeMethods section of the toml file * logged from a method that matches one of the patterns in the includeMethods array for this class * logged from a class with no elements in its includeMethods array (eg differentClass above) 3. excludeMethods - the message must be one of the following: * logged from a class that is not listed in the excludeMethods section of the toml file * logged from a method that does not match one of the patterns in the excludeMethods array for this class * logged from a class with no elements in its excludeMethods array (eg differentClass above)
Example Configuration File and Logger Usage
NB. This example assumes the configuration file above has been saved into ~/.limepoint
for the current user.
irb
require 'mintpress-logger'
class SampleClass
include MintLogger
attr_accessor :sampleVar
def initialize
@sampleVar = "Fred"
end
def testDebug
debug { "Here's a log message from testDebug" }
debug { fmt_variable("sampleVar", @sampleVar) }
end
def anotherTest
info { "Here's a log message from anotherTest" }
info { fmt_variable("sampleVar", @sampleVar) }
end
def differentTest
debug { "Here's a log message from anotherTest" }
debug { fmt_variable("sampleVar", @sampleVar) }
end
def finalTest
info { "Here's a log message from finalTest" }
info { fmt_variable("sampleVar", @sampleVar) }
end
end
class DifferentClass
include MintLogger
attr_accessor :mySample
def initialize
set_log_level("debug", parent_path: __FILE__)
@mySample = SampleClass.new
info "Printing sampleVar in DifferentClass.initialize"
info "#{@mySample.sampleVar}"
info "Calling @mySample.testDebug in DifferentClass.initialize"
@mySample.testDebug
info "End of initialize"
end
def test
debug "Calling @mySample.testDebug in test - debug" # this won't appear due to level override
info "Calling @mySample.testDebug in test - info"
@mySample.testDebug
debug "Creating a new SampleClass object"
newtest = SampleClass.new
info "Calling finalTest"
newtest.finalTest
info "Calling differentTest - mlConfig.toml override will block output"
newtest.differentTest
info "End of Fred.test"
end
end
logTest = DifferentClass.new
logTest.test
License & Authors
-
Author:: LimePoint (support@limepoint.com)
# MintPress® - Automation and Configuration Management
#
# Copyright © 2019 LimePoint. All rights reserved.
#
# This program and its contents are confidential and owned by LimePoint.
# Only licenced users are permitted to access and use of this file.
# This program (or any part of it) may not be disclosed, copied or used
# except as expressly permitted in LimePoint’s End User Licence Agreement.
#
# LimePoint® and MintPress® are Registered Trademarks of LimePoint IP Limited.
# For more information contact LimePoint at http://www.limepoint.com