heartcheck 1.0.0
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.
- checksums.yaml +7 -0
- data/bin/heartcheck +29 -0
- data/lib/generators/generator.rb +63 -0
- data/lib/generators/templates/config.rb +67 -0
- data/lib/heartcheck.rb +111 -0
- data/lib/heartcheck/app.rb +65 -0
- data/lib/heartcheck/checks.rb +3 -0
- data/lib/heartcheck/checks/base.rb +101 -0
- data/lib/heartcheck/checks/firewall.rb +26 -0
- data/lib/heartcheck/checks/process.rb +30 -0
- data/lib/heartcheck/controllers/base.rb +22 -0
- data/lib/heartcheck/controllers/dev.rb +34 -0
- data/lib/heartcheck/controllers/essential.rb +9 -0
- data/lib/heartcheck/controllers/functional.rb +9 -0
- data/lib/heartcheck/controllers/health_check.rb +9 -0
- data/lib/heartcheck/controllers/info.rb +11 -0
- data/lib/heartcheck/errors.rb +2 -0
- data/lib/heartcheck/errors/routing_error.rb +6 -0
- data/lib/heartcheck/errors/warning.rb +6 -0
- data/lib/heartcheck/logger.rb +53 -0
- data/lib/heartcheck/services.rb +1 -0
- data/lib/heartcheck/services/firewall.rb +72 -0
- data/lib/heartcheck/version.rb +3 -0
- metadata +248 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 30402737433dacfa08875ade181a6fb9570b6b0a
|
4
|
+
data.tar.gz: d6747a981694289118544f929e70cb254153bdf4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3be0e45e564098d82e130030a69aaaca7c9858de1021629178745afd803db934f4ed439d9b9c580d67454519b950db42c082220b919992f8e08ae7336a6f73e7
|
7
|
+
data.tar.gz: d4129a1cf932d1ae0e3d724231dc03a0f7a02f158632318d372ee1c29f27cdc581c15983e1fdeafbe209711118769e29301b6a1ae131d9850b81a24991a319ab
|
data/bin/heartcheck
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'optparse'
|
5
|
+
$LOAD_PATH.push File.expand_path('../../lib', __FILE__)
|
6
|
+
require 'heartcheck'
|
7
|
+
|
8
|
+
optparse = OptionParser.new do |opts|
|
9
|
+
opts.banner = "Usage: heartcheck (rails|padrino|sinatra)\n\nYou can use flags as such:"
|
10
|
+
|
11
|
+
opts.on('-h', '--help', 'Display this screen') do
|
12
|
+
puts opts
|
13
|
+
exit
|
14
|
+
end
|
15
|
+
|
16
|
+
if ARGV.size != 1 || !%w(rails sinatra padrino).include?(ARGV[0])
|
17
|
+
puts opts
|
18
|
+
exit
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
optparse.parse!
|
24
|
+
rescue OptionParser::InvalidOption => e
|
25
|
+
puts e
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
|
29
|
+
Heartcheck::Generator.new(ARGV).invoke_all
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'thor/group'
|
2
|
+
|
3
|
+
module Heartcheck
|
4
|
+
class Generator < Thor::Group
|
5
|
+
include Thor::Actions
|
6
|
+
|
7
|
+
desc 'generate default files and instructions to use the Heartcheck'
|
8
|
+
|
9
|
+
argument :framework
|
10
|
+
|
11
|
+
def self.source_root
|
12
|
+
File.join(File.dirname(__FILE__), 'templates')
|
13
|
+
end
|
14
|
+
|
15
|
+
def show_framework
|
16
|
+
box framework.capitalize, :green
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate_initializer
|
20
|
+
template('config.rb', initializer_path)
|
21
|
+
end
|
22
|
+
|
23
|
+
def generate_route
|
24
|
+
case framework
|
25
|
+
when 'rails'
|
26
|
+
instructions(
|
27
|
+
'config/routes.rb',
|
28
|
+
'mount Heartcheck::App.new, at: "/monitoring"'
|
29
|
+
)
|
30
|
+
when 'padrino', 'sinatra'
|
31
|
+
instructions(
|
32
|
+
'config.ru', %(require "heartcheck"
|
33
|
+
map "/monitoring" do
|
34
|
+
use Heartcheck::App
|
35
|
+
end)
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def include_empty_lines
|
41
|
+
puts "\n\n"
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def instructions(file_name, file_content)
|
47
|
+
box "Include the following content to file #{file_name}"
|
48
|
+
say file_content, :blue
|
49
|
+
end
|
50
|
+
|
51
|
+
def box(content, color = :red)
|
52
|
+
size = content.size
|
53
|
+
say "#{'=' * (size + 2)}\n #{content}\n#{'=' * (size + 2)}\n", color
|
54
|
+
end
|
55
|
+
|
56
|
+
def initializer_path
|
57
|
+
case framework
|
58
|
+
when 'rails' then 'config/initializers/heartcheck.rb'
|
59
|
+
when 'padrino', 'sinatra' then 'app/app.rb'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
Heartcheck.setup do |monitor|
|
2
|
+
# monitor has a default logger but you can use yours
|
3
|
+
# default value: Logger.new(STDOUT)
|
4
|
+
# monitor.logger = Rails.logger
|
5
|
+
|
6
|
+
# Services
|
7
|
+
# For each service you can set the folling options
|
8
|
+
# name: String => root name to show in report page (default: class.name)
|
9
|
+
# functional: Boolean => options to set if this service is optional (default: false)
|
10
|
+
# on_error: Block => to customize the errors (default: nil)
|
11
|
+
# to_validate: Block => to validate the sevices (default: nil)
|
12
|
+
#
|
13
|
+
# See the exemple bellow to undertand how you can configure it.
|
14
|
+
#
|
15
|
+
# monitor.add :base do |c|
|
16
|
+
# c.name = "filesystem"
|
17
|
+
# c.functional = true
|
18
|
+
# c.add_service(name: "my_file", path: "/var/www/my_project/my_file")
|
19
|
+
#
|
20
|
+
# c.on_error do |sevices|
|
21
|
+
# errors << "Custom error message for #{service[:name]}"
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# c.to_validate do |services, errors|
|
25
|
+
# services.each do |service|
|
26
|
+
# errors << "erro message" unless if File.exists?(service[:path])
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
|
31
|
+
# Firewall
|
32
|
+
# check with telnet if the firewall is open to conect to the service
|
33
|
+
monitor.add :firewall do |c|
|
34
|
+
# you can add service wth (host and port) or (url)
|
35
|
+
c.add_service(host: 'lala.com', port: 80)
|
36
|
+
c.add_service(url: 'http://lalal.com')
|
37
|
+
|
38
|
+
# add dynamic services when you need it run after initializer
|
39
|
+
c.register_dynamic_services do
|
40
|
+
Pmta.all.map { |p| { host: p.host, port: 25 } }
|
41
|
+
end
|
42
|
+
|
43
|
+
# to customize default error message, the default is:
|
44
|
+
# "connection refused on: #{service.host}:#{service.port}"
|
45
|
+
# params
|
46
|
+
# errors: Array => errors to show on page
|
47
|
+
# service: FirewallService => object that respond to :host and :port
|
48
|
+
c.on_error do |_errors, service|
|
49
|
+
erros << "Custom error message for #{service.host}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Redis
|
54
|
+
# check if you redis conection is working
|
55
|
+
# you need to send a redis conection as a service
|
56
|
+
monitor.add :redis do |c|
|
57
|
+
c.add_service(name: 'Redis', connection: Resque.redis)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Cache
|
61
|
+
# check if your cache is working
|
62
|
+
# you can pass any kind of cache, but this need to respond to
|
63
|
+
# set, get and delete
|
64
|
+
monitor.add :cache do |c|
|
65
|
+
c.add_service(name: 'memcached', connection: Rails.cache.instance_variable_get('@data'))
|
66
|
+
end
|
67
|
+
end
|
data/lib/heartcheck.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
module Heartcheck
|
2
|
+
require 'logger'
|
3
|
+
require 'heartcheck/app'
|
4
|
+
require 'heartcheck/checks'
|
5
|
+
require 'heartcheck/errors'
|
6
|
+
require 'heartcheck/services'
|
7
|
+
require 'heartcheck/logger'
|
8
|
+
|
9
|
+
@checks = []
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# @attr [Array<Checks>] the checks to use when checking
|
13
|
+
attr_accessor :checks
|
14
|
+
# @attr_writer [Object] change the default logger
|
15
|
+
attr_writer :logger
|
16
|
+
|
17
|
+
# Is used to log some messages when checking if the logger
|
18
|
+
# is not set it's returns de default_logger.
|
19
|
+
#
|
20
|
+
# @return [Object] the logger object
|
21
|
+
def logger
|
22
|
+
@logger ||= default_logger
|
23
|
+
end
|
24
|
+
|
25
|
+
# @abstract
|
26
|
+
# Is used to configure.
|
27
|
+
#
|
28
|
+
# @yield A bock that recieve the class
|
29
|
+
# @example
|
30
|
+
# Heartcheck.setup do |c|
|
31
|
+
# puts c
|
32
|
+
# end
|
33
|
+
# @return [void]
|
34
|
+
def setup
|
35
|
+
yield(self)
|
36
|
+
end
|
37
|
+
|
38
|
+
# It's used to add an instance of a check
|
39
|
+
# to the check list
|
40
|
+
#
|
41
|
+
# @param [String] name to identify in the result page
|
42
|
+
# @param [Hash] options the options to create an instance of a check.
|
43
|
+
# @option options [String] :class The class name to get an instance
|
44
|
+
# @yield a block to config the instance
|
45
|
+
# @example
|
46
|
+
# Heartcheck.add(:base) do |c|
|
47
|
+
# c.name = 'Base check'
|
48
|
+
# end
|
49
|
+
# @return [void]
|
50
|
+
def add(name, options = {}, &block)
|
51
|
+
class_name = options.fetch(:class) { constantize(name) }
|
52
|
+
instance = Checks.const_get(class_name).new
|
53
|
+
|
54
|
+
if block_given?
|
55
|
+
checks << instance.tap(&block)
|
56
|
+
else
|
57
|
+
checks << instance
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# filter checks that are essential
|
62
|
+
#
|
63
|
+
# @return [Array<Check>] checks that are essential
|
64
|
+
def essential_checks
|
65
|
+
checks.select { |ctx| !ctx.functional? && !ctx.dev? }
|
66
|
+
end
|
67
|
+
|
68
|
+
# filter checks that are functional
|
69
|
+
#
|
70
|
+
# @return [Array<Check>] checks that are functional
|
71
|
+
def functional_checks
|
72
|
+
checks.select(&:functional?)
|
73
|
+
end
|
74
|
+
|
75
|
+
# filter checks that are not functional
|
76
|
+
#
|
77
|
+
# @return [Array<Check>] checks that are not functional
|
78
|
+
def dev_checks
|
79
|
+
checks.select { |ctx| !ctx.functional? }
|
80
|
+
end
|
81
|
+
|
82
|
+
# filter checks that has some information
|
83
|
+
#
|
84
|
+
# @return [Array<Check>] checks that respond to :info
|
85
|
+
def info_checks
|
86
|
+
checks.select { |ctx| ctx.respond_to?(:info) }
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
# if no logger is setted we create an instance
|
92
|
+
# of ruby logger with STDOUT
|
93
|
+
#
|
94
|
+
# @return [Logger] a ruby logger to STDOUT and info level
|
95
|
+
def default_logger
|
96
|
+
log = ::Logger.new(STDOUT)
|
97
|
+
log.level = ::Logger::INFO
|
98
|
+
log
|
99
|
+
end
|
100
|
+
|
101
|
+
# helper method to get a constant
|
102
|
+
#
|
103
|
+
# @example
|
104
|
+
# contantize('my_check') => 'MyCheck'
|
105
|
+
# @param [String] name of class
|
106
|
+
# @return [String]
|
107
|
+
def constantize(name)
|
108
|
+
name.to_s.split('_').map(&:capitalize).join
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'heartcheck/controllers/base'
|
3
|
+
|
4
|
+
Dir.glob(File.expand_path('../controllers/*.rb', __FILE__))
|
5
|
+
.each { |x| require x }
|
6
|
+
|
7
|
+
# A web app that's use rack
|
8
|
+
module Heartcheck
|
9
|
+
class App
|
10
|
+
# A hash with paths as keys and controllers
|
11
|
+
# as values we use it in #dispath_action
|
12
|
+
# to routes the requests
|
13
|
+
ROUTE_TO_CONTROLLER = {
|
14
|
+
'/' => Controllers::Essential,
|
15
|
+
'' => Controllers::Essential,
|
16
|
+
'/functional' => Controllers::Functional,
|
17
|
+
'/dev' => Controllers::Dev,
|
18
|
+
'/info' => Controllers::Info,
|
19
|
+
'/health_check' => Controllers::HealthCheck
|
20
|
+
}
|
21
|
+
|
22
|
+
# Sets up the rack application.
|
23
|
+
#
|
24
|
+
# @param app [RackApp] is a rack app where
|
25
|
+
# heartcheck is included.
|
26
|
+
# @return [void]
|
27
|
+
def initialize(app = nil)
|
28
|
+
@app = app
|
29
|
+
end
|
30
|
+
|
31
|
+
# Sets up the rack application.
|
32
|
+
#
|
33
|
+
# @param env [Hash] is an instance of Hash
|
34
|
+
# that includes CGI-like headers.
|
35
|
+
# @return [Array] must be an array that contains
|
36
|
+
# - The HTTP response code
|
37
|
+
# - A Hash of headers
|
38
|
+
# - The response body, which must respond to each
|
39
|
+
def call(env)
|
40
|
+
req = Rack::Request.new(env)
|
41
|
+
|
42
|
+
[200, { 'Content-Type' => 'application/json' }, [dispatch_action(req)]]
|
43
|
+
rescue Heartcheck::Errors::RoutingError
|
44
|
+
[404, { 'Content-Type' => 'application/json' }, ['Not found']]
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# Find a controller to espefic path
|
50
|
+
# and call the index method
|
51
|
+
#
|
52
|
+
# @param req [Rack::Request] an instance of request
|
53
|
+
# @return [String] a response body
|
54
|
+
def dispatch_action(req)
|
55
|
+
controller = ROUTE_TO_CONTROLLER[req.path_info]
|
56
|
+
fail Heartcheck::Errors::RoutingError if controller.nil?
|
57
|
+
|
58
|
+
Logger.info "Start [#{controller}] from #{req.ip} at #{Time.now}"
|
59
|
+
|
60
|
+
controller.new.index.tap do |_|
|
61
|
+
Logger.info "End [#{controller}]\n"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Heartcheck
|
2
|
+
module Checks
|
3
|
+
class Base
|
4
|
+
attr_accessor :functional, :dev, :name, :timeout
|
5
|
+
|
6
|
+
alias_method :functional?, :functional
|
7
|
+
alias_method :dev?, :dev
|
8
|
+
|
9
|
+
# call in Heartcheck.set
|
10
|
+
def initialize
|
11
|
+
@dynamic_services = nil
|
12
|
+
@error_proc = nil
|
13
|
+
@errors = []
|
14
|
+
@functional = false
|
15
|
+
@dev = false
|
16
|
+
@name = self.class.name.split('::').last.downcase
|
17
|
+
@services = []
|
18
|
+
@timeout = 0
|
19
|
+
@validate_proc = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def on_error(&block)
|
23
|
+
@error_proc = block if block_given?
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_validate(&block)
|
27
|
+
@validate_proc = block if block_given?
|
28
|
+
end
|
29
|
+
|
30
|
+
def register_dynamic_services(&block)
|
31
|
+
@dynamic_services = block if block_given?
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_service(service)
|
35
|
+
@services << service
|
36
|
+
end
|
37
|
+
|
38
|
+
def services
|
39
|
+
if @dynamic_services
|
40
|
+
@services + @dynamic_services.call
|
41
|
+
else
|
42
|
+
@services
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def check
|
47
|
+
validation
|
48
|
+
hash = { name => { 'status' => (@errors.empty? ? 'ok' : 'error') } }
|
49
|
+
hash[name]['message'] = error_message unless @errors.empty?
|
50
|
+
|
51
|
+
Logger.info Oj.dump(hash)
|
52
|
+
hash
|
53
|
+
end
|
54
|
+
|
55
|
+
def informations
|
56
|
+
info
|
57
|
+
rescue => e
|
58
|
+
{ 'error' => e.message }
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def append_error(*args)
|
64
|
+
if @error_proc
|
65
|
+
@error_proc.call(@errors, *args)
|
66
|
+
else
|
67
|
+
custom_error(*args)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def validation
|
72
|
+
@errors = []
|
73
|
+
begin
|
74
|
+
Timeout.timeout(timeout, Heartcheck::Errors::Warning) do
|
75
|
+
if @validate_proc
|
76
|
+
@validate_proc.call(services, @errors)
|
77
|
+
else
|
78
|
+
validate
|
79
|
+
end
|
80
|
+
end
|
81
|
+
rescue Heartcheck::Errors::Warning => w
|
82
|
+
@errors = [{ type: 'warning', message: w.message }]
|
83
|
+
rescue => e
|
84
|
+
@errors = [e.message]
|
85
|
+
end
|
86
|
+
@errors
|
87
|
+
end
|
88
|
+
|
89
|
+
def error_message
|
90
|
+
@errors.map(&format_error)
|
91
|
+
end
|
92
|
+
|
93
|
+
def format_error
|
94
|
+
lambda do |error|
|
95
|
+
error.is_a?(Hash) ? error : { type: 'error', message: error }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Heartcheck
|
2
|
+
module Checks
|
3
|
+
class Firewall < Base
|
4
|
+
def services
|
5
|
+
super.map { |opts| Services::Firewall.new(opts) }
|
6
|
+
end
|
7
|
+
|
8
|
+
def validate
|
9
|
+
services.each do |service|
|
10
|
+
begin
|
11
|
+
Net::Telnet.new(service.params)
|
12
|
+
rescue Errno::ECONNREFUSED; nil
|
13
|
+
rescue
|
14
|
+
append_error(service)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def custom_error(service)
|
22
|
+
@errors << "connection refused on: #{service.host}:#{service.port}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Heartcheck
|
2
|
+
module Checks
|
3
|
+
class Process < Base
|
4
|
+
def validate
|
5
|
+
services.each do |service|
|
6
|
+
begin
|
7
|
+
pid = get_pid(service)
|
8
|
+
::Process.kill(0, pid)
|
9
|
+
rescue Errno::ESRCH
|
10
|
+
append_error(service, pid)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def custom_error(service, pid)
|
18
|
+
@errors << "The process of #{service[:name]} is not run with pid #{pid}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_pid(service)
|
22
|
+
if service[:pid]
|
23
|
+
service[:pid]
|
24
|
+
else
|
25
|
+
File.read(service[:file]).to_i
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'oj'
|
3
|
+
|
4
|
+
Oj.default_options = { mode: :compat }
|
5
|
+
|
6
|
+
module Heartcheck
|
7
|
+
module Controllers
|
8
|
+
class Base
|
9
|
+
def index
|
10
|
+
fail NotImplementError
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def check(who)
|
16
|
+
Oj.dump(Heartcheck
|
17
|
+
.send("#{who}_checks")
|
18
|
+
.map(&:check))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Heartcheck
|
2
|
+
module Controllers
|
3
|
+
class Dev < Base
|
4
|
+
def index
|
5
|
+
results = []
|
6
|
+
|
7
|
+
total_execution_time = time_diff do
|
8
|
+
checks = Heartcheck.dev_checks
|
9
|
+
|
10
|
+
results += checks.reduce([]) do |acc, elem|
|
11
|
+
context_result = {}
|
12
|
+
|
13
|
+
context_result['execution_time'] = time_diff do
|
14
|
+
context_result.merge!(elem.check)
|
15
|
+
end
|
16
|
+
|
17
|
+
acc << context_result
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
results << { 'total_execution_time' => total_execution_time }
|
22
|
+
Oj.dump(results)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def time_diff
|
28
|
+
start_time = Time.now
|
29
|
+
yield
|
30
|
+
'%.2f ms' % ((Time.now - start_time) * 1_000)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Heartcheck
|
2
|
+
# A simple Interface to log messages
|
3
|
+
class Logger
|
4
|
+
# log message with debug level
|
5
|
+
#
|
6
|
+
# @param message [String] message to log
|
7
|
+
# @return [void]
|
8
|
+
def self.debug(message)
|
9
|
+
logger(:debug, message)
|
10
|
+
end
|
11
|
+
|
12
|
+
# log message with info level
|
13
|
+
#
|
14
|
+
# @param message [String] message to log
|
15
|
+
#
|
16
|
+
# @return [void]
|
17
|
+
def self.info(message)
|
18
|
+
logger(:info, message)
|
19
|
+
end
|
20
|
+
|
21
|
+
# log message with warn level
|
22
|
+
#
|
23
|
+
# @param message [String] message to log
|
24
|
+
#
|
25
|
+
# @return [void]
|
26
|
+
def self.warn(message)
|
27
|
+
logger(:warn, message)
|
28
|
+
end
|
29
|
+
|
30
|
+
# log message with error level
|
31
|
+
#
|
32
|
+
# @param message [String] message to log
|
33
|
+
#
|
34
|
+
# @return [void]
|
35
|
+
def self.error(message)
|
36
|
+
logger(:error, message)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Sent the message to Heartcheck logger
|
42
|
+
# that you can configure
|
43
|
+
#
|
44
|
+
# @see Heartcheck.logger
|
45
|
+
# @param level [Symbol] the level log
|
46
|
+
# @param message [String] message to log
|
47
|
+
#
|
48
|
+
# @return [void]
|
49
|
+
def self.logger(level, message)
|
50
|
+
Heartcheck.logger.send(level, "[Heartcheck] #{message}")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'heartcheck/services/firewall'
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'net/telnet'
|
2
|
+
|
3
|
+
module Heartcheck
|
4
|
+
module Services
|
5
|
+
# A service to check with a simple telnet
|
6
|
+
# if the route to a host is working.
|
7
|
+
class Firewall
|
8
|
+
attr_reader :uri, :proxy
|
9
|
+
|
10
|
+
# Sets up the options to firewall.
|
11
|
+
#
|
12
|
+
# @param params [Hash] a hash with the configurations.
|
13
|
+
# @option params [String] :host The domain/Ip
|
14
|
+
# @option params [Integer] :port Number of port to check
|
15
|
+
# @option params [String] :proxy The uri of your proxy if is required
|
16
|
+
# @option params [integer] :timeout (defaults to: 2) Number in seconds
|
17
|
+
# @option params [string] :uri You can pass a URI instead a host and port
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# Firewall.new(host: 'domain.com', port: 80)
|
21
|
+
# Firewall.new(host: 'domain.com', port: 80, timeout: 5)
|
22
|
+
# Firewall.new(uri: 'https://domain.com')
|
23
|
+
# Firewall.new(uri: 'https://domain.com', proxy: 'http://proxy.domain.com')
|
24
|
+
#
|
25
|
+
# @return [void]
|
26
|
+
def initialize(params)
|
27
|
+
@host = params[:host]
|
28
|
+
@port = params[:port]
|
29
|
+
@proxy = params[:proxy]
|
30
|
+
@timeout = params[:timeout] || 2
|
31
|
+
@uri = URI(params[:url].to_s)
|
32
|
+
end
|
33
|
+
|
34
|
+
# format params to use in Telnet
|
35
|
+
#
|
36
|
+
# @return [Hash] with the config
|
37
|
+
# - Host
|
38
|
+
# - Port
|
39
|
+
# - Timeout
|
40
|
+
# - Proxy - if is seted return a Net::Telnet object
|
41
|
+
def params
|
42
|
+
params = { 'Host' => host, 'Port' => port, 'Timeout' => @timeout }
|
43
|
+
params['Proxy'] = proxy_uri if proxy
|
44
|
+
params
|
45
|
+
end
|
46
|
+
|
47
|
+
# to get the host or stract from @uri
|
48
|
+
#
|
49
|
+
# @return [String] the host that is configured
|
50
|
+
def host
|
51
|
+
@host || uri.host
|
52
|
+
end
|
53
|
+
|
54
|
+
# to get the port or stract from @uri
|
55
|
+
#
|
56
|
+
# @return [Integre] the port that is configured
|
57
|
+
def port
|
58
|
+
@port || uri.port
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# to get the configured proxy
|
64
|
+
#
|
65
|
+
# @return [Net::Telnet] an instance with configured proxy
|
66
|
+
def proxy_uri
|
67
|
+
uri_proxy = URI(proxy)
|
68
|
+
::Net::Telnet.new('Host' => uri_proxy.host, 'Port' => uri_proxy.port, 'Timeout' => @timeout)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
metadata
ADDED
@@ -0,0 +1,248 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: heartcheck
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Locaweb
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.6.0
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.6.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.6.0
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.6.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: oj
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 2.11.0
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 2.11.4
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 2.11.0
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 2.11.4
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: pry-nav
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 0.2.0
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 0.2.4
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.2.0
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 0.2.4
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: rspec
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: 3.1.0
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 3.1.0
|
83
|
+
type: :development
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 3.1.0
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 3.1.0
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: rubocop
|
95
|
+
requirement: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - "~>"
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: 0.27.0
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 0.27.1
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 0.27.0
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: 0.27.1
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: thor
|
115
|
+
requirement: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - "~>"
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: 0.19.0
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: 0.19.1
|
123
|
+
type: :development
|
124
|
+
prerelease: false
|
125
|
+
version_requirements: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - "~>"
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: 0.19.0
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 0.19.1
|
133
|
+
- !ruby/object:Gem::Dependency
|
134
|
+
name: rack-test
|
135
|
+
requirement: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: 0.6.0
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: 0.6.3
|
143
|
+
type: :development
|
144
|
+
prerelease: false
|
145
|
+
version_requirements: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - "~>"
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 0.6.0
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 0.6.3
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: yard
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 0.8.0
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: 0.8.7
|
163
|
+
type: :development
|
164
|
+
prerelease: false
|
165
|
+
version_requirements: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - "~>"
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: 0.8.0
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: 0.8.7
|
173
|
+
- !ruby/object:Gem::Dependency
|
174
|
+
name: redcarpet
|
175
|
+
requirement: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - "~>"
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: 3.2.0
|
180
|
+
- - ">="
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: 3.2.2
|
183
|
+
type: :development
|
184
|
+
prerelease: false
|
185
|
+
version_requirements: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - "~>"
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: 3.2.0
|
190
|
+
- - ">="
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: 3.2.2
|
193
|
+
description: A simple way to check your app heart.
|
194
|
+
email:
|
195
|
+
- desenvolvedores@locaweb.com.br
|
196
|
+
executables:
|
197
|
+
- heartcheck
|
198
|
+
extensions: []
|
199
|
+
extra_rdoc_files: []
|
200
|
+
files:
|
201
|
+
- bin/heartcheck
|
202
|
+
- lib/generators/generator.rb
|
203
|
+
- lib/generators/templates/config.rb
|
204
|
+
- lib/heartcheck.rb
|
205
|
+
- lib/heartcheck/app.rb
|
206
|
+
- lib/heartcheck/checks.rb
|
207
|
+
- lib/heartcheck/checks/base.rb
|
208
|
+
- lib/heartcheck/checks/firewall.rb
|
209
|
+
- lib/heartcheck/checks/process.rb
|
210
|
+
- lib/heartcheck/controllers/base.rb
|
211
|
+
- lib/heartcheck/controllers/dev.rb
|
212
|
+
- lib/heartcheck/controllers/essential.rb
|
213
|
+
- lib/heartcheck/controllers/functional.rb
|
214
|
+
- lib/heartcheck/controllers/health_check.rb
|
215
|
+
- lib/heartcheck/controllers/info.rb
|
216
|
+
- lib/heartcheck/errors.rb
|
217
|
+
- lib/heartcheck/errors/routing_error.rb
|
218
|
+
- lib/heartcheck/errors/warning.rb
|
219
|
+
- lib/heartcheck/logger.rb
|
220
|
+
- lib/heartcheck/services.rb
|
221
|
+
- lib/heartcheck/services/firewall.rb
|
222
|
+
- lib/heartcheck/version.rb
|
223
|
+
homepage: http://developer.locaweb.com.br
|
224
|
+
licenses:
|
225
|
+
- MIT
|
226
|
+
metadata: {}
|
227
|
+
post_install_message:
|
228
|
+
rdoc_options: []
|
229
|
+
require_paths:
|
230
|
+
- lib
|
231
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
232
|
+
requirements:
|
233
|
+
- - ">="
|
234
|
+
- !ruby/object:Gem::Version
|
235
|
+
version: '0'
|
236
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
237
|
+
requirements:
|
238
|
+
- - ">="
|
239
|
+
- !ruby/object:Gem::Version
|
240
|
+
version: '0'
|
241
|
+
requirements: []
|
242
|
+
rubyforge_project:
|
243
|
+
rubygems_version: 2.4.5
|
244
|
+
signing_key:
|
245
|
+
specification_version: 4
|
246
|
+
summary: A simple way to check if your app is runnig like as expected.
|
247
|
+
test_files: []
|
248
|
+
has_rdoc:
|