rails-logstasher 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 +15 -0
- data/MIT-LICENSE +20 -0
- data/README.md +100 -0
- data/Rakefile +38 -0
- data/lib/rails_logstasher.rb +16 -0
- data/lib/rails_logstasher/action_controller/log_subscriber.rb +75 -0
- data/lib/rails_logstasher/action_view/log_subscriber.rb +31 -0
- data/lib/rails_logstasher/active_record/log_subscriber.rb +88 -0
- data/lib/rails_logstasher/active_resource/log_subscriber.rb +34 -0
- data/lib/rails_logstasher/core_ext/object/blank.rb +110 -0
- data/lib/rails_logstasher/event.rb +44 -0
- data/lib/rails_logstasher/logger.rb +55 -0
- data/lib/rails_logstasher/rack/logger.rb +53 -0
- data/lib/rails_logstasher/railtie.rb +70 -0
- data/lib/rails_logstasher/tagged_logging.rb +108 -0
- data/lib/rails_logstasher/version.rb +3 -0
- data/test/action_controller/log_subscriber_test.rb +165 -0
- data/test/action_view/log_subscriber_test.rb +89 -0
- data/test/active_record/log_subscriber_test.rb +87 -0
- data/test/active_resource/log_subscriber_test.rb +42 -0
- data/test/core_ext/blank_test.rb +31 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/javascripts/widgets.js +2 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/assets/stylesheets/scaffold.css +56 -0
- data/test/dummy/app/assets/stylesheets/widgets.css +4 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/log_subscriber_controller.rb +56 -0
- data/test/dummy/app/controllers/widgets_controller.rb +83 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/helpers/widgets_helper.rb +2 -0
- data/test/dummy/app/models/widget.rb +3 -0
- data/test/dummy/app/views/customers/_customer.html.erb +1 -0
- data/test/dummy/app/views/good_customers/_good_customer.html.erb +1 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/test/_customer.erb +1 -0
- data/test/dummy/app/views/test/hello_world.erb +1 -0
- data/test/dummy/app/views/widgets/_form.html.erb +17 -0
- data/test/dummy/app/views/widgets/edit.html.erb +6 -0
- data/test/dummy/app/views/widgets/index.html.erb +21 -0
- data/test/dummy/app/views/widgets/new.html.erb +5 -0
- data/test/dummy/app/views/widgets/show.html.erb +5 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +69 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +22 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +31 -0
- data/test/dummy/config/environments/production.rb +64 -0
- data/test/dummy/config/environments/test.rb +35 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +10 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +69 -0
- data/test/dummy/db/migrate/20120927084605_create_widgets.rb +8 -0
- data/test/dummy/db/schema.rb +16 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/logger_test.rb +126 -0
- data/test/rack/logger_test.rb +68 -0
- data/test/rails_logstasher_test.rb +7 -0
- data/test/support/fake_models.rb +12 -0
- data/test/support/integration_case.rb +5 -0
- data/test/support/multibyte_test_helpers.rb +19 -0
- data/test/tagged_logging_test.rb +155 -0
- data/test/test_helper.rb +40 -0
- metadata +219 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NDk3MDhmNmExY2Y2NDM5MmFiY2Y1OTRhZjBmNzU3YzU5NGRjMmM2Ng==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZjI1YTkzZWQzZDQ3MzRmYWFmNzZlMGE0ZmIwOWJiMzkwYmE0Y2EyYw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
OGMwMDBlNjMyOWM2MTEyYTY3NjYxOTAzMmVmNzAxZWM4MzQwNGZkYzVhMjZj
|
10
|
+
MTk0MjhjYzNiNDM4M2FjY2ZlOTM4ZjQ3MzU3N2VmZTIwMzBiMzc2MGVmN2Qw
|
11
|
+
YTY1MzlmYTA5ZjQyNTdmOGNjYzkyYmVkMDQ3YzA5MGQzNDE4MzI=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZDQyZmUyZmJkMjFmOTRjMWVhNTljYmZhOGVlM2UzOTQyMzQyMGQ4NzNiNWJm
|
14
|
+
YTdmYjI1NmJiNmE0ZDA2MDg4ZmZkNmQ3NjFkZTMyNDNiMTQ2MWY4ZmI2ODQz
|
15
|
+
M2RkYjQ0MjBlMmY2MTU4OTdjOTY0NjcyN2MxODQyNzNhM2RhY2Q=
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 Jeffrey Jones
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# RailsLogstasher
|
2
|
+
|
3
|
+
[](http://travis-ci.org/capriza/rails-logstasher)
|
4
|
+
[](https://coveralls.io/r/capriza/rails-logstasher)
|
5
|
+
[](https://codeclimate.com/github/capriza/rails-logstasher)
|
6
|
+
[](https://gemnasium.com/capriza/rails-logstasher)
|
7
|
+
|
8
|
+
Logstash logging system for Ruby on Rails.
|
9
|
+
This is a fork from https://github.com/rurounijones/yarder.
|
10
|
+
|
11
|
+
This gem will create JSON based log entries designed for consumption by Logstash version 1.2.
|
12
|
+
The JSON will contain the same information as can be found in the default rails logging output.
|
13
|
+
|
14
|
+
## Current Status
|
15
|
+
|
16
|
+
All logging in a Rails3 app should be JSON formatted, including ad-hoc logging.
|
17
|
+
|
18
|
+
RailsLogstasher has been tested against Rails 3.2.16 on Ruby 1.9.3.
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Add this line to your Rails application's Gemfile:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
gem 'rails-logstasher'
|
26
|
+
```
|
27
|
+
|
28
|
+
## Configuration
|
29
|
+
|
30
|
+
RailsLogstasher uses the Rails logger (set using config.logger in application.rb)to log output.
|
31
|
+
|
32
|
+
By default Rails uses the TaggedLogging class to provide this however because RailsLogstasher
|
33
|
+
replaces it you will need to change the default to something else.
|
34
|
+
|
35
|
+
You will need to specify a Ruby Logger compatible logger. RailsLogstasher provides its own
|
36
|
+
logger which is a copy of the ActiveSupport::Logger (Formerly known as
|
37
|
+
ActiveSupport::BufferedLogger)
|
38
|
+
|
39
|
+
If you are not sure what you want yet then set the RailsLogstasher::Logger as in the example
|
40
|
+
below in your application.rb file.
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
module MyApp
|
44
|
+
class Application < Rails::Application
|
45
|
+
|
46
|
+
# Set a logger compatible with the standard ruby logger to be used by RailsLogstasher
|
47
|
+
config.logger = RailsLogstasher::Logger.new(Rails.root.join('log',"#{Rails.env}.log").to_s)
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
## Logstash Configuration
|
54
|
+
|
55
|
+
RailsLogstasher creates log entries with a default type of "rails", therefore your Logstash
|
56
|
+
configuration file should be as follows:
|
57
|
+
|
58
|
+
```
|
59
|
+
input {
|
60
|
+
file {
|
61
|
+
type => "rails"
|
62
|
+
path => "/var/www/rails/application-1/log/production.log" # Path to your log file
|
63
|
+
format => "json_event"
|
64
|
+
}
|
65
|
+
}
|
66
|
+
```
|
67
|
+
|
68
|
+
The type can be configured via the application configuration "log_type" setting, like so:
|
69
|
+
|
70
|
+
```
|
71
|
+
module MyApp
|
72
|
+
class Application < Rails::Application
|
73
|
+
|
74
|
+
# Set a different type for the events
|
75
|
+
config.log_type = 'my_type'
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
You will need to edit the path to point to your application's log file. Because RailsLogstasher creates json
|
82
|
+
serialized Logstash::Event entries there is no need to setup any filters
|
83
|
+
|
84
|
+
### Known issues
|
85
|
+
|
86
|
+
RailsLogstasher currently creates nested JSON. Kibana has pretty good (With a few small UI problems) support
|
87
|
+
for nested JSON but logstash web does not.
|
88
|
+
|
89
|
+
## Developers
|
90
|
+
|
91
|
+
Thoughts, suggestions, opinions and contributions are welcome.
|
92
|
+
|
93
|
+
When contributing please make sure to run your tests with warnings enabled and make sure that
|
94
|
+
rails-logstasher creates no warnings. (Warnings from other libraries like capybara etc. are ok)
|
95
|
+
|
96
|
+
```
|
97
|
+
RUBYOPT=-w rake
|
98
|
+
```
|
99
|
+
|
100
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'RailsLogstasher'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
|
30
|
+
Rake::TestTask.new(:test) do |t|
|
31
|
+
t.libs << 'lib'
|
32
|
+
t.libs << 'test'
|
33
|
+
t.pattern = 'test/**/*_test.rb'
|
34
|
+
t.verbose = false
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
task :default => :test
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rails_logstasher/railtie' if defined?(Rails)
|
2
|
+
require 'rails_logstasher/rack/logger'
|
3
|
+
require 'rails_logstasher/event'
|
4
|
+
require 'logstash-event'
|
5
|
+
require 'rails_logstasher/logger'
|
6
|
+
require 'rails_logstasher/tagged_logging'
|
7
|
+
|
8
|
+
module RailsLogstasher
|
9
|
+
|
10
|
+
class IncompatibleLogger < StandardError; end
|
11
|
+
|
12
|
+
def self.log_entries
|
13
|
+
@@events ||= {}
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'rails_logstasher/core_ext/object/blank'
|
2
|
+
|
3
|
+
module RailsLogstasher
|
4
|
+
module ActionController
|
5
|
+
class LogSubscriber < ::ActiveSupport::LogSubscriber
|
6
|
+
INTERNAL_PARAMS = %w(controller action format _method only_path)
|
7
|
+
|
8
|
+
def start_processing(event)
|
9
|
+
payload = event.payload
|
10
|
+
|
11
|
+
entry.fields['controller'] = payload[:controller]
|
12
|
+
entry.fields['action'] = payload[:action]
|
13
|
+
|
14
|
+
format = payload[:format]
|
15
|
+
entry.fields['format'] = format.to_s.downcase if format.is_a?(Symbol)
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def process_action(event)
|
20
|
+
|
21
|
+
payload = event.payload
|
22
|
+
#TODO Think about additions. Comment out for the moment to shut up warnings
|
23
|
+
#additions = ::ActionController::Base.log_process_action(payload)
|
24
|
+
|
25
|
+
params = payload[:params].except(*INTERNAL_PARAMS)
|
26
|
+
entry.fields['parameters'] = params unless params.empty?
|
27
|
+
|
28
|
+
entry.fields['controller_duration'] = event.duration
|
29
|
+
|
30
|
+
#TODO What on earth are additions and how should we handle them?
|
31
|
+
# message << " (#{additions.join(" | ")})" unless additions.blank?
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
def halted_callback(event)
|
36
|
+
entry.fields['halted_callback'] = event.payload[:filter]
|
37
|
+
end
|
38
|
+
|
39
|
+
def send_file(event)
|
40
|
+
entry.fields['send_file'] = event.payload[:path]
|
41
|
+
entry.fields['send_file_duration'] = event.duration
|
42
|
+
end
|
43
|
+
|
44
|
+
def redirect_to(event)
|
45
|
+
entry.fields['redirect_to'] = event.payload[:location]
|
46
|
+
end
|
47
|
+
|
48
|
+
def send_data(event)
|
49
|
+
entry.fields['send_data'] = event.payload[:filename]
|
50
|
+
entry.fields['send_data_duration'] = event.duration
|
51
|
+
end
|
52
|
+
|
53
|
+
%w(write_fragment read_fragment exist_fragment?
|
54
|
+
expire_fragment expire_page write_page).each do |method|
|
55
|
+
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
56
|
+
def #{method}(event)
|
57
|
+
entry.fields['cache'] ||= []
|
58
|
+
cache_event = {}
|
59
|
+
cache_event['key_or_path'] = event.payload[:key] || event.payload[:path]
|
60
|
+
cache_event['type'] = #{method.to_s.humanize.inspect}
|
61
|
+
cache_event['duration'] = event.duration
|
62
|
+
entry.fields['cache'] << cache_event
|
63
|
+
end
|
64
|
+
METHOD
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def entry
|
70
|
+
RailsLogstasher.log_entries[Thread.current]
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RailsLogstasher
|
2
|
+
module ActionView
|
3
|
+
|
4
|
+
class LogSubscriber < ::ActiveSupport::LogSubscriber
|
5
|
+
|
6
|
+
def render_template(event)
|
7
|
+
entry.fields['rendering'] ||= []
|
8
|
+
render_entry = {}
|
9
|
+
render_entry['identifier'] = from_rails_root(event.payload[:identifier])
|
10
|
+
render_entry['layout'] = from_rails_root(event.payload[:layout]) if event.payload[:layout]
|
11
|
+
render_entry['duration'] = event.duration
|
12
|
+
|
13
|
+
entry.fields['rendering'] << render_entry
|
14
|
+
|
15
|
+
end
|
16
|
+
alias :render_partial :render_template
|
17
|
+
alias :render_collection :render_template
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def from_rails_root(string)
|
22
|
+
string.sub("#{Rails.root}/", "").sub(/^app\/views\//, "")
|
23
|
+
end
|
24
|
+
|
25
|
+
def entry
|
26
|
+
RailsLogstasher.log_entries[Thread.current]
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
|
3
|
+
module RailsLogstasher
|
4
|
+
module ActiveRecord
|
5
|
+
class LogSubscriber < ::ActiveSupport::LogSubscriber
|
6
|
+
|
7
|
+
def self.runtime=(value)
|
8
|
+
Thread.current["active_record_sql_runtime"] = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.runtime
|
12
|
+
Thread.current["active_record_sql_runtime"] ||= 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.reset_runtime
|
16
|
+
rt, self.runtime = runtime, 0
|
17
|
+
rt
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def sql(event)
|
25
|
+
self.class.runtime += event.duration
|
26
|
+
return unless logger.debug?
|
27
|
+
|
28
|
+
payload = event.payload
|
29
|
+
|
30
|
+
return if 'SCHEMA' == payload[:name]
|
31
|
+
|
32
|
+
sql_entry = {}
|
33
|
+
sql_entry['name'] = payload[:name]
|
34
|
+
sql_entry['duration'] = event.duration
|
35
|
+
sql_entry['sql']= payload[:sql].squeeze(' ')
|
36
|
+
|
37
|
+
binds = nil
|
38
|
+
|
39
|
+
unless (payload[:binds] || []).empty?
|
40
|
+
binds = " " + payload[:binds].map { |col,v|
|
41
|
+
[col.name, v]
|
42
|
+
}.inspect
|
43
|
+
end
|
44
|
+
|
45
|
+
sql_entry['binds'] = binds unless binds.nil?
|
46
|
+
|
47
|
+
write_entry sql_entry
|
48
|
+
end
|
49
|
+
|
50
|
+
def identity(event)
|
51
|
+
return unless logger.debug?
|
52
|
+
|
53
|
+
payload = event.payload
|
54
|
+
|
55
|
+
sql_entry = {}
|
56
|
+
sql_entry['name'] = payload[:name]
|
57
|
+
sql_entry['line'] = payload[:line]
|
58
|
+
sql_entry['duration'] = payload[:duration]
|
59
|
+
|
60
|
+
write_entry sql_entry
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def write_entry(sql_entry)
|
66
|
+
entry = log_entry
|
67
|
+
entry.fields['sql'] ||= []
|
68
|
+
entry.fields['sql'] << sql_entry
|
69
|
+
entry.write(false)
|
70
|
+
end
|
71
|
+
|
72
|
+
def logger
|
73
|
+
::ActiveRecord::Base.logger
|
74
|
+
end
|
75
|
+
|
76
|
+
def log_entry
|
77
|
+
RailsLogstasher.log_entries[Thread.current] ||
|
78
|
+
RailsLogstasher::Event.new(Rails.logger, false).tap do |entry|
|
79
|
+
entry.fields['uuid'] = SecureRandom.uuid
|
80
|
+
#TODO Should really move this into the base logger
|
81
|
+
entry.source = Socket.gethostname
|
82
|
+
entry.type = "rails_json_log"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module RailsLogstasher
|
2
|
+
module ActiveResource
|
3
|
+
class LogSubscriber < ::ActiveSupport::LogSubscriber
|
4
|
+
|
5
|
+
def request(event)
|
6
|
+
|
7
|
+
#TODO Think of a better name for this!
|
8
|
+
entry.fields['active_resource'] ||= []
|
9
|
+
|
10
|
+
request_entry = {}
|
11
|
+
|
12
|
+
request_entry['method'] = event.payload[:method].to_s.upcase
|
13
|
+
request_entry['uri'] = event.payload[:request_uri]
|
14
|
+
|
15
|
+
result = event.payload[:result]
|
16
|
+
|
17
|
+
request_entry['code'] = result.code
|
18
|
+
request_entry['message'] = result.message
|
19
|
+
request_entry['length'] = result.body.to_s.length
|
20
|
+
request_entry['duration'] = event.duration
|
21
|
+
|
22
|
+
entry.fields['active_resource'] << request_entry
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def entry
|
28
|
+
RailsLogstasher.log_entries[Thread.current]
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# This file is copied verbatim from ActiveSupport for compatibility
|
4
|
+
# should rails_logstasher be used outside of a Rails project. Therefor we
|
5
|
+
# won't process this file if ActiveSupport is already defined
|
6
|
+
unless defined?(ActiveSupport)
|
7
|
+
class Object
|
8
|
+
# An object is blank if it's false, empty, or a whitespace string.
|
9
|
+
# For example, '', ' ', +nil+, [], and {} are all blank.
|
10
|
+
#
|
11
|
+
# This simplifies:
|
12
|
+
#
|
13
|
+
# if address.nil? || address.empty?
|
14
|
+
#
|
15
|
+
# ...to:
|
16
|
+
#
|
17
|
+
# if address.blank?
|
18
|
+
def blank?
|
19
|
+
respond_to?(:empty?) ? empty? : !self
|
20
|
+
end
|
21
|
+
|
22
|
+
# An object is present if it's not <tt>blank?</tt>.
|
23
|
+
def present?
|
24
|
+
!blank?
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns object if it's <tt>present?</tt> otherwise returns +nil+.
|
28
|
+
# <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>.
|
29
|
+
#
|
30
|
+
# This is handy for any representation of objects where blank is the same
|
31
|
+
# as not present at all. For example, this simplifies a common check for
|
32
|
+
# HTTP POST/query parameters:
|
33
|
+
#
|
34
|
+
# state = params[:state] if params[:state].present?
|
35
|
+
# country = params[:country] if params[:country].present?
|
36
|
+
# region = state || country || 'US'
|
37
|
+
#
|
38
|
+
# ...becomes:
|
39
|
+
#
|
40
|
+
# region = params[:state].presence || params[:country].presence || 'US'
|
41
|
+
def presence
|
42
|
+
self if present?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class NilClass
|
47
|
+
# +nil+ is blank:
|
48
|
+
#
|
49
|
+
# nil.blank? # => true
|
50
|
+
def blank?
|
51
|
+
true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class FalseClass
|
56
|
+
# +false+ is blank:
|
57
|
+
#
|
58
|
+
# false.blank? # => true
|
59
|
+
def blank?
|
60
|
+
true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class TrueClass
|
65
|
+
# +true+ is not blank:
|
66
|
+
#
|
67
|
+
# true.blank? # => false
|
68
|
+
def blank?
|
69
|
+
false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class Array
|
74
|
+
# An array is blank if it's empty:
|
75
|
+
#
|
76
|
+
# [].blank? # => true
|
77
|
+
# [1,2,3].blank? # => false
|
78
|
+
alias_method :blank?, :empty?
|
79
|
+
end
|
80
|
+
|
81
|
+
class Hash
|
82
|
+
# A hash is blank if it's empty:
|
83
|
+
#
|
84
|
+
# {}.blank? # => true
|
85
|
+
# { key: 'value' }.blank? # => false
|
86
|
+
alias_method :blank?, :empty?
|
87
|
+
end
|
88
|
+
|
89
|
+
class String
|
90
|
+
# A string is blank if it's empty or contains whitespaces only:
|
91
|
+
#
|
92
|
+
# ''.blank? # => true
|
93
|
+
# ' '.blank? # => true
|
94
|
+
# ' '.blank? # => true
|
95
|
+
# ' something here '.blank? # => false
|
96
|
+
def blank?
|
97
|
+
self !~ /[^[:space:]]/
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class Numeric #:nodoc:
|
102
|
+
# No number is blank:
|
103
|
+
#
|
104
|
+
# 1.blank? # => false
|
105
|
+
# 0.blank? # => false
|
106
|
+
def blank?
|
107
|
+
false
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|