remexify 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,30 +1,27 @@
1
1
  # Remexify
2
2
 
3
- Remexify is the world's simplest Rails-only ActiveRecord gem to write/retrieve logs written into your database's table.
4
- Its philosophy is not to be a dictator gem, so you have your control over what to log, the log level, and et cetera.
5
- Remexify is happy to be no fluff, and to-the-point!
3
+ Remexify is the simplest way to log anything into your database, build for Rails. It supports ActiveRecord and Mongoid::Document. Remexify is happy to be no fluff, and to-the-point!
6
4
 
7
5
  ## Behind the scene
8
6
 
9
7
  > Roses are red violets are blue, a log is not a poem it should be accessible to you.
10
8
 
11
- Remexify is always by my side whenever I need to log something into the database. I am tired of managing different logger,
12
- or duplicatings codes accross multitude of projects I am working on only to have this kind of ability that I wanted.
13
- Therefore, I refactor it and made it into a gem available to all projects a bundle away not only for mine, but also for yours.
14
- I wish it will help you somehow.
9
+ I always used Remexify whenever I need to log something into the database. I am tired of managing different logger,
10
+ or duplicating codes across projects for getting the simple functionality that I had always wanted to have.
11
+ Therefore, I refactor it, and made it into a gem, so that it become available to all projects a bundle away.
15
12
 
16
13
  ## Why should you use Remexify?
17
14
 
18
15
  Remexify...
19
16
 
20
- 1. Help you log to your own database, by giving you the control and ease on when/where to do that.
21
- 2. Let you log not only an error, but also info, log, etc. Actually, "error" is just a numeric constant.
22
- 3. Gives you the flexible means of accessing your logged error.
23
- 4. Let you *censor* specific error classes which you don't want it to appear in the backtrace.
24
- 5. Let you define acceptable/unacceptable classes of error which you can use to control what instance of exception class you want to dismiss, or to keep.
25
- 6. Logs similar error once, but will record the frequency if similar error occurred again.
26
- 7. Can associate your logs to certain user, object, or anything.
27
- 7. Is free and open source for all the People of Earth.
17
+ 1. Help you log to your own database, giving you the control and ease on when/where to do that.
18
+ 2. Let you log not only an error, but also info, log, etc. (Those info/log/etc definition is just a numeric constant.)
19
+ 3. Give you the easy, and flexible mean of accessing your log.
20
+ 4. Let you *censor* string in the backtrace so it won't pollute your backtrace from noisy, unnecessary information.
21
+ 5. Let you define acceptable/unacceptable classes to be logged.
22
+ 6. Logs error once, and increase its occurence frequency so no 2 similar logs are duplicate of each other.
23
+ 7. Can associate your logs to certain user, object, or anything in order to trace who trigger the error.
24
+ 7. It is free, 100% I contribute it as an open source for all the People of Earth to use it.
28
25
 
29
26
  ## Installation
30
27
 
@@ -40,30 +37,30 @@ Or install it yourself as:
40
37
 
41
38
  $ gem install remexify
42
39
 
40
+ Then, you need to generate some models that the gem needs, here we give our model name of `System::Loggers`:
41
+
42
+ rails g remexify System::Loggers
43
+
44
+ You can name your log class anything, such as `System::Loggers`. After that, you have to migrate it:
45
+
46
+ rake db:migrate
47
+
43
48
  ## Design Decision
44
49
 
45
- This gem monkey patch attribute already_logged(?) in two standard ruby error classes:
50
+ By using this gem, it will monkey patch `already_logged` into these two classes:
46
51
 
47
52
  1. RuntimeError
48
53
  2. StandardError
49
54
 
50
- `already_logged` (or `already_logged?`) will return nil if the exception is not yet logged.
51
-
52
- Additionally, there is new error class `DisplayableError`. DisplayableError will be quite handy if you want to raise an enduser-visible error. In your controller, you may only allow an instance of DisplayableError to be displayed. DisplayableError
53
- is nothing but a StandardError subclassed.
54
-
55
- If Remexify caught exceptions any of the above class, it will mark `already_logged` to `true`. Remexify won't log it again when parent/calling method rescue the error.
55
+ `already_logged` (or `already_logged?`) will return nil if the exception is not yet logged. Additionally, there is new error class
56
+ `DisplayableError`. You can set apart user-visible error for system-only administrative-level error through the use of
57
+ `DisplayableError`. Thus, in your controller, you may allow only an instance of DisplayableError to be displayed. DisplayableError
58
+ is nothing but a sub-classed StandardError.
56
59
 
57
60
  ## Basic Usage
58
61
 
59
- To use this gem, you need to generate some files first. You can let the gem to generate all required files, including migration and initializer, for you. To do so, issue:
60
-
61
- rails g remexify System::Loggers
62
-
63
- You can name your log class anything, such as `System::Loggers`. After that, you have to migrate it.
62
+ ### Logging
64
63
 
65
- rake db:migrate
66
-
67
64
  Finally, you can use the gem!
68
65
 
69
66
  Remexify.log err
@@ -77,16 +74,23 @@ In a rails app, you may invoke the `error()` like this:
77
74
  Remexify.error e, file: __FILE__, class: self.class.name, method: __method__, line: __LINE__
78
75
  raise e
79
76
  end
80
-
81
- Remexify have 4 static functions:
77
+
78
+ Starting from version 1.2.0, you can omit `file`, `method`, and `line` from the hash, which the gem will try to deduct by itself.
79
+
80
+ ```ruby
81
+ Remexify.error e, class: self.class.name
82
+ ```
83
+
84
+ Instead of `error`, Remexify also provide you with other handy method for logging, those are:
82
85
 
83
86
  def write(level, obj, options = {}); end;
84
87
  def info(obj, options = {}); end;
85
88
  def warning(obj, options = {}); end;
86
89
  def error(obj, options = {}); end;
87
-
88
- `write()` is the most basic function, that you will only need to use if you want to define the level yourself.
89
- Some level is predefined:
90
+
91
+ You may define your own level, if you are not satisfied with the already-given `info`, `warning`, and `error`. To do so,
92
+ you will utilise the `write` function. Actually, `write` is the basic function on which the 3 functions above depend on.
93
+ An error, a warning or an info in Remexify is just a constant:
90
94
 
91
95
  INFO = 100
92
96
  WARNING = 200
@@ -94,21 +98,39 @@ Some level is predefined:
94
98
 
95
99
  Thus, if you want to write info log by invoking `info()` then the log will be recorded with level set to 100.
96
100
 
97
- The obj can be any object. You can pass it a(n instance of) `String`, or an `Exception`, `StandardError`, `RuntimeError`, `DisplayableError`.
101
+ ```ruby
102
+ def info(message_object, options = {})
103
+ write INFO, message_object, options
104
+ end
105
+ ```
106
+
107
+ The obj can be any object. You can pass it a `String`, or an `Exception`, `StandardError`, `RuntimeError`, `DisplayableError`.
98
108
 
99
109
  It will **automatically generate the backtrace if the object passed is an exception.**
100
110
 
101
- Options can have:
102
111
 
103
- 1. :method
104
- 2. :line
105
- 3. :file
106
- 4. :parameters
107
- 5. :description
112
+ ### Accepted options for logging
113
+
114
+ Options accepts those parameters:
115
+
116
+ | Option | Optional? | Description |
117
+ |----------------------|-----------|---------------------------------------------------------------------------------------------------------------|
118
+ | :class | N | The class that triggers the error |
119
+ | :method | Y | The method that triggers the error |
120
+ | :line | Y | The line the error is triggered |
121
+ | :file | Y | The file the error is triggered |
122
+ | :params | Y | Additional information (such as query parameters) that may help later on in an effort to replicate the error. |
123
+ | :desc | Y | Description of the error |
124
+ | :extract_params_from | Y | Specify an ActiveRecord model instance, and all of its attributes will be logged as `params` |
125
+ | :owned_by | Y | Associate the error to certain entity |
126
+ | :owned_param1 | Y | Further discrimination of owner |
127
+ | :owned_param2 | Y | Further discrimination of owner |
128
+ | :owned_param3 | Y | Further discrimination of owner |
129
+ | :object | Y | Object of an ActiveRecord model, snatch information about why the error occur if such an information exist. |
108
130
 
109
- All those options are optional, and, if given, will be stored in the database.
131
+ #### Retrieving logs
110
132
 
111
- In order to retrieve the recorded logs, you will deal with Remexify's Retrieve module. You may retrieve all logs:
133
+ You will need to deal with an extremely simple Remexify's `Retrieve` module. You may retrieve all logs:
112
134
 
113
135
  Remexify::Retrieve.all
114
136
 
@@ -128,7 +150,7 @@ You may also delete all the logs in your database:
128
150
 
129
151
  Remexify.delete_all_logs
130
152
 
131
- ## What is recorded in the database?
153
+ ### What is recorded in the database?
132
154
 
133
155
  These are the fields that is recorded:
134
156
 
@@ -289,4 +311,7 @@ by Adam Pahlevi Baihaqi
289
311
  - User can configure `accepted_exceptions`
290
312
  - User can configure `discarded_exceptions`
291
313
  - Ability to associate log to specific user
292
- - Ability to retrieve logs that owned by certain identifier_id (like, user's id)
314
+ - Ability to retrieve logs that owned by certain identifier_id (like, user's id)
315
+ - You are no longer required to specify `file`, `class` and `method` as Remexify now is able to deduct such infomation from the calling trace.
316
+ - [v.1.3.0](#)
317
+ - Added support for Mongoid::Document
@@ -1,17 +1,12 @@
1
- require "rails/generators"
1
+ require "rails/generators/active_record"
2
2
  require "rails/generators/migration"
3
- require "rails/generators/named_base"
4
3
 
5
- module Remexify
4
+ module ActiveRecord
6
5
  module Generators
7
- class RemexifyGenerator < Rails::Generators::NamedBase
6
+ class RemexifyGenerator < ActiveRecord::Generators::Base
8
7
  include Rails::Generators::Migration
9
8
  source_root File.expand_path("../templates", __FILE__)
10
9
 
11
- desc "Generates a model with the given NAME for remexify to log error/informations"
12
-
13
- namespace "remexify"
14
-
15
10
  # to avoid next migration numbers having the same exact identity
16
11
  @secondth = 1
17
12
 
@@ -20,11 +15,13 @@ module Remexify
20
15
  (Time.now.utc. + @secondth).strftime("%Y%m%d%H%M%S")
21
16
  end
22
17
 
18
+ # copy the migration
23
19
  def copy_migration
24
20
  migration_template "create_remexify_lognotes.rb", "db/migrate/create_remexify_lognotes.rb"
25
21
  migration_template "create_remexify_logowners.rb", "db/migrate/create_remexify_logowners.rb"
26
22
  end
27
23
 
24
+ # generate appropriate model
28
25
  def generate_model
29
26
  # don't just call invoke without Rails::Generators because Thor task only run once.
30
27
  Rails::Generators.invoke "active_record:model", [name, "--no-migration"]
@@ -4,7 +4,7 @@ class CreateRemexifyLognotes < ActiveRecord::Migration
4
4
  # 0 the more high the level, the more important.
5
5
  t.integer :level, null: false, default: 0
6
6
 
7
- # let your log unique
7
+ # let your log be unique
8
8
  t.string :md5, null: false
9
9
 
10
10
  t.text :message, null: false
@@ -0,0 +1,74 @@
1
+ require "rails/generators/named_base"
2
+
3
+ module Mongoid
4
+ module Generators
5
+ class RemexifyGenerator < Rails::Generators::NamedBase
6
+ source_root File.expand_path("../templates", __FILE__)
7
+
8
+ def generate_log_model
9
+ Rails::Generators.invoke "mongoid:model", [name]
10
+ end
11
+
12
+ def generate_logowner_model
13
+ Rails::Generators.invoke "mongoid:model", ["#{name}Owners"]
14
+ end
15
+
16
+ def inject_log_model
17
+ log_data = <<RUBY
18
+ include Mongoid::Timestamps::Short
19
+
20
+ # 0; the more high the level, the more important
21
+ field :level, type: Integer, default: 0
22
+
23
+ # let your log be unique
24
+ field :md5, type: String
25
+
26
+ field :message, type: String
27
+ field :backtrace, type: String
28
+ field :file_name, type: String
29
+
30
+ field :class_name, type: String
31
+ field :method_name, type: String
32
+ field :line, type: String
33
+
34
+ # additional parameters that want to be logged as well
35
+ field :parameters, type: String
36
+
37
+ # additional description that want to be logged as well
38
+ field :description, type: String
39
+
40
+ # how many times the system logging this error?
41
+ field :frequency, type: Integer, default: 1
42
+
43
+ validates_presence_of :level, :md5, :message, :class_name, :frequency
44
+ index({ md5: 1 }, {unique: true})
45
+ RUBY
46
+
47
+ inject_into_file File.join("app", "models", "#{file_path}.rb"), log_data, after: "include Mongoid::Document\n"
48
+ end
49
+
50
+ def inject_logowner_model
51
+ log_data = <<RUBY
52
+ include Mongoid::Timestamps::Short
53
+
54
+ field :log_md5, type: String
55
+ field :identifier_id, type: String
56
+
57
+ field :param1, type: String
58
+ field :param2, type: String
59
+ field :param3, type: String
60
+
61
+ validates_presence_of :log_md5, :identifier_id
62
+
63
+ index({ md5: 1, identifier_id: 1 }, { unique: true })
64
+ RUBY
65
+ inject_into_file File.join("app", "models", "#{file_path}_owners.rb"), log_data, after: "include Mongoid::Document\n"
66
+ end
67
+
68
+ def make_initializer
69
+ template "initialize_remexify.rb", "config/initializers/00_remexify.rb"
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,8 @@
1
+ Remexify.setup do |config|
2
+ config.model = <%= class_name %>
3
+ config.model_owner = <%= class_name %>Owners
4
+
5
+ # uncomment lines bellow if you want to out list mongoid. add other similar lines
6
+ # for other libraries if you wish.
7
+ config.censor_strings << "mongoid"
8
+ end
@@ -0,0 +1,13 @@
1
+ require "rails/generators"
2
+ require "rails/generators/named_base"
3
+
4
+ module Remexify
5
+ module Generators
6
+ class RemexifyGenerator < Rails::Generators::NamedBase
7
+ namespace "remexify"
8
+ desc "Generates a model with the given NAME for remexify to log error/informations"
9
+
10
+ hook_for :orm
11
+ end
12
+ end
13
+ end
data/lib/remexify.rb CHANGED
@@ -36,7 +36,19 @@ module Remexify
36
36
  end
37
37
 
38
38
  # model must exists as ActiveRecord model. model_owner is not necessary to exists at all
39
- raise "Remexify.config.model is not an ActiveRecord model" unless config.model < ActiveRecord::Base
39
+ if defined?(ActiveRecord::Base) && defined?(Mongoid::Document)
40
+ if (config.model < ActiveRecord::Base) || (config.model < Mongoid::Document)
41
+ # good!
42
+ else
43
+ raise "Remexify.config.model is neither an ActiveRecord model or Mongoid::Document"
44
+ end
45
+ elsif defined?(ActiveRecord::Base)
46
+ raise "Remexify.config.model is not an ActiveRecord model" unless config.model < ActiveRecord::Base
47
+ elsif defined?(Mongoid::Document)
48
+ raise "Remexify.config.model is not a Mongoid::Document" unless config.model < Mongoid::Document
49
+ else
50
+ raise "Remexify.config.model is neither an ActiveRecord model or Mongoid::Document"
51
+ end
40
52
  end
41
53
  end
42
54
 
@@ -39,6 +39,8 @@ module Remexify
39
39
  backtrace = ""
40
40
  end
41
41
 
42
+ backtrace = "null" if backtrace.blank?
43
+
42
44
  # standardize into options[:parameters]
43
45
  options[:parameters] = options[:param] if options[:param]
44
46
  options[:parameters] = options[:params] if options[:params]
@@ -48,24 +50,43 @@ module Remexify
48
50
  # will override the options[:parameters] if this block execute successfully
49
51
  if options[:extract_params_from]
50
52
  ar_message_objectect = options[:extract_params_from]
51
- if ar_message_objectect.class < ActiveRecord::Base
52
- if ar_message_objectect.respond_to?(:attribute_names) && ar_message_objectect.respond_to?(:read_attribute)
53
- ar_attributes = ar_message_objectect.attribute_names
54
- attributes = {}
53
+
54
+ def parse_model_fields model
55
+ attributes = {}
56
+ if model.respond_to?(:attribute_names) && model.respond_to?(:read_attribute)
57
+ ar_attributes = model.attribute_names
55
58
  ar_attributes.each do |attr|
56
- attributes[attr.to_s] = ar_message_objectect.read_attribute attr.to_sym
59
+ attributes[attr.to_s] = model.read_attribute attr.to_sym
57
60
  end
58
61
  options[:parameters] = attributes
59
62
  end
63
+ attributes
64
+ end
65
+
66
+ if defined?(ActiveRecord::Base)
67
+ options[:parameters] = parse_model_fields(ar_message_objectect) if ar_message_objectect.class < ActiveRecord::Base
68
+ end
69
+
70
+ if defined?(Mongoid::Document)
71
+ options[:parameters] = parse_model_fields(ar_message_objectect) if ar_message_objectect.class < Mongoid::Document
60
72
  end
61
73
  end
62
74
 
63
75
  # if object is given
64
76
  if options[:object]
65
- # and is an active record
66
- if options[:object].class < ActiveRecord::Base
77
+ parse_error_messages = false
78
+ # and is an active record/mongoid document
79
+ if defined?(ActiveRecord::Base)
80
+ parse_error_messages = true if options[:object].class < ActiveRecord::Base
81
+ end
82
+
83
+ if defined?(Mongoid::Document)
84
+ parse_error_messages = true if options[:object].class < Mongoid::Document
85
+ end
86
+
87
+ if parse_error_messages
67
88
  # append to message
68
- message << "\n\nActiveRecord error messages:\n" << options[:object].errors.full_messages.join("\n")
89
+ message << "\n\nerror messages:\n" << options[:object].errors.full_messages.join("\n")
69
90
  end
70
91
  end
71
92
 
@@ -85,7 +106,7 @@ module Remexify
85
106
  # do not quote md5 directly, it is used to query .where
86
107
  md5 = Digest::MD5.hexdigest hashed
87
108
  # the quoted version of md5, do not replace the original value
88
- qmd5 = config.model.connection.quote md5
109
+ qmd5 = md5
89
110
 
90
111
  # assure md5 is not yet exist, if exist, don't save
91
112
  log = config.model.where(md5: md5).first
@@ -93,9 +114,7 @@ module Remexify
93
114
  log.frequency += 1
94
115
  log.save
95
116
  else
96
- message = config.model.connection.quote message
97
- backtrace = backtrace.blank? ? "null" : config.model.connection.quote(backtrace)
98
- class_name = config.model.connection.quote(class_name)
117
+
99
118
 
100
119
  method = line = file = "null"
101
120
  if Kernel.respond_to? :caller_locations
@@ -109,28 +128,58 @@ module Remexify
109
128
  line = options[:line] unless options[:line].blank?
110
129
  file = options[:file] unless options[:file].blank?
111
130
  end
112
- method = config.model.connection.quote(method)
113
- line = config.model.connection.quote(line)
114
- file = config.model.connection.quote(file)
115
131
 
116
- parameters = options[:parameters].blank? ? "null" : config.model.connection.quote(options[:parameters].inspect)
117
- descriptions = options[:description].blank? ? "null" : config.model.connection.quote(options[:description])
118
- time_now = config.model.connection.quote(Time.now.strftime("%Y-%m-%d %H:%M:%S"))
132
+ parameters = options[:parameters].blank? ? "null" : options[:parameters].inspect
133
+ descriptions = options[:description].blank? ? "null" : options[:description]
134
+ time_now = Time.now.strftime("%Y-%m-%d %H:%M:%S")
135
+
136
+ if defined?(ActiveRecord::Base)
137
+ if config.model < ActiveRecord::Base
138
+ if config.model.connection.transaction_open?
139
+ config.model.connection.rollback_transaction
140
+ end
119
141
 
120
- if config.model.connection.transaction_open?
121
- config.model.connection.rollback_transaction
142
+ qmd5 = config.model.connection.quote md5
143
+ message = config.model.connection.quote message
144
+ backtrace = config.model.connection.quote backtrace
145
+ class_name = config.model.connection.quote class_name
146
+ method = config.model.connection.quote method
147
+ line = config.model.connection.quote line
148
+ file = config.model.connection.quote file
149
+ parameters = config.model.connection.quote parameters
150
+ descriptions = config.model.connection.quote parameters
151
+ time_now = config.model.connection.quote time_now
152
+
153
+ ActiveRecord::Base.transaction do
154
+ config.model.connection.execute <<-SQL
155
+ INSERT INTO #{config.model.table_name} (
156
+ md5, level, message, backtrace,
157
+ class_name, method_name, line, file_name,
158
+ parameters, description, created_at, updated_at)
159
+ VALUES (#{qmd5}, #{Integer level}, #{message}, #{backtrace}, #{class_name},
160
+ #{method}, #{line}, #{file}, #{parameters}, #{descriptions},
161
+ #{time_now}, #{time_now});
162
+ SQL
163
+ end
164
+ end
165
+ elsif defined?(Mongoid::Document)
166
+ if config.model < Mongoid::Document
167
+ new_log = config.model.new
168
+ new_log.md5 = qmd5
169
+ new_log.level = Integer(level)
170
+ new_log.message = message
171
+ new_log.backtrace = backtrace
172
+ new_log.class_name = class_name
173
+ new_log.method_name = method
174
+ new_log.line = line
175
+ new_log.file_name = file
176
+ new_log.parameters = parameters
177
+ new_log.description = descriptions
178
+ new_log.created_at = time_now
179
+ new_log.updated_at = time_now
180
+ new_log.save
181
+ end
122
182
  end
123
- config.model.connection.begin_transaction
124
- config.model.connection.execute <<-SQL
125
- INSERT INTO #{config.model.table_name} (
126
- md5, level, message, backtrace,
127
- class_name, method_name, line, file_name,
128
- parameters, description, created_at, updated_at)
129
- VALUES (#{qmd5}, #{Integer level}, #{message}, #{backtrace}, #{class_name},
130
- #{method}, #{line}, #{file}, #{parameters}, #{descriptions},
131
- #{time_now}, #{time_now});
132
- SQL
133
- config.model.connection.commit_transaction
134
183
  end
135
184
 
136
185
  # mark already logged if DisplayableError
@@ -139,19 +188,38 @@ module Remexify
139
188
  end
140
189
 
141
190
  # if owner_by is given, associate this log to the owned_by user
142
- if !options[:owned_by].blank? && (config.model_owner < ActiveRecord::Base)
143
- owned_by = config.model.connection.quote(options[:owned_by])
144
- owned_param1 = config.model.connection.quote(options[:owned_param1])
145
- owned_param2 = config.model.connection.quote(options[:owned_param2])
146
- owned_param3 = config.model.connection.quote(options[:owned_param3])
147
-
148
- config.model.connection.begin_transaction
149
- config.model.connection.execute <<-SQL
150
- INSERT INTO #{config.model_owner.table_name} (
151
- log_md5, identifier_id, param1, param2, param3)
152
- VALUES (#{qmd5}, #{owned_by}, #{owned_param1}, #{owned_param2}, #{owned_param3})
153
- SQL
154
- config.model.connection.commit_transaction
191
+ unless options[:owned_by].blank?
192
+ owned_by = options[:owned_by]
193
+ owned_param1 = options[:owned_param1]
194
+ owned_param2 = options[:owned_param2]
195
+ owned_param3 = options[:owned_param3]
196
+
197
+ if defined?(ActiveRecord::Base)
198
+ if config.model_owner < ActiveRecord::Base
199
+ owned_by = config.model.connection.quote(owned_by)
200
+ owned_param1 = config.model.connection.quote(owned_param1)
201
+ owned_param2 = config.model.connection.quote(owned_param2)
202
+ owned_param3 = config.model.connection.quote(owned_param3)
203
+
204
+ # config.model.connection.begin_transaction
205
+ ActiveRecord::Base.transaction do
206
+ config.model.connection.execute <<-SQL
207
+ INSERT INTO #{config.model_owner.table_name} (
208
+ log_md5, identifier_id, param1, param2, param3)
209
+ VALUES (#{qmd5}, #{owned_by}, #{owned_param1}, #{owned_param2}, #{owned_param3})
210
+ SQL
211
+ end
212
+ # config.model.connection.commit_transaction
213
+ end
214
+ elsif defined?(Mongoid::Document)
215
+ if config.model_owner < Mongoid::Document
216
+ log_owner = config.model_owner.new
217
+ log_owner.owned_by = owned_by
218
+ log_owner.owned_param1 = owned_param1
219
+ log_owner.owned_param2 = owned_param2
220
+ log_owner.owned_param3 = owned_param3
221
+ end
222
+ end
155
223
  end
156
224
 
157
225
  nil # don't return anything for logging!