lug 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fc9dae02bdd39f721d430f65b8cb2072d112b3ca
4
+ data.tar.gz: e5195c3318eb3d578d39f550365887ecec039822
5
+ SHA512:
6
+ metadata.gz: 9b478b21f0f63bb7e5441a9186bd26347aa9ad085762b52a0f1dccba9877979caee251c3c7ffdcd7236b277e6f45f09bc753377b17306f789d8529c69fbb5c7f
7
+ data.tar.gz: 217ac69a8607bfe190a804249d637f3cd4031b1c5d3a5df603d4e445b6e87eeb3c86568ac7a73ca168220e95ce775ee8ace54759a7e62ab7232df8087881534a
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.swp
11
+ *.swo
data/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ Metrics/MethodLength:
2
+ Max: 20
3
+
4
+ Metrics/ClassLength:
5
+ Max: 150
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.0
5
+ before_install: gem install bundler -v 1.13.1
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at munshkr@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in lug.gemspec
4
+ gemspec
5
+
6
+ gem 'pry'
7
+ gem 'pry-byebug'
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Damián Silvani
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,69 @@
1
+ # Lug [![Build Status](https://travis-ci.org/munshkr/lug.svg?branch=master)](https://travis-ci.org/munshkr/lug)
2
+
3
+ A small Ruby logger for debugging libraries and applications. Pretty much a
4
+ clone of [debug](https://github.com/visionmedia/debug) for Node.js
5
+
6
+ ## Features
7
+
8
+ * Smaller and faster than Ruby's logger
9
+ * Colorized output for tty output devices (like stderr)
10
+ * Filter log messages by namespace
11
+ * Standard logger interface (responds to #debug, #warn, #error, etc.)
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'lug'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install lug
28
+
29
+ ## Usage
30
+
31
+ TODO: Write usage instructions here
32
+
33
+ ## Benchmark
34
+
35
+ Performance comparison between Ruby's Logger class and Lug logger classes.
36
+ `TtyLogger` colorizes output and calculates elapsed time between lines.
37
+
38
+ ```
39
+ user system total real
40
+ Logger#debug 2.720000 0.430000 3.150000 ( 3.144094)
41
+ Lug::Logger#log 1.470000 0.050000 1.520000 ( 1.521829)
42
+ Lug::Logger#log + TtyDevice 1.480000 0.040000 1.520000 ( 1.522490)
43
+ Lug::Logger#debug 1.740000 0.050000 1.790000 ( 1.785965)
44
+ Lug::Logger#debug + TtyDevice 1.740000 0.040000 1.780000 ( 1.781318)
45
+ ```
46
+
47
+ ## Development
48
+
49
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
50
+ `rake` to run the tests. You can also run `bin/console` for an interactive
51
+ prompt that will allow you to experiment.
52
+
53
+ To install this gem onto your local machine, run `bundle exec rake install`. To
54
+ release a new version, update the version number in `version.rb`, and then run
55
+ `bundle exec rake release`, which will create a git tag for the version, push
56
+ git commits and tags, and push the `.gem` file to
57
+ [rubygems.org](https://rubygems.org).
58
+
59
+ ## Contributing
60
+
61
+ Bug reports and pull requests are welcome on GitHub at
62
+ https://github.com/munshkr/lug. This project is intended to be a safe,
63
+ welcoming space for collaboration, and contributors are expected to adhere to
64
+ the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
65
+
66
+ ## License
67
+
68
+ The gem is available as open source under the terms of the [MIT
69
+ License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:spec) do |t|
5
+ t.libs << 'spec'
6
+ t.libs << 'lib'
7
+ t.test_files = FileList['spec/**/*_spec.rb']
8
+ end
9
+
10
+ task default: :spec
data/bin/benchmark ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'benchmark'
5
+ require 'lug/logger'
6
+ require 'lug/standard'
7
+ require 'logger'
8
+
9
+ ENV['DEBUG'] = '*'
10
+ null_io = File.open(File::NULL, 'a')
11
+ N = 200_000
12
+
13
+ Benchmark.bmbm do |x|
14
+ logger = Logger.new(null_io)
15
+ x.report('Logger#debug') do
16
+ N.times { |i| logger.debug(i) }
17
+ end
18
+
19
+ lug = Lug::Device.new(null_io).on(:main)
20
+ x.report('Lug::Logger#log') do
21
+ N.times { |i| lug << i }
22
+ end
23
+
24
+ lug = Lug::TtyDevice.new(null_io).on(:main)
25
+ x.report('Lug::Logger#log + TtyDevice') do
26
+ N.times { |i| lug << i }
27
+ end
28
+
29
+ lug = Lug::Device.new(null_io).on(:main)
30
+ x.report('Lug::Logger#debug') do
31
+ N.times { |i| lug.debug(i) }
32
+ end
33
+
34
+ lug = Lug::TtyDevice.new(null_io).on(:main)
35
+ x.report('Lug::Logger#debug + TtyDevice') do
36
+ N.times { |i| lug.debug(i) }
37
+ end
38
+ end
data/bin/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'lug'
5
+ require 'lug/standard'
6
+ require 'lug/extend'
7
+
8
+ LUG = Lug::Logger.new
9
+
10
+ require 'pry'
11
+ Pry.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/lug.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+ require 'lug/version'
3
+ require 'lug/logger'
data/lib/lug/extend.rb ADDED
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lug
4
+ module Extend
5
+ module Object
6
+ def logger
7
+ defined?(LUG) && LUG
8
+ end
9
+ end
10
+
11
+ module Class
12
+ def logger_on(namespace)
13
+ cap_ns = namespace.to_s.split(':').map(&:capitalize).join
14
+ mod_name = :"LoggerOn#{cap_ns}"
15
+
16
+ return const_get(mod_name) if const_defined?(mod_name)
17
+ return unless LUG
18
+
19
+ mod = Module.new
20
+ mod.module_eval(%(
21
+ module ClassMethods
22
+ def logger
23
+ LUG.on(#{namespace.inspect})
24
+ end
25
+ end
26
+
27
+ def self.included(receiver)
28
+ receiver.extend(ClassMethods)
29
+ end
30
+
31
+ def logger
32
+ self.class.logger
33
+ end
34
+ ))
35
+ const_set(mod_name, mod)
36
+
37
+ include mod
38
+ end
39
+ end
40
+ end
41
+
42
+ Object.include Extend::Object
43
+ Class.include Extend::Class
44
+ end
45
+
data/lib/lug/logger.rb ADDED
@@ -0,0 +1,325 @@
1
+ # frozen_string_literal: true
2
+ require 'thread'
3
+
4
+ module Lug
5
+ # Logger class provides a small logging utility for debugging libraries and
6
+ # applications in Ruby.
7
+ #
8
+ # Usually meassages are grouped hierarchically in *namespaces*, so that
9
+ # different parts of your source code can be logged separately from each
10
+ # other, when needed.
11
+ #
12
+ # By convention, namespaces are lowercase strings separated by a colon ':' to
13
+ # denote a nested namespace. Regardless, any string formatting can be used.
14
+ #
15
+ # A Logger is associated with a Device, which manages an IO instance. Lug
16
+ # detects if IO referes to a TTY (Teletype terminal), and uses ANSI colors to
17
+ # format log messages by default. Otherwise, it will use a proper format for
18
+ # log files.
19
+ #
20
+ # logger = Lug::Logger.new
21
+ # logger << 'hi there!'
22
+ #
23
+ # main_logger = logger.on(:main)
24
+ # main_logger << 'now logging from the "main" namespace'
25
+ #
26
+ # Because Lug is intented to be used to debug both libraries and
27
+ # applications, Lug doesn't print anything unless you correctly set the DEBUG
28
+ # environment variable. This variable indicates which namespaces you want to
29
+ # log when you run your Ruby script.
30
+ #
31
+ # For example, if your script is:
32
+ #
33
+ # require 'lug'
34
+ #
35
+ # logger = Lug::Logger.new
36
+ # logger.on(:foo) << 'Message from foo'
37
+ # logger.on(:bar) << 'Message from bar'
38
+ # logger.on(:baz) << 'Message from baz'
39
+ #
40
+ # Then, running with `DEBUG=foo,bar` will print
41
+ #
42
+ # foo Message from foo +0ms
43
+ # bar Message form bar +0ms
44
+ #
45
+ # You can also use wildcars to filter in all messages form a specific
46
+ # namespace and all its nested namespaces.
47
+ #
48
+ # DEBUG=worker:* ruby process.rb
49
+ #
50
+ # worker:a I am worker A +0ms
51
+ # worker:b I am worker B +1ms
52
+ # worker:b Doing something... +0ms
53
+ # worker:a Doing something... +2ms
54
+ # worker:a Done! +963ms
55
+ # worker:b Done! +2s
56
+ #
57
+ class Logger
58
+ attr_reader :device, :namespace
59
+
60
+ # Create a Logger for +device+ within +namespace+
61
+ #
62
+ # When +dev_or_io+ is an IO instance, a Device or TtyDevice will be created
63
+ # with it, depending on IO#isatty. That is, if IO instance refers to a TTY
64
+ # output, it will use a TtyDevice.
65
+ #
66
+ # @param dev_or_io [Lug::Device, IO] device or IO instance
67
+ # @param namespace [String, Symbol]
68
+ #
69
+ def initialize(dev_or_io = nil, namespace = nil)
70
+ dev_or_io ||= STDERR
71
+ @device = dev_or_io.is_a?(Device) ? dev_or_io : Helpers.device_from(dev_or_io)
72
+ @namespace = namespace && namespace.to_s
73
+ @enabled = @device.enabled_for?(@namespace)
74
+ end
75
+
76
+ # Log a +message+ to output device
77
+ #
78
+ # @param message [String]
79
+ # @return [NilClass]
80
+ #
81
+ def log(message = nil)
82
+ return unless @enabled
83
+ message ||= yield if block_given?
84
+ @device.log(message, @namespace)
85
+ end
86
+ alias << log
87
+
88
+ # Clone logger with the same device and +namespace+
89
+ #
90
+ # @param namespace [String, Symbol]
91
+ # @return [Lug::Logger]
92
+ #
93
+ def on(namespace)
94
+ namespace = [@namespace, namespace].compact.join(':'.freeze)
95
+ Logger.new(@device, namespace)
96
+ end
97
+
98
+ # Return true if logger is enabled for current namespace
99
+ #
100
+ # When false, #log won't write anything to its device
101
+ #
102
+ # @return [Boolean]
103
+ #
104
+ def enabled?
105
+ @enabled
106
+ end
107
+ end
108
+
109
+ class Device
110
+ attr_reader :io
111
+
112
+ # Create a Device associated to an +io+ instance
113
+ #
114
+ # @param io [IO] (default: STDERR)
115
+ #
116
+ def initialize(io = STDERR)
117
+ @io = io
118
+ @io.sync = true
119
+
120
+ @enabled_namespaces = []
121
+ enable(ENV['DEBUG'.freeze].to_s) if ENV['DEBUG']
122
+ end
123
+
124
+ # Log a +message+ to output device, within a +namespace+
125
+ #
126
+ # @param message [String]
127
+ # @param namespace [String, Symbol] (default: nil)
128
+ # @return [NilClass]
129
+ #
130
+ def log(message, namespace = nil)
131
+ line = [
132
+ Time.now,
133
+ $$,
134
+ namespace && "[#{namespace}]",
135
+ message
136
+ ].compact.join(' '.freeze)
137
+
138
+ @io.write("#{line}\n")
139
+ nil
140
+ end
141
+ alias << log
142
+
143
+ # Clone logger with the same device and +namespace+ appended
144
+ #
145
+ # @param namespace [String, Symbol]
146
+ # @return [Lug::Logger]
147
+ #
148
+ def on(namespace)
149
+ Logger.new(self, namespace)
150
+ end
151
+
152
+ # Decides whether +namespace+ is enabled on this device
153
+ #
154
+ # @param namespace [String, Symbol]
155
+ # @return [Boolean]
156
+ #
157
+ def enabled_for?(namespace)
158
+ ns = namespace.to_s
159
+ @enabled_namespaces.any? { |re| ns =~ re }
160
+ end
161
+
162
+ # Updates list of enabled namespaces for this device based on +filter+
163
+ #
164
+ # @param filter [String]
165
+ # @return [Array<Regexp>] list of namespace filter regexps
166
+ #
167
+ def enable(filter)
168
+ @enabled_namespaces = Helpers.parse_namespace_filter(filter)
169
+ end
170
+ end
171
+
172
+ # Colors module defines constants of ANSI escape codes used by TtyDevice
173
+ #
174
+ module Colors
175
+ DEFAULT = '0;0'.freeze
176
+ BLACK = '0;30'.freeze
177
+ RED = '0;31'.freeze
178
+ GREEN = '0;32'.freeze
179
+ YELLOW = '0;33'.freeze
180
+ BLUE = '0;34'.freeze
181
+ MAGENTA = '0;35'.freeze
182
+ CYAN = '0;36'.freeze
183
+ WHITE = '0;37'.freeze
184
+ LIGHT_BLACK = '1;30'.freeze
185
+ LIGHT_RED = '1;31'.freeze
186
+ LIGHT_GREEN = '1;32'.freeze
187
+ LIGHT_YELLOW = '1;33'.freeze
188
+ LIGHT_BLUE = '1;34'.freeze
189
+ LIGHT_MAGENTA = '1;35'.freeze
190
+ LIGHT_CYAN = '1;36'.freeze
191
+ LIGHT_WHITE = '1;37'.freeze
192
+ end
193
+
194
+ # Logger class for tty IO devices
195
+ #
196
+ # Output is colorized with standard ANSI escape codes
197
+ #
198
+ class TtyDevice < Device
199
+ NS_COLORS = [
200
+ Colors::LIGHT_CYAN,
201
+ Colors::LIGHT_GREEN,
202
+ Colors::LIGHT_YELLOW,
203
+ Colors::LIGHT_BLUE,
204
+ Colors::LIGHT_MAGENTA,
205
+ Colors::LIGHT_CYAN,
206
+ Colors::LIGHT_RED,
207
+ Colors::CYAN,
208
+ Colors::GREEN,
209
+ Colors::YELLOW,
210
+ Colors::BLUE,
211
+ Colors::MAGENTA,
212
+ Colors::CYAN,
213
+ Colors::RED
214
+ ].freeze
215
+
216
+ MSG_COLOR = Colors::WHITE
217
+
218
+ # Create a TtyDevice associated to an +io+ instance
219
+ #
220
+ # @param io [IO] (default: STDERR)
221
+ #
222
+ def initialize(io = STDERR)
223
+ super(io)
224
+ @mutex = Mutex.new
225
+ @prev_time = nil
226
+ @colored_namespaces = {}
227
+ end
228
+
229
+ # Log a +message+ to output device, within a +namespace+
230
+ #
231
+ # If IO device is a TTY, it will print namespaces with different ANSI
232
+ # colors to make them easily distinguishable.
233
+ #
234
+ # @param message [String]
235
+ # @param namespace [String, Symbol] (default: nil)
236
+ # @return [NilClass]
237
+ #
238
+ def log(message, namespace = nil)
239
+ @mutex.synchronize do
240
+ now = Time.now
241
+ line = [
242
+ namespace && colorize_namespace(namespace),
243
+ colorize(message, MSG_COLOR),
244
+ elapsed_text(now)
245
+ ].compact.join(' '.freeze)
246
+ @prev_time = now
247
+
248
+ @io.write("#{line}\n")
249
+ end
250
+ nil
251
+ end
252
+
253
+ private
254
+
255
+ # Colorize a +namespace+ string
256
+ #
257
+ # Tries to use a different color than the one used for the previous
258
+ # namespace used.
259
+ #
260
+ # @param namespace [String, Symbol]
261
+ # @return [String] colored namespace string
262
+ #
263
+ def colorize_namespace(namespace)
264
+ @colored_namespaces[namespace] ||=
265
+ colorize(namespace, NS_COLORS[@colored_namespaces.size % NS_COLORS.size])
266
+ end
267
+
268
+ # Colorize a +string+ by adding ANSI escape codes for a specific +color+
269
+ #
270
+ # See {Lug::Colors}
271
+ #
272
+ # @param string [String]
273
+ # @param color [String]
274
+ # @return [String] colored string
275
+ #
276
+ def colorize(string, color)
277
+ "\e[#{color}m#{string}\e[0m"
278
+ end
279
+
280
+ # Calculates elapsed time from previous call to #log up to +now+
281
+ #
282
+ # Returns a string that represents elapsed time rounded to minutes,
283
+ # seconds or milliseconds.
284
+ #
285
+ # @param now [Time]
286
+ # @return [String]
287
+ #
288
+ def elapsed_text(now)
289
+ secs = now - (@prev_time || now)
290
+ if secs >= 60
291
+ "+#{(secs / 60).to_i}m"
292
+ elsif secs >= 1
293
+ "+#{secs.to_i}s"
294
+ else
295
+ "+#{(secs * 1000).to_i}ms"
296
+ end
297
+ end
298
+ end
299
+
300
+ module Helpers
301
+ # Create a Device instance from an +io+
302
+ #
303
+ # @param io [IO]
304
+ # @return [Device]
305
+ #
306
+ def self.device_from(io)
307
+ io.isatty ? TtyDevice.new(io) : Device.new(io)
308
+ end
309
+
310
+ # Parse a namespace +filter+ string and build a list of Regexp filters
311
+ #
312
+ # @param filter [String]
313
+ # @return [Array<Regexp>] list of filters
314
+ #
315
+ def self.parse_namespace_filter(filter)
316
+ res = []
317
+ filter.split(/[\s,]+/).each do |ns|
318
+ next if ns.empty?
319
+ ns = ns.gsub('*'.freeze, '.*?'.freeze)
320
+ res << /^#{ns}$/
321
+ end
322
+ res
323
+ end
324
+ end
325
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+ require 'lug/logger'
3
+
4
+ module Lug
5
+ # Standard module extends Lug classes so that it behaves similarly to
6
+ # traditional Logger classes.
7
+ #
8
+ # It basically adds methods for writing messages in different severity
9
+ # levels: `#debug`, `info`, `#warn`, `#error`, `#fatal`, `#unknown`. These
10
+ # methods also accept a block instead of a string, and will call it only if
11
+ # it needs to (in particular, if message level is greater than logger's
12
+ # severity level).
13
+ #
14
+ # By default, severity level is `DEBUG`, but you can set this threshold with
15
+ # the `LOG_LEVEL` environment variable.
16
+ #
17
+ # You can mix these methods with `#log` or `#<<`, but messages logged with
18
+ # `#log` will behave like messages with `DEBUG` level. This means you will
19
+ # see them *only* if severity level is set to `DEBUG`.
20
+ #
21
+ module Standard
22
+ LEVEL_TEXT = [
23
+ 'DEBUG'.freeze,
24
+ 'INFO'.freeze,
25
+ 'WARN'.freeze,
26
+ 'ERROR'.freeze,
27
+ 'FATAL'.freeze,
28
+ 'UNKNOWN'.freeze
29
+ ].freeze
30
+
31
+ LEVEL_COLOR = [
32
+ Colors::CYAN,
33
+ Colors::GREEN,
34
+ Colors::YELLOW,
35
+ Colors::RED,
36
+ Colors::LIGHT_RED,
37
+ Colors::MAGENTA
38
+ ].freeze
39
+
40
+ module DeviceMethods
41
+ attr_accessor :level_threshold
42
+
43
+ def log(message, namespace = nil, level = nil)
44
+ message = "#{LEVEL_TEXT[level]} #{message}" if level
45
+ super(message, namespace)
46
+ end
47
+ alias << log
48
+
49
+ def level_threshold
50
+ @level_threshold ||= begin
51
+ res = nil
52
+ log_level = ENV['LOG_LEVEL'.freeze]
53
+ if log_level
54
+ level = log_level.to_s.upcase
55
+ res = LEVEL_TEXT.index(level)
56
+ end
57
+ res || 0
58
+ end
59
+ end
60
+ end
61
+
62
+ module TtyDeviceMethods
63
+ def log(message, namespace = nil, level = nil)
64
+ if level
65
+ colored_level = colorize(LEVEL_TEXT[level], LEVEL_COLOR[level])
66
+ message = "#{colored_level} #{message}"
67
+ end
68
+ super(message, namespace)
69
+ end
70
+ alias << log
71
+ end
72
+
73
+ module LoggerMethods
74
+ def log(message, level = nil)
75
+ level_i = level.to_i
76
+ return if level_i < @device.level_threshold ||
77
+ (level_i == 0 && !@enabled)
78
+ message ||= yield if block_given?
79
+ @device.log(message, @namespace, level)
80
+ end
81
+ alias << log
82
+ end
83
+
84
+ module LoggerDeviceMethods
85
+ def debug(msg = nil)
86
+ msg ||= yield if block_given?
87
+ log(msg, 0)
88
+ end
89
+
90
+ def info(msg = nil)
91
+ msg ||= yield if block_given?
92
+ log(msg, 1)
93
+ end
94
+
95
+ def warn(msg = nil)
96
+ msg ||= yield if block_given?
97
+ log(msg, 2)
98
+ end
99
+
100
+ def error(msg = nil)
101
+ msg ||= yield if block_given?
102
+ log(msg, 3)
103
+ end
104
+
105
+ def fatal(msg = nil)
106
+ msg ||= yield if block_given?
107
+ log(msg, 4)
108
+ end
109
+
110
+ def unknown(msg = nil)
111
+ msg ||= yield if block_given?
112
+ log(msg, 5)
113
+ end
114
+ end
115
+ end
116
+
117
+ # Overwrite methods on Device and Logger classes
118
+ Device.prepend Standard::DeviceMethods, Standard::LoggerDeviceMethods
119
+ TtyDevice.prepend Standard::TtyDeviceMethods
120
+ Logger.prepend Standard::LoggerMethods, Standard::LoggerDeviceMethods
121
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lug
4
+ VERSION = '0.1.0'.freeze
5
+ end
data/lug.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lug/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'lug'
8
+ spec.version = Lug::VERSION
9
+ spec.authors = ['Damián Silvani']
10
+ spec.email = ['munshkr@gmail.com']
11
+
12
+ spec.summary = 'Simple Ruby logger for debugging applications.'
13
+ spec.homepage = 'https://github.com/munshkr/lug'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.13'
24
+ spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'minitest', '~> 5.0'
26
+ spec.add_development_dependency 'rubocop'
27
+ spec.add_development_dependency 'reek'
28
+ spec.add_development_dependency 'timecop'
29
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lug
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Damián Silvani
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-09-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: reek
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: timecop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description:
98
+ email:
99
+ - munshkr@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rubocop.yml"
106
+ - ".travis.yml"
107
+ - CODE_OF_CONDUCT.md
108
+ - Gemfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - bin/benchmark
113
+ - bin/console
114
+ - bin/setup
115
+ - lib/lug.rb
116
+ - lib/lug/extend.rb
117
+ - lib/lug/logger.rb
118
+ - lib/lug/standard.rb
119
+ - lib/lug/version.rb
120
+ - lug.gemspec
121
+ homepage: https://github.com/munshkr/lug
122
+ licenses:
123
+ - MIT
124
+ metadata: {}
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 2.5.1
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: Simple Ruby logger for debugging applications.
145
+ test_files: []
146
+ has_rdoc: