Class: Slog::Logger

Inherits:
Logger show all
Defined in:
lib/slog/logger.rb

Overview

A colorful structured logger.

Constant Summary collapse

DEFAULT_LEVEL =
::Logger::INFO

Constants inherited from Logger

Logger::TRACE

Instance Method Summary collapse

Methods inherited from Logger

#trace

Constructor Details

#initialize(out: $stdout, shift_age: 7, shift_size: 1_048_576, colorize: true, prettify: true, level: DEFAULT_LEVEL, level_transform: 'downcase', level_field: 'level', message_field: 'message', timestamp_field: '@timestamp', timestamp_format: '%FT%T.%3N%:z', color_map: { 'debug' => [ :blue, :default ], 'info' => [ :green, :default ], 'warn' => [ :yellow, :default ], 'error' => [ :red, :default ], 'fatal' => [ :red, :black ], 'trace' => [ :magenta, :default ] }) ⇒ Logger

Create a new Logger.

A little different than the canonical Logger. Add options to set the log level and to disable both colorization and pretty JSON output. In this form, it’s perfect for use with either Logstash or Franz.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/slog/logger.rb', line 39

def initialize \
  out:$stdout,                     # Output handle
  shift_age:7,                     # Max seven logs
  shift_size:1_048_576,            # 1024 KiB
  colorize:true,                   # Disable for files
  prettify:true,                   # Disable for files
  level:DEFAULT_LEVEL,             # INFO
  level_transform:'downcase',      # Any String method
  level_field:'level',             # nil to disable
  message_field: 'message',        # nil to disable
  timestamp_field:'@timestamp',    # nil to disable
  timestamp_format:'%FT%T.%3N%:z', # ISO-8601
  color_map: {
    'debug' => [ :blue,    :default ],
    'info'  => [ :green,   :default ],
    'warn'  => [ :yellow,  :default ],
    'error' => [ :red,     :default ],
    'fatal' => [ :red,     :black   ],
    'trace' => [ :magenta, :default ]
  }

  @prettify = prettify
  @colorize = colorize
  @color_map = color_map
  @level_field = level_field
  @level_transform = level_transform
  @message_field = message_field
  @timestamp_field = timestamp_field
  @timestamp_format = timestamp_format

  super out, shift_age, shift_size
  self.level = level

  set_formatter
end

Instance Method Details

#format_json(event, severity) ⇒ Object

Convert the structured event into it’s JSON representation



109
110
111
112
113
114
115
116
# File 'lib/slog/logger.rb', line 109

def format_json event, severity
  generator = @prettify ? :pretty_generate : :generate
  event = JSON.send(generator, event) + "\n"
  return event unless @colorize
  event.colorize \
    color: @color_map[severity][0],
    background: @color_map[severity][1]
end

#level=(l) ⇒ Object

Override the level setter to allow symbols and TRACE



120
121
122
123
124
125
# File 'lib/slog/logger.rb', line 120

def level= l
  l = ::Logger.const_get l.upcase if l.is_a? Symbol
  @trace = l == ::Logger::TRACE # TRACE is really a fancy DEBUG
  l = ::Logger::DEBUG if @trace # Here's the proof.
  super l
end

#set_formatterObject

Set the formatter to work our magic



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/slog/logger.rb', line 77

def set_formatter
  self.formatter = proc do |severity, datetime, _, message|
    severity.downcase!

    # If it ain't a structured log, it is now.
    event = structure_event severity, datetime, message

    # When debugging, mark the location in Hoss's source
    unless level == DEFAULT_LEVEL
      event.merge! marker: File.basename(caller[4])
    end

    # Apply colorization and prettification as required
    format_json event, severity
  end
end

#structure_event(severity, datetime, message) ⇒ Object

Turn a call to the formatter into a Hash structure



96
97
98
99
100
101
102
103
104
105
# File 'lib/slog/logger.rb', line 96

def structure_event severity, datetime, message
  message = { @message_field => message } unless message.is_a? Hash
  event = {
    @level_field => severity.send(@level_transform),
    @timestamp_field => datetime.strftime(@timestamp_format)
  }
  event.merge! message
  event.delete nil # ignore @field if @field.nil?
  event
end