oh_my_log 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +65 -0
- data/.document +4 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +73 -0
- data/.ruby-version +1 -0
- data/.travis.yml +31 -0
- data/Appraisals +25 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +21 -0
- data/README.md +180 -0
- data/Rakefile +20 -0
- data/blue_print/oh_my_log_initializer.rb +8 -0
- data/gemfiles/rails_4.2_stable.gemfile +8 -0
- data/gemfiles/rails_4.2_stable.gemfile.lock +181 -0
- data/gemfiles/rails_5.0_stable.gemfile +8 -0
- data/gemfiles/rails_5.0_stable.gemfile.lock +188 -0
- data/gemfiles/rails_5.1_stable.gemfile +8 -0
- data/gemfiles/rails_5.1_stable.gemfile.lock +188 -0
- data/gemfiles/rails_5.2_stable.gemfile +8 -0
- data/gemfiles/rails_5.2_stable.gemfile.lock +196 -0
- data/lib/oh_my_log/active_record_observer.rb +11 -0
- data/lib/oh_my_log/configuration.rb +37 -0
- data/lib/oh_my_log/effect.rb +18 -0
- data/lib/oh_my_log/log.rb +140 -0
- data/lib/oh_my_log/mongoid_observer.rb +11 -0
- data/lib/oh_my_log/observer_factory.rb +90 -0
- data/lib/oh_my_log/request.rb +22 -0
- data/lib/oh_my_log/result.rb +48 -0
- data/lib/oh_my_log/selector.rb +44 -0
- data/lib/oh_my_log/version.rb +5 -0
- data/lib/oh_my_log.rb +47 -0
- data/lib/railtie.rb +48 -0
- data/lib/tasks/oh_my_log.rake +32 -0
- data/oh_my_log.gemspec +36 -0
- data/spec/controllers/foos_controller_spec.rb +116 -0
- data/spec/dummy/Rakefile +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/foos_controller.rb +23 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/models/doo.rb +2 -0
- data/spec/dummy/app/models/foo.rb +2 -0
- data/spec/dummy/app/views/foos/create.html.erb +0 -0
- data/spec/dummy/app/views/foos/index.html.erb +0 -0
- data/spec/dummy/app/views/foos/show.html.erb +0 -0
- data/spec/dummy/app/views/foos/two_in_one.html.erb +0 -0
- data/spec/dummy/app/views/foos/update.html.erb +0 -0
- data/spec/dummy/config/application.rb +20 -0
- data/spec/dummy/config/boot.rb +6 -0
- data/spec/dummy/config/database.yml +7 -0
- data/spec/dummy/config/environment.rb +2 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/migration_class.rb +8 -0
- data/spec/dummy/config/routes.rb +5 -0
- data/spec/dummy/config/secrets.yml +2 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20120508165529_create_tables.rb +21 -0
- data/spec/rails_helper.rb +1 -0
- data/spec/spec_helper.rb +32 -0
- metadata +262 -0
@@ -0,0 +1,140 @@
|
|
1
|
+
require "active_support/all"
|
2
|
+
require_relative '../oh_my_log'
|
3
|
+
|
4
|
+
module OhMyLog
|
5
|
+
module Log
|
6
|
+
#all the models effected by this
|
7
|
+
mattr_accessor :targets
|
8
|
+
#config for this log
|
9
|
+
mattr_accessor :configuration
|
10
|
+
#contains all the request done in a session
|
11
|
+
mattr_accessor :history
|
12
|
+
#last action done by the user
|
13
|
+
mattr_accessor :last_recorded
|
14
|
+
|
15
|
+
def self.configuration_rule
|
16
|
+
configuration.models.keys[0]
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.configuration_models
|
20
|
+
Log.configuration.models.values
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.configure
|
24
|
+
self.configuration ||= Configuration.new
|
25
|
+
self.targets = []
|
26
|
+
self.history = []
|
27
|
+
yield(configuration)
|
28
|
+
self.configuration.add_selector(Selector.universal_for) if self.configuration.selectors.empty?
|
29
|
+
self.configuration.process_path
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.clear
|
33
|
+
self.history = []
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.reset
|
37
|
+
self.clear
|
38
|
+
self.flush
|
39
|
+
self.configuration = nil
|
40
|
+
self.last_recorded = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.add_target(target)
|
44
|
+
#do not add duplicates
|
45
|
+
self.targets << target unless self.targets.include? target
|
46
|
+
end
|
47
|
+
|
48
|
+
#Is the action/controller passed in params allowed by the selectors
|
49
|
+
# TODO: add method as well in the selector
|
50
|
+
#
|
51
|
+
|
52
|
+
def self.permitted_range?(selector, status)
|
53
|
+
in_range = true
|
54
|
+
case selector.status_codes.keys[0]
|
55
|
+
when "ONLY"
|
56
|
+
in_range = false
|
57
|
+
selector.status_codes.values[0].each do |range|
|
58
|
+
range = (range.to_i..range.to_i) if range.class != Range
|
59
|
+
in_range = (range === status.to_i) unless in_range
|
60
|
+
end
|
61
|
+
when "EXCEPT"
|
62
|
+
selector.status_codes.values[0].each do |range|
|
63
|
+
in_range = false if (range === status.to_i)
|
64
|
+
end
|
65
|
+
when "ALL"
|
66
|
+
in_range = true
|
67
|
+
else
|
68
|
+
raise "UNDEFINED RULE: please us any of [ONLY/EXCEPT/ALL]"
|
69
|
+
end
|
70
|
+
return in_range
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.permitted_controller?(selector, ctrl_name)
|
74
|
+
case selector.controllers.keys[0]
|
75
|
+
when "ALL"
|
76
|
+
permitted_controller = true
|
77
|
+
when "ONLY"
|
78
|
+
permitted_controller = selector.controllers.values[0].include?(ctrl_name.classify)
|
79
|
+
when "EXCEPT"
|
80
|
+
permitted_controller = !selector.controllers.values[0].include?(ctrl_name.classify)
|
81
|
+
else
|
82
|
+
raise "UNDEFINED RULE: please us any of [ONLY/EXCEPT/ALL]"
|
83
|
+
end
|
84
|
+
return permitted_controller
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.permitted_ip?(selector, ip)
|
88
|
+
case selector.ips.keys[0]
|
89
|
+
when "EXCEPT"
|
90
|
+
permitted_ip = selector.ips.values[0].include?(ip)
|
91
|
+
when "ONLY"
|
92
|
+
permitted_ip = !selector.ips.values[0].empty? && !selector.ips.values[0].include?(ip)
|
93
|
+
when "ALL"
|
94
|
+
permitted_ip = true
|
95
|
+
else
|
96
|
+
raise "UNDEFINED RULE: please us any of [ONLY/EXCEPT/ALL]"
|
97
|
+
end
|
98
|
+
return permitted_ip
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.permitted_action?(selector, ctrl_action)
|
102
|
+
permitted_action = true
|
103
|
+
case selector.actions.keys[0]
|
104
|
+
when "EXCEPT"
|
105
|
+
selector.actions.values[0].each {|action| permitted_action = false if action.downcase.to_sym == ctrl_action}
|
106
|
+
when "ONLY"
|
107
|
+
selector.actions.values[0].each {|action| permitted_action = true if action.downcase.to_sym == ctrl_action}
|
108
|
+
when "ALL"
|
109
|
+
permitted_action = true
|
110
|
+
else
|
111
|
+
raise "UNDEFINED RULE: please us any of [ONLY/EXCEPT/ALL]"
|
112
|
+
end
|
113
|
+
return permitted_action
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.loggable?(params, status, method)
|
117
|
+
ctrl_name = params["controller"]
|
118
|
+
ctrl_action = params["action"].to_sym
|
119
|
+
final_response = false
|
120
|
+
self.configuration.selectors.each do |selector|
|
121
|
+
final_response = permitted_range?(selector, status)
|
122
|
+
return false unless final_response
|
123
|
+
|
124
|
+
final_response = final_response && permitted_controller?(selector, ctrl_name)
|
125
|
+
return false unless final_response
|
126
|
+
|
127
|
+
final_response = final_response && permitted_ip?(selector, Thread.current[:remote_ip])
|
128
|
+
return false unless final_response
|
129
|
+
|
130
|
+
return false unless permitted_action?(selector, ctrl_action)
|
131
|
+
end
|
132
|
+
final_response
|
133
|
+
end
|
134
|
+
|
135
|
+
#once we processed an action we can get rid of all the cached data(targets) stored in the Log
|
136
|
+
def self.flush
|
137
|
+
self.targets = []
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module OhMyLog
|
2
|
+
class MongoidObserver < ::Mongoid::Observer
|
3
|
+
|
4
|
+
#this is the callback that happens every time after we made changes to the model
|
5
|
+
def after_save(model)
|
6
|
+
#we only add this model in the target list if this model got SUCCESSFULLY changed
|
7
|
+
must_be_logged = model.methods.include?(:saved_changes) ? model.saved_changes.empty? : model.changes.empty?
|
8
|
+
Log::add_target(model) unless must_be_logged
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module OhMyLog
|
2
|
+
module ObserverFactory
|
3
|
+
|
4
|
+
#this will initialize the observes logic
|
5
|
+
def self.activate_observers
|
6
|
+
#should raise an error if there are no observers -> "Build the observer list using the task"
|
7
|
+
Rails.application.eager_load!
|
8
|
+
|
9
|
+
build_activerecord_obs if defined?(ActiveRecord)
|
10
|
+
build_mongoid_obs if defined?(Mongoid)
|
11
|
+
end
|
12
|
+
|
13
|
+
#this will be runned by the task to build the collection of observed models FILE
|
14
|
+
require 'fileutils'
|
15
|
+
|
16
|
+
def self.generate_collection
|
17
|
+
Rails.application.eager_load!
|
18
|
+
|
19
|
+
#rebuild folder if it's already there
|
20
|
+
FileUtils.rm_rf(Rails.root + "app/models/observers/oh_my_log") if File.directory?(Rails.root + "app/models/observers/oh_my_log")
|
21
|
+
FileUtils.mkdir_p(Rails.root + "app/models/observers/oh_my_log")
|
22
|
+
generate_collection_for(ActiveRecord) if defined?(ActiveRecord)
|
23
|
+
generate_collection_for(Mongoid) if defined?(Mongoid)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.remove_collection
|
27
|
+
FileUtils.rm_rf(Rails.root + "app/models/observers/oh_my_log") if File.directory?(Rails.root + "app/models/observers/oh_my_log")
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def self.build_activerecord_obs
|
33
|
+
supported_models = supported_models_for(ActiveRecord)
|
34
|
+
supported_models.each {|class_name| ActiveRecord::Base.add_observer class_name.instance}
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.build_mongoid_obs
|
38
|
+
supported_models = supported_models_for(Mongoid)
|
39
|
+
supported_models.each {|class_name| ::Mongoid::Document.add_observer class_name.instance}
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.generate_collection_for(klass)
|
43
|
+
models = available_models_for(klass)
|
44
|
+
models.each do |model|
|
45
|
+
model_file = File.join("#{Rails.root}/app", "models", "observers", "oh_my_log", model.underscore + "_observer.rb")
|
46
|
+
p "Generated #{model_file}"
|
47
|
+
File.open(model_file, "w+") do |f|
|
48
|
+
f << "class #{model + "Observer"} < OhMyLog::#{klass}Observer\nend"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.supported_models_for(klass)
|
54
|
+
supported_models = []
|
55
|
+
models = available_models_for(klass)
|
56
|
+
models.each do |model|
|
57
|
+
if File.file?(Rails.root + "app/models/observers/oh_my_log/#{model.underscore}_observer.rb")
|
58
|
+
supported_models << ('::' + model + "Observer").constantize
|
59
|
+
else
|
60
|
+
p "You didn't create an observer for #{model.constantize}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
return supported_models
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def self.available_models_for(klass)
|
69
|
+
config_rule = Log.configuration_rule
|
70
|
+
config_models = Log.configuration_models
|
71
|
+
models = []
|
72
|
+
if klass == ActiveRecord
|
73
|
+
models = ActiveRecord::Base.subclasses.collect {|type| type.name}
|
74
|
+
models = models + ApplicationRecord.subclasses.collect {|type| type.name} if defined?(ApplicationRecord)
|
75
|
+
elsif klass == Mongoid
|
76
|
+
models = Mongoid.models.collect {|type| type.name}
|
77
|
+
end
|
78
|
+
#reject modules
|
79
|
+
models = models.reject {|model| model.include?("::") || model.include?("HABTM") || model.include?("Mongoid")}
|
80
|
+
case config_rule
|
81
|
+
when "ONLY"
|
82
|
+
return models.select {|model| config_models.include?(model)}
|
83
|
+
when "ALL"
|
84
|
+
return models
|
85
|
+
when "EXCEPT"
|
86
|
+
return models.reject {|model| config_models.include?(model)}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module OhMyLog
|
2
|
+
module Log
|
3
|
+
#the request is what the user is trying to do
|
4
|
+
class Request
|
5
|
+
attr_reader :sender, :date, :params, :method, :status
|
6
|
+
|
7
|
+
def initialize(args)
|
8
|
+
@sender = args[:sender]
|
9
|
+
@date = args[:date]
|
10
|
+
@params = args[:params]
|
11
|
+
@method = args[:method]
|
12
|
+
@status = args[:status]
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
user_info = @sender.try(:email)
|
17
|
+
sender = !user_info.blank? ? user_info : Thread.current["remote_ip"]
|
18
|
+
"#{@date}, #{sender}, #{@method}, #{@params}, #{@status}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Result contains the request and all the effects that a specific request caused all over the models
|
2
|
+
module OhMyLog
|
3
|
+
module Log
|
4
|
+
class Result
|
5
|
+
attr_reader :effects
|
6
|
+
attr_reader :request
|
7
|
+
|
8
|
+
def initialize(request)
|
9
|
+
@request = request
|
10
|
+
@effects = calculate_effects
|
11
|
+
end
|
12
|
+
|
13
|
+
# call this to record the current action done by the user
|
14
|
+
def record!
|
15
|
+
if OhMyLog::Log.configuration.print_log
|
16
|
+
p "REQUEST"
|
17
|
+
p @request.to_s
|
18
|
+
p "RESPONSE" unless @effects.empty?
|
19
|
+
@effects.each {|effect| p effect.to_s}
|
20
|
+
end
|
21
|
+
|
22
|
+
print_into_log
|
23
|
+
|
24
|
+
#we can record everything that happend (OPTIONALL)
|
25
|
+
if OhMyLog::Log.configuration.record_history
|
26
|
+
OhMyLog::Log.history << self
|
27
|
+
end
|
28
|
+
#We always save the last operation recorded
|
29
|
+
OhMyLog::Log.last_recorded = self
|
30
|
+
#save this string on file or upload it somewhere
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def print_into_log
|
36
|
+
OhMyLog::Log.configuration.log_instance.info('REQUEST')
|
37
|
+
OhMyLog::Log.configuration.log_instance.info(@request.to_s)
|
38
|
+
OhMyLog::Log.configuration.log_instance.info('RESPONSE') unless @effects.empty?
|
39
|
+
@effects.each {|effect| OhMyLog::Log.configuration.log_instance.info(effect.to_s)}
|
40
|
+
end
|
41
|
+
|
42
|
+
def calculate_effects
|
43
|
+
return OhMyLog::Log::targets.map {|target| Effect.new(target)}
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module OhMyLog
|
2
|
+
module Log
|
3
|
+
#Selector is a set of rule that Log.loggable? will have to respect
|
4
|
+
class Selector
|
5
|
+
attr_reader :controllers, :actions, :status_codes, :ips
|
6
|
+
METHODS = ["GET", "HEAD", "POST", "PATCH", "PUT", "DELETE"].freeze
|
7
|
+
ACTIONS = ["ONLY", "EXCEPT", "ALL"].freeze
|
8
|
+
# add methods in the same style as anythingelse
|
9
|
+
# and it will affect the parameter method in the loggable function in LOG.rb
|
10
|
+
##EXCEPT O ONLY
|
11
|
+
def initialize(controllers: default_hash_setting, actions: default_hash_setting, ips: default_hash_setting, status_codes: default_hash_setting)
|
12
|
+
@controllers = controllers
|
13
|
+
@actions = actions
|
14
|
+
@ips = ips
|
15
|
+
@status_codes = status_codes
|
16
|
+
build_attr_setters
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def default_hash_setting
|
22
|
+
return {"ALL" => []}
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.default_hash_setting
|
26
|
+
return {"ALL" => []}
|
27
|
+
end
|
28
|
+
|
29
|
+
def build_attr_setters
|
30
|
+
self.instance_variables.each do |attribute|
|
31
|
+
attribute = attribute.to_s.gsub("@", "")
|
32
|
+
self.define_singleton_method(:"set_#{attribute}") do |value|
|
33
|
+
raise "Unpermitted rule: use #{ACTIONS}" if attribute == "rule" && !ACTIONS.include?(value)
|
34
|
+
instance_variable_set("@#{attribute}", value)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.universal_for(actions: default_hash_setting, controllers: default_hash_setting)
|
40
|
+
return Selector.new(controllers: controllers, actions: actions)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/oh_my_log.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rails/observers/activerecord/base'
|
2
|
+
#force LOAD the gem "rails-observers"
|
3
|
+
module ActiveRecord
|
4
|
+
autoload :Observer, 'rails/observers/activerecord/observer'
|
5
|
+
end
|
6
|
+
|
7
|
+
#load the gem's lib folder
|
8
|
+
Dir[File.dirname(__FILE__) + '/oh_my_log/*.rb'].each do |file|
|
9
|
+
name = File.basename(file, File.extname(file))
|
10
|
+
#we are gonna skip this file FOR NOW since it depends of gem loaded after the rails initializer
|
11
|
+
next if name == "mongoid_observer"
|
12
|
+
require_relative "oh_my_log/" + name
|
13
|
+
end
|
14
|
+
|
15
|
+
module OhMyLog
|
16
|
+
#call this after you configured the Log Module
|
17
|
+
def self.start
|
18
|
+
Railtie.start_oh_my_log
|
19
|
+
|
20
|
+
#the main loop to get callbacks from controllers
|
21
|
+
ActiveSupport::Notifications.subscribe "process_action.action_controller" do |*args|
|
22
|
+
data = args[-1]
|
23
|
+
if Log::loggable?(data[:params], data[:status], data[:method])
|
24
|
+
request = Log::Request.new(sender: Thread.current[:user], date: Time.now.utc, params: data[:params], method: data[:method], status: data[:status])
|
25
|
+
result = Log::Result.new(request)
|
26
|
+
result.record!
|
27
|
+
end
|
28
|
+
Log::flush
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.generate_initializer
|
33
|
+
FileUtils.cp_r(File.expand_path(__dir__ + '/../blue_print/oh_my_log_initializer.rb'), Rails.root + "config/initializers")
|
34
|
+
p "Successfully created initializer!"
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.destroy_initializer
|
38
|
+
path = Rails.root + "config/initializers/oh_my_log_initializer.rb"
|
39
|
+
File.delete(path) if File.exist?(path)
|
40
|
+
p "Successfully destroyed the initializer!"
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
#load the script to inject code to rails source and create rake task
|
46
|
+
require_relative "railtie"
|
47
|
+
|
data/lib/railtie.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#let's inject some code into rails before and after the initialization
|
2
|
+
class Railtie < ::Rails::Railtie
|
3
|
+
#auto load our observers folder before rails freeze this variable
|
4
|
+
initializer 'activeservice.autoload', :before => :set_autoload_paths do |app|
|
5
|
+
if File.directory?(Rails.root + "app/models/observers/oh_my_log")
|
6
|
+
app.config.autoload_paths << "app/models/observers/oh_my_log"
|
7
|
+
else
|
8
|
+
p "Could not find the observers folder, did you use the task to generate them?"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
#now let's start our gem(only if there is an initializer) after the rails initialize process
|
13
|
+
config.after_initialize do
|
14
|
+
load Rails.root + "app/controllers/application_controller.rb"
|
15
|
+
class ::ApplicationController
|
16
|
+
before_action :get__session__info
|
17
|
+
|
18
|
+
def get__session__info
|
19
|
+
user = nil
|
20
|
+
if defined?(current_user)
|
21
|
+
user = current_user
|
22
|
+
elsif defined?(current_admin_user)
|
23
|
+
user = current_admin_user
|
24
|
+
end
|
25
|
+
Thread.current[:user] = user
|
26
|
+
Thread.current[:remote_ip] = request.remote_ip
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.start_oh_my_log
|
32
|
+
if defined?(Mongoid)
|
33
|
+
require 'mongoid-observers'
|
34
|
+
require_relative "oh_my_log/mongoid_observer"
|
35
|
+
end
|
36
|
+
begin
|
37
|
+
require Rails.root + "config/initializers/oh_my_log_initializer.rb"
|
38
|
+
::OhMyLog::ObserverFactory.activate_observers
|
39
|
+
rescue
|
40
|
+
return "could not start the gem, did you run oh_my_log:install ?"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#time to add some tasks
|
45
|
+
rake_tasks do
|
46
|
+
load 'tasks/oh_my_log.rake'
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
namespace :oh_my_log do
|
4
|
+
desc 'Generate the observers for each ActiveRecord model'
|
5
|
+
# in futuro fare che puoi passare parametri e in base a quello limita gli observer da generare
|
6
|
+
task generate_observers: :environment do
|
7
|
+
raise "Cannot create observers without an initializer, did you created it with 'oh_my_log:generate_initializer'" unless File.file?(Rails.root + 'config/initializers/oh_my_log_initializer.rb')
|
8
|
+
OhMyLog::ObserverFactory.generate_collection
|
9
|
+
end
|
10
|
+
desc 'Generate a template initializer for OhMyLog'
|
11
|
+
# in futuro puoi passare direttamente qui alcune impostazioni dell' initialize
|
12
|
+
task generate_initializer: :environment do
|
13
|
+
raise 'The initializer has been already generated!' if File.file?(Rails.root + 'config/initializers/oh_my_log_initializer')
|
14
|
+
OhMyLog.generate_initializer
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Install the gem by building initializer and observers'
|
18
|
+
task install: :environment do
|
19
|
+
OhMyLog.generate_initializer
|
20
|
+
p "generated initializer"
|
21
|
+
sleep(1)
|
22
|
+
require Rails.root + "config/initializers/oh_my_log_initializer.rb"
|
23
|
+
OhMyLog::ObserverFactory.generate_collection
|
24
|
+
p "generated collections"
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Clean observers and initializer'
|
28
|
+
task clean: :environment do
|
29
|
+
OhMyLog.destroy_initializer
|
30
|
+
OhMyLog::ObserverFactory.remove_collection
|
31
|
+
end
|
32
|
+
end
|
data/oh_my_log.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'rubygems'
|
4
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
5
|
+
require 'oh_my_log/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = %q{oh_my_log}
|
9
|
+
s.authors = ["Fabrizio Spadaro"]
|
10
|
+
s.email = ["work.fabriziospadaro@gmail.com"]
|
11
|
+
s.license = "MIT"
|
12
|
+
s.version = OhMyLog::VERSION
|
13
|
+
s.platform = Gem::Platform::RUBY
|
14
|
+
s.date = %q{2018-11-26}
|
15
|
+
s.homepage = 'https://github.com/fabriziospadaro/oh_my_log'
|
16
|
+
s.summary = %q{A powerful auditing logging system}
|
17
|
+
s.files = `git ls-files`.split($\)
|
18
|
+
s.required_ruby_version = '>= 2.3.0' #, '<= 2.5.0'
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
if RUBY_VERSION >= '2.4'
|
22
|
+
s.add_runtime_dependency 'rails', '>= 4.2.0', '< 7.0'
|
23
|
+
else
|
24
|
+
s.add_runtime_dependency 'railties', '>= 4.2.0', '< 6.0'
|
25
|
+
end
|
26
|
+
s.add_runtime_dependency 'json'
|
27
|
+
s.add_runtime_dependency("rails-observers", "~> 0.1.5")
|
28
|
+
s.add_development_dependency 'coveralls'
|
29
|
+
s.add_development_dependency 'rubocop', '~> 0.59.2'
|
30
|
+
s.add_development_dependency 'bundler'
|
31
|
+
s.add_development_dependency 'appraisal'
|
32
|
+
s.add_development_dependency 'sqlite3', '1.3.10'
|
33
|
+
s.add_development_dependency 'rspec-core'
|
34
|
+
s.add_development_dependency 'wwtd'
|
35
|
+
s.add_development_dependency 'rspec-rails'
|
36
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
RSpec.describe FoosController, type: :controller do
|
4
|
+
let(:oml) {OhMyLog::Log}
|
5
|
+
|
6
|
+
context "#When using a custom configuration for the Logger" do
|
7
|
+
before(:all) do
|
8
|
+
Rake::Task['oh_my_log:install'].invoke
|
9
|
+
Foo.destroy_all
|
10
|
+
Doo.destroy_all
|
11
|
+
OhMyLog.start
|
12
|
+
end
|
13
|
+
#reset the configuration to the default state
|
14
|
+
before(:each) do
|
15
|
+
oml.reset
|
16
|
+
oml.configure do |config|
|
17
|
+
config.print_log = true
|
18
|
+
selector = oml::Selector.universal_for(actions: {"EXCEPT" => ["index"]})
|
19
|
+
config.add_selector(selector)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
after(:all) do
|
24
|
+
Rake::Task['oh_my_log:clean'].invoke
|
25
|
+
end
|
26
|
+
|
27
|
+
it "Should not log anything when the response is 200 and we put 200 in the status_codes blacklist" do
|
28
|
+
oml.configuration.selectors[-1].set_status_codes("EXCEPT" => [(200..204)])
|
29
|
+
put :create, params: {name: 'foo name'}
|
30
|
+
expect(oml.last_recorded).to eq(nil)
|
31
|
+
end
|
32
|
+
it "Should log when the response is 200 and we put 200 in the white_list" do
|
33
|
+
oml.configuration.selectors[-1].set_status_codes("ONLY" => [(200..204)])
|
34
|
+
put :create, params: {name: 'foo name'}
|
35
|
+
expect(oml.last_recorded).not_to eq(nil)
|
36
|
+
end
|
37
|
+
it "Should not log when we removing the FooController from the permitted controller list" do
|
38
|
+
oml.configuration.selectors[-1].set_controllers({"ONLY" => ["Doo"]})
|
39
|
+
put :create, params: {name: 'foo name'}
|
40
|
+
expect(oml.last_recorded).to eq(nil)
|
41
|
+
end
|
42
|
+
it "Should log when including FooController in the permitted controller list" do
|
43
|
+
oml.configuration.selectors[-1].set_controllers({"ONLY" => ["Foo"]})
|
44
|
+
put :create, params: {name: 'foo name'}
|
45
|
+
expect(oml.last_recorded).not_to eq(nil)
|
46
|
+
end
|
47
|
+
it "Should not log when using the create method and using a configuration to only log the index action" do
|
48
|
+
oml.configuration.selectors[-1].set_actions("EXCEPT" => ["create"])
|
49
|
+
put :create, params: {name: 'foo name'}
|
50
|
+
expect(oml.last_recorded).to eq(nil)
|
51
|
+
end
|
52
|
+
it "Should log when rooting to index and using a configuration to only log the index action" do
|
53
|
+
oml.configuration.selectors[-1].set_actions("ONLY" => ["index"])
|
54
|
+
get :index
|
55
|
+
expect(oml.last_recorded).not_to eq(nil)
|
56
|
+
end
|
57
|
+
##non va perchè non si riesce a fare il monkeypatch di application controller dato ceh abbiamo il rails dei poveri
|
58
|
+
it "Should not log when black listing the local ip" do
|
59
|
+
oml.configuration.selectors[-1].set_ips("EXCEPT" => ["192.168.0.1"])
|
60
|
+
put :create, params: {name: 'foo name'}
|
61
|
+
expect(oml.last_recorded).to eq(nil)
|
62
|
+
end
|
63
|
+
it "Should be able to correctly use multiple selector" do
|
64
|
+
selector = OhMyLog::Log::Selector.new
|
65
|
+
selector.set_controllers({"EXCEPT" => ["Foo"]})
|
66
|
+
oml.configuration.add_selector(selector)
|
67
|
+
put :create, params: {name: 'foo name'}
|
68
|
+
expect(oml.last_recorded).to eq(nil)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "When testing the event logger for a generic Model" do
|
73
|
+
before(:all) do
|
74
|
+
Foo.destroy_all
|
75
|
+
Doo.destroy_all
|
76
|
+
@dummy = Foo.create(name: "Dummy model", value: 2)
|
77
|
+
end
|
78
|
+
before(:each) do
|
79
|
+
oml.reset
|
80
|
+
oml.configure do |config|
|
81
|
+
config.print_log = true
|
82
|
+
selector = oml::Selector.universal_for(actions: {"EXCEPT" => ["index"]})
|
83
|
+
config.add_selector(selector)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
it "Should create a log in the path specified in teh configuration" do
|
87
|
+
expect(File.file?(Rails.root + "log/oh_my_log.log")).to eq(true)
|
88
|
+
end
|
89
|
+
it "Should write a log when creating a Model" do
|
90
|
+
put :create, params: {name: 'foo name'}
|
91
|
+
expect(oml.last_recorded).not_to eq(nil)
|
92
|
+
end
|
93
|
+
it "Should write a log when changing an Model" do
|
94
|
+
if Rails::VERSION::MAJOR >= 5
|
95
|
+
put :update, params: {name: "dummy name", value: 99, id: @dummy.id}
|
96
|
+
else
|
97
|
+
put :update, {name: "dummy name", value: 99, id: @dummy.id}
|
98
|
+
end
|
99
|
+
expect(oml.last_recorded).not_to eq(nil)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "The log created should have a receiver if the action made any changes to the model" do
|
103
|
+
if Rails::VERSION::MAJOR >= 5
|
104
|
+
put :update, params: {name: "not dummy name", value: 99, id: @dummy.id}
|
105
|
+
else
|
106
|
+
put :update, {name: "not dummy name", value: 99, id: @dummy.id}
|
107
|
+
end
|
108
|
+
expect(oml.last_recorded.effects[0].receiver).not_to eq(nil)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "The action indicated by the log should math the action did by the controller " do
|
112
|
+
put :create, params: {name: "nameless dummy"}
|
113
|
+
expect(oml.last_recorded.request.params["action"]).to eq("create")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/spec/dummy/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
class FoosController < ActionController::Base
|
2
|
+
protect_from_forgery
|
3
|
+
def index
|
4
|
+
end
|
5
|
+
|
6
|
+
def create
|
7
|
+
Foo.create(name: params["name"],value: 0)
|
8
|
+
end
|
9
|
+
|
10
|
+
def update
|
11
|
+
Foo.find(params["id"]).update(name: params["name"],value: params["value"])
|
12
|
+
redirect_to edit_foo_url
|
13
|
+
end
|
14
|
+
|
15
|
+
def edit
|
16
|
+
end
|
17
|
+
|
18
|
+
def two_in_one
|
19
|
+
Doo.create(name: "doo dummy", value: 2)
|
20
|
+
Foo.first.update(name: "Dummy nameee",value: 4)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|