log_master 0.1.1
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/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +67 -0
- data/VERSION +1 -0
- data/features/log_master.feature +5 -0
- data/features/step_definitions/email_steps.rb +121 -0
- data/features/step_definitions/log_master_steps.rb +0 -0
- data/features/support/env.rb +6 -0
- data/init.rb +0 -0
- data/lib/log_master/configuration.rb +39 -0
- data/lib/log_master/director.rb +43 -0
- data/lib/log_master/log_file.rb +39 -0
- data/lib/log_master/notifier.rb +37 -0
- data/lib/log_master/rake/log_task.rb +20 -0
- data/lib/log_master.rb +14 -0
- data/lib/templates/log_master/notifier/update_notification.html.erb +59 -0
- data/log_master.gemspec +81 -0
- data/spec/configuration_spec.rb +18 -0
- data/spec/director_spec.rb +27 -0
- data/spec/fixtures/empty_log.log +0 -0
- data/spec/fixtures/log_with_errors.log +6 -0
- data/spec/fixtures/log_without_errors.log +4 -0
- data/spec/log_file_spec.rb +44 -0
- data/spec/notification_spec.rb +69 -0
- data/spec/spec_helper.rb +32 -0
- data/tasks/log_master.rake +18 -0
- metadata +116 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Zachary Belzer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= log_master
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but
|
13
|
+
bump version in a commit by itself I can ignore when I pull)
|
14
|
+
* Send me a pull request. Bonus points for topic branches.
|
15
|
+
|
16
|
+
== Copyright
|
17
|
+
|
18
|
+
Copyright (c) 2009 Zachary Belzer. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + "/lib")
|
5
|
+
require 'log_master/rake/log_task'
|
6
|
+
|
7
|
+
Dir['tasks/*.rake'].each { |rake| load rake }
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'jeweler'
|
11
|
+
Jeweler::Tasks.new do |gem|
|
12
|
+
gem.name = "log_master"
|
13
|
+
gem.summary = %Q{Creates and emails a simple report for a set of log (or text) files. Useful for aggretating small log files.}
|
14
|
+
gem.description = %Q{Creates and emails a simple report for a set of log (or text) files. Useful for aggretating small log files.}
|
15
|
+
gem.email = "zbelzer@gmail.com"
|
16
|
+
gem.homepage = "http://github.com/moneypools/log_master"
|
17
|
+
gem.authors = ["Zachary Belzer"]
|
18
|
+
gem.add_dependency "actionmailer"
|
19
|
+
gem.add_development_dependency "rspec"
|
20
|
+
gem.add_development_dependency "email_spec", " >= 0.3.5"
|
21
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
22
|
+
end
|
23
|
+
Jeweler::GemcutterTasks.new
|
24
|
+
rescue LoadError
|
25
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'spec/rake/spectask'
|
29
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
30
|
+
spec.libs << 'lib' << 'spec'
|
31
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
35
|
+
spec.libs << 'lib' << 'spec'
|
36
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
37
|
+
spec.rcov = true
|
38
|
+
end
|
39
|
+
|
40
|
+
task :spec => :check_dependencies
|
41
|
+
|
42
|
+
begin
|
43
|
+
require 'cucumber/rake/task'
|
44
|
+
Cucumber::Rake::Task.new(:features)
|
45
|
+
|
46
|
+
task :features => :check_dependencies
|
47
|
+
rescue LoadError
|
48
|
+
task :features do
|
49
|
+
abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
task :default => :spec
|
54
|
+
|
55
|
+
require 'rake/rdoctask'
|
56
|
+
Rake::RDocTask.new do |rdoc|
|
57
|
+
if File.exist?('VERSION')
|
58
|
+
version = File.read('VERSION')
|
59
|
+
else
|
60
|
+
version = ""
|
61
|
+
end
|
62
|
+
|
63
|
+
rdoc.rdoc_dir = 'rdoc'
|
64
|
+
rdoc.title = "log_master #{version}"
|
65
|
+
rdoc.rdoc_files.include('README*')
|
66
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
67
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# Commonly used email steps
|
2
|
+
#
|
3
|
+
# To add your own steps make a custom_email_steps.rb
|
4
|
+
# The provided methods are:
|
5
|
+
#
|
6
|
+
# last_email_address
|
7
|
+
# reset_mailer
|
8
|
+
# open_last_email
|
9
|
+
# visit_in_email
|
10
|
+
# unread_emails_for
|
11
|
+
# mailbox_for
|
12
|
+
# current_email
|
13
|
+
# open_email
|
14
|
+
# read_emails_for
|
15
|
+
# find_email
|
16
|
+
#
|
17
|
+
# General form for email scenarios are:
|
18
|
+
# - clear the email queue (done automatically by email_spec)
|
19
|
+
# - execute steps that sends an email
|
20
|
+
# - check the user received an/no/[0-9] emails
|
21
|
+
# - open the email
|
22
|
+
# - inspect the email contents
|
23
|
+
# - interact with the email (e.g. click links)
|
24
|
+
#
|
25
|
+
# The Cucumber steps below are setup in this order.
|
26
|
+
|
27
|
+
module EmailHelpers
|
28
|
+
def current_email_address
|
29
|
+
# Replace with your a way to find your current email. e.g @current_user.email
|
30
|
+
# last_email_address will return the last email address used by email spec to find an email.
|
31
|
+
# Note that last_email_address will be reset after each Scenario.
|
32
|
+
last_email_address || "example@example.com"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
World(EmailHelpers)
|
37
|
+
|
38
|
+
#
|
39
|
+
# Reset the e-mail queue within a scenario.
|
40
|
+
# This is done automatically before each scenario.
|
41
|
+
#
|
42
|
+
|
43
|
+
Given /^(?:a clear email queue|no emails have been sent)$/ do
|
44
|
+
reset_mailer
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Check how many emails have been sent/received
|
49
|
+
#
|
50
|
+
|
51
|
+
Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails?$/ do |address, amount|
|
52
|
+
unread_emails_for(address).size.should == parse_email_count(amount)
|
53
|
+
end
|
54
|
+
|
55
|
+
Then /^(?:I|they|"([^"]*?)") should have (an|no|\d+) emails?$/ do |address, amount|
|
56
|
+
mailbox_for(address).size.should == parse_email_count(amount)
|
57
|
+
end
|
58
|
+
|
59
|
+
# DEPRECATED
|
60
|
+
# The following methods are left in for backwards compatibility and
|
61
|
+
# should be removed by version 0.4.0
|
62
|
+
Then /^(?:I|they|"([^"]*?)") should not receive an email$/ do |address|
|
63
|
+
email_spec_deprecate "The step 'I/they/[email] should not receive an email' is no longer supported.
|
64
|
+
Please use 'I/they/[email] should receive no emails' instead."
|
65
|
+
unread_emails_for(address).size.should == 0
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Accessing emails
|
70
|
+
#
|
71
|
+
|
72
|
+
# Opens the most recently received email
|
73
|
+
When /^(?:I|they|"([^"]*?)") opens? the email$/ do |address|
|
74
|
+
open_email(address)
|
75
|
+
end
|
76
|
+
|
77
|
+
When /^(?:I|they|"([^"]*?)") opens? the email with subject "([^"]*?)"$/ do |address, subject|
|
78
|
+
open_email(address, :with_subject => subject)
|
79
|
+
end
|
80
|
+
|
81
|
+
When /^(?:I|they|"([^"]*?)") opens? the email with text "([^"]*?)"$/ do |address, text|
|
82
|
+
open_email(address, :with_text => text)
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Inspect the Email Contents
|
87
|
+
#
|
88
|
+
|
89
|
+
Then /^(?:I|they) should see "([^"]*?)" in the email subject$/ do |text|
|
90
|
+
current_email.should have_subject(Regexp.new(text))
|
91
|
+
end
|
92
|
+
|
93
|
+
Then /^(?:I|they) should see "([^"]*?)" in the email body$/ do |text|
|
94
|
+
current_email.body.should =~ Regexp.new(text)
|
95
|
+
end
|
96
|
+
|
97
|
+
# DEPRECATED
|
98
|
+
# The following methods are left in for backwards compatibility and
|
99
|
+
# should be removed by version 0.4.0.
|
100
|
+
Then /^(?:I|they) should see "([^"]*?)" in the subject$/ do |text|
|
101
|
+
email_spec_deprecate "The step 'I/they should see [text] in the subject' is no longer supported.
|
102
|
+
Please use 'I/they should see [text] in the email subject' instead."
|
103
|
+
current_email.should have_subject(Regexp.new(text))
|
104
|
+
end
|
105
|
+
Then /^(?:I|they) should see "([^"]*?)" in the email$/ do |text|
|
106
|
+
email_spec_deprecate "The step 'I/they should see [text] in the email' is no longer supported.
|
107
|
+
Please use 'I/they should see [text] in the email body' instead."
|
108
|
+
current_email.body.should =~ Regexp.new(text)
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Interact with Email Contents
|
113
|
+
#
|
114
|
+
|
115
|
+
When /^(?:I|they) follow "([^"]*?)" in the email$/ do |link|
|
116
|
+
visit_in_email(link)
|
117
|
+
end
|
118
|
+
|
119
|
+
When /^(?:I|they) click the first link in the email$/ do
|
120
|
+
click_first_link_in_email
|
121
|
+
end
|
File without changes
|
data/init.rb
ADDED
File without changes
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module LogMaster
|
4
|
+
class Configuration
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
attr_accessor :title, :reporting
|
8
|
+
|
9
|
+
# These are options that directly affect the email
|
10
|
+
attr_accessor :recipients, :from, :reply_to
|
11
|
+
|
12
|
+
@@configured = false
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
reset
|
16
|
+
end
|
17
|
+
|
18
|
+
def reset
|
19
|
+
@title = "No Title"
|
20
|
+
@reporting = {}
|
21
|
+
|
22
|
+
@@configured = false
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.configure
|
26
|
+
yield instance
|
27
|
+
@@configured = true
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.configured?
|
31
|
+
@@configured === true
|
32
|
+
end
|
33
|
+
|
34
|
+
# For testing purposes
|
35
|
+
def reset_configured_status!
|
36
|
+
@@configured = false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../log_master"
|
2
|
+
|
3
|
+
module LogMaster
|
4
|
+
class Director
|
5
|
+
|
6
|
+
attr_accessor :reports, :logs
|
7
|
+
|
8
|
+
def initialize(files)
|
9
|
+
raise "LogMaster has not yet been configured" unless Configuration.configured?
|
10
|
+
|
11
|
+
create_log_files(files)
|
12
|
+
@reports = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
aggregate!
|
17
|
+
send_email
|
18
|
+
end
|
19
|
+
|
20
|
+
def aggregate!
|
21
|
+
logs.each do |l|
|
22
|
+
l.analyze.each do |name, value|
|
23
|
+
@reports[name] ||= 0
|
24
|
+
@reports[name] += value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def status
|
30
|
+
@reports[:fatal] == 0 && @reports[:error] == 0
|
31
|
+
end
|
32
|
+
|
33
|
+
def send_email
|
34
|
+
Notifier.deliver_update_notification(status, @reports, @logs)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def create_log_files(files)
|
39
|
+
files = files.respond_to?(:each) ? files : [files]
|
40
|
+
@logs = files.map { |f| LogFile.new(f, Configuration.instance.reporting) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module LogMaster
|
2
|
+
class LogFile
|
3
|
+
attr_accessor :file_path
|
4
|
+
|
5
|
+
def initialize(file_path, reporting_configuration={})
|
6
|
+
@file_path = file_path
|
7
|
+
@reporting_configuration = reporting_configuration
|
8
|
+
end
|
9
|
+
|
10
|
+
def analyze
|
11
|
+
reports = @reporting_configuration.keys.inject({}) {|h,l| h.merge(l => 0)}
|
12
|
+
|
13
|
+
if log_file_exists?
|
14
|
+
@reporting_configuration.each do |report_name, report_regexp|
|
15
|
+
reports[report_name] = body.scan(report_regexp).size
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
reports
|
20
|
+
end
|
21
|
+
|
22
|
+
def file_name
|
23
|
+
File.basename(file_path)
|
24
|
+
end
|
25
|
+
|
26
|
+
def valid?
|
27
|
+
log_file_exists?
|
28
|
+
end
|
29
|
+
|
30
|
+
def body
|
31
|
+
log_file_exists? ? File.read(file_path) : "File Missing"
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def log_file_exists?
|
36
|
+
File.exists?(file_path)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module LogMaster
|
2
|
+
class Notifier < ActionMailer::Base
|
3
|
+
helper_method :stylize_output
|
4
|
+
|
5
|
+
def update_notification(status, reports, logs)
|
6
|
+
@status = status
|
7
|
+
@configuration = Configuration.instance
|
8
|
+
|
9
|
+
subject create_subject
|
10
|
+
recipients determine_recipients
|
11
|
+
reply_to @configuration.reply_to || @configuration.from
|
12
|
+
from @configuration.from
|
13
|
+
content_type "text/html"
|
14
|
+
sent_on Time.now
|
15
|
+
body :title => @configuration.title, :logs => logs, :reports => reports
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def create_subject
|
20
|
+
@configuration.title + (@status ? " SUCCESSFUL" : " FAILED")
|
21
|
+
end
|
22
|
+
|
23
|
+
def determine_recipients
|
24
|
+
@status ? @configuration.recipients[:success] : @configuration.recipients[:failure]
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def stylize_output(line)
|
30
|
+
@configuration.reporting.each do |name, regexp|
|
31
|
+
return name if line =~ regexp
|
32
|
+
end
|
33
|
+
|
34
|
+
"info"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'log_master'
|
2
|
+
|
3
|
+
module LogMaster
|
4
|
+
module Rake
|
5
|
+
class LogTask < ::Rake::Task
|
6
|
+
attr_accessor :log_pattern
|
7
|
+
|
8
|
+
protected
|
9
|
+
def execute(*args)
|
10
|
+
super
|
11
|
+
run_log_master
|
12
|
+
end
|
13
|
+
|
14
|
+
def run_log_master
|
15
|
+
files = Dir[log_pattern]
|
16
|
+
LogMaster::Director.new(files).run
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/log_master.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
begin
|
2
|
+
require 'actionmailer'
|
3
|
+
rescue LoadError
|
4
|
+
warn 'To use LogMaster you need the actionmailer gem:'
|
5
|
+
warn '$ sudo gem install actionmailer'
|
6
|
+
raise
|
7
|
+
end
|
8
|
+
|
9
|
+
ActionMailer::Base.template_root = File.dirname(__FILE__) + "/templates"
|
10
|
+
|
11
|
+
require 'log_master/configuration'
|
12
|
+
require 'log_master/director'
|
13
|
+
require 'log_master/log_file'
|
14
|
+
require 'log_master/notifier'
|
@@ -0,0 +1,59 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><%= @subject %></title>
|
5
|
+
<style type="text/css">
|
6
|
+
.pre {
|
7
|
+
white-space: pre;
|
8
|
+
font-family: monospace;
|
9
|
+
font-size: small;
|
10
|
+
}
|
11
|
+
|
12
|
+
.info {
|
13
|
+
color: black;
|
14
|
+
}
|
15
|
+
|
16
|
+
.fatal {
|
17
|
+
color: red;
|
18
|
+
}
|
19
|
+
|
20
|
+
.error {
|
21
|
+
color: red;
|
22
|
+
}
|
23
|
+
|
24
|
+
.warn {
|
25
|
+
color: blue;
|
26
|
+
}
|
27
|
+
|
28
|
+
.log {
|
29
|
+
font-family: monospace;
|
30
|
+
font-weight: bold;
|
31
|
+
margin-bottom: 3px;
|
32
|
+
}
|
33
|
+
</style>
|
34
|
+
</head>
|
35
|
+
<body>
|
36
|
+
<h2>
|
37
|
+
<%= @title %>
|
38
|
+
</h2>
|
39
|
+
<p>
|
40
|
+
<% @reports.each do |name, count| %>
|
41
|
+
<strong class="<%= name %>"><%= name.to_s.titleize %>: </strong><%= count %><br />
|
42
|
+
<% end %>
|
43
|
+
</p>
|
44
|
+
|
45
|
+
<hr />
|
46
|
+
|
47
|
+
<% @logs.each do |log| -%>
|
48
|
+
<div class="log"><%= log.file_name %></div>
|
49
|
+
|
50
|
+
<div class="pre">
|
51
|
+
<% log.body.each do |line| -%>
|
52
|
+
<span class="<%= stylize_output(line) %>"><%= line.chomp -%></span>
|
53
|
+
<% end -%>
|
54
|
+
</div>
|
55
|
+
|
56
|
+
<hr />
|
57
|
+
<% end -%>
|
58
|
+
</body>
|
59
|
+
</html>
|
data/log_master.gemspec
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{log_master}
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Zachary Belzer"]
|
12
|
+
s.date = %q{2009-12-02}
|
13
|
+
s.description = %q{Creates and emails a simple report for a set of log (or text) files. Useful for aggretating small log files.}
|
14
|
+
s.email = %q{zbelzer@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"features/log_master.feature",
|
27
|
+
"features/step_definitions/email_steps.rb",
|
28
|
+
"features/step_definitions/log_master_steps.rb",
|
29
|
+
"features/support/env.rb",
|
30
|
+
"init.rb",
|
31
|
+
"lib/log_master.rb",
|
32
|
+
"lib/log_master/configuration.rb",
|
33
|
+
"lib/log_master/director.rb",
|
34
|
+
"lib/log_master/log_file.rb",
|
35
|
+
"lib/log_master/notifier.rb",
|
36
|
+
"lib/log_master/rake/log_task.rb",
|
37
|
+
"lib/templates/log_master/notifier/update_notification.html.erb",
|
38
|
+
"log_master.gemspec",
|
39
|
+
"spec/configuration_spec.rb",
|
40
|
+
"spec/director_spec.rb",
|
41
|
+
"spec/fixtures/empty_log.log",
|
42
|
+
"spec/fixtures/log_with_errors.log",
|
43
|
+
"spec/fixtures/log_without_errors.log",
|
44
|
+
"spec/log_file_spec.rb",
|
45
|
+
"spec/notification_spec.rb",
|
46
|
+
"spec/spec_helper.rb",
|
47
|
+
"tasks/log_master.rake"
|
48
|
+
]
|
49
|
+
s.homepage = %q{http://github.com/moneypools/log_master}
|
50
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
51
|
+
s.require_paths = ["lib"]
|
52
|
+
s.rubygems_version = %q{1.3.5}
|
53
|
+
s.summary = %q{Creates and emails a simple report for a set of log (or text) files. Useful for aggretating small log files.}
|
54
|
+
s.test_files = [
|
55
|
+
"spec/configuration_spec.rb",
|
56
|
+
"spec/director_spec.rb",
|
57
|
+
"spec/log_file_spec.rb",
|
58
|
+
"spec/notification_spec.rb",
|
59
|
+
"spec/spec_helper.rb"
|
60
|
+
]
|
61
|
+
|
62
|
+
if s.respond_to? :specification_version then
|
63
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
64
|
+
s.specification_version = 3
|
65
|
+
|
66
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
67
|
+
s.add_runtime_dependency(%q<actionmailer>, [">= 0"])
|
68
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
69
|
+
s.add_development_dependency(%q<email_spec>, [">= 0.3.5"])
|
70
|
+
else
|
71
|
+
s.add_dependency(%q<actionmailer>, [">= 0"])
|
72
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
73
|
+
s.add_dependency(%q<email_spec>, [">= 0.3.5"])
|
74
|
+
end
|
75
|
+
else
|
76
|
+
s.add_dependency(%q<actionmailer>, [">= 0"])
|
77
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
78
|
+
s.add_dependency(%q<email_spec>, [">= 0.3.5"])
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
module LogMaster
|
4
|
+
describe "Configuration" do
|
5
|
+
|
6
|
+
describe "configured?" do
|
7
|
+
it "should be false if .confgure has not been called" do
|
8
|
+
Configuration.instance.reset_configured_status!
|
9
|
+
Configuration.should_not be_configured
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should be false if .confgure has not been called" do
|
13
|
+
Configuration.configure {|c|}
|
14
|
+
Configuration.should be_configured
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
module LogMaster
|
4
|
+
describe "Director" do
|
5
|
+
before do
|
6
|
+
@files = %w(log_without_errors.log log_with_errors.log).map {|f| log_file_path(f) }
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should create a LogFile for each file given" do
|
10
|
+
Director.new(@files).logs.size.should == @files.size
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should raise error if not configured" do
|
14
|
+
Configuration.instance.reset_configured_status!
|
15
|
+
lambda {Director.new(@files)}.should raise_error
|
16
|
+
Configuration.configure {|c|} # Reset configured state
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "aggregate" do
|
20
|
+
it "should add the specs for all reports" do
|
21
|
+
log_master = Director.new(@files)
|
22
|
+
log_master.aggregate!
|
23
|
+
log_master.reports[:error].should == 2
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
File without changes
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
module LogMaster
|
4
|
+
describe "LogFile" do
|
5
|
+
before(:all) do
|
6
|
+
@log_with_errors_path = log_file_path("log_with_errors.log")
|
7
|
+
@log_without_errors_path = log_file_path("log_without_errors.log")
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "analyze!" do
|
11
|
+
it "should count the number of errors in the file according to provided regexp" do
|
12
|
+
log_file = LogFile.new(@log_with_errors_path, {:error => /ERROR/ })
|
13
|
+
log_file.analyze[:error].should == 2
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should find no errors in provided file" do
|
17
|
+
log_file = LogFile.new(@log_without_errors_path, {:error => /ERROR/ })
|
18
|
+
log_file.analyze[:error].should be_zero
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "valid?" do
|
23
|
+
it "should be true if file present and no other conditions on validity" do
|
24
|
+
log_file = LogFile.new(@log_without_errors_path)
|
25
|
+
log_file.should be_valid
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be false when file is absent" do
|
29
|
+
log_file = LogFile.new('log_that_does_not_exist.log')
|
30
|
+
log_file.should_not be_valid
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "body" do
|
35
|
+
it "should be 'File Missing' if file does not exist" do
|
36
|
+
LogFile.new('log_that_does_not_exist.log').body.should == "File Missing"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should be the log's data" do
|
40
|
+
LogFile.new(@log_without_errors_path).body.should == File.read(FIXTURES_DIR + "/log_without_errors.log")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
module LogMaster
|
4
|
+
describe "Notification email" do
|
5
|
+
it "should be set to be delivered to success@example.com when successful" do
|
6
|
+
email = Notifier.deliver_update_notification(true, {}, [])
|
7
|
+
email.should deliver_to("success@example.com")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should be set to be delivered to success@example.com when failure" do
|
11
|
+
email = Notifier.deliver_update_notification(false, {}, [])
|
12
|
+
email.should deliver_to("failure@example.com")
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "body" do
|
16
|
+
it "should contain the title" do
|
17
|
+
email = Notifier.deliver_update_notification(true, {}, [])
|
18
|
+
email.should have_body_text(Configuration.instance.title)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should contain the aggregate report" do
|
22
|
+
email = Notifier.deliver_update_notification(true, {:error => 1, :warn => 2, :fatal => 0}, [])
|
23
|
+
email.should have_body_text(/Error:.*1/)
|
24
|
+
email.should have_body_text(/Warn:.*2/)
|
25
|
+
email.should have_body_text(/Fatal:.*0/)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should contain each of the provided logfiles" do
|
29
|
+
log_1 = LogFile.new('log_without_errors.log')
|
30
|
+
log_2 = LogFile.new('log_with_errors.log')
|
31
|
+
email = Notifier.deliver_update_notification(true, {}, [log_1, log_2])
|
32
|
+
|
33
|
+
log_1.body.each do |line|
|
34
|
+
email.should have_body_text(line.chomp)
|
35
|
+
end
|
36
|
+
|
37
|
+
log_2.body.each do |line|
|
38
|
+
email.should have_body_text(line.chomp)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should warn that the file does not exist" do
|
43
|
+
log_file = LogFile.new('fake_log.log')
|
44
|
+
email = Notifier.deliver_update_notification(true, {}, [log_file])
|
45
|
+
email.should have_body_text("File Missing")
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should wrap lines in their respective classes" do
|
49
|
+
log_file = LogFile.new(log_file_path('log_with_errors.log'), {:warn => /WARN/, :error => /ERROR/, :fatal => /FATAL/})
|
50
|
+
email = Notifier.deliver_update_notification(true, {}, [log_file])
|
51
|
+
email.should have_body_text(/class="error".*ERROR/)
|
52
|
+
email.should have_body_text(/class="info".*Not an error/)
|
53
|
+
email.should have_body_text(/class="fatal".*FATAL Oh Noes!/)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "subject" do
|
58
|
+
it "should contain successful message when successful" do
|
59
|
+
email = Notifier.deliver_update_notification(true, {}, [])
|
60
|
+
email.should have_subject(/SUCCESSFUL/)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should contain failure message when failure" do
|
64
|
+
email = Notifier.deliver_update_notification(false, {}, [])
|
65
|
+
email.should have_subject(/FAILED/)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'rubygems'
|
4
|
+
require 'log_master'
|
5
|
+
require 'spec'
|
6
|
+
require 'spec/autorun'
|
7
|
+
|
8
|
+
require "email_spec"
|
9
|
+
require "email_spec/helpers"
|
10
|
+
require "email_spec/matchers"
|
11
|
+
|
12
|
+
require File.dirname(__FILE__) + '/../lib/log_master'
|
13
|
+
|
14
|
+
FIXTURES_DIR = File.dirname(__FILE__) + "/fixtures"
|
15
|
+
|
16
|
+
ActionMailer::Base.delivery_method = :test
|
17
|
+
# ActionMailer::Base.logger = Logger.new('test.log')
|
18
|
+
|
19
|
+
LogMaster::Configuration.configure do |config|
|
20
|
+
config.title = "Testing LogMaster"
|
21
|
+
config.reporting = {:warn => /WARN/, :error => /ERROR/, :fatal => /FATAL/}
|
22
|
+
config.recipients = {:success => "success@example.com", :failure => "failure@example.com"}
|
23
|
+
end
|
24
|
+
|
25
|
+
Spec::Runner.configure do |config|
|
26
|
+
config.include(EmailSpec::Helpers)
|
27
|
+
config.include(EmailSpec::Matchers)
|
28
|
+
end
|
29
|
+
|
30
|
+
def log_file_path(path)
|
31
|
+
File.join(FIXTURES_DIR, path)
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
namespace :log_master do
|
2
|
+
task :configure do
|
3
|
+
require 'action_mailer'
|
4
|
+
ActionMailer::Base.delivery_method = :sendmail
|
5
|
+
|
6
|
+
LogMaster::Configuration.configure do |config|
|
7
|
+
config.title = "This is a sample email"
|
8
|
+
config.recipients = {:success => 'localhost', :failure => 'localhost' }
|
9
|
+
config.reporting = {:warn => /WARN/, :error => /ERROR/, :fatal => /FATAL/}
|
10
|
+
config.reply_to = "sender@example.com"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Runs log master on specified log file"
|
15
|
+
LogMaster::Rake::LogTask.define_task "test" => :configure do |t|
|
16
|
+
t.log_pattern = ENV['log_pattern'] || "spec/fixtures/log_with_errors.log"
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: log_master
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Zachary Belzer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-02 00:00:00 -06:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: actionmailer
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: email_spec
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.3.5
|
44
|
+
version:
|
45
|
+
description: Creates and emails a simple report for a set of log (or text) files. Useful for aggretating small log files.
|
46
|
+
email: zbelzer@gmail.com
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- LICENSE
|
53
|
+
- README.rdoc
|
54
|
+
files:
|
55
|
+
- .document
|
56
|
+
- .gitignore
|
57
|
+
- LICENSE
|
58
|
+
- README.rdoc
|
59
|
+
- Rakefile
|
60
|
+
- VERSION
|
61
|
+
- features/log_master.feature
|
62
|
+
- features/step_definitions/email_steps.rb
|
63
|
+
- features/step_definitions/log_master_steps.rb
|
64
|
+
- features/support/env.rb
|
65
|
+
- init.rb
|
66
|
+
- lib/log_master.rb
|
67
|
+
- lib/log_master/configuration.rb
|
68
|
+
- lib/log_master/director.rb
|
69
|
+
- lib/log_master/log_file.rb
|
70
|
+
- lib/log_master/notifier.rb
|
71
|
+
- lib/log_master/rake/log_task.rb
|
72
|
+
- lib/templates/log_master/notifier/update_notification.html.erb
|
73
|
+
- log_master.gemspec
|
74
|
+
- spec/configuration_spec.rb
|
75
|
+
- spec/director_spec.rb
|
76
|
+
- spec/fixtures/empty_log.log
|
77
|
+
- spec/fixtures/log_with_errors.log
|
78
|
+
- spec/fixtures/log_without_errors.log
|
79
|
+
- spec/log_file_spec.rb
|
80
|
+
- spec/notification_spec.rb
|
81
|
+
- spec/spec_helper.rb
|
82
|
+
- tasks/log_master.rake
|
83
|
+
has_rdoc: true
|
84
|
+
homepage: http://github.com/moneypools/log_master
|
85
|
+
licenses: []
|
86
|
+
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options:
|
89
|
+
- --charset=UTF-8
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: "0"
|
97
|
+
version:
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: "0"
|
103
|
+
version:
|
104
|
+
requirements: []
|
105
|
+
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 1.3.5
|
108
|
+
signing_key:
|
109
|
+
specification_version: 3
|
110
|
+
summary: Creates and emails a simple report for a set of log (or text) files. Useful for aggretating small log files.
|
111
|
+
test_files:
|
112
|
+
- spec/configuration_spec.rb
|
113
|
+
- spec/director_spec.rb
|
114
|
+
- spec/log_file_spec.rb
|
115
|
+
- spec/notification_spec.rb
|
116
|
+
- spec/spec_helper.rb
|