black_box_log_formatter 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+

|
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
|
+

|
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
|
+

|
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
|
+

|
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: []
|