Class: BlackBox::LogFormatter

Inherits:
Logger::Formatter
  • Object
show all
Defined in:
lib/black_box/log_formatter.rb

Overview

Colorized, structured variant of Ruby’s built-in Logger::Formatter.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(logger: nil, color: nil) ⇒ LogFormatter

Initializes a color formatter for the given logger (optional). By default, color will be disabled if the Logger is logging to a file (uses #instance_variable_get(:@filename)), enabled based on ENV otherwise.

If color is true or false (instead of nil), then color will be enabled or disabled regardless of the attached logger’s target or the TERM environment variable.



22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/black_box/log_formatter.rb', line 22

def initialize(logger: nil, color: nil)
  @pidcol = nil
  @appcol = nil
  @appname = nil # App name at last time of app name color calculation
  @color = color == true || (
    color != false &&
    (!logger || !logger.instance_variable_get(:@filename)) &&
    !!(ENV['TERM'].to_s.downcase =~ /(linux|mac|xterm|ansi|putty|screen)/)
  )

  AwesomePrint.force_colors! if Kernel.const_defined?(:AwesomePrint) && @color
end

Instance Attribute Details

#colorObject

Whether to highlight log lines in color.



12
13
14
# File 'lib/black_box/log_formatter.rb', line 12

def color
  @color
end

Class Method Details

.format(event, add_metadata, ap_color) ⇒ Object

Formats the given event into a String, using AwesomePrint or JSON.pretty_generate if possible, or using #inspect if not. Removes common metadata elements from Hash data, and if add_metadata is true, adds some of them back to the message string.

This could definitely be cleaner.



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/black_box/log_formatter.rb', line 79

def self.format(event, , ap_color)
  return event.to_s unless event.is_a?(Hash)

  event = event.clone

  msg = event.delete(:message)
  host = event.delete(:host)
  pname = event.delete(:process_name)
  env = event.delete(:env)
  pid = event.delete(:pid) # Process ID
  tid = event.delete(:tid) # Thread ID
  wid = event.delete(:wid) # Worker ID
  jid = event.delete(:jid) || event.delete('jid') # Job ID
  tags = event.delete(:tags) if event[:tags].is_a?(Array)

  event.delete(:request_id) if event[:request_id] == jid

  if 
    msg = "#{format_tags(tags)}#{msg}"
  end

  if event.any?
    begin
      if Kernel.const_defined?(:AwesomePrint) && event.respond_to?(:ai)
        data = event.ai(indent: -2, plain: !ap_color, multiline: true)
      else
        data = JSON.pretty_generate(event)
      end
    rescue => e
      data = event.inspect rescue "INSPECTION FAILED"
    end

    msg = "#{msg}: #{data}"
  end

  msg
end

.format_tags(tags) ⇒ Object

Formats an array of tags as a string like “[tag1] [tag2]…”, with a trailing space if there are any tags.



119
120
121
# File 'lib/black_box/log_formatter.rb', line 119

def self.format_tags(tags)
  "#{tags.map{|t| "[#{t}]"}.join(' ')} " if tags && tags.any?
end

Instance Method Details

#call(severity, datetime, progname, msg) ⇒ Object



35
36
37
38
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
# File 'lib/black_box/log_formatter.rb', line 35

def call(severity, datetime, progname, msg)
  # FIXME: Add inline metadata (TID, WID, JID) even if color is disabled
  return super(severity, datetime, progname, self.class.format(msg, true, false)) unless @color

  sc = severity_color(severity)
  dc = date_color(severity)
  pc = process_color(severity)
  mc = message_color(severity)
  ac = appname_color(severity, progname)
  ec = env_color(progname)
  rc = "\e[0;1;30m"

  pid = "#{pc}##{$$}"
  host = Socket.gethostname
  env = nil
  tags = nil

  if msg.is_a?(Hash)
    t = msg[:tid]
    w = msg[:wid]
    j = msg[:jid] || msg['jid']

    pid << "#{rc}/#{digest_color_bold(t)}T-#{t}" if t
    pid << "#{rc}/#{digest_color_bold(w)}W-#{w}" if w
    pid << "#{rc}/#{digest_color_bold(j)}J-#{j}" if j

    tags = msg[:tags] if msg[:tags].is_a?(Array)
    host = msg[:host] if msg[:host].is_a?(String)
    env = msg[:env] if msg[:env]
  end

  hc = "\e[1m#{digest_color(host)}"

  "#{sc}#{severity[0..0]}#{rc}, [#{dc}#{format_datetime(datetime)}#{pc}#{pid}#{rc}] #{sc}#{severity[0..4]}" +
    "#{rc} -- #{ac}#{progname}#{env && " #{ec}(#{env})"}#{rc}: #{hc}#{host}#{rc} #{self.class.format_tags(tags)}" +
    "#{mc}#{msg2str(self.class.format(msg, false, true), mc)}\e[0m\n"
end