snoopit 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +39 -0
  4. data/.idea/.name +1 -0
  5. data/.idea/.rakeTasks +7 -0
  6. data/.idea/dictionaries/rbirch.xml +9 -0
  7. data/.idea/encodings.xml +5 -0
  8. data/.idea/misc.xml +5 -0
  9. data/.idea/modules.xml +9 -0
  10. data/.idea/scopes/scope_settings.xml +5 -0
  11. data/.idea/snoopit.iml +233 -0
  12. data/.idea/vcs.xml +7 -0
  13. data/.rspec +2 -0
  14. data/.travis.yml +7 -0
  15. data/Gemfile +15 -0
  16. data/LICENSE.txt +22 -0
  17. data/README.md +411 -0
  18. data/Rakefile +1 -0
  19. data/bin/snoopit +173 -0
  20. data/lib/snoopit.rb +22 -0
  21. data/lib/snoopit/detected.rb +50 -0
  22. data/lib/snoopit/file_info.rb +104 -0
  23. data/lib/snoopit/file_tracker.rb +83 -0
  24. data/lib/snoopit/logger.rb +30 -0
  25. data/lib/snoopit/notification_manager.rb +123 -0
  26. data/lib/snoopit/notifier.rb +25 -0
  27. data/lib/snoopit/notifiers/email.rb +61 -0
  28. data/lib/snoopit/notifiers/http.rb +85 -0
  29. data/lib/snoopit/notifiers/https.rb +21 -0
  30. data/lib/snoopit/notifiers/stomp.rb +59 -0
  31. data/lib/snoopit/register.rb +69 -0
  32. data/lib/snoopit/sniffer.rb +51 -0
  33. data/lib/snoopit/snooper.rb +149 -0
  34. data/lib/snoopit/snoopy.rb +67 -0
  35. data/lib/snoopit/version.rb +3 -0
  36. data/snoopit.gemspec +27 -0
  37. data/spec/bin/snoopit_spec.rb +258 -0
  38. data/spec/file_info_spec.rb +131 -0
  39. data/spec/file_tracker_spec.rb +172 -0
  40. data/spec/notification_manager_spec.rb +103 -0
  41. data/spec/notifiers/email_spec.rb +36 -0
  42. data/spec/notifiers/http_spec.rb +37 -0
  43. data/spec/notifiers/https_spec.rb +38 -0
  44. data/spec/notifiers/stomp_spec.rb +34 -0
  45. data/spec/register_spec.rb +105 -0
  46. data/spec/snooper_spec.rb +538 -0
  47. data/spec/spec_helper.rb +24 -0
  48. data/spec/support/log/snoop_log.test +593 -0
  49. data/spec/support/log/snoop_log_2.test +593 -0
  50. data/spec/support/multiple_snoopies.json +82 -0
  51. data/spec/support/regexp_tester.rb +10 -0
  52. data/spec/support/snoopies.json +93 -0
  53. data/spec/support/snoopies_notifiers.json +66 -0
  54. data/spec/support/test_notifier.rb +18 -0
  55. data/spec/support/test_notifier_load.rb +18 -0
  56. data/support/snoopies.json +110 -0
  57. metadata +190 -0
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'logger'
4
+ require 'snoopit'
5
+
6
+ options = {}
7
+ options[:snoopies_file]='snoopies.json'
8
+ options[:snoopies] = []
9
+ options[:verbose] = false
10
+ options[:line_numbers] = false
11
+ options[:new_line] = true
12
+ options[:json] = false
13
+ options[:pretty_json] = false
14
+ options[:notifications] = false
15
+ options[:tracking] = false
16
+ options[:tracking_file] = './snoopit_db.json'
17
+
18
+ OptionParser.new do |opts|
19
+
20
+ opts.banner = 'Usage: snoopit [options]'
21
+
22
+ opts.on('-s', '--snoopers snoopies.json', 'File contains one or more regular expressions to locate a line of interest in a file' ) do |snoopies_file|
23
+ options[:snoopies_file] = snoopies_file
24
+ end
25
+
26
+ opts.on('-S', '--snooper snooper_name', 'Only use the named snooper. This option can be used more than once to use several snoopers.' ) do |snooper|
27
+ options[:snoopies] << snooper
28
+ end
29
+
30
+ opts.on('-t', '--template', 'Generate a template snoopies.json file to stdout' ) do
31
+ template = File.expand_path '../../support/snoopies.json', __FILE__
32
+ File.readlines(template).each do |line|
33
+ puts line
34
+ end
35
+ exit
36
+ end
37
+
38
+ opts.on('-T', '--tracking', 'Enable log file tracking using file ./snoopit_db.json') do
39
+ options[:tracking] = true
40
+ end
41
+
42
+ opts.on('-f', '--tracking-file file_name', 'Specify a different tracking file name and location instead of the default ./snoopit_db.json') do |tracking_file|
43
+ options[:tracking] = true
44
+ options[:tracking_file] = tracking_file
45
+ end
46
+
47
+ opts.on('-j', '--json', 'Generate output in json' ) do
48
+ options[:json] = true
49
+ end
50
+
51
+ opts.on('-J', '--pretty-json', 'Generate output in pretty json' ) do
52
+ options[:json] = true
53
+ options[:pretty_json] = true
54
+ end
55
+
56
+ opts.on('-N', '--no-newline', 'Do not output new line between found items' ) do |l|
57
+ options[:new_line] = false
58
+ end
59
+
60
+ opts.on('-n', '--enable-notifications', 'Enable notifications' ) do |n|
61
+ options[:notifications] = true
62
+ end
63
+
64
+ opts.on('-l', '--line-numbers', 'show line numbers' ) do |l|
65
+ options[:line_numbers] = true
66
+ end
67
+
68
+ opts.on_tail('-v', '--verbose', 'prints out file name, matched line number') do
69
+ options[:verbose] = true
70
+ end
71
+
72
+ opts.on_tail('-h', '--help') do
73
+ puts opts
74
+ exit
75
+ end
76
+
77
+ end.parse!
78
+
79
+ def verbose(snoopy_name, sniffed)
80
+ puts ''
81
+ puts "File: #{sniffed.file}"
82
+ puts "Snooper: #{snoopy_name}"
83
+ puts "Match at line number: #{sniffed.line_no}"
84
+ puts "** Sniffed Out ** #{sniffed.match}"
85
+ puts ''
86
+ end
87
+
88
+ def get_start_line_number(sniffed)
89
+ start = sniffed.line_no - sniffed.after.size
90
+ start = 1 if start <= 0
91
+ start
92
+ end
93
+
94
+ def line_before(line_no, sniffed)
95
+ sniffed.before.register.each do |b|
96
+ unless b.nil?
97
+ puts "#{line_no}: #{b}"
98
+ line_no += 1
99
+ end
100
+ end
101
+ line_no
102
+ end
103
+
104
+ def line_after(line_no, sniffed)
105
+ sniffed.after.register.each do |a|
106
+ unless a.nil?
107
+ puts "#{line_no}: #{a}"
108
+ line_no += 1
109
+ end
110
+ end
111
+ line_no
112
+ end
113
+
114
+ def line_numbers(sniffed)
115
+ line_no = get_start_line_number sniffed
116
+ line_no = line_before line_no, sniffed
117
+ puts "#{line_no}: #{sniffed.match}"
118
+ line_no += 1
119
+ line_after line_no, sniffed
120
+ end
121
+
122
+ def no_line_numbers(sniffed)
123
+ sniffed.before.register.each {|b| puts b unless b.nil? }
124
+ puts sniffed.match
125
+ sniffed.after.register.each {|a| puts a unless a.nil? }
126
+ end
127
+
128
+ def dump_lines(snoopies, newline, line_no, is_verbose)
129
+ snoopies.each do |snoopie|
130
+ snoopie.sniffers.each do |sniffer|
131
+ sniffer.sniffed.each do |sniffed|
132
+ verbose snoopie.name, sniffed if is_verbose
133
+ line_no ? line_numbers(sniffed) : no_line_numbers(sniffed)
134
+ puts '' if newline
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ def dump_json(snoopies, pretty=false)
141
+ if pretty
142
+ puts JSON.pretty_generate snoopies
143
+ else
144
+ puts snoopies.to_json
145
+ end
146
+ end
147
+
148
+ if options[:tracking]
149
+ puts "File tracking database: #{options[:tracking_file]}"
150
+ else
151
+ options[:tracking_file] = nil
152
+ end
153
+
154
+ unless File.exist? options[:snoopies_file]
155
+ puts "Snooper json file does not exist: #{options[:snoopies_file]}"
156
+ exit 1
157
+ end
158
+
159
+ #debug_file = File.open(File.expand_path('../../tmp/debug.log', __FILE__), 'w+')
160
+ #snooper = Snoopit::Snooper.new options[:notifications], options[:tracking_file], debug_file, ::Logger::DEBUG
161
+ #snooper = Snoopit::Snooper.new options[:notifications], options[:tracking_file], STDOUT, ::Logger::DEBUG
162
+ snooper = Snoopit::Snooper.new options[:notifications], options[:tracking_file]
163
+ snooper.load_file options[:snoopies_file]
164
+ snoopies = snooper.snoop options[:snoopies]
165
+ if options[:json]
166
+ dump_json snoopies, options[:pretty_json]
167
+ else
168
+ dump_lines snoopies, options[:new_line], options[:line_numbers], options[:verbose]
169
+ end
170
+
171
+
172
+
173
+
@@ -0,0 +1,22 @@
1
+ require 'snoopit/version'
2
+ require 'snoopit/logger'
3
+ require 'snoopit/register'
4
+ require 'snoopit/snooper'
5
+ require 'snoopit/snoopy'
6
+ require 'snoopit/sniffer'
7
+ require 'snoopit/detected'
8
+ require 'snoopit/file_info'
9
+ require 'snoopit/file_tracker'
10
+ require 'snoopit/notification_manager'
11
+ require 'snoopit/notifier'
12
+ require 'snoopit/notifiers/email'
13
+ require 'snoopit/notifiers/http'
14
+ require 'snoopit/notifiers/https'
15
+
16
+ module Snoopit
17
+
18
+ def self.logger
19
+ Snoopit::Logging.logger
20
+ end
21
+
22
+ end
@@ -0,0 +1,50 @@
1
+ module Snoopit
2
+ class Detected
3
+
4
+ attr :comment, :before, :after, :after_count, :regexp, :match, :finished, :file, :line_no
5
+
6
+ def initialize(comment, pre_before, after, match, file, line_no)
7
+ setup_before pre_before
8
+ @comment = comment
9
+ @after_count = 0
10
+ @after = Register.new(after)
11
+ @match = match
12
+ @file = file
13
+ @line_no = line_no
14
+ @finished = false
15
+ end
16
+
17
+ def setup_before(pre_before)
18
+ @before = Register.new pre_before.size, pre_before.register
19
+ end
20
+
21
+ def track(line)
22
+ return if line == @match
23
+ if @after_count < @after.size
24
+ @after.push_front line
25
+ @after_count += 1
26
+ else
27
+ @finished = true
28
+ end
29
+ end
30
+
31
+ def finished?
32
+ @finished
33
+ end
34
+
35
+ def as_json(options=nil)
36
+ {
37
+ after: @after,
38
+ match: @match,
39
+ before: @before,
40
+ file: @file,
41
+ line_no: @line_no
42
+ }
43
+ end
44
+
45
+ def to_json(*a)
46
+ as_json.to_json(*a)
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,104 @@
1
+ require 'time'
2
+
3
+ module Snoopit
4
+ class FileInfo
5
+
6
+ attr_accessor :file, :line_no, :offset, :size, :mtime, :last_line, :init_stat
7
+
8
+ def initialize(file=nil)
9
+ @file = file
10
+ @line_no = 0
11
+ @offset = 0
12
+ @size = 0
13
+ @mtime = nil
14
+ @last_line = nil
15
+ @init_stat = true
16
+ end
17
+
18
+ # Update file Info if the file has changed use the file handle to move the file pointer
19
+ # to the character where reading will start
20
+ #
21
+ # @return [boolean] true if updated false not updated
22
+ def updated?(file_handle)
23
+ c_stat = File.stat @file
24
+ if (c_stat.size == @size) && (c_stat.mtime.to_i == @mtime.to_i) && (! @init_stat)
25
+ Snoopit.logger.debug 'FileTracker.updated? file has not changed: ' + @file
26
+ updated = false
27
+ elsif c_stat.size < @size
28
+ Snoopit.logger.debug 'FileTracker.updated? file size is smaller it is a new new file: ' + @file
29
+ updated = new_file? file_handle, c_stat
30
+ elsif (c_stat.size == @size) && (! @mtime.nil?) && (c_stat.mtime.to_i > @mtime.to_i)
31
+ Snoopit.logger.debug 'FileTracker.updated? file size is same but file time is newer it is a new file: ' + @file
32
+ updated = new_file? file_handle, c_stat
33
+ else
34
+ Snoopit.logger.debug 'FileTracker.updated? reading from last read location: ' + @file
35
+ updated = read_from_last? file_handle, c_stat
36
+ end
37
+ @init_stat = false
38
+ updated
39
+ end
40
+
41
+ def new_file?(file_handle, stat)
42
+ # seek to 0
43
+ Snoopit.logger.debug 'FileTracker.updated? file new read from start of file: ' + @file
44
+ @offset = 0
45
+ @size = stat.size
46
+ @mtime = stat.mtime
47
+ @last_line = nil
48
+ file_handle.seek 0, IO::SEEK_SET
49
+ true
50
+ end
51
+
52
+ def read_from_last?(file_handle, stat)
53
+ # seek to last position + 1
54
+ old_size = @size
55
+ @size = stat.size
56
+ @mtime = stat.mtime
57
+ Snoopit.logger.debug "File pointer at byte: #{file_handle.tell}"
58
+ file_handle.seek old_size, IO::SEEK_SET
59
+ Snoopit.logger.debug "Starting read from byte: #{file_handle.tell} destination byte #{old_size} new size #{@size}"
60
+ true
61
+ end
62
+
63
+ def get_last_line(file_handle)
64
+ line = nil
65
+ unless @last_line.nil?
66
+ Snoopit.logger.debug "File point at byte: #{file_handle.tell}"
67
+ file_handle.seek (-@last_line.bytesize), IO::SEEK_END
68
+ Snoopit.logger.debug "Seeked to byte: #{file_handle.tell}"
69
+ line = file_handle.readline
70
+ end
71
+ line
72
+ end
73
+
74
+ def as_json(*)
75
+ {
76
+ file: @file,
77
+ line_no: @line_no,
78
+ offset: @offset,
79
+ size: @size,
80
+ mtime: @mtime.iso8601,
81
+ last_line: @last_line
82
+ }
83
+ end
84
+
85
+ def to_json(*args)
86
+ as_json.to_json(*args)
87
+ end
88
+
89
+ def from_json(json_str)
90
+ from_hash JSON.parse(json_str)
91
+ end
92
+
93
+ def from_hash(hash)
94
+ @file = hash['file']
95
+ @line_no = hash['line_no']
96
+ @offset = hash['offset']
97
+ @size = hash['size']
98
+ @mtime = Time.parse hash['mtime']
99
+ @last_line = hash['last_line']
100
+ @init_stat = false
101
+ end
102
+
103
+ end
104
+ end
@@ -0,0 +1,83 @@
1
+ module Snoopit
2
+ class FileTracker
3
+
4
+ attr_accessor :files, :db_file
5
+
6
+ def initialize(db_file='./snooper_db.json', remove=false)
7
+ @files = { }
8
+ @db_file = db_file
9
+ if remove
10
+ remove_db @db_file
11
+ else
12
+ load_db @db_file
13
+ end
14
+ end
15
+
16
+ def foreach(file, &block)
17
+ file_info = get_file(file)
18
+ unless file_info.nil?
19
+ read_lines(file_info, block)
20
+ save_db @db_file
21
+ end
22
+ end
23
+
24
+ def get_file(file)
25
+ return nil unless File.exist? file
26
+ @files[file] = FileInfo.new(file) if @files[file].nil?
27
+ @files[file]
28
+ end
29
+
30
+ def read_lines(file_info, block)
31
+ begin
32
+ fh = File.new(file_info.file)
33
+ if file_info.updated? fh
34
+ fh.each_line do |line|
35
+ file_info.offset += line.bytesize
36
+ file_info.line_no += 1
37
+ file_info.last_line = line
38
+ block.call line, file_info.line_no
39
+ end
40
+ end
41
+ ensure
42
+ fh.close
43
+ end
44
+ end
45
+
46
+ def load_db(db_file)
47
+ if (! db_file.nil?) && (File.exist? db_file)
48
+ Snoopit.logger.debug 'Loading from db file: ' + db_file
49
+ hash_db = JSON.parse(IO.read db_file)
50
+ hash_db.each do |key, file_info|
51
+ unless file_info.nil?
52
+ fi = FileInfo.new
53
+ fi.from_hash(file_info)
54
+ @files[key] = fi
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ def save_db(db_file)
61
+ unless db_file.nil?
62
+ File.open db_file, 'w' do |f|
63
+ f.write @files.to_json
64
+ end
65
+ end
66
+ end
67
+
68
+ def remove_db(db_file)
69
+ if (! db_file.nil?) && (File.exist? db_file)
70
+ File.delete db_file
71
+ end
72
+ end
73
+
74
+ def as_json(*)
75
+ { files: @files }
76
+ end
77
+
78
+ def to_json(*args)
79
+ as_json.to_json(*args)
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,30 @@
1
+ require 'logger'
2
+ require 'awesome_print'
3
+
4
+ module Snoopit
5
+ module Logging
6
+
7
+ LEVEL_MAP = {
8
+ info: ::Logger::INFO,
9
+ warn: ::Logger::WARN,
10
+ error: ::Logger::ERROR,
11
+ fatal: ::Logger::FATAL,
12
+ debug: ::Logger::DEBUG
13
+ }
14
+
15
+ def self.create_logger(out=STDOUT, level=::Logger::INFO)
16
+ @logger = ::Logger.new(out)
17
+ @logger.level = level
18
+ @logger
19
+ end
20
+
21
+ def self.logger
22
+ @logger || create_logger
23
+ end
24
+
25
+ def logger
26
+ Snoopit::Logging.logger
27
+ end
28
+
29
+ end
30
+ end