Class: Mimi::Logger

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Core::Module
Defined in:
lib/mimi/logger.rb,
lib/mimi/logger/version.rb,
lib/mimi/logger/instance.rb,
lib/mimi/logger/null_logger.rb

Overview

Mimi::Logger is a preconfigured logger which outputs log messages to STDOUT.

Defined Under Namespace

Modules: Instance Classes: NullLogger

Constant Summary collapse

CONTEXT_ID_SIZE =

bytes

8
CONTEXT_ID_THREAD_VARIABLE =
'mimi_logger_context_id'
VERSION =
'0.2.2'.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Logger

Creates a new Logger instance

Examples:

logger = Mimi::Logger.new
logger.info 'I am a banana!' # outputs "I, I am a banana!" to the STDOUT

logger = Mimi::Logger.new(level: :debug)
logger.debug 'blabla' # => "D, blabla"

Parameters:

  • io (IO)

    An IO object to output log messages to, defaults to STDOUT

  • opts (Hash)
  • [String,Symbol,Integer] (Hash)

    a customizable set of options

Raises:

  • (ArgumentError)


45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/mimi/logger.rb', line 45

def initialize(*args)
  io = args.shift if args.first.is_a?(IO) || args.first.is_a?(StringIO)
  io ||= STDOUT
  opts = args.shift if args.first.is_a?(Hash)
  opts ||= {}
  raise ArgumentError, '(io, opts) are expected as parameters' unless args.empty?

  @options = self.class.module_options.deep_merge(opts)
  @logger_instance = ::Logger.new(io)
  @logger_instance.level = self.class.level_from_any(options[:level])
  io.sync = true if io.respond_to?(:sync=)
  @logger_instance.formatter = self.class.formatter(options)
end

Instance Attribute Details

#logger_instanceObject (readonly)

Returns the value of attribute logger_instance.



19
20
21
# File 'lib/mimi/logger.rb', line 19

def logger_instance
  @logger_instance
end

#optionsObject (readonly)

Returns the value of attribute options.



19
20
21
# File 'lib/mimi/logger.rb', line 19

def options
  @options
end

Class Method Details

.context_idString

Returns current context ID if set, otherwise generates and sets a new context ID and returns it.

Context ID is local to the current thread. It identifies a group of instructions happening within same logical context, as a single operation. For example, processing an incoming request may be seen as a single context.

Context ID is logged with every message

Returns:

  • (String)

    a hex encoded context ID



225
226
227
# File 'lib/mimi/logger.rb', line 225

def self.context_id
  Thread.current[CONTEXT_ID_THREAD_VARIABLE] || new_context_id!
end

.context_id=(id) ⇒ Object

Sets the new context ID to the given value

Parameters:

  • id (String)


237
238
239
# File 'lib/mimi/logger.rb', line 237

def self.context_id=(id)
  Thread.current[CONTEXT_ID_THREAD_VARIABLE] = id
end

.formatter(options) ⇒ Proc

Returns formatter Proc object depending on configured format

Returns:

  • (Proc)


127
128
129
130
131
132
133
134
135
136
# File 'lib/mimi/logger.rb', line 127

def self.formatter(options)
  case options[:format].to_s
  when 'json'
    formatter_json(options)
  when 'string'
    formatter_string(options)
  else
    raise "Invalid format specified for Mimi::Logger: '#{module_options[:format]}'"
  end
end

.formatter_json(options) ⇒ Proc

Returns formatter for ‘json’ format

Parameters:

  • options (Hash)

    logger options

Returns:

  • (Proc)


144
145
146
147
148
149
150
151
# File 'lib/mimi/logger.rb', line 144

def self.formatter_json(options)
  proc do |severity, _datetime, _progname, message|
    h = formatter_message_args_to_hash(message)
    h[:c] = context_id if options[:log_context]
    h[:s] = severity.to_s[0]
    h.to_json + "\n"
  end
end

.formatter_message_args_to_hash(message_args) ⇒ Hash

Converts logger methods arguments passed in various forms to a message hash.

Arguments to a logger may be passed in 6 different ways: This helper method converts all possible variations into one Hash, where key m: refers to the message and the rest are optional parameters passed in a Hash argument.

Examples:

logger.info('String')
logger.info('String', param1: '..and a Hash')
logger.info(m: 'Just a Hash', param1: 'with optional data')

# and the same 3 ways in a block form
logger.info { ... }

Returns:

  • (Hash)


187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/mimi/logger.rb', line 187

def self.formatter_message_args_to_hash(message_args)
  message_args = message_args.is_a?(String) || message_args.is_a?(Hash) ? [message_args] : message_args
  if !message_args.is_a?(Array) || message_args.size > 2
    raise ArgumentError, "Mimi::Logger arguments expected to be Array of up to 2 elements: #{message_args.inspect}"
  end

  h = {}
  arg1 = message_args.shift
  arg2 = message_args.shift

  if arg1.is_a?(String)
    if arg2 && !arg2.is_a?(Hash)
      raise ArgumentError, 'Mimi::Logger arguments are expected to be one of (<String>, <Hash>, [<String>, <Hash>])'
    end
    h = arg2.dup || {}
    h[:m] = arg1
  elsif arg1.is_a?(Hash)
    if arg2
      raise ArgumentError, 'Mimi::Logger arguments are expected to be one of (<String>, <Hash>, [<String>, <Hash>])'
    end
    h = arg1.dup
  else
    raise ArgumentError, 'Mimi::Logger arguments are expected to be one of (<String>, <Hash>, [<String>, <Hash>])'
  end
  h
end

.formatter_string(options) ⇒ Proc

Returns formatter for ‘string’ format

Parameters:

  • options (Hash)

    logger options

Returns:

  • (Proc)


159
160
161
162
163
164
165
166
167
168
169
# File 'lib/mimi/logger.rb', line 159

def self.formatter_string(options)
  proc do |severity, _datetime, _progname, message|
    h = formatter_message_args_to_hash(message)
    parts = []
    parts << severity.to_s[0]
    parts << context_id if options[:log_context]
    parts << h[:m].to_s.tr("\n", options[:cr_character])
    parts << '...' unless h.except(:m).empty?
    parts.join(', ') + "\n"
  end
end

.level_from_any(value) ⇒ Object

Returns the log level inferred from value

Parameters:

  • value (String, Symbol, Integer)


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/mimi/logger.rb', line 103

def self.level_from_any(value)
  return value if value.is_a?(Integer)
  case value.to_s.downcase.to_sym
  when :debug
    ::Logger::DEBUG
  when :info
    ::Logger::INFO
  when :warn
    ::Logger::WARN
  when :error
    ::Logger::ERROR
  when :fatal
    ::Logger::FATAL
  when :unknown
    ::Logger::UNKNOWN
  else
    raise ArgumentError, "Invalid value for the log level: '#{value}'"
  end
end

.module_manifestObject

private-ish



259
260
261
262
263
264
265
266
# File 'lib/mimi/logger.rb', line 259

def self.module_manifest
  {
    log_level: {
      desc: 'Logging level (any of the "debug", "info", "warn", "error", "fatal")',
      default: 'info'
    }
  }
end

.new_context_id!String

Generates a new random context ID and sets it as current

Returns:

  • (String)

    a new context ID



249
250
251
# File 'lib/mimi/logger.rb', line 249

def self.new_context_id!
  self.context_id = SecureRandom.hex(CONTEXT_ID_SIZE)
end

Instance Method Details

#context_idObject



229
230
231
# File 'lib/mimi/logger.rb', line 229

def context_id
  self.class.context_id
end

#context_id=(id) ⇒ Object



241
242
243
# File 'lib/mimi/logger.rb', line 241

def context_id=(id)
  self.class.context_id = id
end

#debug(*args, &block) ⇒ Object

Logs a new message at the corresponding logging level



80
81
82
# File 'lib/mimi/logger.rb', line 80

def debug(*args, &block)
  logger_instance.debug(args, &block)
end

#error(*args, &block) ⇒ Object



89
90
91
# File 'lib/mimi/logger.rb', line 89

def error(*args, &block)
  logger_instance.error(args, &block)
end

#fatal(*args, &block) ⇒ Object



92
93
94
# File 'lib/mimi/logger.rb', line 92

def fatal(*args, &block)
  logger_instance.fatal(args, &block)
end

#info(*args, &block) ⇒ Object



83
84
85
# File 'lib/mimi/logger.rb', line 83

def info(*args, &block)
  logger_instance.info(args, &block)
end

#levelInteger

Returns the current log level

Returns:

  • (Integer)


63
64
65
# File 'lib/mimi/logger.rb', line 63

def level
  logger_instance.level
end

#level=(value) ⇒ Object

Sets the log level. Allows setting the log level from a String or a Symbol, in addition to the standard ::Logger::INFO etc.

Parameters:

  • value (String, Symbol, Integer)


72
73
74
# File 'lib/mimi/logger.rb', line 72

def level=(value)
  logger_instance.level = self.class.level_from_any(value)
end

#new_context_id!Object



253
254
255
# File 'lib/mimi/logger.rb', line 253

def new_context_id!
  self.class.new_context_id!
end

#unknown(*args, &block) ⇒ Object



95
96
97
# File 'lib/mimi/logger.rb', line 95

def unknown(*args, &block)
  logger_instance.unknown(args, &block)
end

#warn(*args, &block) ⇒ Object



86
87
88
# File 'lib/mimi/logger.rb', line 86

def warn(*args, &block)
  logger_instance.warn(args, &block)
end