SheepDog 0.1.0.20110705 → 0.2.0.20120314
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +2 -1
- data/ChangeLog +22 -1
- data/LICENSE +1 -1
- data/README +2 -5
- data/ReleaseInfo +3 -3
- data/bin/sheepdog.rb +6 -6
- data/lib/sheepdog/Common.rb +33 -0
- data/lib/sheepdog/Executor.rb +167 -135
- data/lib/sheepdog/Monitors/LogFile.rb +21 -12
- data/lib/sheepdog/Monitors/Process.rb +20 -10
- data/lib/sheepdog/Monitors/Top.rb +63 -0
- data/lib/sheepdog/Notifiers/SendMail.rb +5 -4
- data/lib/sheepdog/Notifiers/StdOut.rb +5 -4
- data/lib/sheepdog/Report.rb +6 -6
- data/sheepdog.conf.rb.example +24 -1
- metadata +22 -7
data/AUTHORS
CHANGED
data/ChangeLog
CHANGED
@@ -1,4 +1,25 @@
|
|
1
|
-
=
|
1
|
+
= SheepDog Release History
|
2
|
+
|
3
|
+
== 0.2.0.20120314 (Alpha)
|
4
|
+
|
5
|
+
* Added rUtilAnts dependency in the release file.
|
6
|
+
* Adapted release info to last version of Ruby Packager.
|
7
|
+
* Removed rdoc warning in documentation.
|
8
|
+
* Adapted to Ruby's standard conventions.
|
9
|
+
* Updated Copyright information.
|
10
|
+
* Updated email address of Muriel Salvan.
|
11
|
+
* Adapted comments to match a better RDoc syntax.
|
12
|
+
* Adapted to new version of rUtilAnts.
|
13
|
+
* Adding possibility to add conditions to monitors.
|
14
|
+
* Added a common file that can define common methods.
|
15
|
+
* Added Monitors/Top to monitor global values returned by top command (configuration example file modified).
|
16
|
+
* Monitors/LogFile: Increased robustness in case of a previous SheepDog crash.
|
17
|
+
* Monitors/LogFile: Added possibility to not specify a filter in logs parsing.
|
18
|
+
* Monitors/Process: Added possibility to monitor resident memory per process (example configuration file updated).
|
19
|
+
* Bug correction: Notifiers/SendMail: Multi reports were sending only the last report.
|
20
|
+
* Bug correction: Notifiers/StdOut: Multi reports were sending only the last report.
|
21
|
+
* Bug correction: Notifiers/SendMail: Notifications could not be sent when grouped.
|
22
|
+
* Bug correction: Notifiers/StdOut: Notifications could not be sent when grouped.
|
2
23
|
|
3
24
|
== 0.1.0.20110705 (Alpha)
|
4
25
|
|
data/LICENSE
CHANGED
@@ -6,7 +6,7 @@ This list is found in the file named AUTHORS.
|
|
6
6
|
The AUTHORS and LICENSE files have to be included in any release of software
|
7
7
|
embedding source code of this package, or using it as a derivative software.
|
8
8
|
|
9
|
-
Copyright (c) 2011 Muriel Salvan (
|
9
|
+
Copyright (c) 2011 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
10
10
|
|
11
11
|
Redistribution and use in source and binary forms, with or without
|
12
12
|
modification, are permitted provided that the following conditions are met:
|
data/README
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
-- This file is best viewed when processed by rdoc.
|
2
|
-
++
|
3
|
-
|
4
1
|
= Sheep Dog
|
5
2
|
|
6
3
|
Simple command line tool that monitors files and processes and sends notifications or take corrective actions when problems arise. Monitor log files for errors, processes CPU and memory consumption (can kill if exceeding), respawn dead processes.
|
@@ -11,8 +8,8 @@ Check the website at http://sheepdogsys.sourceforge.net
|
|
11
8
|
|
12
9
|
== Who wrote it ?
|
13
10
|
|
14
|
-
Check the AUTHORS[link:
|
11
|
+
Check the AUTHORS[link:AUTHORS.html] file.
|
15
12
|
|
16
13
|
== What is the license ?
|
17
14
|
|
18
|
-
You can find out in the LICENSE[link:
|
15
|
+
You can find out in the LICENSE[link:LICENSE.html] file.
|
data/ReleaseInfo
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# This file has been generated by RubyPackager during a delivery.
|
3
3
|
# More info about RubyPackager: http://rubypackager.sourceforge.net
|
4
4
|
{
|
5
|
-
:
|
6
|
-
:
|
7
|
-
:
|
5
|
+
:version => '0.2.0.20120314',
|
6
|
+
:tags => [ 'Alpha' ],
|
7
|
+
:dev_status => 'Alpha'
|
8
8
|
}
|
data/bin/sheepdog.rb
CHANGED
@@ -1,24 +1,24 @@
|
|
1
1
|
#!/bin/env ruby
|
2
2
|
#--
|
3
|
-
# Copyright (c) 2011 Muriel Salvan (
|
3
|
+
# Copyright (c) 2011 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
4
4
|
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
5
5
|
#++
|
6
6
|
|
7
7
|
require 'rUtilAnts/Logging'
|
8
|
-
RUtilAnts::Logging::
|
8
|
+
RUtilAnts::Logging::install_logger_on_object
|
9
9
|
require 'tmpdir'
|
10
10
|
lLogFile = "#{Dir.tmpdir}/SheepDog_#{Process.pid}.log"
|
11
|
-
|
12
|
-
|
11
|
+
set_log_file(lLogFile)
|
12
|
+
log_info 'Starting SheepDog'
|
13
13
|
require 'sheepdog/Executor'
|
14
14
|
|
15
15
|
lConfFileName = ARGV[0]
|
16
16
|
if (lConfFileName == nil)
|
17
|
-
|
17
|
+
log_err "Usage: sheepdog.rb <ConfigFileName>"
|
18
18
|
elsif (File.exists?(lConfFileName))
|
19
19
|
SheepDog::Executor.new.execute(eval(File.read(lConfFileName)))
|
20
20
|
else
|
21
|
-
|
21
|
+
log_err "Missing file: #{lConfFileName}"
|
22
22
|
end
|
23
23
|
|
24
24
|
File.unlink(lLogFile)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2011 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
module SheepDog
|
7
|
+
|
8
|
+
module Common
|
9
|
+
|
10
|
+
# Convert a string representing a memory quantity to its integer value.
|
11
|
+
# Useful to decode top output, that uses k and m for its quantities.
|
12
|
+
#
|
13
|
+
# Parameters::
|
14
|
+
# * *iStrValue* (_String_): The value as a string
|
15
|
+
# Return::
|
16
|
+
# * _Integer_: Corresponding value
|
17
|
+
def quantity2Int(iStrValue)
|
18
|
+
rResult = nil
|
19
|
+
|
20
|
+
if (iStrValue[-1..-1] == 'k')
|
21
|
+
rResult = iStrValue[0..-2].to_i * 1024
|
22
|
+
elsif (iStrValue[-1..-1] == 'm')
|
23
|
+
rResult = iStrValue[0..-2].to_i * 1024 * 1024
|
24
|
+
else
|
25
|
+
rResult = iStrValue.to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
return rResult
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/lib/sheepdog/Executor.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2011 Muriel Salvan (
|
2
|
+
# Copyright (c) 2011 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
3
|
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
4
|
#++
|
5
5
|
|
6
6
|
require 'time'
|
7
7
|
require 'fileutils'
|
8
|
+
require 'sheepdog/Common'
|
8
9
|
require 'sheepdog/Report'
|
9
10
|
|
10
11
|
module SheepDog
|
@@ -15,14 +16,14 @@ module SheepDog
|
|
15
16
|
def initialize
|
16
17
|
# Parse plugins
|
17
18
|
require 'rUtilAnts/Plugins'
|
18
|
-
RUtilAnts::Plugins::
|
19
|
-
|
20
|
-
|
19
|
+
RUtilAnts::Plugins::install_plugins_on_object
|
20
|
+
parse_plugins_from_dir('Notifiers', "#{File.expand_path(File.dirname(__FILE__))}/Notifiers", 'SheepDog::Notifiers')
|
21
|
+
parse_plugins_from_dir('Monitors', "#{File.expand_path(File.dirname(__FILE__))}/Monitors", 'SheepDog::Monitors')
|
21
22
|
end
|
22
23
|
|
23
24
|
# Execute a given configuration
|
24
25
|
#
|
25
|
-
# Parameters
|
26
|
+
# Parameters::
|
26
27
|
# * *iConf* (<em>map<Symbol,Object></em>): The sheep dog configuration
|
27
28
|
def execute(iConf)
|
28
29
|
# Get the local database, storing dates of last reports sent...
|
@@ -49,125 +50,73 @@ module SheepDog
|
|
49
50
|
lDelayedReports = {}
|
50
51
|
# Loop through the objects to monitor
|
51
52
|
iConf[:Monitors].each do |iMonitorName, iMonitorInfo|
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
#
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
53
|
+
# First check if conditions are met
|
54
|
+
if ((iMonitorInfo[:Conditions] == nil) or
|
55
|
+
(checkConditions(iMonitorInfo[:Conditions])))
|
56
|
+
# Check that it is a known monitor, by accessing the plugin
|
57
|
+
lMonitorPluginInstance, lError = get_plugin_instance('Monitors', iMonitorInfo[:Type])
|
58
|
+
if (lMonitorPluginInstance == nil)
|
59
|
+
# Unknown monitor
|
60
|
+
log_err "Unknown Monitor #{iMonitorInfo[:Type]}: #{lError}. Ignoring corresponding monitoring process. Please check configuration."
|
61
|
+
else
|
62
|
+
# Create the report to be filled by this process
|
63
|
+
lReport = Report.new
|
64
|
+
# Create the monitor configuration dir
|
65
|
+
lMonitorDir = "#{iConf[:WorkingDir]}/#{iMonitorName}"
|
66
|
+
FileUtils::mkdir_p(lMonitorDir)
|
67
|
+
# Set instance variables and methods for this monitor
|
68
|
+
lMonitorPluginInstance.instance_variable_set(:@SheepDogConf, iConf)
|
69
|
+
lMonitorPluginInstance.instance_variable_set(:@Report, lReport)
|
70
|
+
lMonitorPluginInstance.instance_variable_set(:@MonitorDir, lMonitorDir)
|
71
|
+
if (!lMonitorPluginInstance.respond_to?(:report))
|
72
|
+
# Report an entry
|
73
|
+
#
|
74
|
+
# Parameters::
|
75
|
+
# * *iEntry* (_String_): Entry to be reported
|
76
|
+
def lMonitorPluginInstance.report(iEntry)
|
77
|
+
@Report.addEntry(iEntry)
|
78
|
+
log_info "Report: #{iEntry}"
|
79
|
+
end
|
75
80
|
end
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
report "!!! Exception while executing monitor #{iMonitorName}: #{$!}.\n#{$!.backtrace.join("\n")}"
|
84
|
-
end
|
85
|
-
# If this report is not empty, save it in a file
|
86
|
-
lCurrentReportFileName = nil
|
87
|
-
lCurrentReportTime = nil
|
88
|
-
if (!lReport.empty?)
|
89
|
-
lCurrentReportTime = Time.now.utc
|
90
|
-
lCurrentReportFileName = "#{lMonitorDir}/Report_#{lCurrentReportTime.strftime('%Y-%m-%d-%H-%M-%S')}"
|
91
|
-
File.open(lCurrentReportFileName, 'w') do |oFile|
|
92
|
-
oFile.write(Marshal.dump(lReport))
|
81
|
+
# Call this monitor
|
82
|
+
begin
|
83
|
+
log_info "Executing monitoring process #{iMonitorName} ..."
|
84
|
+
lMonitorPluginInstance.execute(iMonitorInfo)
|
85
|
+
rescue Exception
|
86
|
+
log_err "Exception while executing monitor #{iMonitorName}: #{$!}.\n#{$!.backtrace.join("\n")}"
|
87
|
+
report "!!! Exception while executing monitor #{iMonitorName}: #{$!}.\n#{$!.backtrace.join("\n")}"
|
93
88
|
end
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
lReportFiles[Time.parse("#{lMatch[1]}-#{lMatch[2]}-#{lMatch[3]} #{lMatch[4]}:#{lMatch[5]}:#{lMatch[6]} UTC")] = iReportFile
|
89
|
+
# If this report is not empty, save it in a file
|
90
|
+
lCurrentReportFileName = nil
|
91
|
+
lCurrentReportTime = nil
|
92
|
+
if (!lReport.empty?)
|
93
|
+
lCurrentReportTime = Time.now.utc
|
94
|
+
lCurrentReportFileName = "#{lMonitorDir}/Report_#{lCurrentReportTime.strftime('%Y-%m-%d-%H-%M-%S')}"
|
95
|
+
File.open(lCurrentReportFileName, 'w') do |oFile|
|
96
|
+
oFile.write(Marshal.dump(lReport))
|
97
|
+
end
|
104
98
|
end
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
#
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
if (iNotifierConf[:GroupReports] == nil)
|
113
|
-
# Send the report now if it exists
|
114
|
-
if (lCurrentReportFileName != nil)
|
115
|
-
# Send [iMonitorInfo, [lCurrentReportFileName]] to iNotifierName
|
116
|
-
if (iNotifierConf[:GroupWithOtherMonitors] == true)
|
117
|
-
if (lGroupedMonitorReports[lNotifierID] == nil)
|
118
|
-
lGroupedMonitorReports[lNotifierID] = {}
|
119
|
-
end
|
120
|
-
if (lGroupedMonitorReports[lNotifierID][iMonitorName] == nil)
|
121
|
-
lGroupedMonitorReports[lNotifierID][iMonitorName] = []
|
122
|
-
end
|
123
|
-
lGroupedMonitorReports[lNotifierID][iMonitorName] << [ iNotifierConf, [ lCurrentReportFileName ] ]
|
124
|
-
else
|
125
|
-
notify(iConf, {lNotifierID => {iMonitorName => [ [ iNotifierConf, [lCurrentReportFileName] ] ] }}, lDelayedReports)
|
126
|
-
end
|
127
|
-
lSentReports[lCurrentReportFileName] = nil
|
128
|
-
# Remember last report sent
|
129
|
-
if (lDatabase[:LastReportsSent][iMonitorName] == nil)
|
130
|
-
lDatabase[:LastReportsSent][iMonitorName] = {}
|
131
|
-
end
|
132
|
-
lDatabase[:LastReportsSent][iMonitorName][iNotifierName] = lCurrentReportTime
|
133
|
-
end
|
99
|
+
# Get the list of reports to send, per time
|
100
|
+
# map< Time, FileName >
|
101
|
+
lReportFiles = {}
|
102
|
+
Dir.glob("#{lMonitorDir}/Report_*").each do |iReportFile|
|
103
|
+
lMatch = File.basename(iReportFile).match(/^Report_(\d\d\d\d)-(\d\d)-(\d\d)-(\d\d)-(\d\d)-(\d\d)$/)
|
104
|
+
if (lMatch == nil)
|
105
|
+
log_err "Invalid file report name: #{iReportFile}. Ignoring it."
|
134
106
|
else
|
135
|
-
#
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
end
|
149
|
-
else
|
150
|
-
# Send all corresponding reports now
|
151
|
-
lLastReportSentDate = nil
|
152
|
-
if ((lDatabase[:LastReportsSent][iMonitorName] != nil) and
|
153
|
-
(lDatabase[:LastReportsSent][iMonitorName][iNotifierName] != nil))
|
154
|
-
lLastReportSentDate = lDatabase[:LastReportsSent][iMonitorName][iNotifierName]
|
155
|
-
else
|
156
|
-
lLastReportSentDate = Time.parse('1970-01-01 00:00:00 UTC')
|
157
|
-
end
|
158
|
-
lReportFilesToSend = []
|
159
|
-
lLastReportTime = Time.parse('1970-01-01 00:00:00 UTC')
|
160
|
-
lReportFiles.each do |iReportTime, iReportFileName|
|
161
|
-
if (iReportTime > lLastReportSentDate)
|
162
|
-
lReportFilesToSend << iReportFileName
|
163
|
-
lSentReports[iReportFileName] = nil
|
164
|
-
if (iReportTime > lLastReportTime)
|
165
|
-
lLastReportTime = iReportTime
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
if (!lReportFilesToSend.empty?)
|
170
|
-
# Send [iMonitorInfo, lReportFilesToSend] to iNotifierName
|
107
|
+
lReportFiles[Time.parse("#{lMatch[1]}-#{lMatch[2]}-#{lMatch[3]} #{lMatch[4]}:#{lMatch[5]}:#{lMatch[6]} UTC")] = iReportFile
|
108
|
+
end
|
109
|
+
end
|
110
|
+
# For each report file, compute the list of notifiers that will send it
|
111
|
+
if (!lReportFiles.empty?)
|
112
|
+
# There are some report files to be (maybe) sent.
|
113
|
+
# Loop through the notifiers.
|
114
|
+
iMonitorInfo[:Notifiers].each do |iNotifierName, iNotifierConf|
|
115
|
+
lNotifierID = iNotifierConf[:Type]
|
116
|
+
if (iNotifierConf[:GroupReports] == nil)
|
117
|
+
# Send the report now if it exists
|
118
|
+
if (lCurrentReportFileName != nil)
|
119
|
+
# Send [iMonitorInfo, [lCurrentReportFileName]] to iNotifierName
|
171
120
|
if (iNotifierConf[:GroupWithOtherMonitors] == true)
|
172
121
|
if (lGroupedMonitorReports[lNotifierID] == nil)
|
173
122
|
lGroupedMonitorReports[lNotifierID] = {}
|
@@ -175,15 +124,71 @@ module SheepDog
|
|
175
124
|
if (lGroupedMonitorReports[lNotifierID][iMonitorName] == nil)
|
176
125
|
lGroupedMonitorReports[lNotifierID][iMonitorName] = []
|
177
126
|
end
|
178
|
-
lGroupedMonitorReports[lNotifierID][iMonitorName] << [ iNotifierConf,
|
127
|
+
lGroupedMonitorReports[lNotifierID][iMonitorName] << [ iNotifierConf, [ lCurrentReportFileName ] ]
|
179
128
|
else
|
180
|
-
notify(iConf, {lNotifierID => {iMonitorName => [ [ iNotifierConf,
|
129
|
+
notify(iConf, {lNotifierID => {iMonitorName => [ [ iNotifierConf, [lCurrentReportFileName] ] ] }}, lDelayedReports)
|
181
130
|
end
|
131
|
+
lSentReports[lCurrentReportFileName] = nil
|
182
132
|
# Remember last report sent
|
183
133
|
if (lDatabase[:LastReportsSent][iMonitorName] == nil)
|
184
134
|
lDatabase[:LastReportsSent][iMonitorName] = {}
|
185
135
|
end
|
186
|
-
lDatabase[:LastReportsSent][iMonitorName][iNotifierName] =
|
136
|
+
lDatabase[:LastReportsSent][iMonitorName][iNotifierName] = lCurrentReportTime
|
137
|
+
end
|
138
|
+
else
|
139
|
+
# Get the interval in seconds
|
140
|
+
lSecsInterval = getSecsInterval(iNotifierConf[:GroupReports])
|
141
|
+
# Maybe we don't want to send reports now
|
142
|
+
# Get the last time we sent reports for this one
|
143
|
+
if ((lDatabase[:LastReportsSent][iMonitorName] != nil) and
|
144
|
+
(lDatabase[:LastReportsSent][iMonitorName][iNotifierName] != nil) and
|
145
|
+
((Time.now.utc - lDatabase[:LastReportsSent][iMonitorName][iNotifierName]) < lSecsInterval))
|
146
|
+
# Reports from last one sent to the most recent one are marked to be sent later
|
147
|
+
lReportFiles.each do |iReportTime, iReportFileName|
|
148
|
+
if (iReportTime > lDatabase[:LastReportsSent][iMonitorName][iNotifierName])
|
149
|
+
# This report will be sent another time
|
150
|
+
lDelayedReports[iReportFileName] = nil
|
151
|
+
end
|
152
|
+
end
|
153
|
+
else
|
154
|
+
# Send all corresponding reports now
|
155
|
+
lLastReportSentDate = nil
|
156
|
+
if ((lDatabase[:LastReportsSent][iMonitorName] != nil) and
|
157
|
+
(lDatabase[:LastReportsSent][iMonitorName][iNotifierName] != nil))
|
158
|
+
lLastReportSentDate = lDatabase[:LastReportsSent][iMonitorName][iNotifierName]
|
159
|
+
else
|
160
|
+
lLastReportSentDate = Time.parse('1970-01-01 00:00:00 UTC')
|
161
|
+
end
|
162
|
+
lReportFilesToSend = []
|
163
|
+
lLastReportTime = Time.parse('1970-01-01 00:00:00 UTC')
|
164
|
+
lReportFiles.each do |iReportTime, iReportFileName|
|
165
|
+
if (iReportTime > lLastReportSentDate)
|
166
|
+
lReportFilesToSend << iReportFileName
|
167
|
+
lSentReports[iReportFileName] = nil
|
168
|
+
if (iReportTime > lLastReportTime)
|
169
|
+
lLastReportTime = iReportTime
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
if (!lReportFilesToSend.empty?)
|
174
|
+
# Send [iMonitorInfo, lReportFilesToSend] to iNotifierName
|
175
|
+
if (iNotifierConf[:GroupWithOtherMonitors] == true)
|
176
|
+
if (lGroupedMonitorReports[lNotifierID] == nil)
|
177
|
+
lGroupedMonitorReports[lNotifierID] = {}
|
178
|
+
end
|
179
|
+
if (lGroupedMonitorReports[lNotifierID][iMonitorName] == nil)
|
180
|
+
lGroupedMonitorReports[lNotifierID][iMonitorName] = []
|
181
|
+
end
|
182
|
+
lGroupedMonitorReports[lNotifierID][iMonitorName] << [ iNotifierConf, lReportFilesToSend ]
|
183
|
+
else
|
184
|
+
notify(iConf, {lNotifierID => {iMonitorName => [ [ iNotifierConf, lReportFilesToSend ] ]}}, lDelayedReports)
|
185
|
+
end
|
186
|
+
# Remember last report sent
|
187
|
+
if (lDatabase[:LastReportsSent][iMonitorName] == nil)
|
188
|
+
lDatabase[:LastReportsSent][iMonitorName] = {}
|
189
|
+
end
|
190
|
+
lDatabase[:LastReportsSent][iMonitorName][iNotifierName] = lLastReportTime
|
191
|
+
end
|
187
192
|
end
|
188
193
|
end
|
189
194
|
end
|
@@ -203,7 +208,7 @@ module SheepDog
|
|
203
208
|
end
|
204
209
|
# Log reports to be sent delayed
|
205
210
|
lDelayedReports.keys.each do |iReportFileName|
|
206
|
-
|
211
|
+
log_info "Report to be sent later: #{iReportFileName}"
|
207
212
|
end
|
208
213
|
|
209
214
|
# Write back database
|
@@ -214,19 +219,46 @@ module SheepDog
|
|
214
219
|
|
215
220
|
private
|
216
221
|
|
222
|
+
# Check conditions
|
223
|
+
#
|
224
|
+
# Parameters::
|
225
|
+
# * *iConditions* (<em>map<Symbol,Object></em>): The conditions to check
|
226
|
+
# Return::
|
227
|
+
# * _Boolean_: Are the conditions respected ?
|
228
|
+
def checkConditions(iConditions)
|
229
|
+
rPassed = true
|
230
|
+
|
231
|
+
if (iConditions[:TimeRanges] != nil)
|
232
|
+
require 'time'
|
233
|
+
# If current time falls into at least 1 range of the list, it's ok.
|
234
|
+
lNow = Time.parse(Time.now.utc.strftime('2001-01-01 %H:%m:%S UTC')).utc
|
235
|
+
rPassed = false
|
236
|
+
iConditions[:TimeRanges].each do |iTimeRangeInfo|
|
237
|
+
iBeginTime, iEndTime = iTimeRangeInfo.map { |iStrTime| Time.parse("2001-01-01 #{iStrTime}").utc }
|
238
|
+
rPassed = ((lNow >= iBeginTime) and
|
239
|
+
(lNow <= iEndTime))
|
240
|
+
if (rPassed)
|
241
|
+
break
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
return rPassed
|
247
|
+
end
|
248
|
+
|
217
249
|
# Process notifications to be sent.
|
218
250
|
#
|
219
|
-
# Parameters
|
251
|
+
# Parameters::
|
220
252
|
# * *iConf* (<em>map<Symbol,Object></em>): SheepDog config
|
221
|
-
# * *iNotificationsInfo* (<em>map<NotifierName,map<MonitorName,list<[NotifierConf,list<ReportFileName>]>>></em>): The list of report files to send along with their notifier config, per monitor name, per notifier name
|
253
|
+
# * *iNotificationsInfo* (<em>map<NotifierName,map<MonitorName,list< [NotifierConf,list<ReportFileName>] >>></em>): The list of report files to send along with their notifier config, per monitor name, per notifier name
|
222
254
|
# * *ioErrorReports* (<em>map<ReportFileName,nil></em>): The set of report file names that could not be sent through notifications
|
223
255
|
def notify(iConf, iNotificationsInfo, ioErrorReports)
|
224
256
|
iNotificationsInfo.each do |iNotifierName, iNotifierNotificationsInfo|
|
225
257
|
# Find this notifier
|
226
258
|
if (iConf[:Notifiers][iNotifierName] == nil)
|
227
|
-
|
259
|
+
log_err "Unknown notifier named #{iNotifierName}. Ignoring notifications to be sent there. Please check configuration."
|
228
260
|
else
|
229
|
-
|
261
|
+
access_plugin('Notifiers', iConf[:Notifiers][iNotifierName][:Type]) do |iNotifierPlugin|
|
230
262
|
# List of reports to send through this notifier
|
231
263
|
# list< Report >
|
232
264
|
lLstReports = []
|
@@ -241,7 +273,7 @@ module SheepDog
|
|
241
273
|
begin
|
242
274
|
lReport = Marshal.load(File.read(iReportFileName))
|
243
275
|
rescue Exception
|
244
|
-
|
276
|
+
log_err "Invalid report stored in file #{iReportFileName}: #{$!}.\n#{$!.backtrace.join("\n")}"
|
245
277
|
ioErrorReports[iReportFileName] = nil
|
246
278
|
lReport = nil
|
247
279
|
end
|
@@ -257,10 +289,10 @@ module SheepDog
|
|
257
289
|
end
|
258
290
|
end
|
259
291
|
begin
|
260
|
-
|
261
|
-
iNotifierPlugin.
|
292
|
+
log_info "===== Send notification to #{iNotifierName} of #{lLstReports.size} reports..."
|
293
|
+
iNotifierPlugin.send_notification(iConf[:Notifiers][iNotifierName], lLstReports)
|
262
294
|
rescue Exception
|
263
|
-
|
295
|
+
log_err "Exception while sending notification from #{iNotifierName} for reports #{lReportFilesSet.keys.join(', ')}: #{$!}.\n#{$!.backtrace.join("\n")}"
|
264
296
|
ioErrorReports.merge!(lReportFilesSet)
|
265
297
|
end
|
266
298
|
end
|
@@ -270,15 +302,15 @@ module SheepDog
|
|
270
302
|
|
271
303
|
# Get the number of seconds defined in a configuration
|
272
304
|
#
|
273
|
-
# Parameters
|
305
|
+
# Parameters::
|
274
306
|
# * *iConf* (<em>map<Symbol,Object></em>): The configuration
|
275
|
-
# Return
|
307
|
+
# Return::
|
276
308
|
# * _Fixnum_: The number of seconds
|
277
309
|
def getSecsInterval(iConf)
|
278
310
|
if (iConf[:Interval_Secs] != nil)
|
279
311
|
return iConf[:Interval_Secs]
|
280
312
|
else
|
281
|
-
|
313
|
+
log_err "Unable to decode interval from #{iConf.inspect}"
|
282
314
|
return 0
|
283
315
|
end
|
284
316
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2011 Muriel Salvan (
|
2
|
+
# Copyright (c) 2011 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
3
|
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
4
|
#++
|
5
5
|
|
@@ -11,14 +11,19 @@ module SheepDog
|
|
11
11
|
|
12
12
|
# Execute the monitoring process for a given configuration
|
13
13
|
#
|
14
|
-
# Parameters
|
14
|
+
# Parameters::
|
15
15
|
# * *iConf* (<em>map<Symbol,Object></em>): The monitor configuration
|
16
16
|
def execute(iConf)
|
17
17
|
# Get past values
|
18
18
|
lReadValuesFileName = "#{@MonitorDir}/ReadValues"
|
19
19
|
lReadValues = nil
|
20
20
|
if (File.exists?(lReadValuesFileName))
|
21
|
-
|
21
|
+
begin
|
22
|
+
lReadValues = Marshal.load(File.read(lReadValuesFileName))
|
23
|
+
rescue Exception
|
24
|
+
report "Error while reading previously read values: #{$!}"
|
25
|
+
lReadValues = nil
|
26
|
+
end
|
22
27
|
else
|
23
28
|
lReadValues = {
|
24
29
|
:LastPos => 0,
|
@@ -41,16 +46,20 @@ module SheepDog
|
|
41
46
|
iFile.seek(lStartPos)
|
42
47
|
iFile.read.split("\n").each do |iLine|
|
43
48
|
# Match the line against filters
|
44
|
-
|
45
|
-
iConf[:Filters].each do |iFilter|
|
46
|
-
if (iLine.match(iFilter) != nil)
|
47
|
-
lMatch = true
|
48
|
-
break
|
49
|
-
end
|
50
|
-
end
|
51
|
-
if (lMatch)
|
52
|
-
# Report this line
|
49
|
+
if (iConf[:Filters] == nil)
|
53
50
|
report iLine
|
51
|
+
else
|
52
|
+
lMatch = false
|
53
|
+
iConf[:Filters].each do |iFilter|
|
54
|
+
if (iLine.match(iFilter) != nil)
|
55
|
+
lMatch = true
|
56
|
+
break
|
57
|
+
end
|
58
|
+
end
|
59
|
+
if (lMatch)
|
60
|
+
# Report this line
|
61
|
+
report iLine
|
62
|
+
end
|
54
63
|
end
|
55
64
|
end
|
56
65
|
lReadValues[:LastPos] = iFile.pos
|
@@ -1,10 +1,10 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2011 Muriel Salvan (
|
2
|
+
# Copyright (c) 2011 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
3
|
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
4
|
#++
|
5
5
|
|
6
6
|
require 'rUtilAnts/Misc'
|
7
|
-
RUtilAnts::Misc::
|
7
|
+
RUtilAnts::Misc::install_misc_on_object
|
8
8
|
|
9
9
|
module SheepDog
|
10
10
|
|
@@ -14,7 +14,7 @@ module SheepDog
|
|
14
14
|
|
15
15
|
# Execute the monitoring process for a given configuration
|
16
16
|
#
|
17
|
-
# Parameters
|
17
|
+
# Parameters::
|
18
18
|
# * *iConf* (<em>map<Symbol,Object></em>): The monitor configuration
|
19
19
|
def execute(iConf)
|
20
20
|
# Get the list of processes
|
@@ -50,7 +50,7 @@ module SheepDog
|
|
50
50
|
# Maybe we want to execute something
|
51
51
|
if (iConf.has_key?(:ExecuteIfMissing))
|
52
52
|
report "Missing process. Executing \"#{iConf[:ExecuteIfMissing][:CmdLine]}\" from \"#{iConf[:ExecuteIfMissing][:Pwd]}\":"
|
53
|
-
|
53
|
+
change_dir(iConf[:ExecuteIfMissing][:Pwd]) do
|
54
54
|
report `#{iConf[:ExecuteIfMissing][:CmdLine]}`
|
55
55
|
end
|
56
56
|
end
|
@@ -60,7 +60,7 @@ module SheepDog
|
|
60
60
|
# map< Integer, nil >
|
61
61
|
lAboveLimitsPIDs = {}
|
62
62
|
lLstPIDs.each do |iPID|
|
63
|
-
lCPUPercent, lMemPercent, lVirtualSize = getPIDMetrics(iPID)
|
63
|
+
lCPUPercent, lMemPercent, lVirtualSize, lResidentSize = getPIDMetrics(iPID)
|
64
64
|
# Challenge metrics against limits
|
65
65
|
if ((iConf[:Limits].has_key?(:CPUPercent)) and
|
66
66
|
(lCPUPercent > iConf[:Limits][:CPUPercent]))
|
@@ -77,6 +77,11 @@ module SheepDog
|
|
77
77
|
report "PID #{iPID} exceeds virtual mem size limit: #{lVirtualSize} > #{iConf[:Limits][:VirtualMemSize]}"
|
78
78
|
lAboveLimitsPIDs[iPID] = nil
|
79
79
|
end
|
80
|
+
if ((iConf[:Limits].has_key?(:ResidentMemSize)) and
|
81
|
+
(lResidentSize > iConf[:Limits][:ResidentMemSize]))
|
82
|
+
report "PID #{iPID} exceeds resident mem size limit: #{lResidentSize} > #{iConf[:Limits][:ResidentMemSize]}"
|
83
|
+
lAboveLimitsPIDs[iPID] = nil
|
84
|
+
end
|
80
85
|
end
|
81
86
|
if (!lAboveLimitsPIDs.empty?)
|
82
87
|
# What to do with PIDs exceeding limits ?
|
@@ -91,14 +96,17 @@ module SheepDog
|
|
91
96
|
|
92
97
|
private
|
93
98
|
|
99
|
+
include SheepDog::Common
|
100
|
+
|
94
101
|
# Get metrics of a PID
|
95
102
|
#
|
96
|
-
# Parameters
|
103
|
+
# Parameters::
|
97
104
|
# * *iPID* (_Integer_): The PID to get metrics from
|
98
|
-
# Return
|
105
|
+
# Return::
|
99
106
|
# * _Float_: The CPU percentage
|
100
107
|
# * _Float_: The mem percentage
|
101
108
|
# * _Integer_: The total virtual memory size
|
109
|
+
# * _Integer_: The total resident memory size
|
102
110
|
def getPIDMetrics(iPID)
|
103
111
|
rCPUPercent = nil
|
104
112
|
rMemPercent = nil
|
@@ -106,11 +114,13 @@ module SheepDog
|
|
106
114
|
|
107
115
|
# From top
|
108
116
|
lTopOutput = `top -n1 -p#{iPID} -b | tail -2 | head -1`.strip
|
109
|
-
lMatch = lTopOutput.match(/^\d+\s+\S+\s+\d+\s+\d+\s+\S+\s
|
117
|
+
lMatch = lTopOutput.match(/^\d+\s+\S+\s+\d+\s+\d+\s+\S+\s+(\S+)\s+\d+\s+\S+\s+(\S+)\s+(\S+)\s+\S+\s+.+$/)
|
110
118
|
if (lMatch == nil)
|
111
119
|
report "Unable to decode top output for PID #{iPID}: \"#{lTopOutput}\""
|
112
120
|
else
|
113
|
-
|
121
|
+
# Convert RES column to integer
|
122
|
+
rRESValue = quantity2Int(lMatch[1])
|
123
|
+
rCPUPercent, rMemPercent = lMatch[2..3].map { |iStrValue| iStrValue.to_f }
|
114
124
|
end
|
115
125
|
# From proc/<PID>/stat
|
116
126
|
lStatOutput = `cat /proc/#{iPID}/stat`.strip
|
@@ -121,7 +131,7 @@ module SheepDog
|
|
121
131
|
rVS = lMatch[1].to_i
|
122
132
|
end
|
123
133
|
|
124
|
-
return rCPUPercent, rMemPercent, rVS
|
134
|
+
return rCPUPercent, rMemPercent, rVS, rRESValue
|
125
135
|
end
|
126
136
|
|
127
137
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2011 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'rUtilAnts/Misc'
|
7
|
+
RUtilAnts::Misc::install_misc_on_object
|
8
|
+
|
9
|
+
module SheepDog
|
10
|
+
|
11
|
+
module Monitors
|
12
|
+
|
13
|
+
class Top
|
14
|
+
|
15
|
+
include SheepDog::Common
|
16
|
+
|
17
|
+
# Execute the monitoring process for a given configuration
|
18
|
+
#
|
19
|
+
# Parameters::
|
20
|
+
# * *iConf* (<em>map<Symbol,Object></em>): The monitor configuration
|
21
|
+
def execute(iConf)
|
22
|
+
lLstTopOutput = `top -b -p0 -n1 | head -4`.split("\n").map { |iLine| iLine.strip }
|
23
|
+
# The loads
|
24
|
+
if (iConf[:Limits][:Loads] != nil)
|
25
|
+
lLine = lLstTopOutput[0]
|
26
|
+
lMatch = lLine.match(/load average: ([^,]+), ([^,]+), ([^,]+)$/)
|
27
|
+
if (lMatch == nil)
|
28
|
+
report "Unable to decode top output for loads: \"#{lLine}\"."
|
29
|
+
else
|
30
|
+
lTopValues = lMatch[1..3].map { |iStrValue| iStrValue.to_f }
|
31
|
+
3.times do |iIdx|
|
32
|
+
if ((iConf[:Limits][:Loads][iIdx] != nil) and
|
33
|
+
(lTopValues[iIdx] > iConf[:Limits][:Loads][iIdx]))
|
34
|
+
report "Value ##{iIdx} of load exceeds limit: #{lTopValues[iIdx]} > #{iConf[:Limits][:Loads][iIdx]}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
# The memory
|
40
|
+
if (iConf[:Limits][:Memory] != nil)
|
41
|
+
lLine = lLstTopOutput[3]
|
42
|
+
lMatch = lLine.match(/\s+(\S+) used,\s+(\S+) free/)
|
43
|
+
if (lMatch == nil)
|
44
|
+
report "Unable to decode top output for memory: \"#{lLine}\"."
|
45
|
+
else
|
46
|
+
lMemUsed, lMemFree = lMatch[1..2].map { |iStrValue| quantity2Int(iStrValue) }
|
47
|
+
if ((iConf[:Limits][:Memory][:MaxUsed] != nil) and
|
48
|
+
(lMemUsed > iConf[:Limits][:Memory][:MaxUsed]))
|
49
|
+
report "Used memory exceed maximal limit: #{lMemUsed} > #{iConf[:Limits][:Memory][:MaxUsed]}"
|
50
|
+
end
|
51
|
+
if ((iConf[:Limits][:Memory][:MinFree] != nil) and
|
52
|
+
(lMemFree < iConf[:Limits][:Memory][:MinFree]))
|
53
|
+
report "Free memory below minimal limit: #{lMemFree} < #{iConf[:Limits][:Memory][:MinFree]}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2010 -
|
2
|
+
# Copyright (c) 2010 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
3
|
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
4
|
#++
|
5
5
|
|
@@ -11,19 +11,20 @@ module SheepDog
|
|
11
11
|
|
12
12
|
# Send notifications for a given list of reports.
|
13
13
|
#
|
14
|
-
# Parameters
|
14
|
+
# Parameters::
|
15
15
|
# * *iConf* (<em>map<Symbol,Object></em>): The notifier config
|
16
16
|
# * *iLstReports* (<em>list<Report></em>): List of reports to notify
|
17
|
-
def
|
17
|
+
def send_notification(iConf, iLstReports)
|
18
18
|
lTitle = nil
|
19
19
|
lMessage = nil
|
20
20
|
if (iLstReports.size > 1)
|
21
21
|
lTitle = "#{iLstReports.size} reports"
|
22
|
+
lMessage = ''
|
22
23
|
iLstReports.each_with_index do |iReport, iIdx|
|
23
24
|
lMessage << "===============================================\n"
|
24
25
|
lMessage << "========== Report #{iIdx+1} (#{iReport.CreationTime.utc.strftime('%Y-%m-%d %H:%M:%S')} UTC from #{iReport.ReportFileName}): #{iReport.Title}\n"
|
25
26
|
lMessage << iReport.getSimpleText
|
26
|
-
lMessage << "===============================================\n\n"
|
27
|
+
lMessage << "\n===============================================\n\n"
|
27
28
|
end
|
28
29
|
else
|
29
30
|
lReport = iLstReports.first
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2011 Muriel Salvan (
|
2
|
+
# Copyright (c) 2011 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
3
|
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
4
|
#++
|
5
5
|
|
@@ -11,19 +11,20 @@ module SheepDog
|
|
11
11
|
|
12
12
|
# Send notifications for a given list of reports.
|
13
13
|
#
|
14
|
-
# Parameters
|
14
|
+
# Parameters::
|
15
15
|
# * *iConf* (<em>map<Symbol,Object></em>): The notifier config
|
16
16
|
# * *iLstReports* (<em>list<Report></em>): List of reports to notify
|
17
|
-
def
|
17
|
+
def send_notification(iConf, iLstReports)
|
18
18
|
lTitle = nil
|
19
19
|
lMessage = nil
|
20
20
|
if (iLstReports.size > 1)
|
21
21
|
lTitle = "#{iLstReports.size} reports"
|
22
|
+
lMessage = ''
|
22
23
|
iLstReports.each_with_index do |iReport, iIdx|
|
23
24
|
lMessage << "===============================================\n"
|
24
25
|
lMessage << "========== Report #{iIdx+1} (#{iReport.CreationTime.utc.strftime('%Y-%m-%d %H:%M:%S')} UTC from #{iReport.ReportFileName}): #{iReport.Title}\n"
|
25
26
|
lMessage << iReport.getSimpleText
|
26
|
-
lMessage << "===============================================\n\n"
|
27
|
+
lMessage << "\n===============================================\n\n"
|
27
28
|
end
|
28
29
|
else
|
29
30
|
lReport = iLstReports.first
|
data/lib/sheepdog/Report.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2011 Muriel Salvan (
|
2
|
+
# Copyright (c) 2011 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
3
|
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
4
|
#++
|
5
5
|
|
@@ -30,7 +30,7 @@ module SheepDog
|
|
30
30
|
|
31
31
|
# Add an entry to the report
|
32
32
|
#
|
33
|
-
# Parameters
|
33
|
+
# Parameters::
|
34
34
|
# * *iEntry* (_String_): Entry to be added
|
35
35
|
def addEntry(iEntry)
|
36
36
|
@Entries << iEntry
|
@@ -38,7 +38,7 @@ module SheepDog
|
|
38
38
|
|
39
39
|
# Set the report's title
|
40
40
|
#
|
41
|
-
# Parameters
|
41
|
+
# Parameters::
|
42
42
|
# * *iTitle* (_String_): Report's title
|
43
43
|
def setTitle(iTitle)
|
44
44
|
@Title = iTitle
|
@@ -46,7 +46,7 @@ module SheepDog
|
|
46
46
|
|
47
47
|
# Set the report's file name
|
48
48
|
#
|
49
|
-
# Parameters
|
49
|
+
# Parameters::
|
50
50
|
# * *iFileName* (_String_): Report's file name
|
51
51
|
def setReportFileName(iFileName)
|
52
52
|
@ReportFileName = iFileName
|
@@ -54,7 +54,7 @@ module SheepDog
|
|
54
54
|
|
55
55
|
# Get the report as simple text
|
56
56
|
#
|
57
|
-
# Return
|
57
|
+
# Return::
|
58
58
|
# * _String_: The report as simple text
|
59
59
|
def getSimpleText
|
60
60
|
return @Entries.join("\n")
|
@@ -62,7 +62,7 @@ module SheepDog
|
|
62
62
|
|
63
63
|
# Is this report empty ?
|
64
64
|
#
|
65
|
-
# Return
|
65
|
+
# Return::
|
66
66
|
# * _Boolean_: Is this report empty ?
|
67
67
|
def empty?
|
68
68
|
return @Entries.empty?
|
data/sheepdog.conf.rb.example
CHANGED
@@ -56,6 +56,9 @@
|
|
56
56
|
:GroupWithOtherMonitors => true
|
57
57
|
}
|
58
58
|
},
|
59
|
+
:Conditions => {
|
60
|
+
:TimeRanges => [ [ '02:00:00 UTC', '03:00:00 UTC' ], [ '07:00:00 UTC', '15:00:00 UTC' ] ]
|
61
|
+
},
|
59
62
|
|
60
63
|
:Processes => [
|
61
64
|
{
|
@@ -66,7 +69,8 @@
|
|
66
69
|
:Limits => {
|
67
70
|
:CPUPercent => 5,
|
68
71
|
:MemPercent => 5,
|
69
|
-
:VirtualMemSize => 16777216
|
72
|
+
:VirtualMemSize => 16777216,
|
73
|
+
:ResidentMemSize => 8192
|
70
74
|
},
|
71
75
|
:ActionAboveLimits => :Kill
|
72
76
|
},
|
@@ -92,6 +96,25 @@
|
|
92
96
|
:CmdLine => '/usr/bin/ruby /usr/bin/mongrel_rails start -p 12004 -d -e production -P log/mongrel.pid',
|
93
97
|
:Pwd => '/my/home/rails'
|
94
98
|
}
|
99
|
+
},
|
100
|
+
|
101
|
+
# Monitor global top values
|
102
|
+
'TopValues' => {
|
103
|
+
:Type => 'Top',
|
104
|
+
:Notifiers => {
|
105
|
+
'Mail' => {
|
106
|
+
:Type => 'Mail',
|
107
|
+
:Title => 'top values',
|
108
|
+
:GroupWithOtherMonitors => true
|
109
|
+
}
|
110
|
+
},
|
111
|
+
:Limits => {
|
112
|
+
:Loads => [ 2.00, 1.50, nil ],
|
113
|
+
:Memory => {
|
114
|
+
:MaxUsed => 4000000000,
|
115
|
+
:MinFree => 400000000
|
116
|
+
}
|
117
|
+
}
|
95
118
|
}
|
96
119
|
|
97
120
|
}
|
metadata
CHANGED
@@ -4,10 +4,10 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 2
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.
|
9
|
+
- 20120314
|
10
|
+
version: 0.2.0.20120314
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Muriel Salvan
|
@@ -15,12 +15,25 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2012-03-14 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
|
-
dependencies:
|
21
|
-
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rUtilAnts
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
segments:
|
30
|
+
- 1
|
31
|
+
- 0
|
32
|
+
version: "1.0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
22
35
|
description: Simple command line tool that monitors files and processes and sends notifications or take corrective actions when problems arise. Monitor log files for errors, processes CPU and memory consumption (can kill if exceeding), respawn dead processes.
|
23
|
-
email:
|
36
|
+
email: muriel@x-aeon.com
|
24
37
|
executables:
|
25
38
|
- sheepdog.rb
|
26
39
|
extensions: []
|
@@ -32,9 +45,11 @@ files:
|
|
32
45
|
- bin/sheepdog.rb
|
33
46
|
- ChangeLog
|
34
47
|
- Credits
|
48
|
+
- lib/sheepdog/Common.rb
|
35
49
|
- lib/sheepdog/Executor.rb
|
36
50
|
- lib/sheepdog/Monitors/LogFile.rb
|
37
51
|
- lib/sheepdog/Monitors/Process.rb
|
52
|
+
- lib/sheepdog/Monitors/Top.rb
|
38
53
|
- lib/sheepdog/Notifiers/SendMail.rb
|
39
54
|
- lib/sheepdog/Notifiers/StdOut.rb
|
40
55
|
- lib/sheepdog/Report.rb
|