smart_logger_wrapper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9e74dde7e2e9f462afec29ffccaf4066fffe25f4
4
+ data.tar.gz: bcbbe35862489fe01aa3629cbe8d6026f09889aa
5
+ SHA512:
6
+ metadata.gz: aeef4e5d071ba8d79f3ca8c335c82b31430759090dc0e38ae95ce7f8d0ea3a64bad34a82f5fe542dcf5411e671397be23d04f386ac3d0e0ef6f7fc04edc1de95
7
+ data.tar.gz: 32f1a2b6ddc5fb8ba57a93b3e7aaec27f4fdbad2dcd3be215968a4a48844613aed9cc49e64ce67ed9af21530ae05daef93d82654623c1085a62272ce664eab1a
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ /vendor
12
+
13
+ # rspec failure tracking
14
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.0
5
+ before_install: gem install bundler -v 1.14.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in smart_logger_wrapper.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 akihiro
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.
@@ -0,0 +1,127 @@
1
+ # SmartLoggerWrapper
2
+
3
+ SmartLoggerWrapper adds some useful features to the Ruby Logger or the compatibles. See Usage below to find out how it benefits your development.
4
+
5
+ [![Build Status](https://travis-ci.org/akeyhero/smart_logger_wrapper.svg?branch=master)](https://travis-ci.org/akeyhero/smart_logger_wrapper)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'smart_logger_wrapper'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install smart_logger_wrapper
22
+
23
+ ### For Ruby on Rails
24
+
25
+ Wrap your logger with `SmartLoggerWrapper`, for example:
26
+
27
+ ```diff
28
+ - config.logger = Logger.new('log/production.log', 'daily')
29
+ + config.logger = SmartLoggerWrapper(Logger.new('log/production.log', 'daily')).with_position
30
+ ```
31
+
32
+ Note that it is strongly recommended to use the wrapper for all environments so that you can avoid exceptions such as `NoMethodError` due to the unique features of this library.
33
+
34
+ ## Usage
35
+
36
+ ### Basic
37
+
38
+ Initialize with a Ruby `Logger` or an instance of the compatibles (e.g. `ActiveSupport::TaggedLogging`):
39
+
40
+ ```ruby
41
+ require 'logger'
42
+ require 'smart_logger_wrapper'
43
+
44
+ logger = SmartLoggerWrapper.new(Logger.new('log/development.log'))
45
+
46
+ logger.info 'Call logging methods as usual.'
47
+ ```
48
+
49
+ The compatibles must respond to `#log` with the same arguments as `Logger#log`.
50
+
51
+ ### Feature 1: Integrate multiple logger calls
52
+
53
+ `SmartLoggerWrapper` accepts multiple arguments like `puts` method does. Then the wrapped logger will be called for each of the arguments.
54
+
55
+ ```ruby
56
+ logger.info 'foo', 'bar'
57
+ # => I, [2018-03-19T03:03:52.525503 #92534] INFO -- : foo
58
+ # => I, [2018-03-19T03:03:52.527478 #92534] INFO -- : bar
59
+ ```
60
+
61
+ ### Feature 2: Better exception logging
62
+
63
+ When you pass an exception to this logger, it logs the backtrace of the exception along with the message.
64
+
65
+ ```ruby
66
+ logger.error ex
67
+ # => E, [2018-03-19T02:53:01.605740 #92534] ERROR -- : #<RuntimeError: an error>
68
+ # => path/to/code.rb:6:in `foo'
69
+ # => path/to/code.rb:2:in `bar'
70
+ ```
71
+
72
+ ### Feature 3: Optional modifiers
73
+
74
+ You can chain options to the logger instance to modify logging messages.
75
+
76
+ ```ruby
77
+ logger.with_position.to(STDERR).info 'A message'
78
+
79
+ # You can use blocks to log several times with the same options.
80
+ logger.with_position do |pos_logger|
81
+ pos_logger.info 'A message'
82
+ pos_logger.append_backtrace.error 'An error'
83
+ end
84
+ ```
85
+
86
+ #### #to
87
+
88
+ With `to` option, this logger leaves your messages to another location besides the original where the wrapped logger logs.
89
+
90
+ ```ruby
91
+ logger.to(STDERR).info 'A message'
92
+ ```
93
+
94
+ #### #with\_position
95
+
96
+ `with_position` option makes the logger tag the position where the logger is called.
97
+
98
+ ```ruby
99
+ logger.with_position.info 'A message'
100
+ # => I, [2018-03-19T03:34:10.448542 #92534] INFO -- : [path/to/caller.rb@foo:2] A message
101
+
102
+ # You can turn off this option by chaining #with_position with false
103
+ logger.with_position.with_position(false).info 'A message'
104
+ ```
105
+
106
+ #### #append\_backtrace
107
+
108
+ With `append_backtrace`, the logger adjoins its caller's backtrace.
109
+
110
+ ```ruby
111
+ logger.append_backtrace.info 'A message'
112
+ # => I, [2018-03-19T03:44:36.987404 #97956] INFO -- : A message
113
+ # => I, [2018-03-19T03:44:36.987530 #97956] INFO -- : BACKTRACE:
114
+ # => path/to/code.rb:6:in `foo'
115
+ # => path/to/code.rb:2:in `bar'
116
+
117
+ # You can specify the length of the backtrace to log
118
+ logger.append_backtrace(2).info 'A message'
119
+ ```
120
+
121
+ ## Contributing
122
+
123
+ Bug reports and pull requests are welcome on GitHub at https://github.com/akeyhero/smart_logger_wrapper.
124
+
125
+ ## License
126
+
127
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "smart_logger_wrapper"
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(__FILE__)
@@ -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
@@ -0,0 +1,81 @@
1
+ require 'logger'
2
+ require 'smart_logger_wrapper/version'
3
+ require 'smart_logger_wrapper/options'
4
+
5
+ class SmartLoggerWrapper
6
+ include Logger::Severity
7
+
8
+ SEVERITY_MAPPING = {
9
+ debug: DEBUG,
10
+ info: INFO,
11
+ warn: WARN,
12
+ error: ERROR,
13
+ fatal: FATAL,
14
+ unknown: UNKNOWN
15
+ }.freeze
16
+
17
+ attr_reader :logger, :options
18
+
19
+ def initialize(logger = Logger.new(STDOUT), **options)
20
+ @logger = logger
21
+ @options = options
22
+ end
23
+
24
+ def log(severity, *args, &block)
25
+ _log(severity, *args, &block)
26
+ end
27
+ alias add log
28
+
29
+ SEVERITY_MAPPING.each do |severity_name, severity|
30
+ define_method(severity_name) do |*args, &block|
31
+ _log(severity, *args, &block)
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ # All methods calling this must have the synchronized call stack depth so that this can show neat positions and backtraces
38
+ def _log(severity, *args, &block)
39
+ messages = args.map { |arg| to_message(arg) }
40
+ messages << to_message(block.call) if block_given?
41
+ begin
42
+ Options.apply_all!(messages, options)
43
+ true
44
+ rescue Options::ApplicationError => e
45
+ logger.error(<<~EOM)
46
+ Failed to apply options: #{e.inspect}
47
+ #{e.backtrace.join("\n")}
48
+ EOM
49
+ false
50
+ end.tap do |succeeded|
51
+ messages.each do |message|
52
+ logger.log(severity, nil, message)
53
+ end
54
+ end
55
+ end
56
+
57
+ def to_message(object)
58
+ case object
59
+ when String
60
+ object
61
+ when Exception
62
+ backtrace = object.backtrace ? Utils::Backtrace.clean_backtrace(object.backtrace) : []
63
+ info = [object.inspect]
64
+ (info + backtrace).join("\n")
65
+ else
66
+ object.inspect
67
+ end
68
+ end
69
+
70
+ def method_missing(method_name, *args, &block)
71
+ if Options.defined_option?(method_name)
72
+ # if there is an defined option with the same name as the method name, return a new logger with the option.
73
+ new_logger = self.class.new(logger, **options.merge(method_name => args.first))
74
+ return block.(new_logger) if block_given?
75
+ new_logger
76
+ else
77
+ # otherwise, call the method of the warpped logger.
78
+ logger.public_send(method_name, *args, &block)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,58 @@
1
+ class SmartLoggerWrapper
2
+ module Options
3
+ class ApplicationError < StandardError; end
4
+
5
+ # XXX: Be careful! This relies strongly on the implementation of this and the callers
6
+ APPLY_CALLER_STACK_DEPTH = 4
7
+
8
+ module_function
9
+
10
+ def apply_all!(messages, options)
11
+ [defined_appenders, defined_taggers, defined_redirectors].flatten.each do |option_key|
12
+ defined_options[option_key].apply!(messages, options[option_key]) if options.include?(option_key)
13
+ end
14
+ end
15
+
16
+ def define_option(option_name, option_object, defined_option_keys)
17
+ key = option_name.to_sym
18
+ defined_option_keys.push(key)
19
+ defined_options.merge!(key => option_object)
20
+ end
21
+
22
+ def define_appender(option_name, option_object)
23
+ define_option(option_name, option_object, defined_appenders)
24
+ end
25
+
26
+ def define_tagger(option_name, option_object)
27
+ define_option(option_name, option_object, defined_taggers)
28
+ end
29
+
30
+ def define_redirector(option_name, option_object)
31
+ define_option(option_name, option_object, defined_redirectors)
32
+ end
33
+
34
+ def defined_appenders
35
+ @defined_appenders ||= []
36
+ end
37
+
38
+ def defined_taggers
39
+ @defined_taggers ||= []
40
+ end
41
+
42
+ def defined_redirectors
43
+ @defined_redirectors ||= []
44
+ end
45
+
46
+ def defined_options
47
+ @defined_options ||= {}
48
+ end
49
+
50
+ def defined_option?(option_name)
51
+ defined_options.include?(option_name.to_sym)
52
+ end
53
+ end
54
+ end
55
+
56
+ require 'smart_logger_wrapper/options/to'
57
+ require 'smart_logger_wrapper/options/append_backtrace'
58
+ require 'smart_logger_wrapper/options/with_position'
@@ -0,0 +1,22 @@
1
+ require 'smart_logger_wrapper/options/base'
2
+ require 'smart_logger_wrapper/utils/backtrace'
3
+
4
+ class SmartLoggerWrapper
5
+ module Options
6
+ class AppendBacktrace < Base
7
+ include ::SmartLoggerWrapper::Utils::Backtrace
8
+
9
+ def initialize(start)
10
+ super()
11
+ @start = start
12
+ end
13
+
14
+ def apply!(messages, value = nil)
15
+ length = value.is_a?(Numeric) ? value : nil
16
+ messages << "BACKTRACE:\n" + get_backtrace(@start + 1, length).join("\n")
17
+ end
18
+ end
19
+
20
+ define_appender :append_backtrace, AppendBacktrace.new(APPLY_CALLER_STACK_DEPTH + 1)
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ class SmartLoggerWrapper
2
+ module Options
3
+ class Base
4
+ def apply!(messages, value)
5
+ raise NotImplementedError, __callee__
6
+ end
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,16 @@
1
+ require 'smart_logger_wrapper/options/base'
2
+
3
+ class SmartLoggerWrapper
4
+ module Options
5
+ class To < Base
6
+ def apply!(messages, value)
7
+ raise ApplicationError, 'No handler given' if value == nil
8
+ value.puts messages.join("\n")
9
+ rescue NoMethodError => e
10
+ raise ApplicationError, e.message
11
+ end
12
+ end
13
+
14
+ define_redirector :to, To.new
15
+ end
16
+ end
@@ -0,0 +1,33 @@
1
+ require 'smart_logger_wrapper/options/base'
2
+ require 'smart_logger_wrapper/utils/path'
3
+
4
+ class SmartLoggerWrapper
5
+ module Options
6
+ class WithPosition < Base
7
+ include ::SmartLoggerWrapper::Utils::Path
8
+
9
+ def initialize(start)
10
+ super()
11
+ @start = start
12
+ end
13
+
14
+ def apply!(messages, value = nil)
15
+ return if value == false
16
+ # add 1 to `start` because this method dug the backtrace by 1
17
+ location = caller_locations(@start + 1, 1)
18
+ prefix =
19
+ if location && location.length > 0
20
+ method_name = location[0].label
21
+ path = trim_dirname(location[0].absolute_path)
22
+ lineno = location[0].lineno
23
+ "[#{method_name}@#{path}:#{lineno}]"
24
+ else
25
+ nil
26
+ end
27
+ messages.map! { |message| [prefix, message].compact.join(' ') }
28
+ end
29
+ end
30
+
31
+ define_tagger :with_position, WithPosition.new(APPLY_CALLER_STACK_DEPTH + 1)
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ require 'smart_logger_wrapper/utils/path'
2
+
3
+ class SmartLoggerWrapper
4
+ module Utils
5
+ module Backtrace
6
+ module_function
7
+
8
+ def get_backtrace(start, length = nil)
9
+ # add 1 to `start` because this method dug the backtrace by 1
10
+ backtrace = clean_backtrace(caller_locations(start + 1).map(&:to_s).lazy)
11
+ length == nil ? backtrace.to_a : backtrace.first(length)
12
+ end
13
+
14
+ def clean_backtrace(backtrace)
15
+ (
16
+ if defined?(::Rails) && ::Rails.respond_to?(:backtrace_cleaner)
17
+ Rails.backtrace_cleaner.filter(backtrace)
18
+ else
19
+ backtrace
20
+ end
21
+ ).map { |line| Path.trim_dirname(line) }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ class SmartLoggerWrapper
2
+ module Utils
3
+ module Path
4
+ DIR_TRIMMER_PATTERN = /^#{Dir.pwd}\/?/
5
+
6
+ module_function
7
+
8
+ def trim_dirname(line)
9
+ line.sub(DIR_TRIMMER_PATTERN, '')
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ class SmartLoggerWrapper
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'smart_logger_wrapper/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "smart_logger_wrapper"
8
+ spec.version = SmartLoggerWrapper::VERSION
9
+ spec.authors = ["Akihiro Katsura"]
10
+ spec.email = ["info@kats.la"]
11
+
12
+ spec.summary = %q{SmartLoggerWrapper adds some useful features to the Ruby Logger or the compatibles.}
13
+ # spec.description = %q{SmartLoggerWrapper adds some useful features to the Ruby Logger or the compatibles.}
14
+ spec.homepage = "https://github.com/akeyhero/smart_logger_wrapper"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.14"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smart_logger_wrapper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Akihiro Katsura
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-03-23 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.14'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description:
56
+ email:
57
+ - info@kats.la
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - ".travis.yml"
65
+ - Gemfile
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - bin/console
70
+ - bin/setup
71
+ - lib/smart_logger_wrapper.rb
72
+ - lib/smart_logger_wrapper/options.rb
73
+ - lib/smart_logger_wrapper/options/append_backtrace.rb
74
+ - lib/smart_logger_wrapper/options/base.rb
75
+ - lib/smart_logger_wrapper/options/to.rb
76
+ - lib/smart_logger_wrapper/options/with_position.rb
77
+ - lib/smart_logger_wrapper/utils/backtrace.rb
78
+ - lib/smart_logger_wrapper/utils/path.rb
79
+ - lib/smart_logger_wrapper/version.rb
80
+ - smart_logger_wrapper.gemspec
81
+ homepage: https://github.com/akeyhero/smart_logger_wrapper
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 2.6.8
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: SmartLoggerWrapper adds some useful features to the Ruby Logger or the compatibles.
105
+ test_files: []