apache_log_tail 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/apache_log_tail.rb +137 -0
  2. metadata +65 -0
@@ -0,0 +1,137 @@
1
+
2
+ # Facilitates reading the most recent additions to a log file.
3
+ #
4
+ # Note that rotation of log files is *not* handled.
5
+ #
6
+ # Example:
7
+ # >> tail = LogTail.new "/var/log/apache2/access.log"
8
+ # >> tail.state_store.path_to_file = "/tmp/my-state.txt" # Optional: there is a default path
9
+ # >> tail.each_new_line {|line| puts line }
10
+ #
11
+ #
12
+ class LogTail
13
+
14
+ def initialize path_to_file
15
+ @path_to_file = path_to_file
16
+ end
17
+
18
+
19
+ # Provides a StateStore object that provides persistent storage of a Hash.
20
+ #
21
+ def state_store
22
+ @state_store ||= FileStateStore.new
23
+ end
24
+
25
+ # Accepts a StateStore object that provides persistent storage of a Hash.
26
+ #
27
+ # Example:
28
+ # >> tail.state_store = MyStateStore.new
29
+ #
30
+ # A StateStore object must provide these methods:
31
+ #
32
+ # - remember( state:Hash)
33
+ # - recall(): Hash
34
+ #
35
+ attr_writer :state_store
36
+
37
+
38
+ def each_new_line path_to_file = @path_to_file
39
+
40
+ # Recall the cursor ( the location in the log file where we left off
41
+ # reading last time)
42
+ state = state_store.recall
43
+ state[:cursor] ||= 0
44
+
45
+ File.open path_to_file do |stream|
46
+ # Move the file reading "head" to the place where we left off reading
47
+ # last time
48
+ stream.seek state[:cursor]
49
+
50
+ stream.each_line {|line| yield line }
51
+
52
+ # Remember where the log file reading cursor is for next time:
53
+ state[:cursor] = stream.tell
54
+ state_store.remember state
55
+ end
56
+ end
57
+
58
+
59
+ # This is the default implementation of StateStore, which stores the state in
60
+ # a file ( by default in /tmp with a static name although this is
61
+ # configurable).
62
+ #
63
+ class FileStateStore
64
+
65
+ def path_to_file
66
+ @path_to_file ||= "/tmp/.apache_log_tail-state.yml"
67
+ end
68
+ attr_writer :path_to_file
69
+
70
+ require "yaml"
71
+
72
+ def recall
73
+ if not File.exists? path_to_file
74
+ {}
75
+ else
76
+ YAML.load File.read( path_to_file)
77
+ end
78
+ end
79
+
80
+ def remember state
81
+ File.open path_to_file, "w" do |file|
82
+ file.write state.to_yaml
83
+ end
84
+ end
85
+
86
+ end # of FileStateStore
87
+
88
+ end
89
+
90
+
91
+ # Note that this class does no parse Apache log entries, only knows how Apache
92
+ # log files are rotated on Debian. I have enjoyed using the apachelogregex gem
93
+ # for parsing.
94
+ #
95
+ class ApacheLogTail < LogTail
96
+
97
+ # Note: This method must be invoked more frequently than the log file
98
+ # rotation period ( typically 1 week) otherwise an entire file will be
99
+ # missed.
100
+ #
101
+ def each_new_line
102
+ state = state_store.recall
103
+ first_line_now = first_line_of @path_to_file
104
+ # If the Apache log file has been rotated..
105
+ # The file has been rotated if it has been read ( cursor is remembered) but
106
+ # the first line is not as remembered
107
+ file_has_been_rotated = lambda { state[:cursor] and first_line_now != state[:first_line] }
108
+ if file_has_been_rotated[]
109
+ # Check that the renamed file is as we expect before reading the rest of it:
110
+ renamed_file = @path_to_file + ".1"
111
+ if first_line_of( renamed_file) != state[:first_line]
112
+ raise StandardError.new "Rotated file could not be found"
113
+ end
114
+ # Process the last lines of the rotated file:
115
+ super renamed_file
116
+ # Reset the cursor ready for the new file:
117
+ state[:cursor] = 0
118
+ end
119
+ if first_line_now != state[:first_line]
120
+ state[:first_line] = first_line_now
121
+ state_store.remember state
122
+ end
123
+ # Process the lines that have since been added to the new file:
124
+ super
125
+ end
126
+
127
+
128
+ private
129
+
130
+ def first_line_of file
131
+ File.open file do |f|
132
+ f.gets
133
+ end
134
+ end
135
+
136
+ end
137
+
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: apache_log_tail
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Neil Stockbridge
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-10-30 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: Presents lines from an Apache log file that were written since the previous invocation. Supports log file rotation.
22
+ email: neil@dist.ro
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - lib/apache_log_tail.rb
31
+ homepage: http://rubygems.org/gems/apache_log_tail
32
+ licenses: []
33
+
34
+ post_install_message:
35
+ rdoc_options: []
36
+
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ hash: 3
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ requirements: []
58
+
59
+ rubyforge_project:
60
+ rubygems_version: 1.8.15
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: Process only the new lines from an Apache log file
64
+ test_files: []
65
+