queryable_logs 0.1.0 → 0.1.2
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 +4 -4
- data/Gemfile.lock +7 -92
- data/README.md +47 -5
- data/lib/generators/queryable_logs_generator.rb +1 -6
- data/lib/generators/templates/initializer.rb +3 -4
- data/lib/generators/templates/migration.rb +1 -1
- data/lib/generators/templates/task.rb +3 -1
- data/lib/queryable_logs/trail_log.rb +4 -43
- data/lib/queryable_logs/version.rb +1 -1
- data/lib/queryable_logs/write_log.rb +3 -14
- data/queryable_logs.gemspec +4 -3
- metadata +24 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8022ed8aff78bfff25367198a3a95f95bfddb4b8c4596276e85634efe01cea67
|
4
|
+
data.tar.gz: 3f8d87a7bc9702831b6f0f4a4b0e4e90a0d025b680f422dbc4bf8cd4e5560958
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6bd153ba202ae69f51fbbee6b6a3a5828c8c0c68321b8d4519ce08f526261a5035a2b49d64e8077cfc84e21a6f40f1d055d26e08d2ae25c387b65335b84ce9da
|
7
|
+
data.tar.gz: 0ccda5b146fdde3f8f9fa7276516213616b271840f76f69e6bd0f3c3fd92258d2a42b6e3bb9db3b6262a26682de172d3ca8f76c4625d2f255e80f34b0d4e59fd
|
data/Gemfile.lock
CHANGED
@@ -1,105 +1,31 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
queryable_logs (0.1.
|
5
|
-
|
4
|
+
queryable_logs (0.1.2)
|
5
|
+
activerecord (>= 4)
|
6
|
+
activesupport (>= 4)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
9
10
|
specs:
|
10
|
-
actioncable (5.2.8.1)
|
11
|
-
actionpack (= 5.2.8.1)
|
12
|
-
nio4r (~> 2.0)
|
13
|
-
websocket-driver (>= 0.6.1)
|
14
|
-
actionmailer (5.2.8.1)
|
15
|
-
actionpack (= 5.2.8.1)
|
16
|
-
actionview (= 5.2.8.1)
|
17
|
-
activejob (= 5.2.8.1)
|
18
|
-
mail (~> 2.5, >= 2.5.4)
|
19
|
-
rails-dom-testing (~> 2.0)
|
20
|
-
actionpack (5.2.8.1)
|
21
|
-
actionview (= 5.2.8.1)
|
22
|
-
activesupport (= 5.2.8.1)
|
23
|
-
rack (~> 2.0, >= 2.0.8)
|
24
|
-
rack-test (>= 0.6.3)
|
25
|
-
rails-dom-testing (~> 2.0)
|
26
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
27
|
-
actionview (5.2.8.1)
|
28
|
-
activesupport (= 5.2.8.1)
|
29
|
-
builder (~> 3.1)
|
30
|
-
erubi (~> 1.4)
|
31
|
-
rails-dom-testing (~> 2.0)
|
32
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
33
|
-
activejob (5.2.8.1)
|
34
|
-
activesupport (= 5.2.8.1)
|
35
|
-
globalid (>= 0.3.6)
|
36
11
|
activemodel (5.2.8.1)
|
37
12
|
activesupport (= 5.2.8.1)
|
38
13
|
activerecord (5.2.8.1)
|
39
14
|
activemodel (= 5.2.8.1)
|
40
15
|
activesupport (= 5.2.8.1)
|
41
16
|
arel (>= 9.0)
|
42
|
-
activestorage (5.2.8.1)
|
43
|
-
actionpack (= 5.2.8.1)
|
44
|
-
activerecord (= 5.2.8.1)
|
45
|
-
marcel (~> 1.0.0)
|
46
17
|
activesupport (5.2.8.1)
|
47
18
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
48
19
|
i18n (>= 0.7, < 2)
|
49
20
|
minitest (~> 5.1)
|
50
21
|
tzinfo (~> 1.1)
|
51
22
|
arel (9.0.0)
|
52
|
-
builder (3.2.4)
|
53
23
|
concurrent-ruby (1.2.2)
|
54
|
-
crass (1.0.6)
|
55
24
|
diff-lcs (1.5.0)
|
56
|
-
erubi (1.12.0)
|
57
|
-
globalid (0.4.2)
|
58
|
-
activesupport (>= 4.2.0)
|
59
25
|
i18n (1.14.1)
|
60
26
|
concurrent-ruby (~> 1.0)
|
61
|
-
loofah (2.21.1)
|
62
|
-
crass (~> 1.0.2)
|
63
|
-
nokogiri (>= 1.5.9)
|
64
|
-
mail (2.7.1)
|
65
|
-
mini_mime (>= 0.1.1)
|
66
|
-
marcel (1.0.2)
|
67
|
-
method_source (1.0.0)
|
68
|
-
mini_mime (1.1.2)
|
69
|
-
mini_portile2 (2.4.0)
|
70
27
|
minitest (5.15.0)
|
71
|
-
|
72
|
-
nokogiri (1.10.10)
|
73
|
-
mini_portile2 (~> 2.4.0)
|
74
|
-
rack (2.2.8)
|
75
|
-
rack-test (2.1.0)
|
76
|
-
rack (>= 1.3)
|
77
|
-
rails (5.2.8.1)
|
78
|
-
actioncable (= 5.2.8.1)
|
79
|
-
actionmailer (= 5.2.8.1)
|
80
|
-
actionpack (= 5.2.8.1)
|
81
|
-
actionview (= 5.2.8.1)
|
82
|
-
activejob (= 5.2.8.1)
|
83
|
-
activemodel (= 5.2.8.1)
|
84
|
-
activerecord (= 5.2.8.1)
|
85
|
-
activestorage (= 5.2.8.1)
|
86
|
-
activesupport (= 5.2.8.1)
|
87
|
-
bundler (>= 1.3.0)
|
88
|
-
railties (= 5.2.8.1)
|
89
|
-
sprockets-rails (>= 2.0.0)
|
90
|
-
rails-dom-testing (2.1.1)
|
91
|
-
activesupport (>= 5.0.0)
|
92
|
-
minitest
|
93
|
-
nokogiri (>= 1.6)
|
94
|
-
rails-html-sanitizer (1.5.0)
|
95
|
-
loofah (~> 2.19, >= 2.19.1)
|
96
|
-
railties (5.2.8.1)
|
97
|
-
actionpack (= 5.2.8.1)
|
98
|
-
activesupport (= 5.2.8.1)
|
99
|
-
method_source
|
100
|
-
rake (>= 0.8.7)
|
101
|
-
thor (>= 0.19.0, < 2.0)
|
102
|
-
rake (10.5.0)
|
28
|
+
rake (13.2.1)
|
103
29
|
rspec (3.12.0)
|
104
30
|
rspec-core (~> 3.12.0)
|
105
31
|
rspec-expectations (~> 3.12.0)
|
@@ -113,29 +39,18 @@ GEM
|
|
113
39
|
diff-lcs (>= 1.2.0, < 2.0)
|
114
40
|
rspec-support (~> 3.12.0)
|
115
41
|
rspec-support (3.12.0)
|
116
|
-
sprockets (3.7.2)
|
117
|
-
concurrent-ruby (~> 1.0)
|
118
|
-
rack (> 1, < 3)
|
119
|
-
sprockets-rails (3.2.2)
|
120
|
-
actionpack (>= 4.0)
|
121
|
-
activesupport (>= 4.0)
|
122
|
-
sprockets (>= 3.0.0)
|
123
|
-
thor (1.2.2)
|
124
42
|
thread_safe (0.3.6)
|
125
43
|
tzinfo (1.2.11)
|
126
44
|
thread_safe (~> 0.1)
|
127
|
-
websocket-driver (0.7.6)
|
128
|
-
websocket-extensions (>= 0.1.0)
|
129
|
-
websocket-extensions (0.1.5)
|
130
45
|
|
131
46
|
PLATFORMS
|
132
47
|
ruby
|
133
48
|
|
134
49
|
DEPENDENCIES
|
135
|
-
bundler (~>
|
50
|
+
bundler (~> 2)
|
136
51
|
queryable_logs!
|
137
|
-
rake (
|
52
|
+
rake (>= 13.0)
|
138
53
|
rspec (~> 3.0)
|
139
54
|
|
140
55
|
BUNDLED WITH
|
141
|
-
|
56
|
+
2.6.7
|
data/README.md
CHANGED
@@ -21,12 +21,54 @@ Or install it yourself as:
|
|
21
21
|
Run
|
22
22
|
`rails g queryable_logs`.
|
23
23
|
|
24
|
-
This will generate a migration file
|
24
|
+
This will generate a migration file.
|
25
|
+
```ruby
|
26
|
+
class CreateTrailLogs < ActiveRecord::Migration
|
27
|
+
def change
|
28
|
+
create_table :trail_logs do |t|
|
29
|
+
t.integer :user_id
|
30
|
+
t.string :ip_address
|
31
|
+
t.string :controller
|
32
|
+
t.string :action
|
33
|
+
t.string :format
|
34
|
+
t.string :http_verb
|
35
|
+
t.text :params_hash
|
36
|
+
t.datetime :logged_at
|
37
|
+
t.string :response_code
|
38
|
+
t.string :request_url
|
39
|
+
t.string :sig
|
40
|
+
|
41
|
+
t.timestamps null: false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
```
|
46
|
+
and an initializer file.
|
47
|
+
```ruby
|
48
|
+
class Trail
|
49
|
+
cattr_accessor :current_user_method, :logger, :saving_logs
|
50
|
+
LogFile = Rails.root.join('log', 'trail.log')
|
51
|
+
delegate :debug, :info, :warn, :error, :fatal, :to => :logger
|
52
|
+
end
|
53
|
+
|
54
|
+
Trail.logger = Logger.new(Trail::LogFile)
|
55
|
+
Trail.logger.level = 'info' # could be debug, info, warn, error or fatal
|
56
|
+
Trail.current_user_method = :current_user
|
57
|
+
```
|
58
|
+
queryable_logs also logs the current user id. Let the gem know which method you are using to get the current user. Default is set to `current_user`.
|
59
|
+
|
60
|
+
Finally, include the `QueryableLogs::WriteLog` in the base controller, typically the `ApplicationController`.
|
61
|
+
```ruby
|
62
|
+
class ApplicationController < ActionController::Base
|
63
|
+
include QueryableLogs::WriteLog
|
64
|
+
end
|
65
|
+
```
|
66
|
+
|
67
|
+
Enter the following task to your crontab `rake parse:logs_to_db`
|
68
|
+
|
69
|
+
eg: `0 * * * * cd /Users/akshaytakkar/sample_rails_app && /Users/akshaytakkar/.rvm/wrappers/ruby-3.1.0/rake db:parse_log_and_save_trails >> /Users/akshaytakkar/sample_rails_app/log/worker.log 2>&1`
|
25
70
|
|
26
|
-
|
27
|
-
`rake parse:logs_to_db`
|
28
|
-
eg:
|
29
|
-
`* * * * * cd /Users/akshaytakkar/sample_rails_app && /Users/akshaytakkar/.rvm/wrappers/ruby-3.1.0/rake db:parse_log_and_save_trails >> /Users/akshaytakkar/sample_rails_app/log/worker.log 2>&1`
|
71
|
+
This will run the `rake parse:logs_to_db` rake task every hour and log any errors or output from the task to `worker.log` file.
|
30
72
|
|
31
73
|
## Usage
|
32
74
|
|
@@ -28,11 +28,6 @@ class QueryableLogsGenerator < Rails::Generators::Base
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def self.next_migration_number(dirname)
|
31
|
-
|
32
|
-
current_time = Time.now.utc
|
33
|
-
current_time.strftime("%Y%m%d%H%M%S")
|
34
|
-
else
|
35
|
-
"%.3d" % (current_numeric_version(dirname) + 1)
|
36
|
-
end
|
31
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
37
32
|
end
|
38
33
|
end
|
@@ -1,10 +1,9 @@
|
|
1
1
|
class Trail
|
2
2
|
cattr_accessor :current_user_method, :logger, :saving_logs
|
3
|
-
LogFile = Rails.root.join('log',
|
3
|
+
LogFile = Rails.root.join('log', "trail.log")
|
4
4
|
delegate :debug, :info, :warn, :error, :fatal, :to => :logger
|
5
5
|
end
|
6
6
|
|
7
|
-
Trail.logger = Logger.new(Trail::LogFile)
|
7
|
+
Trail.logger = Logger.new(Trail::LogFile, 'daily', 7)
|
8
8
|
Trail.logger.level = 'info' # could be debug, info, warn, error or fatal
|
9
|
-
Trail.current_user_method = :current_user
|
10
|
-
Trail.saving_logs = false
|
9
|
+
Trail.current_user_method = :current_user
|
@@ -1,6 +1,8 @@
|
|
1
1
|
namespace :db do
|
2
2
|
desc "Parse trail log file and save to DB"
|
3
3
|
task :parse_log_and_save_trails => :environment do
|
4
|
-
|
4
|
+
file_name = ENV["FILE_NAME"] || "trail.log"
|
5
|
+
b = Benchmark.measure { QueryableLogs::TrailLog.parse_log_and_save_trails(file_name) }
|
6
|
+
puts "Trail file #{file_name} processed at #{Time.zone.now.strftime('%Y-%m-%d %H:%M')} in: #{'%.4f' % b.total}s"
|
5
7
|
end
|
6
8
|
end
|
@@ -1,33 +1,14 @@
|
|
1
1
|
module QueryableLogs
|
2
2
|
class TrailLog < ActiveRecord::Base
|
3
|
-
serialize :params_hash, JSON
|
4
|
-
|
5
3
|
def self.parse_log_and_save_trails(log_file_name="trail.log")
|
6
|
-
trails_recorded = []
|
7
|
-
lines = []
|
8
|
-
bytes_to_read = 0
|
9
4
|
log_file_path = "#{Rails.root}/log/#{log_file_name}"
|
10
|
-
|
11
|
-
|
12
|
-
File.open(log_file_path, File::RDONLY) do |f|
|
13
|
-
f.flock(File::LOCK_SH)
|
14
|
-
bytes_to_read = File.size(log_file_path)
|
15
|
-
f.flock(File::LOCK_UN)
|
16
|
-
end
|
17
|
-
rescue
|
18
|
-
f.flock(File::LOCK_UN)
|
19
|
-
return
|
20
|
-
end
|
21
|
-
|
22
|
-
return if bytes_to_read == 0
|
23
|
-
|
24
|
-
File.open(log_file_path) do |f|
|
25
|
-
lines = f.read(bytes_to_read).split("\n")
|
26
|
-
end
|
5
|
+
lines = []
|
6
|
+
File.open(log_file_path) { |f| f.each_line { |line| lines << line } }
|
27
7
|
lines.each do |line|
|
28
8
|
next if line.match(/\A# Logfile created on/) != nil
|
29
9
|
if m = line.match(/^I, \[(.+?)\] INFO -- : (.*)$/)
|
30
10
|
request_time_and_pid, log_line = m[1..2]
|
11
|
+
next if TrailLog.where(sig: request_time_and_pid).count > 0
|
31
12
|
log_line = log_line.sub(/ p:(.*)$/, '')
|
32
13
|
log_params = {"p" => $1}
|
33
14
|
log_params = log_params.merge(Hash[log_line.scan(/(\w+):(\S+)/)])
|
@@ -49,27 +30,7 @@ module QueryableLogs
|
|
49
30
|
logged_at: request_time)
|
50
31
|
end
|
51
32
|
end
|
52
|
-
|
53
|
-
if bytes_to_read > 0
|
54
|
-
log_file_ptr = nil
|
55
|
-
begin
|
56
|
-
File.open(log_file_path, "r+") do |f|
|
57
|
-
f.flock(File::LOCK_EX)
|
58
|
-
f.seek(bytes_to_read + 1)
|
59
|
-
fsize = File.size(log_file_path)
|
60
|
-
buffer = f.read(fsize - bytes_to_read)
|
61
|
-
f.seek(0)
|
62
|
-
f.write(buffer)
|
63
|
-
f.truncate(fsize - bytes_to_read)
|
64
|
-
f.flock(File::LOCK_UN)
|
65
|
-
end
|
66
|
-
rescue Exception => e
|
67
|
-
puts "msg = #{e.message}"
|
68
|
-
puts "backtrace = #{e.backtrace}"
|
69
|
-
log_file_ptr&.flock(File::LOCK_UN)
|
70
|
-
return
|
71
|
-
end
|
72
|
-
end
|
33
|
+
QueryableLogs::ParsedTrailLogFile.create(file_name: log_file_name)
|
73
34
|
end
|
74
35
|
end
|
75
36
|
end
|
@@ -9,7 +9,7 @@ module QueryableLogs
|
|
9
9
|
def write_to_trail_log
|
10
10
|
# vid, mid, ip, vrb, url, ctl, act, fmt, res, p (must be last)
|
11
11
|
log_string = "uid:%{user_id} ip:%{ip_address} vrb:%{http_verb} url:%{url} ctl:%{controller} act:%{action} fmt:%{format} res:%{response_code} p:%{params_as_json}" % {
|
12
|
-
user_id: send(Trail.current_user_method).try(:id)
|
12
|
+
user_id: self.respond_to?(Trail.current_user_method) ? send(Trail.current_user_method).try(:id) : '',
|
13
13
|
ip_address: request.remote_ip,
|
14
14
|
http_verb: request.request_method,
|
15
15
|
url: Nokogiri::HTML(request.fullpath).text.strip,
|
@@ -19,19 +19,8 @@ module QueryableLogs
|
|
19
19
|
params_as_json: Nokogiri::HTML(params.to_json).text.strip,
|
20
20
|
response_code: response.code
|
21
21
|
}
|
22
|
-
|
23
|
-
|
24
|
-
begin
|
25
|
-
File.open(JSON.parse(Trail.logger.to_json)["logdev"]["filename"], File::RDWR) do |f|
|
26
|
-
log_file_ptr = f
|
27
|
-
f.flock(File::LOCK_EX)
|
28
|
-
Trail.logger.info(log_string)
|
29
|
-
f.flock(File::LOCK_UN)
|
30
|
-
end
|
31
|
-
rescue Exception => e
|
32
|
-
puts "something went wrong ->>>>> #{e.message} #{e.backtrace}"
|
33
|
-
puts "log_string = #{log_string}"
|
34
|
-
log_file_ptr&.flock(File::LOCK_UN)
|
22
|
+
|
23
|
+
Trail.logger.info(log_string)
|
35
24
|
end
|
36
25
|
end
|
37
26
|
end
|
data/queryable_logs.gemspec
CHANGED
@@ -36,8 +36,9 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
37
37
|
spec.require_paths = ["lib"]
|
38
38
|
|
39
|
-
spec.add_runtime_dependency "
|
40
|
-
spec.
|
41
|
-
spec.add_development_dependency "
|
39
|
+
spec.add_runtime_dependency "activerecord", ">= 4"
|
40
|
+
spec.add_runtime_dependency "activesupport", ">= 4"
|
41
|
+
spec.add_development_dependency "bundler", "~> 2"
|
42
|
+
spec.add_development_dependency "rake", ">= 13.0"
|
42
43
|
spec.add_development_dependency "rspec", "~> 3.0"
|
43
44
|
end
|
metadata
CHANGED
@@ -1,17 +1,31 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: queryable_logs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akshay Takkar
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
16
30
|
requirements:
|
17
31
|
- - ">="
|
@@ -30,28 +44,28 @@ dependencies:
|
|
30
44
|
requirements:
|
31
45
|
- - "~>"
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
47
|
+
version: '2'
|
34
48
|
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
54
|
+
version: '2'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
|
-
- - "
|
59
|
+
- - ">="
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
61
|
+
version: '13.0'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
|
-
- - "
|
66
|
+
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
68
|
+
version: '13.0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rspec
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -115,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
129
|
- !ruby/object:Gem::Version
|
116
130
|
version: '0'
|
117
131
|
requirements: []
|
118
|
-
rubygems_version: 3.
|
132
|
+
rubygems_version: 3.4.1
|
119
133
|
signing_key:
|
120
134
|
specification_version: 4
|
121
135
|
summary: Make logs queryable, just like you would query any other activerecord table
|