catamaran 0.2.0 → 0.3.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.
- data/README.md +54 -8
- data/lib/catamaran/formatter/base_formatter.rb +68 -0
- data/lib/catamaran/formatter/caller_formatter.rb +2 -22
- data/lib/catamaran/formatter/no_caller_formatter.rb +6 -20
- data/lib/catamaran/logger.rb +57 -9
- data/lib/catamaran/manager.rb +13 -0
- data/lib/catamaran/version.rb +1 -1
- data/lib/catamaran.rb +4 -2
- data/spec/catamaran_spec.rb +23 -0
- metadata +3 -2
data/README.md
CHANGED
|
@@ -6,7 +6,7 @@ I think logging is a powerful and often undervalued tool in software development
|
|
|
6
6
|
Gemfile
|
|
7
7
|
-------
|
|
8
8
|
|
|
9
|
-
gem 'catamaran',
|
|
9
|
+
gem 'catamaran', '~> 0.2.0'
|
|
10
10
|
|
|
11
11
|
Rails-related setup:
|
|
12
12
|
|
|
@@ -14,11 +14,56 @@ Rails-related setup:
|
|
|
14
14
|
|
|
15
15
|
Now modify `development.rb` as needed
|
|
16
16
|
|
|
17
|
-
Quickstart
|
|
18
|
-
|
|
17
|
+
Ruby Quickstart
|
|
18
|
+
-------------------------------
|
|
19
|
+
Catamaran::Manager.stderr = true
|
|
20
|
+
Catamaran::LogLevel.default_log_level = Catamaran::LogLevel::DEBUG
|
|
21
|
+
Catamaran::Manager.formatter_class = Catamaran::Formatter::NoCallerFormatter
|
|
19
22
|
|
|
20
|
-
class
|
|
21
|
-
LOGGER =
|
|
23
|
+
class FirstRubyDemo
|
|
24
|
+
LOGGER = Catamaran.logger( "FirstRubyDemo" )
|
|
25
|
+
|
|
26
|
+
def run
|
|
27
|
+
LOGGER.debug( "Note that DEBUG messages are getting logged" ) if LOGGER.debug?
|
|
28
|
+
LOGGER.trace( "Note that TRACE messages are NOT getting logged" ) if LOGGER.trace?
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class SecondRubyDemo
|
|
33
|
+
LOGGER = Catamaran.logger( { :class => name(), :file => __FILE__ } )
|
|
34
|
+
|
|
35
|
+
def run
|
|
36
|
+
LOGGER.debug( "Sample DEBUG statement", { :line => __LINE__, :method => 'run'} ) if LOGGER.debug?
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class ThirdRubyDemo
|
|
41
|
+
LOGGER = Catamaran.logger( "com.mycompany.ThirdRubyDemo", { :class => name(), :file => __FILE__ } )
|
|
42
|
+
|
|
43
|
+
def run
|
|
44
|
+
LOGGER.debug( "Sample DEBUG statement", { :line => __LINE__, :method => 'run'} ) if LOGGER.debug?
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
puts "Catamaran VERSION = #{Catamaran::VERSION}"
|
|
50
|
+
FirstRubyDemo.new.run
|
|
51
|
+
SecondRubyDemo.new.run
|
|
52
|
+
ThirdRubyDemo.new.run
|
|
53
|
+
|
|
54
|
+
And the output
|
|
55
|
+
|
|
56
|
+
Catamaran VERSION = 0.3.0
|
|
57
|
+
DEBUG pid-2729 [2013-12-23 19:35:35:732] FirstRubyDemo - Note that DEBUG messages are getting logged
|
|
58
|
+
DEBUG pid-2729 [2013-12-23 19:35:35:732] - Sample DEBUG statement (catmaran_ruby_demos.rb:21:in `SecondRubyDemo.run')
|
|
59
|
+
DEBUG pid-2729 [2013-12-23 19:35:35:732] com.mycompany.ThirdRubyDemo - Sample DEBUG statement (catmaran_ruby_demos.rb:29:in `ThirdRubyDemo.run')
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
Rails Quickstart
|
|
63
|
+
--------------------------------
|
|
64
|
+
|
|
65
|
+
class PagesController < ApplicationController
|
|
66
|
+
LOGGER = Catamaran.logger.com.mycompany.myrailsapp.app.controllers.PagesController
|
|
22
67
|
|
|
23
68
|
def index
|
|
24
69
|
# LOGGER.io methods are reserved for logs related to entering and returning from methods
|
|
@@ -36,9 +81,10 @@ Quickstart coding
|
|
|
36
81
|
|
|
37
82
|
Load the `index` page and check out your `development.log` file
|
|
38
83
|
|
|
39
|
-
Sample log entry (in your development.log file)
|
|
40
|
-
|
|
41
|
-
|
|
84
|
+
### Sample log entry (in your development.log file)
|
|
85
|
+
IO pid-86000 [2013-12-17 17:26:39:176] pany.myrailsapp.app.controllers.PagesController - Entering with params = {"controller"=>"pages", "action"=>"index"} (`/myrailsapp/app/controllers/pages_controller.rb:7`:in `index`)
|
|
86
|
+
|
|
87
|
+
|
|
42
88
|
|
|
43
89
|
Inspiration
|
|
44
90
|
-----------
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Catamaran
|
|
2
|
+
module Formatter
|
|
3
|
+
##
|
|
4
|
+
# Construct a properly formatted log message based
|
|
5
|
+
|
|
6
|
+
class BaseFormatter
|
|
7
|
+
def self.base_construct_formatted_message( log_level, path, msg, opts )
|
|
8
|
+
# Truncate on the left
|
|
9
|
+
if path.length > 47
|
|
10
|
+
updated_path = path.dup[-47,47]
|
|
11
|
+
else
|
|
12
|
+
updated_path = path
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# TODO: Abstract out the logger so that it's easy to use different formats
|
|
16
|
+
# Implicit return
|
|
17
|
+
retval = sprintf( "%6s pid-#{Process.pid} [#{Time.now.strftime( "%G-%m-%d %H:%M:%S:%L" )}] %47s - #{msg}", LogLevel.to_s(log_level), updated_path )
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def self.contruct_suffix_info( opts )
|
|
22
|
+
msg = ''
|
|
23
|
+
|
|
24
|
+
if opts
|
|
25
|
+
if opts[:file]
|
|
26
|
+
msg << "(#{opts[:file]}"
|
|
27
|
+
|
|
28
|
+
if opts[:line]
|
|
29
|
+
msg << ":#{opts[:line]}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if opts[:class] || opts[:method]
|
|
33
|
+
msg << ":in `"
|
|
34
|
+
|
|
35
|
+
msg << construct_class_method_info( opts )
|
|
36
|
+
|
|
37
|
+
msg << "'"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
msg << ')'
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Implicit return
|
|
45
|
+
msg
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def self.construct_class_method_info( opts )
|
|
50
|
+
msg = ''
|
|
51
|
+
if opts
|
|
52
|
+
if opts[:class] || opts[:method]
|
|
53
|
+
if opts[:class]
|
|
54
|
+
msg << "#{opts[:class]}."
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
msg << "#{opts[:method]}" if opts[:method]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Implicit Return
|
|
62
|
+
msg
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
@@ -3,29 +3,9 @@ module Catamaran
|
|
|
3
3
|
##
|
|
4
4
|
# Construct a properly formatted log message based
|
|
5
5
|
|
|
6
|
-
class CallerFormatter
|
|
6
|
+
class CallerFormatter < BaseFormatter
|
|
7
7
|
def self.construct_formatted_message( log_level, path, msg, opts )
|
|
8
|
-
|
|
9
|
-
##
|
|
10
|
-
# If the client has specified a __FILE__ or a __LINE__ in the log opts, make use of them
|
|
11
|
-
|
|
12
|
-
if opts
|
|
13
|
-
if opts[:file] && opts[:line]
|
|
14
|
-
path = path + " (#{opts[:file]}:#{opts[:line]})"
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Truncate on the left
|
|
19
|
-
if path.length > 42
|
|
20
|
-
updated_path = path.dup[-42,42]
|
|
21
|
-
else
|
|
22
|
-
updated_path = path
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# Making use of the caller here is slow.
|
|
26
|
-
# TODO: Abstract out the logger so that it's easy to use different formats
|
|
27
|
-
# Implicit return
|
|
28
|
-
sprintf( "%6s pid-#{Process.pid} [#{Time.now.strftime( "%G-%m-%d %H:%M:%S:%L" )}] %42s - #{msg} (#{caller(3)[0]})", LogLevel.to_s(log_level), updated_path )
|
|
8
|
+
"#{base_construct_formatted_message( log_level, path, msg, opts )} (#{caller(3)[0]})"
|
|
29
9
|
end
|
|
30
10
|
end
|
|
31
11
|
end
|
|
@@ -3,28 +3,14 @@ module Catamaran
|
|
|
3
3
|
##
|
|
4
4
|
# Construct a properly formatted log message based
|
|
5
5
|
|
|
6
|
-
class NoCallerFormatter
|
|
7
|
-
def self.construct_formatted_message( log_level, path, msg, opts )
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if opts
|
|
13
|
-
if opts[:file] && opts[:line]
|
|
14
|
-
path = path + " (#{opts[:file]}:#{opts[:line]})"
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Truncate on the left
|
|
19
|
-
if path.length > 42
|
|
20
|
-
updated_path = path.dup[-42,42]
|
|
6
|
+
class NoCallerFormatter < BaseFormatter
|
|
7
|
+
def self.construct_formatted_message( log_level, path, msg, opts )
|
|
8
|
+
suffix_info = contruct_suffix_info( opts )
|
|
9
|
+
if suffix_info && suffix_info.length > 0
|
|
10
|
+
base_construct_formatted_message( log_level, path, msg, opts ) + ' ' + suffix_info
|
|
21
11
|
else
|
|
22
|
-
|
|
12
|
+
base_construct_formatted_message( log_level, path, msg, opts )
|
|
23
13
|
end
|
|
24
|
-
|
|
25
|
-
# TODO: Abstract out the logger so that it's easy to use different formats
|
|
26
|
-
# Implicit return
|
|
27
|
-
sprintf( "%6s pid-#{Process.pid} [#{Time.now.strftime( "%G-%m-%d %H:%M:%S:%L" )}] %42s - #{msg}", LogLevel.to_s(log_level), updated_path )
|
|
28
14
|
end
|
|
29
15
|
end
|
|
30
16
|
end
|
data/lib/catamaran/logger.rb
CHANGED
|
@@ -3,6 +3,8 @@ module Catamaran
|
|
|
3
3
|
attr_accessor :name
|
|
4
4
|
attr_accessor :path
|
|
5
5
|
attr_reader :parent
|
|
6
|
+
attr_reader :specified_file
|
|
7
|
+
attr_reader :specified_class
|
|
6
8
|
|
|
7
9
|
##
|
|
8
10
|
# The getter associated with retrieving the current log level for this logger.
|
|
@@ -190,8 +192,13 @@ module Catamaran
|
|
|
190
192
|
##
|
|
191
193
|
# Usually get_logger is a reference to self, unless a path has been specified as a parameter
|
|
192
194
|
|
|
193
|
-
def get_logger(
|
|
195
|
+
def get_logger( *args )
|
|
194
196
|
current_logger = self
|
|
197
|
+
|
|
198
|
+
path, opts = determine_path_and_opts_arguments( *args )
|
|
199
|
+
Catamaran.debugging( "Catamaran::Logger#get_logger() - path = '#{path}' opts = #{opts} from args = #{args}" ) if Catamaran.debugging?
|
|
200
|
+
|
|
201
|
+
|
|
195
202
|
if path
|
|
196
203
|
method_names = path.split(/\./)
|
|
197
204
|
|
|
@@ -200,6 +207,16 @@ module Catamaran
|
|
|
200
207
|
end
|
|
201
208
|
end
|
|
202
209
|
|
|
210
|
+
if opts
|
|
211
|
+
if opts[:file]
|
|
212
|
+
current_logger.instance_variable_set( :@specified_file, opts[:file] )
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
if opts[:class]
|
|
216
|
+
current_logger.instance_variable_set( :@specified_class, opts[:class] )
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
203
220
|
# Implicit return
|
|
204
221
|
current_logger
|
|
205
222
|
end
|
|
@@ -247,7 +264,7 @@ module Catamaran
|
|
|
247
264
|
_path = self.path
|
|
248
265
|
if _path
|
|
249
266
|
# Implicit return
|
|
250
|
-
_path.join( delimiter )
|
|
267
|
+
_path.join( Catamaran::Manager.delimiter )
|
|
251
268
|
else
|
|
252
269
|
# Implicit return
|
|
253
270
|
nil
|
|
@@ -294,6 +311,38 @@ module Catamaran
|
|
|
294
311
|
"#<#{self.class}:0x#{object_id.to_s(16)}>[name=#{self.name},path=#{path_to_s},depth=#{self.depth},log_level=#{@log_level}]"
|
|
295
312
|
end
|
|
296
313
|
|
|
314
|
+
protected
|
|
315
|
+
|
|
316
|
+
def determine_path_and_opts_arguments( *args )
|
|
317
|
+
Catamaran.debugging( "Catamaran::Logger#reset() - Entering with args = #{args}" ) if Catamaran.debugging?
|
|
318
|
+
|
|
319
|
+
if ( args.length == 0 )
|
|
320
|
+
opts = nil
|
|
321
|
+
path = nil
|
|
322
|
+
elsif ( args.length == 1 )
|
|
323
|
+
argument1 = args[0]
|
|
324
|
+
|
|
325
|
+
if ( argument1.nil? )
|
|
326
|
+
path = nil
|
|
327
|
+
opts = nil
|
|
328
|
+
elsif ( argument1.kind_of?( String ) )
|
|
329
|
+
path = argument1
|
|
330
|
+
opts = nil
|
|
331
|
+
elsif ( argument1.kind_of?( Hash ) )
|
|
332
|
+
path = nil
|
|
333
|
+
opts = argument1
|
|
334
|
+
else
|
|
335
|
+
raise ArgumentError.new "Unsupported argument type"
|
|
336
|
+
end
|
|
337
|
+
elsif ( args.length == 2 )
|
|
338
|
+
path, opts = *args
|
|
339
|
+
else
|
|
340
|
+
raise ArgumentError.new "Unexpected number of arguments: #{args.length}"
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
[ path, opts ]
|
|
344
|
+
end
|
|
345
|
+
|
|
297
346
|
private
|
|
298
347
|
|
|
299
348
|
##
|
|
@@ -330,6 +379,12 @@ module Catamaran
|
|
|
330
379
|
# All log statements eventually call _write_to_log
|
|
331
380
|
|
|
332
381
|
def _write_to_log( log_level, msg, opts )
|
|
382
|
+
if self.specified_file || self.specified_class
|
|
383
|
+
opts = {} unless opts
|
|
384
|
+
opts[:file] = self.specified_file if self.specified_file
|
|
385
|
+
opts[:class] = self.specified_class if self.specified_class
|
|
386
|
+
end
|
|
387
|
+
|
|
333
388
|
formatted_msg = Manager.formatter_class.construct_formatted_message( log_level, self.path_to_s(), msg, opts )
|
|
334
389
|
Outputter.write( formatted_msg )
|
|
335
390
|
end
|
|
@@ -355,12 +410,5 @@ module Catamaran
|
|
|
355
410
|
Catamaran.debugging( "Catamaran::Logger#initialize() - I am #{self.to_s}" ) if Catamaran.debugging?
|
|
356
411
|
end
|
|
357
412
|
|
|
358
|
-
##
|
|
359
|
-
# The delimiter is a period
|
|
360
|
-
|
|
361
|
-
def delimiter
|
|
362
|
-
"."
|
|
363
|
-
end
|
|
364
|
-
|
|
365
413
|
end
|
|
366
414
|
end
|
data/lib/catamaran/manager.rb
CHANGED
|
@@ -18,9 +18,22 @@ module Catamaran
|
|
|
18
18
|
def formatter_class=( value )
|
|
19
19
|
@formatter_class = value
|
|
20
20
|
end
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# The default delimiter
|
|
24
|
+
#
|
|
25
|
+
def delimiter
|
|
26
|
+
@delimiter || '.'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def delimiter=( value )
|
|
30
|
+
@delimiter = value
|
|
31
|
+
end
|
|
21
32
|
end
|
|
22
33
|
|
|
23
34
|
|
|
35
|
+
|
|
36
|
+
|
|
24
37
|
##
|
|
25
38
|
# Used to reset Catamaran
|
|
26
39
|
|
data/lib/catamaran/version.rb
CHANGED
data/lib/catamaran.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require 'catamaran/logger'
|
|
2
2
|
require 'catamaran/manager'
|
|
3
|
+
require 'catamaran/formatter/base_formatter'
|
|
3
4
|
require 'catamaran/formatter/caller_formatter'
|
|
4
5
|
require 'catamaran/formatter/no_caller_formatter'
|
|
5
6
|
require 'catamaran/outputter'
|
|
@@ -22,8 +23,9 @@ module Catamaran
|
|
|
22
23
|
@debugging = value
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
def self.logger(
|
|
26
|
-
Catamaran
|
|
26
|
+
def self.logger( *args )
|
|
27
|
+
Catamaran.debugging( "Catamaran.logger() - Entering with args = #{args}" ) if Catamaran.debugging?
|
|
28
|
+
Catamaran::Manager.root_logger().get_logger( *args )
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
##
|
data/spec/catamaran_spec.rb
CHANGED
|
@@ -13,8 +13,17 @@ describe Catamaran do
|
|
|
13
13
|
Catamaran.logger.object_id.should == Catamaran.logger.object_id
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
context "when working with a blank path" do
|
|
17
|
+
it "should reuse the same root logger instance" do
|
|
18
|
+
Catamaran.logger( '' ).object_id.should == Catamaran.logger.object_id
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
16
22
|
it "should reuse the same logger instance when contextually the same" do
|
|
17
23
|
Catamaran.logger.Company.Product.App.Model.User.object_id.should == Catamaran.logger.Company.Product.App.Model.User.object_id
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should reuse the same logger instance when contextually the same regardless of if the logger was determined by a string or by sequential method calls" do
|
|
18
27
|
Catamaran.logger( "Company.Product.App.Model.User" ).object_id.should == Catamaran.logger.Company.Product.App.Model.User.object_id
|
|
19
28
|
end
|
|
20
29
|
|
|
@@ -169,6 +178,20 @@ describe Catamaran do
|
|
|
169
178
|
Catamaran.logger.debug( "Testing a DEBUG log" )
|
|
170
179
|
end
|
|
171
180
|
|
|
181
|
+
describe "#determine_path_and_opts_arguments" do
|
|
182
|
+
it "should return the correct path when one string parameter is specified" do
|
|
183
|
+
Catamaran.logger.send( :determine_path_and_opts_arguments, "Company.Product.App.Model.User" ).should == [ "Company.Product.App.Model.User", nil ]
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "should return the correct opts when one hash parameter is specified" do
|
|
187
|
+
Catamaran.logger.send( :determine_path_and_opts_arguments, {} ).should == [ nil, {} ]
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it "should return the correct path and opts when two parameters are specified" do
|
|
191
|
+
Catamaran.logger.send( :determine_path_and_opts_arguments, "Company.Product.App.Model.User", {} ).should == [ "Company.Product.App.Model.User", {} ]
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
172
195
|
context "when using smart_log_level" do
|
|
173
196
|
it "should inherit the log level from a parent" do
|
|
174
197
|
Catamaran::LogLevel.default_log_level = Catamaran::LogLevel::INFO
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: catamaran
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeano
|
|
@@ -9,7 +9,7 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date: 2013-12-
|
|
12
|
+
date: 2013-12-23 00:00:00 -06:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies: []
|
|
15
15
|
|
|
@@ -28,6 +28,7 @@ files:
|
|
|
28
28
|
- catamaran.gemspec
|
|
29
29
|
- init.rb
|
|
30
30
|
- lib/catamaran.rb
|
|
31
|
+
- lib/catamaran/formatter/base_formatter.rb
|
|
31
32
|
- lib/catamaran/formatter/caller_formatter.rb
|
|
32
33
|
- lib/catamaran/formatter/no_caller_formatter.rb
|
|
33
34
|
- lib/catamaran/integration/rails.rb
|