-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 883f4b5
Showing
15 changed files
with
1,165 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
*.gem | ||
*.rbc | ||
/.config | ||
/coverage/ | ||
/InstalledFiles | ||
/pkg/ | ||
/spec/reports/ | ||
/spec/examples.txt | ||
/test/tmp/ | ||
/test/version_tmp/ | ||
/tmp/ | ||
|
||
# Used by dotenv library to load environment variables. | ||
# .env | ||
|
||
## Specific to RubyMotion: | ||
.dat* | ||
.repl_history | ||
build/ | ||
*.bridgesupport | ||
build-iPhoneOS/ | ||
build-iPhoneSimulator/ | ||
|
||
## Specific to RubyMotion (use of CocoaPods): | ||
# | ||
# We recommend against adding the Pods directory to your .gitignore. However | ||
# you should judge for yourself, the pros and cons are mentioned at: | ||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control | ||
# | ||
# vendor/Pods/ | ||
|
||
## Documentation cache and generated files: | ||
/.yardoc/ | ||
/_yardoc/ | ||
/doc/ | ||
/rdoc/ | ||
|
||
## Environment normalization: | ||
/.bundle/ | ||
/vendor/bundle | ||
/lib/bundler/man/ | ||
|
||
# for a library or gem, you might want to ignore these files since the code is | ||
# intended to run in multiple environments; otherwise, check them in: | ||
# Gemfile.lock | ||
# .ruby-version | ||
# .ruby-gemset | ||
|
||
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this: | ||
.rvmrc | ||
|
||
config/config\.json |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
Service-Monitor | ||
= | ||
|
||
The Service-Monitor tool provides the functionality to continuously watch the response time of a set of specified web services. | ||
|
||
How to use | ||
- | ||
|
||
Take a look into the sample_config.json. | ||
|
||
You will find a working configuration with a bunch of comments, explaining what you can configure. | ||
|
||
Save your own configuration as 'config.json'. The existence of this file will cause the program to use it. | ||
|
||
Run the program using 'ruby main.rb', and navigate your browser to the server address and port you specified in your config.json file. | ||
|
||
You will see a webpage showing boxes for each service specified, colorized with respect to how short or long the service took to respond. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative 'stop_watch' | ||
|
||
# Offers the functionality to get a 'tick' after every <interval_ms> milliseconds. | ||
# 'start' takes a lambda as callback | ||
class ClockWork | ||
def initialize(interval_ms) | ||
@interval_ms = interval_ms | ||
@running = false | ||
end | ||
|
||
def start(&callback) | ||
@running = true | ||
@thread = Thread.new {run(&callback)} | ||
end | ||
|
||
def run(&callback) | ||
@sw ||= StopWatch.new | ||
while @running do | ||
execution_time_ms = @sw.measure { | ||
callback.call | ||
} | ||
sleep_time_ms = @interval_ms - execution_time_ms | ||
sleep(sleep_time_ms / 1000) | ||
end | ||
end | ||
|
||
def stop | ||
@running = false | ||
@thread.kill | ||
@thread.join | ||
end | ||
|
||
private :run | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'json' | ||
|
||
class Config | ||
|
||
@look_for_file = 'config/config.json' | ||
@fallback_file = 'config/sample_config.json' | ||
|
||
def self.from_file(filename = nil) | ||
filename ||= @fallback_file | ||
json = File.read(filename) | ||
from_json(json) | ||
end | ||
|
||
def self.from_json(json) | ||
@settings ||= JSON.parse(json) | ||
end | ||
|
||
def self.[](element) | ||
if @settings.nil? | ||
config_file = File.exists?(@look_for_file) ? @look_for_file : nil | ||
Config::from_file(config_file) | ||
end | ||
@settings[element] | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# frozen_string_literal: true | ||
|
||
# Wrapping a given service response time | ||
class ResponseTime | ||
def initialize(time) | ||
@time = time | ||
end | ||
|
||
def to_s | ||
if @time.nil? | ||
"N/A" | ||
else | ||
"#{@time}ms" | ||
end | ||
end | ||
|
||
def to_i | ||
if @time.nil? | ||
Float::INFINITY | ||
else | ||
@time | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'net/http' | ||
require_relative 'response_time' | ||
require_relative 'stop_watch' | ||
|
||
# Wrapping a specific service, offering the functionality to query it and measure its response time | ||
class Service | ||
|
||
attr_reader :name, :url, :path, :port, :last_response_time, :response_time_classification | ||
|
||
def initialize(name, url, path = nil, port = nil, good_below_ms = nil, bad_above_ms = nil) | ||
@name = name | ||
@url = url | ||
@path = path || '/' | ||
@port = port || 80 | ||
@good_below_ms = good_below_ms || 200 | ||
@bad_above_ms = bad_above_ms || 500 | ||
@last_response_time = ResponseTime.new(nil) | ||
end | ||
|
||
def determine_response_time_async(&callback) | ||
Thread.new { | ||
determine_response_time | ||
callback.call(self) | ||
} | ||
end | ||
|
||
def determine_response_time | ||
@sw ||= StopWatch.new | ||
@sw.start | ||
result = query | ||
@sw.stop | ||
|
||
if !result.nil? | ||
result = @sw.diff | ||
end | ||
@last_response_time = ResponseTime.new(result) | ||
end | ||
|
||
def query | ||
begin | ||
http = Net::HTTP.new(@url, @port) | ||
http.read_timeout = 2 | ||
http.open_timeout = 2 | ||
|
||
result = http.start() { |http| | ||
http.get(@path) | ||
} | ||
rescue StandardError => err | ||
result = nil | ||
end | ||
result | ||
end | ||
|
||
def response_time_classification | ||
if @last_response_time.nil? || (@last_response_time.to_i > @bad_above_ms) | ||
:bad | ||
elsif (@last_response_time.to_i < @good_below_ms) | ||
:good | ||
else | ||
:medium | ||
end | ||
end | ||
|
||
private :query | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative 'clock_work' | ||
require_relative 'service' | ||
|
||
class ServiceMonitor | ||
|
||
def initialize(service_collection) | ||
@services = service_collection | ||
end | ||
|
||
def on_response_time_updated | ||
lambda { |service| | ||
puts "<< #{service.name} --> #{service.last_response_time} (#{service.response_time_classification})" | ||
} | ||
end | ||
|
||
def on_clock_tick | ||
lambda { | ||
@services.each do |service| | ||
puts ">> #{service.name}" | ||
service.determine_response_time_async(&on_response_time_updated) | ||
end | ||
} | ||
end | ||
|
||
def watch(interval_seconds = nil) | ||
interval_seconds = interval_seconds || 10 | ||
@clock ||= ClockWork.new(interval_seconds * 1000) | ||
@clock.start(&on_clock_tick) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative 'time' | ||
|
||
# Offers the functionality to measure timings of certain actions, | ||
# either by hand using 'start' and 'stop' or by specifying a block to 'measure' | ||
class StopWatch | ||
def start | ||
@start_time = Time::now | ||
@end_time = nil | ||
end | ||
|
||
def stop | ||
@end_time = Time::now | ||
end | ||
|
||
def diff | ||
if !@start_time || !@end_time | ||
raise 'StopWatch has not been started or not been stopped!' | ||
else | ||
@end_time.to_ms() - @start_time.to_ms() | ||
end | ||
end | ||
|
||
def measure(&block) | ||
start | ||
block.call | ||
stop | ||
diff | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'erb' | ||
|
||
# Simple wrapper around ERB | ||
class TemplateEngine | ||
def initialize(template_file) | ||
@template = File.read(template_file) | ||
@erb = ERB.new(@template) | ||
end | ||
|
||
def render(binding) | ||
@erb.result(binding) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# frozen_string_literal: true | ||
|
||
# This class extends the ruby std lib Time class | ||
class Time | ||
def to_ms | ||
(self.to_f * 1000.0).to_i | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'socket' | ||
|
||
# Offers the functionality to receive tcp requests and calls a lambda which should handle them. | ||
# Cann be called blocking(listen) and non-blocking(listen_async) | ||
class WebServer | ||
def initialize(addr, port) | ||
@addr = addr | ||
@port = port | ||
@running = false | ||
end | ||
|
||
def listen(&callback) | ||
@listener = TCPServer.new(@addr, @port) | ||
@running = true | ||
run(&callback) | ||
end | ||
|
||
def listen_async(&callback) | ||
@thread = Thread.new {listen(&callback)} | ||
end | ||
|
||
def run(&callback) | ||
while @running do | ||
session = @listener.accept | ||
Thread.new { | ||
callback.call(session) | ||
} | ||
end | ||
end | ||
|
||
def stop | ||
if !@thread.nil? | ||
@running = false | ||
@thread.kill | ||
@thread.join | ||
end | ||
end | ||
|
||
private :run | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"server-addr": "0.0.0.0", // mandatory; specify the local address on which the web server should be reachable. "0.0.0.0" means any address. | ||
"server-port": 8080, // mandatory; specify the local port the web server should bind to. | ||
"template-file": "templates//template.rhtml", // mandatory; specify the file which contains the ERB template for the web page. | ||
"service-monitor": { | ||
"watch-intervall-seconds": 5 // optional; specify the amount of seconds between two response time calculations. Defaults to 10. | ||
}, | ||
"services":[ | ||
{ | ||
"name": "Is it Friday yet", // mandatory; specify the name that should be shown on the web page. | ||
"url": "www.isitfridayyet.net", // mandatory; specify the url under which the service can be reached. | ||
"path": "/", // optional; specify the request path that should be added to the url. Defaults to "/". | ||
"port": 80, // optional; specify the port under which the service is reachable. Defaults to 80. | ||
"good_below_ms": 100, // optional; specify the amount of milliseconds that separates a good from a medium connection. Defaults to 200. | ||
"bad_above_ms": 300 // optional; specify the amount of milliseconds that separates a medium from a bad connection. Defaults to 500. | ||
}, | ||
{ // this is what a minimal service config looks like | ||
"name": "Google", | ||
"url": "www.google.com" | ||
} | ||
] | ||
} |
Oops, something went wrong.