rack-monitor-opentsdb 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.travis.yml +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +31 -0
- data/LICENSE +13 -0
- data/README.md +30 -0
- data/Rakefile +23 -0
- data/lib/rack/monitor/opentsdb/reporter.rb +118 -0
- data/lib/rack/monitor/opentsdb/version.rb +13 -0
- data/lib/rack/monitor/opentsdb.rb +48 -0
- data/rack-monitor-opentsdb.gemspec +17 -0
- data/spec/monitor_spec.rb +55 -0
- data/spec/reporter_spec.rb +4 -0
- data/spec/spec_helper.rb +6 -0
- metadata +96 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a9afbff4ac650e92c2dbd3f916be7787e88b00f8
|
4
|
+
data.tar.gz: 7ede01a4ebbf70501ca057ea0243bdb14d910df8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 41ebb0204e780f94c16e45d03d47c7fb6c544f9b04af119df80fd17c0cb21e03e92fd63bea8516063c9cfd98607d02a96694bac84e415a95e0777ae8d6bd7f29
|
7
|
+
data.tar.gz: 7cc1a7f1246e936cb4f1a503ba38e50447147847e6f237a0ad35a05b5e5d9302bdf7769e50342a56057f7e5edacb17a36b5f4c59f7ba786e472572521df96b2c
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rack-monitor-opentsdb (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.2.5)
|
10
|
+
rake (10.3.2)
|
11
|
+
rspec (3.1.0)
|
12
|
+
rspec-core (~> 3.1.0)
|
13
|
+
rspec-expectations (~> 3.1.0)
|
14
|
+
rspec-mocks (~> 3.1.0)
|
15
|
+
rspec-core (3.1.3)
|
16
|
+
rspec-support (~> 3.1.0)
|
17
|
+
rspec-expectations (3.1.1)
|
18
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
19
|
+
rspec-support (~> 3.1.0)
|
20
|
+
rspec-mocks (3.1.0)
|
21
|
+
rspec-support (~> 3.1.0)
|
22
|
+
rspec-support (3.1.0)
|
23
|
+
|
24
|
+
PLATFORMS
|
25
|
+
java
|
26
|
+
ruby
|
27
|
+
|
28
|
+
DEPENDENCIES
|
29
|
+
rack-monitor-opentsdb!
|
30
|
+
rake (~> 10.3, >= 10.3.2)
|
31
|
+
rspec (~> 3.1, >= 3.1.0)
|
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2014 FriendScout24 GmbH
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
rack-monitor-opentsdb
|
2
|
+
=====================
|
3
|
+
|
4
|
+
Rack middleware to monitor requests with OpenTSDB.
|
5
|
+
|
6
|
+
Usage:
|
7
|
+
------
|
8
|
+
|
9
|
+
require 'sinatra'
|
10
|
+
require 'rack/monitor/opentsdb'
|
11
|
+
|
12
|
+
use Rack::Monitor::OpenTSDB, 'service.rest.hworld',
|
13
|
+
:host => 'opentsdb.example.com',
|
14
|
+
:port => 4242,
|
15
|
+
:report_interval => 60,
|
16
|
+
:tags => {
|
17
|
+
:host => `hostname`.chomp,
|
18
|
+
:env => ENV['RACK_ENV'] || 'development' }
|
19
|
+
|
20
|
+
get '/' do
|
21
|
+
'Hello World'
|
22
|
+
end
|
23
|
+
|
24
|
+
Links:
|
25
|
+
------
|
26
|
+
|
27
|
+
- [Homepage](http://friendscout24.github.io/rack-monitor-opentsdb)
|
28
|
+
- [Sources](http://github.com/friendscout24/rack-monitor-opentsdb)
|
29
|
+
- [Issues](http://github.com/friendscout24/rack-monitor-opentsdb/issues)
|
30
|
+
- [](https://travis-ci.org/friendscout24/rack-monitor-opentsdb)
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
task :default => :spec
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'rspec/core/rake_task'
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
10
|
+
rescue LoadError
|
11
|
+
task :spec do
|
12
|
+
abort 'RSpec is not available'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'run console'
|
17
|
+
task :console do
|
18
|
+
require 'irb'
|
19
|
+
require 'irb/completion'
|
20
|
+
require 'rack/monitor/opentsdb'
|
21
|
+
ARGV.clear
|
22
|
+
IRB.start
|
23
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Rack
|
2
|
+
module Monitor
|
3
|
+
class OpenTSDB
|
4
|
+
class Reporter
|
5
|
+
|
6
|
+
MAX_CACHE = 1024
|
7
|
+
|
8
|
+
# stats has the following structure:
|
9
|
+
#
|
10
|
+
# {
|
11
|
+
# 'GET /monitored/path/1': {
|
12
|
+
# '<httpstatus>': [<time>, ...],
|
13
|
+
# ...
|
14
|
+
# },
|
15
|
+
# ...
|
16
|
+
# }
|
17
|
+
#
|
18
|
+
# The stats parameter must be extended with MonitorMixin. Like this it
|
19
|
+
# can be accessed synchronized.
|
20
|
+
def initialize(stats, host, port, key = 'unconfigured.rack.monitor', interval = 60, tags = {})
|
21
|
+
raise ArgumentError, "Interval less than zero" if interval < 0
|
22
|
+
raise ArgumentError, 'stats does not support synchronize' unless stats.respond_to? :synchronize
|
23
|
+
|
24
|
+
@interval = interval
|
25
|
+
@tags = tags
|
26
|
+
@stats = stats
|
27
|
+
@host = host
|
28
|
+
@port = port
|
29
|
+
@key = key
|
30
|
+
@tosend = []
|
31
|
+
start
|
32
|
+
end
|
33
|
+
|
34
|
+
def start
|
35
|
+
return if @run
|
36
|
+
@run = true
|
37
|
+
@th = Thread.new do
|
38
|
+
t = Time.now
|
39
|
+
while run?
|
40
|
+
t += @interval
|
41
|
+
(sleep(t - Time.now) rescue nil) and send_report rescue nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def stop
|
47
|
+
@stats.synchronize do
|
48
|
+
@run = false
|
49
|
+
end
|
50
|
+
@th.join
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def run?
|
56
|
+
@stats.synchronize do
|
57
|
+
@run
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def send_report
|
62
|
+
timestamp = Time.now.to_i
|
63
|
+
data = copy_and_clear_stats
|
64
|
+
data.each do |url, url_stats|
|
65
|
+
verb, path = url.split(/ /)
|
66
|
+
url_stats.each do |status, timings|
|
67
|
+
tags = @tags.merge({:status => status, :verb => verb, :path => path}).map { |key, value| "#{key}=#{value}" }.join(' ')
|
68
|
+
@tosend.push("put #{@key}.min #{timestamp} #{timings.min} #{tags}")
|
69
|
+
@tosend.push("put #{@key}.max #{timestamp} #{timings.max} #{tags}")
|
70
|
+
@tosend.push("put #{@key}.num #{timestamp} #{timings.size} #{tags}")
|
71
|
+
@tosend.push("put #{@key}.avg #{timestamp} #{timings.inject(0.0) { |sum, e| sum + e } / timings.size} #{tags}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# cleanup if cannot send anything, only keep MAX_CACHE entries to send
|
76
|
+
if @tosend.size > MAX_CACHE
|
77
|
+
@tosend.shift(@tosend.length - - MAX_CACHE)
|
78
|
+
end
|
79
|
+
|
80
|
+
send_to_socket
|
81
|
+
end
|
82
|
+
|
83
|
+
def send_to_socket
|
84
|
+
begin
|
85
|
+
@tosend.delete_if do |line|
|
86
|
+
# throws in first go NoMethodError: undefined method `puts' for nil:NilClass
|
87
|
+
# this is rescued and the connection is opened for retry
|
88
|
+
@socket.puts line
|
89
|
+
true
|
90
|
+
end
|
91
|
+
rescue IOError, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EPIPE
|
92
|
+
# Don't retry immediately (preventing loops), next run will retry
|
93
|
+
@socket = nil
|
94
|
+
rescue
|
95
|
+
begin
|
96
|
+
@socket = TCPSocket.new(@host, @port)
|
97
|
+
retry
|
98
|
+
rescue
|
99
|
+
# will do no retry in this case
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def copy_and_clear_stats
|
105
|
+
copy = {}
|
106
|
+
@stats.synchronize do
|
107
|
+
@stats.each do |url, url_stats|
|
108
|
+
copy[url] = url_stats
|
109
|
+
end
|
110
|
+
@stats.clear
|
111
|
+
end
|
112
|
+
copy
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rack/monitor/opentsdb/reporter'
|
2
|
+
require 'monitor' # MonitorMixin
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
module Monitor
|
6
|
+
class OpenTSDB
|
7
|
+
|
8
|
+
class Stats < Hash
|
9
|
+
include MonitorMixin
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(app, key, options={})
|
13
|
+
@app = app
|
14
|
+
@options = {
|
15
|
+
:host => 'localhost',
|
16
|
+
:port => 4242,
|
17
|
+
:key => key,
|
18
|
+
# If somebody has a better idea than defining a regex and gsub
|
19
|
+
# replacement tell me.
|
20
|
+
:track_regex => /^(\/[^\/]+).*?$/, # Regex to select trackable string
|
21
|
+
:track_replace => '\1', # gsub pattern to select trackable string
|
22
|
+
:report_interval => 60,
|
23
|
+
:tags => {}
|
24
|
+
}.merge(options)
|
25
|
+
@stats = Stats.new
|
26
|
+
@reporter = Reporter.new(@stats, @options[:host], @options[:port], @options[:key], @options[:report_interval], @options[:tags])
|
27
|
+
@reporter.start
|
28
|
+
end
|
29
|
+
|
30
|
+
def call(env, options={})
|
31
|
+
track_path = env['REQUEST_METHOD'] + ' ' + env['PATH_INFO'].gsub(@options[:track_regex], @options[:track_replace])
|
32
|
+
|
33
|
+
beginning_time = Time.now
|
34
|
+
status, headers, body = @app.call(env)
|
35
|
+
execution_time = (Time.now - beginning_time)
|
36
|
+
|
37
|
+
@stats.synchronize do
|
38
|
+
@stats[track_path] ||= {}
|
39
|
+
@stats[track_path][status] ||= []
|
40
|
+
@stats[track_path][status] << execution_time
|
41
|
+
end
|
42
|
+
|
43
|
+
[status, headers, body]
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'lib', 'rack', 'monitor', 'opentsdb', 'version')
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'rack-monitor-opentsdb'
|
5
|
+
s.version = Rack::Monitor::OpenTSDB::Version::VERSION
|
6
|
+
s.licenses = ['ALv2']
|
7
|
+
s.summary = 'Rack Monitoring to OpenTSDB'
|
8
|
+
s.description = 'Send monitoring info to OpenTSDB'
|
9
|
+
s.authors = ['Rainer Jung']
|
10
|
+
s.email = 'rainer.jung@gmail.com'
|
11
|
+
s.homepage = 'http://github.com/friendscout24/rack-monitor-opentsdb'
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
15
|
+
s.add_development_dependency 'rake', '~> 10.3', '>= 10.3.2'
|
16
|
+
s.add_development_dependency 'rspec', '~> 3.1', '>= 3.1.0'
|
17
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rack::Monitor::OpenTSDB do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@app = double(:app)
|
7
|
+
@env = {'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/path'}
|
8
|
+
@sut = Rack::Monitor::OpenTSDB.new(@app, 'test.monitor')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'starts with empty stats' do
|
12
|
+
expect(@sut.instance_variable_get('@stats')).to be_empty
|
13
|
+
end
|
14
|
+
|
15
|
+
describe :call do
|
16
|
+
|
17
|
+
it 'does return apps result' do
|
18
|
+
allow(@app).to receive(:call).and_return(['status', 'headers', 'body'])
|
19
|
+
expect(@sut.call @env).to eq(['status', 'headers', 'body'])
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'stats' do
|
23
|
+
before do
|
24
|
+
allow(@app).to receive(:call).and_return(['200', 'headers', 'body'])
|
25
|
+
@sut.call @env
|
26
|
+
@stats = @sut.instance_variable_get('@stats')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'includes path' do
|
30
|
+
expect(@stats).to include 'GET /path'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'includes status' do
|
34
|
+
expect(@stats['GET /path']).to include '200'
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'call with regexable path' do
|
42
|
+
|
43
|
+
before do
|
44
|
+
allow(@app).to receive(:call).and_return(['200', 'headers', 'body'])
|
45
|
+
@sut.call({'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/some/longer/path'})
|
46
|
+
@stats = @sut.instance_variable_get('@stats')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'includes path' do
|
50
|
+
# Default regex does shorten to first path-segment
|
51
|
+
expect(@stats).to include 'GET /some'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-monitor-opentsdb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rainer Jung
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-09-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '10.3'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 10.3.2
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '10.3'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 10.3.2
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rspec
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '3.1'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 3.1.0
|
43
|
+
type: :development
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '3.1'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 3.1.0
|
53
|
+
description: Send monitoring info to OpenTSDB
|
54
|
+
email: rainer.jung@gmail.com
|
55
|
+
executables: []
|
56
|
+
extensions: []
|
57
|
+
extra_rdoc_files: []
|
58
|
+
files:
|
59
|
+
- ".travis.yml"
|
60
|
+
- Gemfile
|
61
|
+
- Gemfile.lock
|
62
|
+
- LICENSE
|
63
|
+
- README.md
|
64
|
+
- Rakefile
|
65
|
+
- lib/rack/monitor/opentsdb.rb
|
66
|
+
- lib/rack/monitor/opentsdb/reporter.rb
|
67
|
+
- lib/rack/monitor/opentsdb/version.rb
|
68
|
+
- rack-monitor-opentsdb.gemspec
|
69
|
+
- spec/monitor_spec.rb
|
70
|
+
- spec/reporter_spec.rb
|
71
|
+
- spec/spec_helper.rb
|
72
|
+
homepage: http://github.com/friendscout24/rack-monitor-opentsdb
|
73
|
+
licenses:
|
74
|
+
- ALv2
|
75
|
+
metadata: {}
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 2.2.2
|
93
|
+
signing_key:
|
94
|
+
specification_version: 4
|
95
|
+
summary: Rack Monitoring to OpenTSDB
|
96
|
+
test_files: []
|