logsaber 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in logomatic.gemspec
4
+ gemspec
5
+
6
+ group :development, :test do
7
+ gem 'pry'
8
+ gem 'pry-theme'
9
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Anthony Cook
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,156 @@
1
+ Logsaber
2
+ =========
3
+
4
+ A logger for a more civilized age.
5
+
6
+ Philosophy/Why Logsaber?
7
+ -------------------------
8
+
9
+ Logsaber is a lot like Ruby's built in Logger class,
10
+ but it is based on the real world experience of how I actually use loggers.
11
+
12
+ The biggest difference is Logsaber's intelligent output.
13
+
14
+ ### Intelligent Logging
15
+
16
+ If you pass a single string argument to an event method Logsaber will just log that string without any frills.
17
+
18
+ But if you pass it an object like an Array:
19
+
20
+ ```ruby
21
+ array = [1,2,3]
22
+ $log.info array
23
+ ```
24
+
25
+ ...it will inspect the array and the output will reflect the intent:
26
+
27
+ ```
28
+ 2013-03-02 21:08:30.797 [ INFO] 32981 | OBJ : [1, 2, 3]
29
+ ```
30
+
31
+ Even better, if you pass in two arguments, like this:
32
+
33
+ ```ruby
34
+ $log.info 'using environment', ENV['MYAPP_ENV']
35
+ ```
36
+
37
+ ...the first will be treated as a label, and the second as an object to be inspected:
38
+
39
+ ```
40
+ 2013-03-02 20:11:22.630 [ INFO] 31395 | using environment : development
41
+ ```
42
+
43
+ If you pass in a block:
44
+
45
+ ```ruby
46
+ @log.info :heavy, 'this could be resource intensive' do
47
+ 10000.times.to_a.last
48
+ end
49
+ ```
50
+
51
+ ...Logsaber will intelligently evaluate it and format your output sanely:
52
+
53
+ ```
54
+ 2013-03-02 21:20:04.715 [ INFO] 32981 | heavy : \"this could be resource intensive\" | 9999
55
+ ```
56
+
57
+ Also, since blocks are lazy loaded, they won't be evaluated at all if the severity is below the log level threshold, this is really important if your debug output is resource intensive.
58
+
59
+ ### Ruby Logger Limitations Surpassed
60
+
61
+ There's also some complaints about the native Logger than I address:
62
+
63
+ 1. You can't specify the log level on instantiation
64
+ - Logsaber lets you set the log level when you create it:
65
+ `$log = Logsaber.create file, :warn`
66
+ - But you can still change the default later:
67
+ `$log.level = :info`
68
+ 2. You must specify the "progname" for every event
69
+ - Logsaber lets you set the app name when you create it:
70
+ `$log = Logsaber.create file, :warn, 'MyApp'`
71
+ - Or change it to something else at any time:
72
+ `$log.appname = 'SomethingElse'`
73
+
74
+ Installation
75
+ ------------
76
+
77
+ Add this line to your application's Gemfile:
78
+
79
+ gem 'logomatic'
80
+
81
+ And then execute:
82
+
83
+ $ bundle
84
+
85
+ Or install it yourself as:
86
+
87
+ $ gem install logomatic
88
+
89
+ Setup
90
+ -----
91
+
92
+ Give it a filename and it will log to a file:
93
+
94
+ ```ruby
95
+ $log = Logsaber.create './log/my_app.log'
96
+ ```
97
+
98
+ Give it an IO and it will log to it:
99
+
100
+ ```ruby
101
+ $log = Logsaber.create $stdout
102
+ ```
103
+
104
+ Even give it a StringIO and it will log to that:
105
+
106
+ ```ruby
107
+ require 'stringio'
108
+ stringio = StringIO.create
109
+
110
+ $log = Logsaber.create stringio
111
+ ```
112
+
113
+ You can also set the log level on initialization (it's :info by default):
114
+
115
+ ```ruby
116
+ $log = Logsaber.create $stdout, :debug
117
+ ```
118
+
119
+ And you can optionally specify a program name:
120
+
121
+ ```ruby
122
+ $log = Logsaber.create $stdout, :info, 'MyApp'
123
+ ```
124
+
125
+ Usage
126
+ -----
127
+
128
+ Then you can use any of the logging commands:
129
+
130
+ `debug`, `info`, `warn`, `error`, or `fatal`
131
+
132
+ like this:
133
+
134
+ ```ruby
135
+ $log.warn 'Something might be amiss here'
136
+ ```
137
+
138
+ or this:
139
+
140
+ ```ruby
141
+ $log.error 'PEBKAC', @user
142
+ ```
143
+
144
+ Contributing
145
+ ------------
146
+
147
+ 1. Fork it
148
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
149
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
150
+ 4. Push to the branch (`git push origin my-new-feature`)
151
+ 5. Create new Pull Request
152
+
153
+ Author
154
+ ======
155
+
156
+ Anthony M. Cook 2013
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,3 @@
1
+ class Logsaber
2
+ VERSION = "0.0.1"
3
+ end
data/lib/logsaber.rb ADDED
@@ -0,0 +1,100 @@
1
+ require 'logsaber/version'
2
+
3
+ class Logsaber
4
+ def self.create new_output = $stdout, new_level = :info, new_appname = nil
5
+ log = self.new
6
+
7
+ log.output =
8
+ if new_output.is_a? String then
9
+ File.new new_output, 'a'
10
+ else
11
+ new_output
12
+ end
13
+
14
+ log.level = new_level
15
+ log.appname = new_appname
16
+
17
+ log
18
+ end
19
+ attr_accessor :output, :level, :appname, :time_format
20
+
21
+ DEFAULT_TIME_FORMAT ||= '%Y-%m-%d %H:%M:%S.%L'
22
+ SEVERITY_LEVELS ||= [:debug, :info, :warn, :error, :fatal]
23
+
24
+ SEVERITY_LEVELS.each do |method_name|
25
+ eval <<-END_OF_METHOD
26
+ def #{method_name} *args, &block
27
+ log :#{method_name}, *args, &block
28
+ end
29
+ END_OF_METHOD
30
+ end
31
+
32
+ def level= new_level
33
+ @level = new_level if SEVERITY_LEVELS.include? new_level
34
+ end
35
+
36
+ def time_format
37
+ @time_format ||= DEFAULT_TIME_FORMAT
38
+ end
39
+
40
+ protected
41
+
42
+ def log severity, *details
43
+ return unless loggable? severity
44
+ label, info, object = extract_details details, block_given?
45
+
46
+ if block_given? then
47
+ result = yield
48
+
49
+ info << ' | ' unless info.empty?
50
+ info << result.to_s
51
+
52
+ object = result
53
+ end
54
+
55
+ message = format severity, "#{label} : #{info}"
56
+ output.puts message
57
+ output.flush
58
+
59
+ object
60
+ end
61
+
62
+ def extract_details details, given_block
63
+ primary, secondary, object = details
64
+
65
+ if details.length == 2 then
66
+ [primary.to_s, secondary.inspect, object || secondary]
67
+ elsif given_block then
68
+ [primary, secondary.to_s, object]
69
+ elsif [String, Numeric].any?{|klass| primary.is_a? klass} then
70
+ ['MSG', primary, object || primary]
71
+ else
72
+ ['OBJ', primary.to_s, object || primary]
73
+ end
74
+ end
75
+
76
+ def loggable? severity
77
+ SEVERITY_LEVELS.index(severity) >= SEVERITY_LEVELS.index(level)
78
+ end
79
+
80
+ def format severity, contents
81
+ %Q{#{timestamp} [#{severity_info severity}] #{process_info} | #{contents}}
82
+ end
83
+
84
+ def process_info
85
+ pid = Process.pid.to_s
86
+ appname? ? "#{appname}:#{pid}" : pid
87
+ end
88
+
89
+ def severity_info severity
90
+ severity.to_s.upcase.rjust 5
91
+ end
92
+
93
+ def timestamp
94
+ Time.now.strftime time_format
95
+ end
96
+
97
+ def appname?
98
+ !!@appname
99
+ end
100
+ end
data/logsaber.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'logsaber/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "logsaber"
8
+ gem.version = Logsaber::VERSION
9
+ gem.authors = ["Anthony Cook"]
10
+ gem.email = ["anthonymichaelcook@gmail.com"]
11
+ gem.description = %q{A logger for a more civilized age. Intelligent logs for your applications.}
12
+ gem.summary = %q{A logger for a more civilized age.}
13
+ gem.homepage = "http://github.com/acook/logsaber"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_development_dependency 'uspec'
21
+ end
@@ -0,0 +1,107 @@
1
+ require_relative 'spec_helper'
2
+
3
+ test_string = 'foo'
4
+
5
+ spec 'will output to a file, given a filename' do
6
+ filename = './test_file.log'
7
+ begin
8
+ File.delete filename
9
+ rescue Errno::ENOENT => e
10
+ # ignore if file doesn't exist
11
+ end
12
+
13
+ log = Logsaber.create filename
14
+ log.info test_string
15
+
16
+ contents = File.open(filename, 'r').gets
17
+ contents.include?(test_string).tap{File.delete filename}
18
+ end
19
+
20
+ require 'stringio'
21
+ spec 'can use a StringIO' do
22
+ stringio = StringIO.new
23
+
24
+ log = Logsaber.create stringio
25
+ log.info test_string
26
+
27
+ stringio.string.include? test_string
28
+ end
29
+
30
+ spec 'can use an IO' do
31
+ output = capture do
32
+ log = Logsaber.create $stdout
33
+ log.info test_string
34
+ end
35
+
36
+ output.include?(test_string) || output
37
+ end
38
+
39
+ @log = Logsaber.create
40
+
41
+ spec 'has shortcut methods' do
42
+ methods = [:debug, :info, :warn, :error, :fatal]
43
+ has = methods.map do |m|
44
+ @log.respond_to?(m) && m
45
+ end
46
+
47
+ has.all? || methods - has
48
+ end
49
+
50
+ spec 'can tell you the current minimum log level' do
51
+ @log.level == :info || @log.level
52
+ end
53
+
54
+
55
+ @output = StringIO.new
56
+ @log = Logsaber.create @output
57
+
58
+ def self.clear_log
59
+ @output.truncate 0
60
+ @output.rewind
61
+ end
62
+
63
+ def format label, info
64
+ "[ INFO] #{Process.pid} | #{label} : #{info}"
65
+ end
66
+
67
+
68
+ spec 'basic usage' do
69
+ clear_log
70
+
71
+ @log.info test_string
72
+ @output.string.include? format('MSG', test_string)
73
+ end
74
+
75
+ spec ' with details usage' do
76
+ clear_log
77
+
78
+ @log.info :test_string, test_string
79
+ @output.string.include? format(:test_string, test_string.inspect)
80
+ end
81
+
82
+ spec 'object usage' do
83
+ clear_log
84
+
85
+ array = [1,2,3]
86
+ @log.info array
87
+ @output.string.include? format('OBJ', array.inspect)
88
+ end
89
+
90
+ spec 'basic block usage' do
91
+ clear_log
92
+
93
+ @log.info 'label' do
94
+ 'block'
95
+ end
96
+ @output.string.include?(format('label', 'block')) || @output.string
97
+ end
98
+
99
+ spec 'block with details usage' do
100
+ clear_log
101
+
102
+ @log.info 'label', 'details' do
103
+ 'block'
104
+ end
105
+ @output.string.include?(format('label', '"details" | block')) || @output.string
106
+ end
107
+
@@ -0,0 +1,27 @@
1
+ require 'bundler/setup'
2
+
3
+ Bundler.require :development, :test
4
+
5
+ require 'uspec'
6
+
7
+ Dir.chdir File.dirname(__FILE__)
8
+
9
+ require_relative '../lib/logsaber'
10
+
11
+ extend Uspec
12
+
13
+ def self.capture
14
+ readme, writeme = IO.pipe
15
+ pid = fork do
16
+ $stdout.reopen writeme
17
+ readme.close
18
+
19
+ yield
20
+ end
21
+
22
+ writeme.close
23
+ output = readme.read
24
+ Process.waitpid(pid)
25
+
26
+ output
27
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logsaber
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Anthony Cook
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: uspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: A logger for a more civilized age. Intelligent logs for your applications.
31
+ email:
32
+ - anthonymichaelcook@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - LICENSE.txt
40
+ - README.markdown
41
+ - Rakefile
42
+ - lib/logsaber.rb
43
+ - lib/logsaber/version.rb
44
+ - logsaber.gemspec
45
+ - spec/logsaber_spec.rb
46
+ - spec/spec_helper.rb
47
+ homepage: http://github.com/acook/logsaber
48
+ licenses: []
49
+ post_install_message:
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ requirements: []
66
+ rubyforge_project:
67
+ rubygems_version: 1.8.25
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: A logger for a more civilized age.
71
+ test_files:
72
+ - spec/logsaber_spec.rb
73
+ - spec/spec_helper.rb
74
+ has_rdoc: