black_box_log_formatter 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +123 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/black_box_log_formatter.gemspec +33 -0
- data/lib/black_box/awesome_backtrace.rb +68 -0
- data/lib/black_box/log_formatter.rb +207 -0
- data/lib/black_box_log_formatter.rb +7 -0
- data/lib/black_box_log_formatter/version.rb +3 -0
- data/lib/tasks/benchmark.rake +39 -0
- data/screenshots/colorized_backtraces.png +0 -0
- data/screenshots/colorized_levels.png +0 -0
- data/screenshots/colorized_threads.png +0 -0
- data/screenshots/readme_example_1.png +0 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 275820a316bedaf428836876bfcb9be824e1ef31
|
4
|
+
data.tar.gz: 9adf51ced61d0ad3427e604f5547a2294da41f88
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6cd2cba3fbd305bee6e99057c426c0a1a9addbe839a703096e3e50d1e45a148e95cce21acc91a5d5a7af48f21b7bfa984fcbb7ff7ac905b1a9b59b17640a5f4d
|
7
|
+
data.tar.gz: 1e7fb47903ed23881e664fd8775491dd8576692b67c2a0ef23ef03922ad638e9d5a41ee5a4d981ed1e558a62ff7d6c8b5612dd6a4eb6b4bcc69f4cd9ff93c769
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
black_box_log_formatter
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.10
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Deseret Book and contributors
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
# BlackBox::LogFormatter
|
2
|
+
|
3
|
+
This is an incredibly colorful highlighting formatter for structured log
|
4
|
+
events. It is visually similar to Ruby's `Logger::Formatter`, but can display
|
5
|
+
additional color-highlighted metadata on the same line or on subsequent lines,
|
6
|
+
using ANSI color escape sequences.
|
7
|
+
|
8
|
+
Not everyone likes this much color and detail, so you (TODO) can configure which
|
9
|
+
log event fields to display inline, which to display in a multi-line format, and
|
10
|
+
which to hide altogether. You can also disable color.
|
11
|
+
|
12
|
+
This gem was extracted from an internal middleware framework at Deseret Book
|
13
|
+
called BlackBox Framework. It's named for the fact that good middleware should
|
14
|
+
allow frontend services to treat backend services like a black box, not caring
|
15
|
+
about implementation details.
|
16
|
+
|
17
|
+
|
18
|
+
## Features
|
19
|
+
|
20
|
+
- Each application name, process, thread, worker, and job gets its own color,
|
21
|
+
so you can visually identify log messages from the same process, thread, or
|
22
|
+
worker in a combined log stream. You need to manually add these metadata
|
23
|
+
fields to your log events if your logger doesn't do it for you.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
threads = []
|
27
|
+
10.times do |i|
|
28
|
+
threads << Thread.new do
|
29
|
+
l.info message: "On thread #{i}", tid: Thread.current.__id__
|
30
|
+
sleep rand
|
31
|
+
l.info message: "Back on #{i}", tid: Thread.current.__id__
|
32
|
+
end
|
33
|
+
end ; threads.each(&:join)
|
34
|
+
```
|
35
|
+
|
36
|
+
![Colorized thread IDs](screenshots/colorized_threads.png?raw=true)
|
37
|
+
|
38
|
+
|
39
|
+
- Log events are colored according to severity:
|
40
|
+
- DEBUG - dark gray
|
41
|
+
- INFO - default
|
42
|
+
- WARN - yellow
|
43
|
+
- ERROR - red
|
44
|
+
- FATAL - magenta
|
45
|
+
- UNKNOWN - cyan
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
[:debug, :info, :warn, :error, :fatal, :unknown].each do |level|
|
49
|
+
l.send(level, { message: "Message at #{level}", a: 1, b: 2, colors: true })
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
![Colorized log levels](screenshots/colorized_levels.png?raw=true)
|
54
|
+
|
55
|
+
- Backtraces are colorized to make it easy to identify files, line numbers, and
|
56
|
+
method names:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
l.warn trace: caller
|
60
|
+
```
|
61
|
+
|
62
|
+
![Highlighted backtrace](screenshots/colorized_backtraces.png?raw=true)
|
63
|
+
|
64
|
+
|
65
|
+
## Installation
|
66
|
+
|
67
|
+
Add this line to your application's Gemfile:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
gem 'black_box_log_formatter'
|
71
|
+
```
|
72
|
+
|
73
|
+
## Usage
|
74
|
+
|
75
|
+
Set `BlackBox::LogFormatter` as the formatter for a logger, then pass it
|
76
|
+
`Hash`es instead of `String`s. Event `Hash`es should be simliar to those used
|
77
|
+
by Logstash. Do not pass untrusted data in the `message` field or as
|
78
|
+
unfiltered fields in the event.
|
79
|
+
|
80
|
+
Pass primary metadata fields using symbols as keys, not strings.
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
require 'black_box_log_formatter'
|
84
|
+
|
85
|
+
l = Logger.new($stdout)
|
86
|
+
l.progname = 'A Program'
|
87
|
+
l.formatter = BlackBox::LogFormatter.new
|
88
|
+
|
89
|
+
l.debug "The old way to log"
|
90
|
+
# => D, [2016-05-06T16:21:44.520640 #32413] DEBUG -- A Program: hostname The old way to log
|
91
|
+
|
92
|
+
l.debug(
|
93
|
+
message: "The new way to log",
|
94
|
+
tid: 'some thread',
|
95
|
+
wid: 'some worker',
|
96
|
+
data: { useful: :fields }
|
97
|
+
)
|
98
|
+
# => D, [2016-05-06T16:22:32.027060 #32413/T-some thread/W-some worker] DEBUG -- A Program: hostname The new way to log: {
|
99
|
+
# :data => {
|
100
|
+
# :useful => :fields
|
101
|
+
# }
|
102
|
+
# }
|
103
|
+
```
|
104
|
+
|
105
|
+
![Simple logging example](screenshots/readme_example_1.png?raw=true)
|
106
|
+
|
107
|
+
|
108
|
+
TODO: describe configuring the color and formatting options
|
109
|
+
|
110
|
+
|
111
|
+
## Contributing
|
112
|
+
|
113
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/deseretbook/black\_box\_log\_formatter.
|
114
|
+
|
115
|
+
|
116
|
+
## License
|
117
|
+
|
118
|
+
The gem is available as open source under the terms of the [MIT
|
119
|
+
License](http://opensource.org/licenses/MIT) (see the LICENSE file).
|
120
|
+
|
121
|
+
©2016 Deseret Book and contributors. Developed by Mike Bourgeous at
|
122
|
+
DeseretBook.com, with metadata work by Dustin Grange. See Git for any
|
123
|
+
additional contributors.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "black_box_log_formatter"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'black_box_log_formatter/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "black_box_log_formatter"
|
8
|
+
spec.version = BlackBoxLogFormatter::VERSION
|
9
|
+
spec.authors = ["Mike Bourgeous", "Dustin Grange", "Deseret Book"]
|
10
|
+
spec.email = ["webdev@deseretbook.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{A colorful formatter and highlighter for structued log events}
|
13
|
+
spec.description = <<-DESC
|
14
|
+
This is an incredibly colorful highlighting formatter for structured log
|
15
|
+
events. It is visually similar to Ruby's `Logger::Formatter`, but can display
|
16
|
+
additional color-highlighted metadata on the same line or on subsequent lines.
|
17
|
+
DESC
|
18
|
+
spec.homepage = "https://github.com/deseretbook/black_box_log_formatter"
|
19
|
+
spec.license = "MIT"
|
20
|
+
|
21
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
22
|
+
spec.bindir = "exe"
|
23
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.required_ruby_version = '>= 2.1.0'
|
27
|
+
|
28
|
+
spec.add_runtime_dependency 'awesome_print', '~> 1.6.1'
|
29
|
+
|
30
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
31
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
32
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
33
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Extension for AwesomePrint that highlights Arrays of backtrace strings. Not
|
2
|
+
# compatible with AwesomePrint's HTML output.
|
3
|
+
# (C)2016 Deseret Book, created April 2016 by Mike Bourgeous/DeseretBook.com
|
4
|
+
|
5
|
+
require 'awesome_print'
|
6
|
+
|
7
|
+
module BlackBox
|
8
|
+
module AwesomeBacktrace
|
9
|
+
# Regular expression identifying and modifying a backtrace line
|
10
|
+
TRACE_REGEX = %r{(/?)([^:/]+):(\d+):in `([^']*)'}
|
11
|
+
|
12
|
+
def self.included(base)
|
13
|
+
base.send :alias_method, :cast_without_awesome_backtrace, :cast
|
14
|
+
base.send :alias_method, :cast, :cast_with_awesome_backtrace
|
15
|
+
end
|
16
|
+
|
17
|
+
# Check for a backtrace-decorated array from BlackBox::Log.
|
18
|
+
def cast_with_awesome_backtrace(object, type)
|
19
|
+
if type == :array
|
20
|
+
if defined?(::Thread::Backtrace::Location) && object.all?{|e| e.is_a?(::Thread::Backtrace::Location) }
|
21
|
+
cast = :caller_location_backtrace
|
22
|
+
elsif object.all?{|t| t.is_a?(String) && (t == '...' || t =~ TRACE_REGEX) }
|
23
|
+
# FIXME: this highlights [ '...' ] as well
|
24
|
+
cast = :string_backtrace
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
cast || cast_without_awesome_backtrace(object, type)
|
29
|
+
end
|
30
|
+
|
31
|
+
# TODO: Consider using #awesome_array and formatting each string
|
32
|
+
# separately to get the indentation and numbering for free
|
33
|
+
|
34
|
+
# TODO: Consider searching for common backtrace filters, such as Rails,
|
35
|
+
# for excluding unwanted backtrace entries.
|
36
|
+
|
37
|
+
# Format a Thread::Backtrace::Location array from #caller_locations.
|
38
|
+
def awesome_caller_location_backtrace(object)
|
39
|
+
awesome_string_backtrace(object.map(&:to_s), '=> ', nil) # TODO: maybe use the objects directly?
|
40
|
+
end
|
41
|
+
|
42
|
+
# Format a String array from #caller or Exception#backtrace.
|
43
|
+
def awesome_string_backtrace(object, open_quote='"', close_quote='"')
|
44
|
+
open_quote = colorize(open_quote, :string) if open_quote
|
45
|
+
close_quote = colorize(close_quote, :string) if close_quote
|
46
|
+
|
47
|
+
s = "[\n"
|
48
|
+
s << object.map{|s|
|
49
|
+
s = AwesomeBacktrace.format_line(s) unless @options[:plain] || !@inspector.colorize?
|
50
|
+
"#{indent}#{open_quote}#{s}#{close_quote},\n"
|
51
|
+
}.join
|
52
|
+
s << "#{outdent}]"
|
53
|
+
|
54
|
+
s
|
55
|
+
end
|
56
|
+
|
57
|
+
# Adds ANSI highlights to and escapes control characters in the given
|
58
|
+
# backtrace line.
|
59
|
+
def self.format_line(line)
|
60
|
+
"\e[0;36m" + line.inspect[1..-2].sub(
|
61
|
+
TRACE_REGEX,
|
62
|
+
"\\1\e[1;33m\\2\e[0m:\e[34m\\3\e[0m:in `\e[1;35m\\4\e[0m'"
|
63
|
+
).rstrip
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
AwesomePrint::Formatter.send(:include, BlackBox::AwesomeBacktrace)
|
@@ -0,0 +1,207 @@
|
|
1
|
+
# Colorized, structured variant of Ruby's built-in Logger::Formatter.
|
2
|
+
# (C)2016 Deseret Book, created September 2014 by Mike Bourgeous/DeseretBook.com
|
3
|
+
|
4
|
+
require 'logger'
|
5
|
+
require 'digest/md5'
|
6
|
+
require 'socket'
|
7
|
+
|
8
|
+
module BlackBox
|
9
|
+
# Colorized, structured variant of Ruby's built-in Logger::Formatter.
|
10
|
+
class LogFormatter < ::Logger::Formatter
|
11
|
+
# Whether to highlight log lines in color.
|
12
|
+
attr_accessor :color
|
13
|
+
|
14
|
+
# Initializes a color formatter for the given +logger+ (optional). By
|
15
|
+
# default, color will be disabled if the Logger is logging to a file
|
16
|
+
# (uses #instance_variable_get(:@filename)), enabled based on ENV['TERM']
|
17
|
+
# otherwise.
|
18
|
+
#
|
19
|
+
# If +color+ is true or false (instead of nil), then color will be
|
20
|
+
# enabled or disabled regardless of the attached logger's target or the
|
21
|
+
# TERM environment variable.
|
22
|
+
def initialize(logger: nil, color: nil)
|
23
|
+
@pidcol = nil
|
24
|
+
@appcol = nil
|
25
|
+
@appname = nil # App name at last time of app name color calculation
|
26
|
+
@color = color == true || (
|
27
|
+
color != false &&
|
28
|
+
(!logger || !logger.instance_variable_get(:@filename)) &&
|
29
|
+
!!(ENV['TERM'].to_s.downcase =~ /(linux|mac|xterm|ansi|putty|screen)/)
|
30
|
+
)
|
31
|
+
|
32
|
+
AwesomePrint.force_colors! if Kernel.const_defined?(:AwesomePrint) && @color
|
33
|
+
end
|
34
|
+
|
35
|
+
def call(severity, datetime, progname, msg)
|
36
|
+
# FIXME: Add inline metadata (TID, WID, JID) even if color is disabled
|
37
|
+
return super(severity, datetime, progname, self.class.format(msg, true, false)) unless @color
|
38
|
+
|
39
|
+
sc = severity_color(severity)
|
40
|
+
dc = date_color(severity)
|
41
|
+
pc = process_color(severity)
|
42
|
+
mc = message_color(severity)
|
43
|
+
ac = appname_color(severity, progname)
|
44
|
+
ec = env_color(progname)
|
45
|
+
rc = "\e[0;1;30m"
|
46
|
+
|
47
|
+
pid = "#{pc}##{$$}"
|
48
|
+
host = Socket.gethostname
|
49
|
+
env = nil
|
50
|
+
tags = nil
|
51
|
+
|
52
|
+
if msg.is_a?(Hash)
|
53
|
+
t = msg[:tid]
|
54
|
+
w = msg[:wid]
|
55
|
+
j = msg[:jid] || msg['jid']
|
56
|
+
|
57
|
+
pid << "#{rc}/#{digest_color_bold(t)}T-#{t}" if t
|
58
|
+
pid << "#{rc}/#{digest_color_bold(w)}W-#{w}" if w
|
59
|
+
pid << "#{rc}/#{digest_color_bold(j)}J-#{j}" if j
|
60
|
+
|
61
|
+
tags = msg[:tags] if msg[:tags].is_a?(Array)
|
62
|
+
host = msg[:host] if msg[:host].is_a?(String)
|
63
|
+
env = msg[:env] if msg[:env]
|
64
|
+
end
|
65
|
+
|
66
|
+
hc = "\e[1m#{digest_color(host)}"
|
67
|
+
|
68
|
+
"#{sc}#{severity[0..0]}#{rc}, [#{dc}#{format_datetime(datetime)}#{pc}#{pid}#{rc}] #{sc}#{severity[0..4]}" +
|
69
|
+
"#{rc} -- #{ac}#{progname}#{env && " #{ec}(#{env})"}#{rc}: #{hc}#{host}#{rc} #{self.class.format_tags(tags)}" +
|
70
|
+
"#{mc}#{msg2str(self.class.format(msg, false, true), mc)}\e[0m\n"
|
71
|
+
end
|
72
|
+
|
73
|
+
# Formats the given +event+ into a String, using AwesomePrint or
|
74
|
+
# JSON.pretty_generate if possible, or using #inspect if not. Removes
|
75
|
+
# common metadata elements from Hash data, and if +add_metadata+ is
|
76
|
+
# true, adds some of them back to the message string.
|
77
|
+
#
|
78
|
+
# This could definitely be cleaner.
|
79
|
+
def self.format(event, add_metadata, ap_color)
|
80
|
+
return event.to_s unless event.is_a?(Hash)
|
81
|
+
|
82
|
+
event = event.clone
|
83
|
+
|
84
|
+
msg = event.delete(:message)
|
85
|
+
host = event.delete(:host)
|
86
|
+
pname = event.delete(:process_name)
|
87
|
+
env = event.delete(:env)
|
88
|
+
pid = event.delete(:pid) # Process ID
|
89
|
+
tid = event.delete(:tid) # Thread ID
|
90
|
+
wid = event.delete(:wid) # Worker ID
|
91
|
+
jid = event.delete(:jid) || event.delete('jid') # Job ID
|
92
|
+
tags = event.delete(:tags) if event[:tags].is_a?(Array)
|
93
|
+
|
94
|
+
event.delete(:request_id) if event[:request_id] == jid
|
95
|
+
|
96
|
+
if add_metadata
|
97
|
+
msg = "#{format_tags(tags)}#{msg}"
|
98
|
+
end
|
99
|
+
|
100
|
+
if event.any?
|
101
|
+
begin
|
102
|
+
if Kernel.const_defined?(:AwesomePrint) && event.respond_to?(:ai)
|
103
|
+
data = event.ai(indent: -2, plain: !ap_color, multiline: true)
|
104
|
+
else
|
105
|
+
data = JSON.pretty_generate(event)
|
106
|
+
end
|
107
|
+
rescue => e
|
108
|
+
data = event.inspect rescue "INSPECTION FAILED"
|
109
|
+
end
|
110
|
+
|
111
|
+
msg = "#{msg}: #{data}"
|
112
|
+
end
|
113
|
+
|
114
|
+
msg
|
115
|
+
end
|
116
|
+
|
117
|
+
# Formats an array of +tags+ as a string like "[tag1] [tag2]...", with
|
118
|
+
# a trailing space if there are any tags.
|
119
|
+
def self.format_tags(tags)
|
120
|
+
"#{tags.map{|t| "[#{t}]"}.join(' ')} " if tags && tags.any?
|
121
|
+
end
|
122
|
+
|
123
|
+
protected
|
124
|
+
# FIXME: These would be more efficient as constant arrays
|
125
|
+
def severity_color(severity)
|
126
|
+
case severity
|
127
|
+
when 'DEBUG'
|
128
|
+
"\e[1;30m"
|
129
|
+
when 'INFO'
|
130
|
+
"\e[1;34m"
|
131
|
+
when 'WARN'
|
132
|
+
"\e[1;33m"
|
133
|
+
when 'ERROR'
|
134
|
+
"\e[1;31m"
|
135
|
+
when 'FATAL'
|
136
|
+
"\e[1;35m"
|
137
|
+
else
|
138
|
+
"\e[1;36m"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def message_color(severity)
|
143
|
+
case severity
|
144
|
+
when 'DEBUG'
|
145
|
+
"\e[1;30m"
|
146
|
+
when 'INFO'
|
147
|
+
"\e[0m"
|
148
|
+
when 'WARN'
|
149
|
+
"\e[0;33m"
|
150
|
+
when 'ERROR'
|
151
|
+
"\e[0;31m"
|
152
|
+
when 'FATAL'
|
153
|
+
"\e[0;35m"
|
154
|
+
else
|
155
|
+
"\e[0;36m"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def date_color(severity)
|
160
|
+
"\e[0;36m"
|
161
|
+
end
|
162
|
+
|
163
|
+
def process_color(severity)
|
164
|
+
return @pidcol if @pidcol
|
165
|
+
@pidcol = "\e[0m#{digest_color($$)}"
|
166
|
+
end
|
167
|
+
|
168
|
+
def appname_color(severity, progname)
|
169
|
+
return @appcol if @appcol && @appname == progname
|
170
|
+
@appname = progname
|
171
|
+
@appcol = "\e[1m#{digest_color(@appname)}"
|
172
|
+
end
|
173
|
+
|
174
|
+
def env_color(progname)
|
175
|
+
return @envcol if @envcol && @appname == progname
|
176
|
+
@appname = progname
|
177
|
+
@envcol = "\e[0m#{digest_color(@appname)}"
|
178
|
+
end
|
179
|
+
|
180
|
+
# Returns a color escape based on the digest of the given +value+.
|
181
|
+
def digest_color(value)
|
182
|
+
"\e[#{31 + digest(value) % 6}m"
|
183
|
+
end
|
184
|
+
|
185
|
+
# Returns a reset, bold, and color escape based on the +value+.
|
186
|
+
def digest_color_bold(value)
|
187
|
+
color = digest(value) % 15 + 1
|
188
|
+
if color > 7
|
189
|
+
"\e[0;1;#{30 + color - 8}m"
|
190
|
+
else
|
191
|
+
"\e[0;#{30 + color}m"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Returns an integer based on the MD5 digest of the given +value+.
|
196
|
+
def digest(value)
|
197
|
+
digest = Digest::MD5.digest(value.to_s).unpack('I*')
|
198
|
+
digest[0] ^ digest[1] ^ digest[2] ^ digest[3]
|
199
|
+
end
|
200
|
+
|
201
|
+
private
|
202
|
+
# Overrides superclass to preserve the color for the message level.
|
203
|
+
def msg2str(msg, color=nil)
|
204
|
+
super(msg).gsub("\e[0m", "\e[0m#{color}")
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
desc 'Crude benchmark of the log formatter'
|
2
|
+
task :benchmark do
|
3
|
+
require 'black_box_log_formatter'
|
4
|
+
require 'benchmark'
|
5
|
+
|
6
|
+
benchmarks = {
|
7
|
+
'plain string' => 'This is a message to format',
|
8
|
+
'simple hash' => { message: 'This is a message to format' },
|
9
|
+
'hash with data' => { message: 'This is a message to format', meta: 'data', a: 1, b: 2 },
|
10
|
+
'hash with only data' => { meta: 'data', a: 1, b: 2 },
|
11
|
+
'hash with backtrace' => { message: 'Something bad happened', error: caller(0, 5) },
|
12
|
+
'hash with non-trace array' => { message: 'This is a message to format', list: (1..5).to_a },
|
13
|
+
}
|
14
|
+
|
15
|
+
iterations = 100000
|
16
|
+
|
17
|
+
color = BlackBox::LogFormatter.new(color: true)
|
18
|
+
bw = BlackBox::LogFormatter.new(color: false)
|
19
|
+
|
20
|
+
date = Time.now.utc
|
21
|
+
|
22
|
+
benchmarks.each do |name, message|
|
23
|
+
puts "\n\e[1mTesting color with #{name}\e[0m"
|
24
|
+
time = Benchmark.realtime do
|
25
|
+
iterations.times do
|
26
|
+
color.call('FATAL', date, 'a program', message)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
puts "\t#{iterations}/#{time}s = #{'%.2f' % (iterations.to_f / time)}/s"
|
30
|
+
|
31
|
+
puts "\n\e[1mTesting non-color with #{name}\e[0m"
|
32
|
+
time = Benchmark.realtime do
|
33
|
+
iterations.times do
|
34
|
+
bw.call('FATAL', date, 'a program', message)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
puts "\t#{iterations}/#{time}s = #{'%.2f' % (iterations.to_f / time)}/s"
|
38
|
+
end
|
39
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: black_box_log_formatter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mike Bourgeous
|
8
|
+
- Dustin Grange
|
9
|
+
- Deseret Book
|
10
|
+
autorequire:
|
11
|
+
bindir: exe
|
12
|
+
cert_chain: []
|
13
|
+
date: 2016-05-24 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: awesome_print
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "~>"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.6.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: 1.6.1
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: bundler
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '1.11'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '1.11'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: rake
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '10.0'
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '10.0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: rspec
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '3.0'
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - "~>"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '3.0'
|
71
|
+
description: |2
|
72
|
+
This is an incredibly colorful highlighting formatter for structured log
|
73
|
+
events. It is visually similar to Ruby's `Logger::Formatter`, but can display
|
74
|
+
additional color-highlighted metadata on the same line or on subsequent lines.
|
75
|
+
email:
|
76
|
+
- webdev@deseretbook.com
|
77
|
+
executables: []
|
78
|
+
extensions: []
|
79
|
+
extra_rdoc_files: []
|
80
|
+
files:
|
81
|
+
- ".gitignore"
|
82
|
+
- ".rspec"
|
83
|
+
- ".ruby-gemset"
|
84
|
+
- ".ruby-version"
|
85
|
+
- ".travis.yml"
|
86
|
+
- Gemfile
|
87
|
+
- LICENSE.txt
|
88
|
+
- README.md
|
89
|
+
- Rakefile
|
90
|
+
- bin/console
|
91
|
+
- bin/setup
|
92
|
+
- black_box_log_formatter.gemspec
|
93
|
+
- lib/black_box/awesome_backtrace.rb
|
94
|
+
- lib/black_box/log_formatter.rb
|
95
|
+
- lib/black_box_log_formatter.rb
|
96
|
+
- lib/black_box_log_formatter/version.rb
|
97
|
+
- lib/tasks/benchmark.rake
|
98
|
+
- screenshots/colorized_backtraces.png
|
99
|
+
- screenshots/colorized_levels.png
|
100
|
+
- screenshots/colorized_threads.png
|
101
|
+
- screenshots/readme_example_1.png
|
102
|
+
homepage: https://github.com/deseretbook/black_box_log_formatter
|
103
|
+
licenses:
|
104
|
+
- MIT
|
105
|
+
metadata: {}
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: 2.1.0
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
requirements: []
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 2.4.8
|
123
|
+
signing_key:
|
124
|
+
specification_version: 4
|
125
|
+
summary: A colorful formatter and highlighter for structued log events
|
126
|
+
test_files: []
|