logmerge 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ All original code copyright 2005 Eric Hodel, The Robot Co-op. All rights
2
+ reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+ 3. Neither the names of the authors nor the names of their contributors
14
+ may be used to endorse or promote products derived from this software
15
+ without specific prior written permission.
16
+
17
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
18
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
21
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
23
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
data/Manifest.txt ADDED
@@ -0,0 +1,14 @@
1
+ LICENSE
2
+ Manifest.txt
3
+ README
4
+ Rakefile
5
+ bin/ip2name
6
+ bin/logmerge
7
+ lib/logmerge.rb
8
+ lib/logmerge/merger.rb
9
+ lib/logmerge/resolv.rb
10
+ lib/logmerge/resolver.rb
11
+ resolv_test
12
+ test/access.log
13
+ test/test_merger.rb
14
+ test/test_resolver.rb
data/README ADDED
@@ -0,0 +1,35 @@
1
+ = logmerge
2
+
3
+ Rubyforge Project:
4
+
5
+ http://rubyforge.org/projects/rctools/
6
+
7
+ == About
8
+
9
+ Logmerge contains two utilities logmerge and ip2name. logmerge merges Apache
10
+ access logs into one log ordered by date. ip2name performs DNS lookups on
11
+ Apache access logs using multiple threads and Ruby's DNS resolver library to
12
+ speed through log files.
13
+
14
+ == Using logmerge
15
+
16
+ Simply pass in all the logs you want to merge on the command line. logmerge
17
+ gives you the merged log on STDOUT.
18
+
19
+ logmerge hal/access.log nestor/access.log herbie/access.log > merged.log
20
+
21
+ Note that logmerge expects the input log files to be ordered by date.
22
+
23
+ == Using ip2name
24
+
25
+ Simply pass in the log files you want to perform DNS lookups on the command
26
+ line or via STDIN. ip2name gives you the looked-up log lines on STDOUT.
27
+
28
+ ip2name < merged.log > resolved.log
29
+
30
+ ip2name merged.log > resolved.log
31
+
32
+ In order to speed DNS lookups, ip2name creates a .name_cache file in the
33
+ current directory. ip2name uses double the DNS record TTL value so
34
+ rapidly-changing names may not be correctly resolved.
35
+
data/Rakefile ADDED
@@ -0,0 +1,63 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+
6
+ $VERBOSE = nil
7
+
8
+ spec = Gem::Specification.new do |s|
9
+ s.name = 'logmerge'
10
+ s.version = '1.0.0'
11
+ s.summary = 'Resolves IP addresses and merges Apache access logs.'
12
+ s.author = 'Eric Hodel'
13
+ s.email = 'eric@robotcoop.com'
14
+
15
+ s.files = File.read('Manifest.txt').split($/)
16
+ s.require_path = 'lib'
17
+
18
+ s.executables = %w[ip2name logmerge]
19
+ end
20
+
21
+ desc 'Run tests'
22
+ task :default => [ :test ]
23
+
24
+ Rake::TestTask.new('test') do |t|
25
+ t.libs << 'test'
26
+ t.verbose = true
27
+ end
28
+
29
+ desc 'Update Manifest.txt'
30
+ task :update_manifest do
31
+ sh "find . -type f | sed -e 's%./%%' | egrep -v 'svn|swp|~' | egrep -v '^(doc|pkg)/' | sort > Manifest.txt"
32
+ end
33
+
34
+ desc 'Generate RDoc'
35
+ Rake::RDocTask.new :rdoc do |rd|
36
+ rd.rdoc_dir = 'doc'
37
+ rd.rdoc_files.add 'lib', 'README', 'LICENSE'
38
+ rd.rdoc_files.exclude '*/resolv.rb' # WTF doesn't this work?
39
+ rd.main = 'README'
40
+ rd.options << '-d' if `which dot` =~ /\/dot/
41
+ end
42
+
43
+ desc 'Generate RDoc for dev.robotcoop.com'
44
+ Rake::RDocTask.new :dev_rdoc do |rd|
45
+ rd.rdoc_dir = '../../../www/trunk/dev/html/Tools/logmerge'
46
+ rd.rdoc_files.add 'lib', 'README', 'LICENSE'
47
+ rd.main = 'README'
48
+ rd.options << '-d' if `which dot` =~ /\/dot/
49
+ end
50
+
51
+ desc 'Build Gem'
52
+ Rake::GemPackageTask.new spec do |pkg|
53
+ pkg.need_tar = true
54
+ end
55
+
56
+ desc 'Clean up'
57
+ task :clean => [ :clobber_rdoc, :clobber_package ]
58
+
59
+ desc 'Clean up'
60
+ task :clobber => [ :clean ]
61
+
62
+ # vim: syntax=Ruby
63
+
data/bin/ip2name ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ require 'logmerge'
4
+
5
+ Thread.abort_on_exception = true
6
+
7
+ LogMerge::IPResolver.resolve
8
+
data/bin/logmerge ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ require 'logmerge'
4
+
5
+ LogMerge::Merger.merge
6
+
@@ -0,0 +1,74 @@
1
+ $TESTING = defined? $TESTING
2
+
3
+ require 'logmerge'
4
+
5
+ ##
6
+ # Merges multiple Apache log files by date.
7
+
8
+ class LogMerge::Merger
9
+
10
+ ##
11
+ # Merges +files+ into +output+. If +files+ is nil, ARGV is used.
12
+
13
+ def self.merge(output = STDOUT, *files)
14
+ files = ARGV if files.empty?
15
+ merger = LogMerge::Merger.new files.map { |file| File.open file }
16
+ merger.merge output
17
+ end
18
+
19
+ ##
20
+ # Creates a new Merger that will operate on an array of IO-like objects
21
+ # +streams+.
22
+
23
+ def initialize(streams)
24
+ @streams = streams
25
+ @buf = []
26
+
27
+ @streams.each_index { |slot| buf_fill slot }
28
+
29
+ @all_closed = @streams.empty?
30
+ end
31
+
32
+ ##
33
+ # Are all the streams closed?
34
+
35
+ def all_closed?
36
+ @all_closed
37
+ end
38
+
39
+ ##
40
+ # Adds a line to the buffer from input strem +slot+.
41
+
42
+ def buf_fill(slot)
43
+ line = @streams[slot].gets
44
+
45
+ if line.nil? and @streams[slot].eof? then
46
+ @streams.delete_at slot
47
+ @buf.delete_at slot
48
+ elsif line.nil? then
49
+ raise "WTF? line.nil? and not eof?"
50
+ else
51
+ line =~ / \[(.+?)\] /
52
+ time = Time.parse($1.sub(':', ' ').gsub('/', '-')).to_i
53
+ @buf[slot] = [time, line]
54
+ end
55
+ end
56
+
57
+ ##
58
+ # Merges streams into +out_stream+.
59
+
60
+ def merge(out_stream)
61
+ index, min, line = nil
62
+
63
+ until @streams.empty? do
64
+ min = @buf.min { |a,b| a.first <=> b.first}
65
+ slot = @buf.index min
66
+ buf_fill slot
67
+ out_stream.puts min.last
68
+ end
69
+
70
+ @all_closed = true
71
+ end
72
+
73
+ end
74
+