qnotifier 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest ADDED
@@ -0,0 +1,21 @@
1
+ Manifest
2
+ Rakefile
3
+ bin/qnotifier
4
+ config/qnotifier_config.yml
5
+ gem-public_cert.pem
6
+ lib/command.rb
7
+ lib/plugin.rb
8
+ lib/qnotifier.rb
9
+ lib/storage.rb
10
+ lib/web_service.rb
11
+ plugins/apache.rb
12
+ plugins/iostat.rb
13
+ plugins/mysql.rb
14
+ plugins/network.rb
15
+ plugins/nginx.rb
16
+ plugins/passenger.rb
17
+ plugins/processes.rb
18
+ plugins/rails.rb
19
+ plugins/ruby.rb
20
+ plugins/system.rb
21
+ plugins/urls.rb
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('qnotifier', '0.6.0') do |p|
6
+ p.description = "The server side agent for the QNotifier monitoring system"
7
+ p.url = "http://qnotifier.com/qnotifier_gem"
8
+ p.author = "Gersham Meharg"
9
+ p.email = "gersham@qnotifier.com"
10
+ p.ignore_pattern = ["var/*"]
11
+ p.runtime_dependencies = ["rest-client >=1.4.2", "json >=1.2.3", "elif >=0.1.0"]
12
+ p.development_dependencies = ["rest-client >=1.4.2", "json >=1.2.3", "elif >=0.1.0"]
13
+ p.executable_pattern = ["bin/*"]
14
+ p.install_message = "Qnotifier installed, please register by running 'qnotifier -r CODE' in order to register this server."
15
+ end
data/bin/qnotifier ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift( File.join( File.dirname(__FILE__), '../lib' ) )
3
+ require "command"
4
+
5
+ Qnotifier::Command.run(ARGV)
6
+
@@ -0,0 +1,112 @@
1
+ # qnotifier_config.yml file
2
+ ---
3
+ #
4
+ # This is the configuration file for the Qnotifier Agent
5
+ # It should live in /etc/qnotifier.config
6
+ #
7
+ # Note that this file is YML formatted, please respect the indents
8
+ #
9
+
10
+ #
11
+ # General Settings
12
+ #
13
+
14
+ # Whether to resend alerts
15
+ resend_alerts: true
16
+ # resend_alert_time: Resend alerts every X seconds
17
+ resend_alert_time: 1 #14400 # Four hours
18
+
19
+ # alert_email_address: if this is defined any alerts will be copied to this email address
20
+ # Note that is in addition to the Qnotifier notifications
21
+ #alert_email_address: user@domain.com
22
+
23
+ #
24
+ # PLUGINS
25
+ #
26
+
27
+ # Where to look for user generated plugins
28
+ # To add your own plugin subclass the Qnotifier::Plugin class and put this in to this directory
29
+ # You may add configuration parameters here based on the name of your plugin class
30
+ plugin_directory: "/var/qnotifier"
31
+
32
+ # The System Plugin must be enabled, this gives basic stats like load average, disk use, memory, etc
33
+ System:
34
+ # use_load: either one_minute, five_minute or fifteen_minutes
35
+ use_load: five_minute
36
+ # normalize_load: whether to divide the reported load by the number of CPUs in the system
37
+ normalize_load: true
38
+ # Alert if the CPU is above this percent usage, 0 disables
39
+ alert_cpu_threshold: 10
40
+ # Alert if the memory is above this percent usage, 0 disables
41
+ alert_memory_threshold: 10
42
+ # Alert if the memory is above this percent usage, 0 disables
43
+ alert_load_threshold: 1.0
44
+ # Alert if the memory is above this percent usage, 0 disables
45
+ alert_disk_threshold: 90
46
+ # Partitions which to monitor for free disk space
47
+ partitions:
48
+ - "/"
49
+
50
+ # The Apache built-in plugin
51
+ Apache:
52
+ # Enabled, set to either true or false
53
+ enabled: false
54
+ monitor_url: "http://localhost/foo"
55
+ username: "username"
56
+ password: "password"
57
+
58
+ # The IOStat built-in plugin
59
+ Iostat:
60
+ # Enabled, set to either true or false
61
+ enabled: false
62
+
63
+ # The MySQL built-in plugin
64
+ Mysql:
65
+ # Enabled, set to either true or false
66
+ enabled: false
67
+ username: "username"
68
+ password: "password"
69
+
70
+ # The Network Interface built-in plugin
71
+ Network:
72
+ # Enabled, set to either true or false
73
+ enabled: false
74
+ interfaces:
75
+ - eth0
76
+
77
+ # The Nginx built-in plugin
78
+ Nginx:
79
+ # Enabled, set to either true or false
80
+ enabled: false
81
+ username: "username"
82
+ password: "password"
83
+
84
+ # The Passenger Phusion built-in plugin
85
+ Passenger:
86
+ # Enabled, set to either true or false
87
+ enabled: false
88
+
89
+ # The Process List built-in plugin
90
+ Processes:
91
+ # Enabled, set to either true or false
92
+ enabled: false
93
+
94
+ # The Rails built-in plugin
95
+ Rails:
96
+ # Enabled, set to either true or false
97
+ enabled: false
98
+ log_file: "/var/www/rails/log/production.log"
99
+
100
+ # The Ruby built-in plugin
101
+ Ruby:
102
+ enabled: true
103
+ list_gems: true
104
+
105
+ #
106
+ # Other settings that you generally will not need to modify
107
+ #
108
+
109
+ # The API End Point in which to send our pings
110
+ #api_endpoint: "http://ping.qnotifier.com"
111
+ api_endpoint: "http://localhost:4567"
112
+
@@ -0,0 +1,20 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMRAwDgYDVQQDDAdnZXJz
3
+ aGFtMRkwFwYKCZImiZPyLGQBGRYJcW5vdGlmaWVyMRMwEQYKCZImiZPyLGQBGRYD
4
+ Y29tMB4XDTEwMDMxNzE4MjAwOFoXDTExMDMxNzE4MjAwOFowQjEQMA4GA1UEAwwH
5
+ Z2Vyc2hhbTEZMBcGCgmSJomT8ixkARkWCXFub3RpZmllcjETMBEGCgmSJomT8ixk
6
+ ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMS8vIaSE0eA
7
+ DfL3OqRwmY+b3ueQ+cfm2nxU1J+TE7yFFGiv+bk4z4YMtHtbqsGxlmL4HZKW7Ur/
8
+ RrS7+d+fVTskoRC7t9g6mRoww/4+fTgmX25g7YLe4vuiSBkBeBMXBt5Vd3ombU9F
9
+ b0CrguX2a2ffYxnF/RlrXnhsU2VywZry+qz1NJglaCa+qb0S0W3BnvoB8T+MxNOM
10
+ 7feKF/HvWRCM7DdHyqXqHFqMBIWJlCC7MFV4kQVW/a8b49VC5Dgmz6QVWcPqQ8cl
11
+ GK35UW+1WZXRB5Mhv5HBAQQqzLut46pxbUJ3qIpibtp1ltgyu81ZIRAwKIWx0YNv
12
+ lP5V85hTZ1ECAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUn3O2jt+12CmU
13
+ t1GEK8NZRNRbzqwwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQBb5gk8
14
+ OyfuloScbz/oHOopNmSc+o/s/5MvyrslPYDZA0WGR/63Q4Wl6l/tFFPwuAZH1KAI
15
+ MtLf7mVDdijHQf3Q6e+DicNRRQrl1w3s2m4PHyPiFUmXULzWHbMc3OK4LdM+1f5q
16
+ oZvsRrAAz6esBChxfdpuNCsP9Eu3j9MIWHy4KPTNuqOFyI+p3YVW2+SHeN4gBCyV
17
+ b7VZHIY+1kKjmMYXPeG9xlXaxLABhS1iN66tAyg66l6u6vuLt5Rdh1RUIY534Edq
18
+ ciUZJrPp/am/m0FtGWggbAohDKjiKRL0E6OCFQ7wSCTUPKoB9MbIJkKSGFo6ExWe
19
+ wu7A8rLN6CU0SfWf
20
+ -----END CERTIFICATE-----
data/lib/command.rb ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+ require "optparse"
3
+ require "qnotifier"
4
+
5
+ module Qnotifier
6
+ class Command
7
+
8
+ def self.parse_options(argv)
9
+ options = {}
10
+
11
+ op = OptionParser.new do |opts|
12
+
13
+ opts.banner = "\nQnotifier is an agent for the Qnotifer server reporting and alerting system"
14
+ opts.separator "See http://qnotifier.com for details."
15
+ opts.separator "\nUsage:"
16
+
17
+ opts.on("-r", "--register CODE", String, "Register agent with code.") do |register_code|
18
+ qnotifier = Qnotifier::Process.new
19
+ qnotifier.debug = true if @debug
20
+ qnotifier.register(register_code)
21
+ exit
22
+ end
23
+ opts.on("-v", "--version", "Displays the agent version") do |version|
24
+ puts "Qnotifier Agent Version: #{Qnotifier::VERSION}"
25
+ exit
26
+ end
27
+ opts.on("-d", "--debug", "Run in debug mode") do |debug|
28
+ @debug = true
29
+ end
30
+ opts.on("-h", "--help", "Shows this help") do
31
+ puts opts
32
+ exit
33
+ end
34
+ opts.separator "\n"
35
+ end
36
+
37
+ begin
38
+ op.parse!(argv)
39
+ @usage = op.to_s
40
+ rescue OptionParser::InvalidOption
41
+ puts op
42
+ exit
43
+ rescue OptionParser::MissingArgument
44
+ puts op
45
+ exit
46
+ end
47
+ options
48
+ end
49
+
50
+ def self.run(argv)
51
+ argv.push("--help") if argv.first == 'help'
52
+ options = parse_options(argv)
53
+ qnotifier = Qnotifier::Process.new
54
+ qnotifier.debug = true if @debug
55
+ qnotifier.run
56
+ end
57
+ end
58
+ end
59
+
data/lib/plugin.rb ADDED
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env ruby
2
+ require "storage"
3
+
4
+ # Subclass this to create a new plugin
5
+ # Note that plugins only get 30 seconds to run and do their thing
6
+ module Qnotifier
7
+ class Plugin
8
+
9
+ attr_accessor :reports
10
+ attr_accessor :alerts
11
+ attr_accessor :stats
12
+ attr_accessor :config
13
+ attr_accessor :alert_count
14
+
15
+ # The run method, do not override
16
+ def run
17
+ @class_name = self.class.to_s.split("::").last
18
+ @alert_count = 0
19
+
20
+ # Read the options from the global config and mix them in to the defaults for this plugin
21
+ if @config[@class_name]
22
+ @options = @defaults.update(@config[@class_name])
23
+ else
24
+ @options = @defaults
25
+ end
26
+
27
+ # Only run this plugin if it's enabled
28
+ return unless @options["enabled"]
29
+
30
+ Qnotifier.log.debug("Plugin #{@class_name} running")
31
+ main
32
+ end
33
+
34
+ # You'll need to override this in your subclass
35
+ def main
36
+ Qnotifier.log.error("You must implement the main method in the plugin: #{self.class.name}")
37
+ end
38
+
39
+ # Log something to console
40
+ # Log levels: log.info, log.warn, log.error, log.fatal, log.unknown
41
+ def log
42
+ return Qnotifier.log
43
+ end
44
+
45
+ # Alert is an alert to the adminstrators that something requires looking at
46
+ # Severity should usually be 3
47
+ def alert(name, message, severity = 3)
48
+ @alerts = {@class_name => []} unless @alerts
49
+ @alert_count += 1
50
+ # Only send the alert if we haven't already
51
+ if Qnotifier::Storage.get("AlertTime_#{@class_name}-#{name}")
52
+ # Check to see if we need to resend the alert
53
+ if @config["resend_alerts"] and Qnotifier::Storage.get("AlertTime_#{@class_name}-#{name}") < Time.now - @config["resend_alert_time"]
54
+ add_alert(name, message, severity)
55
+ else
56
+ Qnotifier.log.debug("Already sent alert: #{message}")
57
+ end
58
+ else
59
+ add_alert(name, message, severity)
60
+ end
61
+ end
62
+
63
+ # Add the alert to the outbound queue
64
+ def add_alert(name, message, severity)
65
+
66
+ if severity == 1 # emergency
67
+ log.fatal message
68
+ elsif severity == 2 # critical
69
+ log.error message
70
+ elsif severity == 3 # alert
71
+ log.error message
72
+ elsif severity == 4 # error
73
+ log.error message
74
+ elsif severity == 5 # warn
75
+ log.warn message
76
+ elsif severity == 6 # clear
77
+ log.info message
78
+ end
79
+ data = [name, message, severity]
80
+ @alerts[@class_name].push(data)
81
+ Qnotifier::Storage.put("AlertTime_#{@class_name}-#{name}", Time.now)
82
+ end
83
+
84
+ # Alert is no longer needed as the value has crossed back over the threshold value
85
+ def reset_alert(name, message)
86
+ @alerts = {@class_name => []} unless @alerts
87
+ if Qnotifier::Storage.get("AlertTime_#{@class_name}-#{name}")
88
+ log.warn message
89
+ Qnotifier::Storage.delete("AlertTime_#{@class_name}-#{name}")
90
+ data = [name, message, 6] # Clear
91
+ @alerts[@class_name].push(data)
92
+ end
93
+ end
94
+
95
+ # Report is an ongoing data point for graphing and realtime reporting for this server
96
+ def report(key, value)
97
+ @reports = {@class_name => []} unless @reports
98
+ @reports[@class_name].push([key, value])
99
+ end
100
+
101
+ # Stat is a one time statistic about this server, it doesn't get tracked and graphed
102
+ def stat(key, value)
103
+ @stats = {@class_name => {}} unless @stats
104
+ @stats[@class_name].merge!(key => value.to_s)
105
+ end
106
+
107
+ # Store this value for later retrieval
108
+ def put(key, value)
109
+ Qnotifier::Storage.put(key, value)
110
+ end
111
+
112
+ # Retrieve this value
113
+ def get(key)
114
+ Qnotifier::Storage.get(key)
115
+ end
116
+
117
+ # Delete the value
118
+ def delete(key)
119
+ Qnotifier::Storage.delete(key)
120
+ end
121
+ end
122
+ end
data/lib/qnotifier.rb ADDED
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env ruby
2
+ require "yaml"
3
+ require "timeout"
4
+ require "logger"
5
+ require "plugin"
6
+ require "web_service"
7
+ require "storage"
8
+
9
+ module Qnotifier
10
+ VERSION = "0.7.0".freeze
11
+
12
+ def self.log
13
+ unless @logger
14
+ begin
15
+ @logger = Logger.new("/var/log/qnotifier.log","monthly")
16
+ rescue Exception => e
17
+ puts "Error starting logging - using stdout (#{e.message})"
18
+ @logger = Logger.new($stdout)
19
+ end
20
+ end
21
+ return @logger
22
+ end
23
+
24
+ class Process
25
+
26
+ attr_accessor :debug
27
+
28
+ def initialize
29
+ Qnotifier::Storage.restore
30
+
31
+ @alerts = {}
32
+ @reports = {}
33
+ @stats = {}
34
+ @alert_count = 0
35
+ end
36
+
37
+ def start_logging
38
+ # Logging
39
+ if @debug
40
+ puts "Starting in debug mode"
41
+ Qnotifier.log.level = Logger::DEBUG
42
+ else
43
+ Qnotifier.log.level = Logger::INFO
44
+ end
45
+ end
46
+
47
+ def run
48
+ start_logging
49
+ load_config
50
+
51
+ last_run = Qnotifier::Storage.get("last_run")
52
+
53
+ if Qnotifier::Storage.get("server_disabled_pings")
54
+ Qnotifier.log.fatal "Disabled by the Qnotifer API, please re-register (qnotifier --register key) this agent to enable. Exiting."
55
+ exit
56
+ end
57
+
58
+ # Start up
59
+ Qnotifier.log.info "Running#{", last run: #{last_run}" if last_run}"
60
+ Qnotifier::Storage.put("last_run", Time.now) unless @debug
61
+ unless @debug
62
+ if last_run and (Time.now - last_run) < 120
63
+ message = "Starting too frequently, please run every 5 minutes (use debug mode to override)\nLast start up: #{last_run}"
64
+ puts message
65
+ Qnotifier.log.fatal message
66
+ exit
67
+ end
68
+ end
69
+
70
+ unless @config["api_key"]
71
+ error_message = "Missing API Key, please register this agent first."
72
+ puts error_message
73
+ Qnotifier.log.fatal error_message
74
+ exit
75
+ end
76
+
77
+ # Load the built in plugins
78
+ Dir[File.dirname(__FILE__) + '/../plugins/*.rb'].each do |file|
79
+ process_plugin_file(file)
80
+ end
81
+
82
+ # Load the user plugins
83
+ Dir[@config["plugin_directory"] + '/*.rb'].each do |file|
84
+ process_plugin_file(file)
85
+ end
86
+
87
+ # Send the alerts, reports and stats to the API
88
+ webservice = Qnotifier::WebService.new
89
+ webservice.config = @config
90
+ webservice.send_alerts(@alerts)
91
+ webservice.send_reports_stats(@reports, @stats, @alert_count)
92
+
93
+ Qnotifier::Storage.save
94
+
95
+ # Done, clean up and save
96
+ Qnotifier::Storage.save
97
+ end
98
+
99
+ def process_plugin_file(file)
100
+ return unless file =~ /\.rb/
101
+ require file
102
+ class_name = "Qnotifier::#{File.basename(file, ".rb").split(/[^a-z0-9]/i).map{|w| w.capitalize}.join}"
103
+ begin
104
+ plugin = eval(class_name).new
105
+ rescue
106
+ Qnotifier.log.error "Couldn't process the plugin file #{file}"
107
+ return
108
+ end
109
+ plugin.config = @config
110
+ unless plugin.class.superclass.name == "Qnotifier::Plugin"
111
+ Qnotifier.log.fatal "Attempted to load a non Qnotifier::Plugin plugin subclass at #{file} - make sure this directory only includes Qnotifier::Plugin subclasses"
112
+ return
113
+ end
114
+ begin
115
+ Timeout.timeout 30 do
116
+ plugin.run
117
+ end
118
+ rescue RuntimeError => e
119
+ Qnotifier.log.error "#{class_name} Plugin Error: #{e.message}"
120
+ rescue Errno::ENOENT => e
121
+ Qnotifier.log.error "#{class_name} Plugin Error: #{e.message}"
122
+ end
123
+ @alerts.merge!(plugin.alerts) if plugin.alerts
124
+ @reports.merge!(plugin.reports) if plugin.reports
125
+ @stats.merge!(plugin.stats) if plugin.stats
126
+ @alert_count += plugin.alert_count
127
+ end
128
+
129
+ def register(code)
130
+
131
+ start_logging
132
+ load_config
133
+
134
+ if @config["api_key"]
135
+ Qnotifier.log.error "Server already registered. You should not keep registering the server, you only need to do this once."
136
+ end
137
+
138
+ webservice = Qnotifier::WebService.new
139
+ webservice.config = @config
140
+ api_key = webservice.register_server(code)
141
+
142
+ save_api_key(api_key)
143
+
144
+ end
145
+
146
+ def save_api_key(api_key)
147
+ return unless api_key
148
+ @config["api_key"] = api_key
149
+ begin
150
+ File.open(File.dirname(__FILE__) + "/../var/api_key", 'w') {|f| f.write(api_key) }
151
+ rescue Exception => e
152
+ Qnotifier.log.fatal "Can't save API Key #{e.message}"
153
+ end
154
+ end
155
+
156
+ def load_config
157
+
158
+ # Make the var dir if it doesn't exist
159
+ var_dir = File.dirname(__FILE__) + "/../var"
160
+ FileUtils.mkdir_p var_dir
161
+
162
+ # Load from /etc/qnotifier_config.yml if the file is there
163
+ begin
164
+ @config = YAML::load(File.open('/etc/qnotifier_config.yml'))
165
+ rescue Exception => e
166
+ Qnotifier.log.error "Can't open /etc/qnotifier_config.yml (loading default config and copying it to /etc/qnotifier_config.yml)"
167
+ begin
168
+ default_config_file = File.dirname(__FILE__) + "/../config/qnotifier_config.yml"
169
+ @config = YAML::load(File.open(default_config_file))
170
+ `cp #{default_config_file} /etc/qnotifier_config.yml`
171
+ rescue Exception => e
172
+ Qnotifier.log.fatal "Can't open default config #{e.message}"
173
+ exit
174
+ end
175
+ end
176
+
177
+ unless @config["api_key"]
178
+ begin
179
+ api_key_file = File.open(File.dirname(__FILE__) + "/../var/api_key")
180
+ while (line = api_key_file.readline)
181
+ @config["api_key"] = line
182
+ end
183
+ rescue EOFError
184
+ rescue Exception => e
185
+ Qnotifier.log.debug "Can't get API key, have you registered?"
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
data/lib/storage.rb ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env
2
+ require "yaml"
3
+
4
+ module Qnotifier
5
+ class Storage
6
+
7
+ @@stored_variables = {}
8
+ @@restored = false
9
+
10
+ def self.restore
11
+ begin
12
+ saved_variables = File.dirname(__FILE__) + "/../var/saved_variables.yml"
13
+ @@stored_variables = YAML::load(File.open(saved_variables))
14
+ rescue Exception => e
15
+ Qnotifier.log.debug "Error loading stored variables file. #{e.message}"
16
+ end
17
+ @@restored = true
18
+ end
19
+
20
+ def self.get(key)
21
+ restore unless @@restored
22
+ if @@stored_variables[key]
23
+ return @@stored_variables[key]
24
+ else
25
+ return nil
26
+ end
27
+ end
28
+
29
+ def self.put(key, value)
30
+ restore unless @@restored
31
+ @@stored_variables[key] = value
32
+ end
33
+
34
+ def self.delete(key)
35
+ restore unless @@restored
36
+ @@stored_variables.delete(key)
37
+ end
38
+
39
+ def self.save
40
+ begin
41
+ saved_variables = File.dirname(__FILE__) + "/../var/saved_variables.yml"
42
+ File.open(saved_variables, "w") do |f|
43
+ f.write(YAML::dump(@@stored_variables))
44
+ end
45
+ rescue Exception => e
46
+ Qnotifier.log.error "Error saving stored variables file. #{e.message}"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rest_client'
3
+ require 'json'
4
+ require "storage"
5
+
6
+ module Qnotifier
7
+ class WebService
8
+
9
+ attr_accessor :config
10
+
11
+ def initialize
12
+
13
+ RestClient.proxy = ENV['http_proxy']
14
+ end
15
+
16
+ def send_alerts(alerts)
17
+
18
+ return if alerts.empty?
19
+ Qnotifier.log.debug "Sending #{alerts.count} alerts"
20
+
21
+ # Hostname
22
+ unless @config["hostname"]
23
+ @hostname = `hostname`.strip
24
+ else
25
+ @hostname = @config["hostname"]
26
+ end
27
+
28
+ message = {"api_key" => @config["api_key"],
29
+ "api_version" => "1.0",
30
+ "agent_version" => Qnotifier::VERSION,
31
+ "hostname" => @hostname,
32
+ "alerts" => alerts}.to_json
33
+
34
+ begin
35
+ resource = RestClient::Resource.new(@config["api_endpoint"],
36
+ :timeout => 30,
37
+ :headers => { :user_agent => "Qnotifier-#{Qnotifier::VERSION}" })
38
+ response = resource["/send_alert"].post(message, :content_type => 'application/json')
39
+
40
+ if response.code == 200
41
+ Qnotifier.log.debug "Server Response: HTTP #{response.code} #{response.body}"
42
+ else
43
+ Qnotifier.log.warn "Server Response: HTTP #{response.code} #{response.body}"
44
+ end
45
+
46
+ rescue Exception => e
47
+ Qnotifier.log.error "Sending Alerts: Can't connect to #{@config["api_endpoint"]} - #{e.message}"
48
+ if e.message == "HTTP status code 402"
49
+ # The server doesn't want to hear from us any more, disable pinging
50
+ Qnotifier::Storage.put("server_disabled_pings", Time.now)
51
+ Qnotifier.log.error "Server has asked us to disable pings"
52
+ end
53
+ end
54
+ end
55
+
56
+ def send_reports_stats(reports, stats, alert_count)
57
+
58
+ return if reports.empty? and stats.empty?
59
+ Qnotifier.log.debug "Sending Reports and Stats"
60
+
61
+ # Hostname
62
+ unless @config["hostname"]
63
+ @hostname = `hostname`.strip
64
+ else
65
+ @hostname = @config["hostname"]
66
+ end
67
+
68
+ message = {"api_key" => @config["api_key"],
69
+ "api_version" => "1.0",
70
+ "agent_version" => Qnotifier::VERSION,
71
+ "hostname" => @hostname,
72
+ "stats" => stats,
73
+ "alert_count" => alert_count,
74
+ "reports" => reports}.to_json
75
+
76
+ begin
77
+ resource = RestClient::Resource.new(@config["api_endpoint"],
78
+ :timeout => 30,
79
+ :headers => { :user_agent => "Qnotifier-#{Qnotifier::VERSION}" })
80
+ response = resource["/update_server"].post(message, :content_type => 'application/json')
81
+
82
+ if response.code == 200
83
+ Qnotifier.log.debug "Server Response: HTTP #{response.code} #{response.body}"
84
+ else
85
+ Qnotifier.log.warn "Server Response: HTTP #{response.code} #{response.body}"
86
+ end
87
+
88
+ rescue Exception => e
89
+ Qnotifier.log.error "Sending Reports/Stats: Can't connect to #{@config["api_endpoint"]} - #{e.message}"
90
+ if e.message == "HTTP status code 402"
91
+ # The server doesn't want to hear from us any more, disable pinging
92
+ Qnotifier::Storage.put("server_disabled_pings", Time.now)
93
+ Qnotifier.log.error "Server has asked us to disable pings"
94
+ end
95
+ end
96
+ end
97
+
98
+ def register_server(temp_key)
99
+ return if temp_key.empty?
100
+ Qnotifier.log.info "Registering Server"
101
+
102
+ message = {"temp_key" => temp_key, "hostname" => `hostname`.strip}.to_json
103
+
104
+ begin
105
+ resource = RestClient::Resource.new(@config["api_endpoint"],
106
+ :timeout => 30,
107
+ :headers => { :user_agent => "Qnotifier-#{Qnotifier::VERSION}" })
108
+ response = resource["/register_server"].post(message, :content_type => 'application/json')
109
+
110
+ if response.code == 200 and response.body
111
+ Qnotifier.log.debug "Registration Request Response: HTTP #{response.code} #{response.body}"
112
+ puts "OK, the server has been successfully registered."
113
+ puts "You now need to call this script from cron every 5 minutes, add to root's crontab (sudo crontab -e):"
114
+ puts "*/5 * * * * qnotifier"
115
+ return response.body
116
+ else
117
+ Qnotifier.log.warn "Registration Request Response: HTTP #{response.code} #{response.body}"
118
+ end
119
+
120
+ rescue Exception => e
121
+ if e.message == "Bad Request"
122
+ puts "Can\'t find that key to register the server, please check it and try again. The key may have expired."
123
+ Qnotifier.log.error "Can\'t find that key to register the server, please check it and try again. The key may have expired."
124
+ else
125
+ Qnotifier.log.error "Registering Server: Can't connect to #{@config["api_endpoint"]} - #{e.message}"
126
+ end
127
+ end
128
+
129
+ return nil
130
+ end
131
+ end
132
+ end
data/plugins/apache.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Apache < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
data/plugins/iostat.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Iostat < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
data/plugins/mysql.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Mysql < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Network < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
data/plugins/nginx.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Nginx < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Passenger < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Processes < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
data/plugins/rails.rb ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+ require "elif"
3
+
4
+ module Qnotifier
5
+ class Rails < Qnotifier::Plugin
6
+
7
+ def initialize
8
+ @defaults = {
9
+ :rails_log_file => "/var/www/rails/log/production.log"
10
+ }
11
+ patch_elif
12
+ end
13
+
14
+ def main
15
+ puts "here"
16
+ #log_file = read_backwards_to_timestamp(@options[:rails_log_file], last_summary)
17
+ end
18
+
19
+ def patch_elif
20
+ if Elif::VERSION < "0.2.0"
21
+ Elif.send(:define_method, :pos) do
22
+ @current_pos +
23
+ @line_buffer.inject(0) { |bytes, line| bytes + line.size }
24
+ end
25
+ end
26
+ end
27
+
28
+ def read_backwards_to_timestamp(path, timestamp)
29
+ start = nil
30
+ Elif.open(path) do |elif|
31
+ elif.each do |line|
32
+ if line =~ /\AProcessing .+ at (\d+-\d+-\d+ \d+:\d+:\d+)\)/
33
+ time_of_request = Time.parse($1)
34
+ if time_of_request < timestamp
35
+ break
36
+ else
37
+ start = elif.pos
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ file = open(path)
44
+ file.seek(start) if start
45
+ file
46
+ end
47
+ end
48
+ end
data/plugins/ruby.rb ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Ruby < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ # Ruby Info
12
+ ruby_info = [RUBY_VERSION, RUBY_RELEASE_DATE, RUBY_PATCHLEVEL, RUBY_PLATFORM]
13
+ stat("Ruby", "ruby %s (%s patchlevel %s) [%s]" % ruby_info)
14
+
15
+ # Gems
16
+ gem_list = `gem list`.split("\n")
17
+ gems = []
18
+ if gem_list
19
+ for line in gem_list
20
+ next if line.match(/^[\*\n]/)
21
+ gems << line.strip
22
+ end
23
+ stat("Gems", gems.join(", "))
24
+ end
25
+ end
26
+ end
27
+ end
data/plugins/system.rb ADDED
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class System < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ "enabled" => true,
8
+ "use_load" => "five_minute",
9
+ "normalize_load" => true,
10
+ "alert_cpu_threshold" => 0,
11
+ "alert_memory_threshold" => 0,
12
+ "alert_load_threshold" => 2.0,
13
+ "alert_disk_threshold" => 0,
14
+ "partitions" => ["/"]
15
+ }
16
+ count_cpus
17
+ end
18
+
19
+ def main
20
+
21
+ # Uptime, Users and Load Average
22
+ uptime = `uptime`.strip
23
+ if uptime
24
+ if uptime =~ /load average(s*): ([\d.]+)(,*) ([\d.]+)(,*) ([\d.]+)\Z/
25
+ load_one_minute = $2.to_f
26
+ load_five_minute = $4.to_f
27
+ load_fifteen_minute = $6.to_f
28
+
29
+ if @options["normalize_load"]
30
+ load_one_minute = load_one_minute / @cpu_count
31
+ load_five_minute = load_five_minute / @cpu_count
32
+ load_fifteen_minute = load_fifteen_minute / @cpu_count
33
+ end
34
+
35
+ case @options["use_load"]
36
+ when "one_minute"
37
+ load_average = load_one_minute
38
+ when "five_minute"
39
+ load_average = load_one_minute
40
+ else
41
+ load_average = load_one_minute
42
+ end
43
+
44
+ report("Load", load_average)
45
+ stat("Load", load_average)
46
+
47
+ if @options["alert_load_threshold"] != 0 and load_average >= @options["alert_load_threshold"]
48
+ alert("load", "Load is at #{load_average} #{"(normalized)" if @options[:normalize_load]}")
49
+ else
50
+ reset_alert("load", "Load is now #{load_average}")
51
+ end
52
+
53
+ else
54
+ raise "Unable to parse load averages"
55
+ end
56
+
57
+ stat("Uptime", uptime)
58
+ end
59
+
60
+ # CPU
61
+ vmstat = `vmstat | tail -1`
62
+ if vmstat
63
+ vmstat = vmstat.split
64
+ if vmstat.size == 16
65
+
66
+ cpu = "User: #{vmstat[12].to_i}%, System: #{vmstat[13].to_i}%, Idle: #{vmstat[14].to_i}%, Wait: #{vmstat[15].to_i}%"
67
+ cpu_percent = (100 - vmstat[14].to_i)
68
+
69
+ stat("CPU", cpu)
70
+ report("CPU %", cpu_percent)
71
+
72
+ if @options["alert_cpu_threshold"] != 0 and cpu_percent >= @options["alert_cpu_threshold"]
73
+ alert("cpu", "CPU is at #{cpu_percent}%")
74
+ else
75
+ reset_alert("cpu", "CPU is now #{cpu_percent}%")
76
+ end
77
+
78
+ else
79
+ raise "Can't parse vmstat"
80
+ end
81
+ else
82
+ raise "Can't run vmstat, is it installed/supported?"
83
+ end
84
+
85
+ # Disk
86
+ df = `df -Phl`
87
+ if df
88
+ df = df.split("\n")
89
+ for partition in @options["partitions"]
90
+ for line in df
91
+ if line =~ /#{partition}$/
92
+ items = line.split
93
+
94
+ disk = "Used: #{items[-2]} (#{items[-4]}), #{items[-3]} free"
95
+ stat("Disk #{partition}", disk) if partition == "/"
96
+ report("Disk #{partition} %", items[-2].delete("%").to_i)
97
+
98
+ if @options["alert_disk_threshold"] != 0 and items[-2].delete("%").to_i >= @options["alert_disk_threshold"]
99
+ alert("partition-#{partition}", "Partition #{partition} is at #{items[-2]}")
100
+ else
101
+ reset_alert("partition-#{partition}", "Partition #{partition} is now #{items[-2]}")
102
+ end
103
+ end
104
+ end
105
+ end
106
+ else
107
+ raise "Can't run df -Phl"
108
+ end
109
+
110
+
111
+ # Uname
112
+ stat("Uname", `uname -srm`.strip)
113
+
114
+ # Memory
115
+ meminfo = {}
116
+ `cat /proc/meminfo`.each_line do |line|
117
+ _, key, value = *line.match(/^(\w+):\s+(\d+)\s/)
118
+ meminfo[key] = value.to_i
119
+ end
120
+
121
+ memory = {}
122
+ unless meminfo.empty?
123
+ memory["Free"] = meminfo['MemFree'] / 1024
124
+ memory["Total"] = meminfo['MemTotal'] / 1024
125
+ memory_percent = ((memory["Total"] - memory["Free"]) / memory["Total"] * 100).to_i
126
+ memory["Percent"] = memory_percent
127
+
128
+ stat("Memory", "Free: #{memory["Free"]}M, Total: #{memory["Total"]}M")
129
+ report("Memory %", memory_percent)
130
+
131
+ if @options["alert_memory_threshold"] != 0 and memory_percent >= @options["alert_memory_threshold"]
132
+ alert("memory", "Memory is at #{memory_percent}%")
133
+ else
134
+ reset_alert("memory", "Memory is now #{memory_percent}%")
135
+ end
136
+ else
137
+ raise "Can't get memory information from /proc/meminfo (is it supported by this OS?)"
138
+ end
139
+
140
+
141
+ end
142
+
143
+
144
+ def count_cpus
145
+ if get("cpu_count")
146
+ @cpu_count = get("cpu_count")
147
+ else
148
+ cpu_count = `cat /proc/cpuinfo | grep "model name" | wc -l`.to_i
149
+ if cpu_count != 0
150
+ @cpu_count = cpu_count
151
+ else
152
+ @cpu_count = 1
153
+ end
154
+ put("cpu_count", @cpu_count)
155
+ end
156
+ end
157
+ end
158
+ end
data/plugins/urls.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Urls < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
data/qnotifier.gemspec ADDED
@@ -0,0 +1,53 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{qnotifier}
5
+ s.version = "0.6.2"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Gersham Meharg"]
9
+ s.date = %q{2010-03-17}
10
+ s.default_executable = %q{qnotifier}
11
+ s.description = %q{The server side agent for the QNotifier monitoring system. This software will monitor local Linux system parameters and upload them to the Qnotifier servers where users can use iPhone/iPad applications to view those stats and recevie alerts.}
12
+ s.email = %q{gersham@qnotifier.com}
13
+ s.executables = ["qnotifier"]
14
+ s.extra_rdoc_files = ["bin/qnotifier", "lib/command.rb", "lib/plugin.rb", "lib/qnotifier.rb", "lib/storage.rb", "lib/web_service.rb"]
15
+ s.files = ["Manifest", "Rakefile", "bin/qnotifier", "config/qnotifier_config.yml", "gem-public_cert.pem", "lib/command.rb", "lib/plugin.rb", "lib/qnotifier.rb", "lib/storage.rb", "lib/web_service.rb", "plugins/apache.rb", "plugins/iostat.rb", "plugins/mysql.rb", "plugins/network.rb", "plugins/nginx.rb", "plugins/passenger.rb", "plugins/processes.rb", "plugins/rails.rb", "plugins/ruby.rb", "plugins/system.rb", "plugins/urls.rb", "qnotifier.gemspec"]
16
+ s.homepage = %q{http://qnotifier.com/qnotifier_gem}
17
+ s.post_install_message = %q{Qnotifier installed, please register by running 'qnotifier -r CODE' in order to register this server.}
18
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Qnotifier"]
19
+ s.require_paths = ["lib"]
20
+ s.rubyforge_project = %q{qnotifier}
21
+ s.rubygems_version = %q{1.3.5}
22
+ s.summary = %q{The server side agent for the QNotifier monitoring system}
23
+ s.signing_key = "/Users/gersham/Sources/qanix-documents/qnotifier-gem-private_key.pem"
24
+ s.cert_chain = ['gem-public_cert.pem']
25
+
26
+ if s.respond_to? :specification_version then
27
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
28
+ s.specification_version = 3
29
+
30
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
31
+ s.add_runtime_dependency(%q<rest-client>, [">= 1.4.2"])
32
+ s.add_runtime_dependency(%q<json>, [">= 1.2.3"])
33
+ s.add_runtime_dependency(%q<elif>, [">= 0.1.0"])
34
+ s.add_development_dependency(%q<rest-client>, [">= 1.4.2"])
35
+ s.add_development_dependency(%q<json>, [">= 1.2.3"])
36
+ s.add_development_dependency(%q<elif>, [">= 0.1.0"])
37
+ else
38
+ s.add_dependency(%q<rest-client>, [">= 1.4.2"])
39
+ s.add_dependency(%q<json>, [">= 1.2.3"])
40
+ s.add_dependency(%q<elif>, [">= 0.1.0"])
41
+ s.add_dependency(%q<rest-client>, [">= 1.4.2"])
42
+ s.add_dependency(%q<json>, [">= 1.2.3"])
43
+ s.add_dependency(%q<elif>, [">= 0.1.0"])
44
+ end
45
+ else
46
+ s.add_dependency(%q<rest-client>, [">= 1.4.2"])
47
+ s.add_dependency(%q<json>, [">= 1.2.3"])
48
+ s.add_dependency(%q<elif>, [">= 0.1.0"])
49
+ s.add_dependency(%q<rest-client>, [">= 1.4.2"])
50
+ s.add_dependency(%q<json>, [">= 1.2.3"])
51
+ s.add_dependency(%q<elif>, [">= 0.1.0"])
52
+ end
53
+ end
data.tar.gz.sig ADDED
Binary file
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qnotifier
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.2
5
+ platform: ruby
6
+ authors:
7
+ - Gersham Meharg
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMRAwDgYDVQQDDAdnZXJz
14
+ aGFtMRkwFwYKCZImiZPyLGQBGRYJcW5vdGlmaWVyMRMwEQYKCZImiZPyLGQBGRYD
15
+ Y29tMB4XDTEwMDMxNzE4MjAwOFoXDTExMDMxNzE4MjAwOFowQjEQMA4GA1UEAwwH
16
+ Z2Vyc2hhbTEZMBcGCgmSJomT8ixkARkWCXFub3RpZmllcjETMBEGCgmSJomT8ixk
17
+ ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMS8vIaSE0eA
18
+ DfL3OqRwmY+b3ueQ+cfm2nxU1J+TE7yFFGiv+bk4z4YMtHtbqsGxlmL4HZKW7Ur/
19
+ RrS7+d+fVTskoRC7t9g6mRoww/4+fTgmX25g7YLe4vuiSBkBeBMXBt5Vd3ombU9F
20
+ b0CrguX2a2ffYxnF/RlrXnhsU2VywZry+qz1NJglaCa+qb0S0W3BnvoB8T+MxNOM
21
+ 7feKF/HvWRCM7DdHyqXqHFqMBIWJlCC7MFV4kQVW/a8b49VC5Dgmz6QVWcPqQ8cl
22
+ GK35UW+1WZXRB5Mhv5HBAQQqzLut46pxbUJ3qIpibtp1ltgyu81ZIRAwKIWx0YNv
23
+ lP5V85hTZ1ECAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUn3O2jt+12CmU
24
+ t1GEK8NZRNRbzqwwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQBb5gk8
25
+ OyfuloScbz/oHOopNmSc+o/s/5MvyrslPYDZA0WGR/63Q4Wl6l/tFFPwuAZH1KAI
26
+ MtLf7mVDdijHQf3Q6e+DicNRRQrl1w3s2m4PHyPiFUmXULzWHbMc3OK4LdM+1f5q
27
+ oZvsRrAAz6esBChxfdpuNCsP9Eu3j9MIWHy4KPTNuqOFyI+p3YVW2+SHeN4gBCyV
28
+ b7VZHIY+1kKjmMYXPeG9xlXaxLABhS1iN66tAyg66l6u6vuLt5Rdh1RUIY534Edq
29
+ ciUZJrPp/am/m0FtGWggbAohDKjiKRL0E6OCFQ7wSCTUPKoB9MbIJkKSGFo6ExWe
30
+ wu7A8rLN6CU0SfWf
31
+ -----END CERTIFICATE-----
32
+
33
+ date: 2010-03-17 00:00:00 -07:00
34
+ default_executable: qnotifier
35
+ dependencies:
36
+ - !ruby/object:Gem::Dependency
37
+ name: rest-client
38
+ type: :runtime
39
+ version_requirement:
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 1.4.2
45
+ version:
46
+ - !ruby/object:Gem::Dependency
47
+ name: json
48
+ type: :runtime
49
+ version_requirement:
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.2.3
55
+ version:
56
+ - !ruby/object:Gem::Dependency
57
+ name: elif
58
+ type: :runtime
59
+ version_requirement:
60
+ version_requirements: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 0.1.0
65
+ version:
66
+ - !ruby/object:Gem::Dependency
67
+ name: rest-client
68
+ type: :development
69
+ version_requirement:
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 1.4.2
75
+ version:
76
+ - !ruby/object:Gem::Dependency
77
+ name: json
78
+ type: :development
79
+ version_requirement:
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 1.2.3
85
+ version:
86
+ - !ruby/object:Gem::Dependency
87
+ name: elif
88
+ type: :development
89
+ version_requirement:
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 0.1.0
95
+ version:
96
+ description: The server side agent for the QNotifier monitoring system. This software will monitor local Linux system parameters and upload them to the Qnotifier servers where users can use iPhone/iPad applications to view those stats and recevie alerts.
97
+ email: gersham@qnotifier.com
98
+ executables:
99
+ - qnotifier
100
+ extensions: []
101
+
102
+ extra_rdoc_files:
103
+ - bin/qnotifier
104
+ - lib/command.rb
105
+ - lib/plugin.rb
106
+ - lib/qnotifier.rb
107
+ - lib/storage.rb
108
+ - lib/web_service.rb
109
+ files:
110
+ - Manifest
111
+ - Rakefile
112
+ - bin/qnotifier
113
+ - config/qnotifier_config.yml
114
+ - gem-public_cert.pem
115
+ - lib/command.rb
116
+ - lib/plugin.rb
117
+ - lib/qnotifier.rb
118
+ - lib/storage.rb
119
+ - lib/web_service.rb
120
+ - plugins/apache.rb
121
+ - plugins/iostat.rb
122
+ - plugins/mysql.rb
123
+ - plugins/network.rb
124
+ - plugins/nginx.rb
125
+ - plugins/passenger.rb
126
+ - plugins/processes.rb
127
+ - plugins/rails.rb
128
+ - plugins/ruby.rb
129
+ - plugins/system.rb
130
+ - plugins/urls.rb
131
+ - qnotifier.gemspec
132
+ has_rdoc: true
133
+ homepage: http://qnotifier.com/qnotifier_gem
134
+ licenses: []
135
+
136
+ post_install_message: Qnotifier installed, please register by running 'qnotifier -r CODE' in order to register this server.
137
+ rdoc_options:
138
+ - --line-numbers
139
+ - --inline-source
140
+ - --title
141
+ - Qnotifier
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: "0"
149
+ version:
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: "1.2"
155
+ version:
156
+ requirements: []
157
+
158
+ rubyforge_project: qnotifier
159
+ rubygems_version: 1.3.5
160
+ signing_key:
161
+ specification_version: 3
162
+ summary: The server side agent for the QNotifier monitoring system
163
+ test_files: []
164
+
metadata.gz.sig ADDED
Binary file