remexify 1.0.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.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in remexify.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Adam Pahlevi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,138 @@
1
+ # Remexify
2
+
3
+ Remexify is a simple, opinionated Ruby on Rails gem to write logs to your database. No fluff and to the point,
4
+ record and access your logs anytime from your database.
5
+
6
+ ## Behind the scene
7
+
8
+ > Roses are red violets are blue, a log is not a poem it should be accessible to you.
9
+
10
+ In all the projects I am working on, I always have a database-backed logger. I am tired of managing
11
+ all of those, but should-be identical logger. So, this gem really helped in.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ gem 'remexify'
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install remexify
26
+
27
+ ## Design Decision
28
+
29
+ This gem monkey patch attribute already_logged(?) in two standard ruby error classes:
30
+
31
+ 1. RuntimeError
32
+ 2. StandardError
33
+
34
+ `already_logged` (or `already_logged?`) will return nil if the exception is not yet logged.
35
+
36
+ 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
37
+ is nothing but a StandardError subclassed.
38
+
39
+ 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.
40
+
41
+ ## Usage
42
+
43
+ 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:
44
+
45
+ rails g remexify System::Loggers
46
+
47
+ You can name your log class anything, such as `System::Loggers`. After that, you have to migrate it.
48
+
49
+ rake db:migrate
50
+
51
+ Finally, you can use the gem!
52
+
53
+ Remexify.log err
54
+ Remexify.info "System is starting"
55
+
56
+ In a rails app, you may invoke the `error()` like this:
57
+
58
+ begin
59
+ raise "error"
60
+ rescue => e
61
+ Remexify.error e, file: __FILE__, class: self.class.name, method: __method__, line: __LINE__
62
+ raise e
63
+ end
64
+
65
+ Remexify have 3 static functions:
66
+
67
+ def write(level, obj, options = {}); end;
68
+ def info(obj, options = {}); end;
69
+ def warning(obj, options = {}); end;
70
+ def error(obj, options = {}); end;
71
+
72
+ `write()` is the most basic function, that you will only need to use if you want to define the level yourself.
73
+ Some level is predefined:
74
+
75
+ INFO = 100
76
+ WARNING = 200
77
+ ERROR = 300
78
+
79
+ Thus, if you invoke `info()` level will be 100.
80
+
81
+ The obj can be any object. You can pass it a(n instance of) `String`, or an `Exception`, `StandardError`, `RuntimeError`, `DisplayableError`.
82
+
83
+ It will **automatically generate the backtrace if the object passed is an exception.**
84
+
85
+ Options can have:
86
+
87
+ 1. :method
88
+ 2. :line
89
+ 3. :file
90
+ 4. :parameters
91
+ 5. :description
92
+
93
+ All those options are optional, and, if given, will be stored in the database.
94
+
95
+ In order to retrieve the recorded logs, you will deal with Remexify's Retrieve module. You may retrieve all logs:
96
+
97
+ Remexify::Retrieve.all
98
+
99
+ Or, you may also retrieve all logs recorded today:
100
+
101
+ Remexify::Retrieve.today
102
+
103
+ Both methods accepts a hash to which you can indicate an ordering of retrieved data:
104
+
105
+ Remexify::Retrieve.all order: "created_at DESC"
106
+
107
+ You may also delete all the logs in your database:
108
+
109
+ Remexify.delete_all_logs
110
+
111
+ ## What is recorded?
112
+
113
+ These are the fields that is recorded:
114
+
115
+ Field name | Key | Is for...
116
+ ---------- | ------------- | ------------
117
+ level | N/A | let you know the level of the log: error, warning or info.
118
+ md5 | N/A | the fingerprint of the error, similar error should have similar fingerprint.
119
+ message | :message | string of the error
120
+ backtrace | N/A | backtrace of error, if the object is an instance of Error
121
+ file_name | :file | file where the log was recorded
122
+ class_name | :class | class where the log was recorded
123
+ method_name | :method | method where the log was recorded
124
+ line | :line | line where the log was recorded
125
+ parameters | :params | arguments that's passed in a function/block that can be used later in attemp to reproduce the error
126
+ description | :desc | programmer may pass in additional description here
127
+ frequency | N/A | how many times `Remexify` encounter this error?
128
+ timestamps | N/A | timestamp of the error when it was created, and last updated.
129
+
130
+ ## Contributing
131
+
132
+ 1. Fork it ( https://github.com/[my-github-username]/remexify/fork )
133
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
134
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
135
+ 4. Push to the branch (`git push origin my-new-feature`)
136
+ 5. Create a new Pull Request
137
+
138
+ by Adam Pahlevi Baihaqi
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,33 @@
1
+ require "rails/generators"
2
+ require "rails/generators/migration"
3
+ require "rails/generators/named_base"
4
+
5
+ module Remexify
6
+ module Generators
7
+ class RemexifyGenerator < Rails::Generators::NamedBase
8
+ include Rails::Generators::Migration
9
+ source_root File.expand_path("../templates", __FILE__)
10
+
11
+ desc "Generates a model with the given NAME for remexify to log error/informations"
12
+
13
+ namespace "remexify"
14
+
15
+ def self.next_migration_number(path)
16
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
17
+ end
18
+
19
+ def copy_migration
20
+ migration_template "create_remexify_lognotes.rb", "db/migrate/create_remexify_lognotes.rb"
21
+ end
22
+
23
+ def generate_model
24
+ invoke "active_record:model", [name], migration: false
25
+ # invoke "active_record:model", ["Remexify::Logs", "md5:string"], {migration: true, timestamps: true}
26
+ end
27
+
28
+ def make_initializer
29
+ template "initialize_remexify.rb", "config/initializers/remexify.rb"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,38 @@
1
+ class CreateRemexifyLognotes < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :<%= table_name %> do |t|
4
+ # 0 the more high the level, the more important.
5
+ t.integer :level, null: false, default: 0
6
+
7
+ # let your log unique
8
+ t.string :md5, null: false
9
+
10
+ t.text :message, null: false
11
+ t.text :backtrace
12
+ t.text :file_name
13
+
14
+ t.string :class_name, null: false
15
+ t.string :method_name
16
+ t.string :line
17
+
18
+ # additional parameters that want to be logged as well
19
+ t.text :parameters
20
+
21
+ # additional description that want to be logged as well
22
+ t.text :description
23
+
24
+ # how many times the system logging this error?
25
+ t.integer :frequency, null: false, default: 1
26
+
27
+ t.timestamps
28
+ end
29
+ add_index :<%= table_name %>, [:md5], unique: true
30
+ end
31
+
32
+ def self.down
33
+ # we don't want to make assumption of your roll back, please
34
+ # by all mean edit it.
35
+ # drop_table :<%= table_name %>
36
+ raise ActiveRecord::IrreversibleMigration
37
+ end
38
+ end
@@ -0,0 +1,3 @@
1
+ Remexify.setup do |config|
2
+ config.model = <%= class_name %>
3
+ end
@@ -0,0 +1,2 @@
1
+ class DisplayableError < StandardError
2
+ end
@@ -0,0 +1,30 @@
1
+ module Remexify
2
+ module Retrieve
3
+ class << self
4
+ def all(options = {})
5
+ if options[:order]
6
+ return Remexify.config.model.order(options[:order]).all.to_a
7
+ end
8
+ return Remexify.config.model.all.to_a
9
+ end
10
+
11
+ def today(options = {})
12
+ ar_statement = Remexify.config.model.where(created_at: Time.now.beginning_of_day..Time.now.end_of_day)
13
+ if options[:order]
14
+ return ar_statement.order(options[:order]).all.to_a
15
+ end
16
+ return ar_statement.all.to_a
17
+ end
18
+
19
+ def where_fingerprint_is(fingerprint)
20
+ Remexify.config.model.where(md5: fingerprint).first
21
+ end
22
+ end
23
+ end
24
+
25
+ class << self
26
+ def delete_all_logs
27
+ Remexify.config.model.delete_all
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,79 @@
1
+ module Remexify
2
+ class << self
3
+ # options = class, method, line, file, params/param/parameters, desc/description
4
+ def write(level, obj, options = {})
5
+ if (obj.is_a?(StandardError) || obj.is_a?(RuntimeError)) && obj.already_logged
6
+ return
7
+ end
8
+
9
+ message = "message is nil"
10
+ backtrace = "backtrace is nil"
11
+
12
+ if obj.class <= Exception
13
+ message = obj.message
14
+ backtrace = obj.backtrace.join("\n")
15
+ elsif obj.class <= String
16
+ message = obj
17
+ backtrace = nil
18
+ end
19
+
20
+ # standardize into options[:parameters]
21
+ options[:parameters] = options[:param] if options[:param]
22
+ options[:parameters] = options[:params] if options[:params]
23
+ options[:parameters] = options[:parameter] if options[:parameter]
24
+ options[:parameters] ||= ""
25
+
26
+ # standardize into options[:description]
27
+ options[:description] = options[:desc] if options[:desc]
28
+ options[:description] ||= ""
29
+
30
+ # class name cannot be blank
31
+ class_name = options[:class]
32
+ class_name = Time.now.strftime("%Y%m%d") if class_name.blank?
33
+
34
+ # generate hash
35
+ hashed = "#{message}#{class_name}"
36
+ md5 = Digest::MD5.hexdigest hashed
37
+
38
+ # assure md5 is not yet exist, if exist, don't save
39
+ log = config.model.where(md5: md5).first
40
+ if log
41
+ log.frequency += 1
42
+ log.save
43
+ else
44
+ config.model.create({
45
+ md5: md5,
46
+ level: level,
47
+ message: message,
48
+ backtrace: backtrace,
49
+ class_name: class_name,
50
+ method_name: options[:method],
51
+ line: options[:line],
52
+ file_name: options[:file],
53
+ parameters: (options[:parameters].blank? ? "" : options[:parameters].inspect),
54
+ description: options[:description]
55
+ })
56
+ end
57
+
58
+ # mark already logged if DisplayableError
59
+ if obj.is_a?(StandardError) || obj.is_a?(DisplayableError)
60
+ obj.already_logged = true
61
+ end
62
+
63
+ nil # don't return anything for logging!
64
+ end
65
+
66
+ def info(obj, options = {})
67
+ write INFO, obj, options
68
+ end
69
+
70
+ def warning(obj, options = {})
71
+ write WARNING, obj, options
72
+ end
73
+
74
+ def error(obj, options = {})
75
+ write ERROR, obj, options
76
+ end
77
+ end
78
+
79
+ end
@@ -0,0 +1,4 @@
1
+ class RuntimeError
2
+ attr_accessor :already_logged
3
+ alias_method :already_logged?, :already_logged
4
+ end
@@ -0,0 +1,4 @@
1
+ class StandardError
2
+ attr_accessor :already_logged
3
+ alias_method :already_logged?, :already_logged
4
+ end
@@ -0,0 +1,3 @@
1
+ module Remexify
2
+ VERSION = "1.0.0"
3
+ end
data/lib/remexify.rb ADDED
@@ -0,0 +1,24 @@
1
+ require "remexify/version"
2
+ require "active_support/configurable"
3
+
4
+ module Remexify
5
+ include ActiveSupport::Configurable
6
+
7
+ INFO = 100
8
+ WARNING = 200
9
+ ERROR = 300
10
+
11
+ class << self
12
+ def setup
13
+ config.model = nil
14
+ yield config
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ require "remexify/standard_error"
21
+ require "remexify/runtime_error"
22
+ require "remexify/displayable_error"
23
+ require "remexify/remexify_retriever"
24
+ require "remexify/remexify_writer"
data/remexify.gemspec ADDED
@@ -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 'remexify/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "remexify"
8
+ spec.version = Remexify::VERSION
9
+ spec.platform = Gem::Platform::RUBY
10
+ spec.authors = ["Adam Pahlevi"]
11
+ spec.email = ["adam.pahlevi@gmail.com"]
12
+ spec.summary = %q{Simply log any message/error to your database}
13
+ spec.description = %q{A gem that make your system a log handler as well, by saving any error to your database system}
14
+ spec.homepage = "http://adampahlevi.com"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.6"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "railties", ">= 3.2.6", "< 5"
25
+ spec.add_development_dependency "rails", "~> 3"
26
+ spec.add_development_dependency "activesupport"
27
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: remexify
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Pahlevi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-30 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.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: railties
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 3.2.6
48
+ - - "<"
49
+ - !ruby/object:Gem::Version
50
+ version: '5'
51
+ type: :development
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: 3.2.6
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: '5'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rails
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3'
75
+ - !ruby/object:Gem::Dependency
76
+ name: activesupport
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ description: A gem that make your system a log handler as well, by saving any error
90
+ to your database system
91
+ email:
92
+ - adam.pahlevi@gmail.com
93
+ executables: []
94
+ extensions: []
95
+ extra_rdoc_files: []
96
+ files:
97
+ - ".gitignore"
98
+ - ".idea/.name"
99
+ - ".idea/.rakeTasks"
100
+ - ".idea/encodings.xml"
101
+ - ".idea/misc.xml"
102
+ - ".idea/modules.xml"
103
+ - ".idea/remexify.iml"
104
+ - ".idea/scopes/scope_settings.xml"
105
+ - ".idea/vcs.xml"
106
+ - ".idea/workspace.xml"
107
+ - Gemfile
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - lib/generators/remexify_generator.rb
112
+ - lib/generators/templates/create_remexify_lognotes.rb
113
+ - lib/generators/templates/initialize_remexify.rb
114
+ - lib/remexify.rb
115
+ - lib/remexify/displayable_error.rb
116
+ - lib/remexify/remexify_retriever.rb
117
+ - lib/remexify/remexify_writer.rb
118
+ - lib/remexify/runtime_error.rb
119
+ - lib/remexify/standard_error.rb
120
+ - lib/remexify/version.rb
121
+ - remexify.gemspec
122
+ homepage: http://adampahlevi.com
123
+ licenses:
124
+ - MIT
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 2.2.2
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: Simply log any message/error to your database
146
+ test_files: []