johnf-fnordmetric 1.2.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +6 -0
- data/Rakefile +9 -0
- data/fnordmetric.gemspec +41 -0
- data/lib/fnordmetric/acceptors/acceptor.rb +42 -0
- data/lib/fnordmetric/acceptors/amqp_acceptor.rb +56 -0
- data/lib/fnordmetric/acceptors/fyrehose_acceptor.rb +43 -0
- data/lib/fnordmetric/acceptors/stomp_acceptor.rb +71 -0
- data/lib/fnordmetric/acceptors/tcp_acceptor.rb +58 -0
- data/lib/fnordmetric/acceptors/udp_acceptor.rb +37 -0
- data/lib/fnordmetric/api.rb +46 -0
- data/lib/fnordmetric/cache.rb +20 -0
- data/lib/fnordmetric/context.rb +96 -0
- data/lib/fnordmetric/defaults.rb +22 -0
- data/lib/fnordmetric/enterprise/compatibility_handler.rb +42 -0
- data/lib/fnordmetric/ext.rb +75 -0
- data/lib/fnordmetric/gauge.rb +98 -0
- data/lib/fnordmetric/gauge_calculations.rb +106 -0
- data/lib/fnordmetric/gauge_modifiers.rb +144 -0
- data/lib/fnordmetric/gauge_rendering.rb +40 -0
- data/lib/fnordmetric/gauge_validations.rb +15 -0
- data/lib/fnordmetric/gauges/distribution_gauge.rb +87 -0
- data/lib/fnordmetric/gauges/server_health_gauge.rb +13 -0
- data/lib/fnordmetric/gauges/timeseries_gauge.rb +138 -0
- data/lib/fnordmetric/gauges/toplist_gauge.rb +44 -0
- data/lib/fnordmetric/histogram.rb +64 -0
- data/lib/fnordmetric/logger.rb +63 -0
- data/lib/fnordmetric/namespace.rb +208 -0
- data/lib/fnordmetric/session.rb +139 -0
- data/lib/fnordmetric/standalone.rb +20 -0
- data/lib/fnordmetric/timeseries.rb +79 -0
- data/lib/fnordmetric/toplist.rb +61 -0
- data/lib/fnordmetric/udp_client.rb +22 -0
- data/lib/fnordmetric/util.rb +25 -0
- data/lib/fnordmetric/version.rb +3 -0
- data/lib/fnordmetric/web/app.rb +63 -0
- data/lib/fnordmetric/web/app_helpers.rb +42 -0
- data/lib/fnordmetric/web/dashboard.rb +40 -0
- data/lib/fnordmetric/web/event.rb +99 -0
- data/lib/fnordmetric/web/reactor.rb +127 -0
- data/lib/fnordmetric/web/web.rb +59 -0
- data/lib/fnordmetric/web/websocket.rb +41 -0
- data/lib/fnordmetric/widget.rb +82 -0
- data/lib/fnordmetric/widgets/bars_widget.rb +44 -0
- data/lib/fnordmetric/widgets/html_widget.rb +28 -0
- data/lib/fnordmetric/widgets/numbers_widget.rb +80 -0
- data/lib/fnordmetric/widgets/pie_widget.rb +23 -0
- data/lib/fnordmetric/widgets/timeseries_widget.rb +65 -0
- data/lib/fnordmetric/widgets/toplist_widget.rb +68 -0
- data/lib/fnordmetric/worker.rb +89 -0
- data/lib/fnordmetric/zero_config_gauge.rb +138 -0
- data/lib/fnordmetric.rb +149 -0
- data/run_specs.sh +11 -0
- data/spec/api_spec.rb +49 -0
- data/spec/context_spec.rb +42 -0
- data/spec/dashboard_spec.rb +38 -0
- data/spec/event_spec.rb +170 -0
- data/spec/ext_spec.rb +14 -0
- data/spec/fnordmetric_spec.rb +56 -0
- data/spec/gauge_like_shared.rb +56 -0
- data/spec/gauge_modifiers_spec.rb +583 -0
- data/spec/gauge_spec.rb +230 -0
- data/spec/namespace_spec.rb +114 -0
- data/spec/session_spec.rb +231 -0
- data/spec/spec_helper.rb +49 -0
- data/spec/tcp_acceptor_spec.rb +35 -0
- data/spec/timeseries_gauge_spec.rb +56 -0
- data/spec/udp_acceptor_spec.rb +35 -0
- data/spec/util_spec.rb +46 -0
- data/spec/widget_spec.rb +113 -0
- data/spec/worker_spec.rb +40 -0
- data/web/.gitignore +4 -0
- data/web/build.sh +34 -0
- data/web/css/fnordmetric.core.css +868 -0
- data/web/fnordmetric-core.css +1409 -0
- data/web/fnordmetric-core.js +3420 -0
- data/web/fnordmetric-ui.css +282 -0
- data/web/fnordmetric-ui.js +12032 -0
- data/web/haml/app.haml +20 -0
- data/web/haml/distribution_gauge.haml +118 -0
- data/web/haml/timeseries_gauge.haml +80 -0
- data/web/haml/toplist_gauge.haml +194 -0
- data/web/img/head.png +0 -0
- data/web/img/list.png +0 -0
- data/web/img/list_active.png +0 -0
- data/web/img/list_hover.png +0 -0
- data/web/img/loader.gif +0 -0
- data/web/img/loader_white.gif +0 -0
- data/web/img/navbar.png +0 -0
- data/web/img/navbar_btn.png +0 -0
- data/web/img/picto_gauge.png +0 -0
- data/web/js/fnordmetric.bars_widget.js +178 -0
- data/web/js/fnordmetric.dashboard_view.js +99 -0
- data/web/js/fnordmetric.gauge_explorer.js +173 -0
- data/web/js/fnordmetric.gauge_view.js +260 -0
- data/web/js/fnordmetric.html_widget.js +21 -0
- data/web/js/fnordmetric.js +315 -0
- data/web/js/fnordmetric.numbers_widget.js +122 -0
- data/web/js/fnordmetric.overview_view.js +35 -0
- data/web/js/fnordmetric.pie_widget.js +118 -0
- data/web/js/fnordmetric.realtime_timeline_widget.js +175 -0
- data/web/js/fnordmetric.session_view.js +342 -0
- data/web/js/fnordmetric.timeline_widget.js +333 -0
- data/web/js/fnordmetric.timeseries_widget.js +405 -0
- data/web/js/fnordmetric.toplist_widget.js +119 -0
- data/web/js/fnordmetric.ui.js +91 -0
- data/web/js/fnordmetric.util.js +248 -0
- data/web/vendor/font-awesome/css/font-awesome-ie7.min.css +22 -0
- data/web/vendor/font-awesome/css/font-awesome.css +540 -0
- data/web/vendor/font-awesome/css/font-awesome.min.css +33 -0
- data/web/vendor/font-awesome/font/FontAwesome.otf +0 -0
- data/web/vendor/font-awesome/font/fontawesome-webfont.eot +0 -0
- data/web/vendor/font-awesome/font/fontawesome-webfont.svg +284 -0
- data/web/vendor/font-awesome/font/fontawesome-webfont.ttf +0 -0
- data/web/vendor/font-awesome/font/fontawesome-webfont.woff +0 -0
- data/web/vendor/jquery-1.6.2.min.js +18 -0
- data/web/vendor/jquery-ui.min.js +6 -0
- data/web/vendor/jquery.combobox.js +129 -0
- data/web/vendor/jquery.maskedinput.js +252 -0
- metadata +444 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
class FnordMetric::PieWidget < FnordMetric::Widget
|
2
|
+
|
3
|
+
def data
|
4
|
+
super.merge(
|
5
|
+
:gauges => gauges.map(&:name),
|
6
|
+
:gauge_titles => gauge_titles,
|
7
|
+
:autoupdate => (@opts[:autoupdate] || 60)
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
def gauge_titles
|
12
|
+
{}.tap do |_hash|
|
13
|
+
gauges.each do |gauge|
|
14
|
+
_hash.merge!(gauge.name => gauge.title)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_tick?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class FnordMetric::TimeseriesWidget < FnordMetric::Widget
|
2
|
+
|
3
|
+
def self.execute(namespace, event)
|
4
|
+
resp = if event["cmd"] == "values_at"
|
5
|
+
{
|
6
|
+
:cmd => :values_at,
|
7
|
+
:gauges => event["gauges"].map{ |gkey|
|
8
|
+
_gauge = namespace.gauges[gkey.to_sym]
|
9
|
+
unless _gauge
|
10
|
+
return { :error => "gauge not found: #{gkey}" }
|
11
|
+
end
|
12
|
+
|
13
|
+
t_since = FnordMetric::Util.parse_time(event["since"].to_s)
|
14
|
+
t_until = FnordMetric::Util.parse_time(event["until"].to_s)
|
15
|
+
|
16
|
+
vals = _gauge.values_in(t_since..t_until)
|
17
|
+
{ :key => gkey, :vals => vals, :title => _gauge.title }
|
18
|
+
}
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
return false unless resp
|
23
|
+
|
24
|
+
resp.merge(
|
25
|
+
:type => "widget_response",
|
26
|
+
:widget_key => event["widget_key"]
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def data
|
31
|
+
super.merge(
|
32
|
+
:series => series,
|
33
|
+
:gauges => gauges.map(&:name),
|
34
|
+
:start_timestamp => ticks.first,
|
35
|
+
:end_timestamp => ticks.last,
|
36
|
+
:xticks => (@opts[:xticks] || 30),
|
37
|
+
:autoupdate => (@opts[:autoupdate] || 60),
|
38
|
+
:include_current => !!@opts[:include_current],
|
39
|
+
:default_style => (@opts[:plot_style] || 'line'),
|
40
|
+
:async_chart => true,
|
41
|
+
:tick => tick
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
def series
|
46
|
+
colors = FnordMetric::COLORS.dup
|
47
|
+
|
48
|
+
gauges.map do |gauge|
|
49
|
+
{
|
50
|
+
:name => gauge.name,
|
51
|
+
:title => gauge.title,
|
52
|
+
:data => [{:x => ticks.first, :y => 0}],
|
53
|
+
:color => colors.unshift(colors.pop).first
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def has_tick?
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
class FnordMetric::TimelineWidget < FnordMetric::TimeseriesWidget
|
65
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class FnordMetric::ToplistWidget < FnordMetric::Widget
|
2
|
+
|
3
|
+
def self.execute(namespace, event)
|
4
|
+
t = Time.now.to_i
|
5
|
+
|
6
|
+
return false unless event["gauge"]
|
7
|
+
|
8
|
+
resp = if event["cmd"] == "values_for"
|
9
|
+
vals = execute_values_for(namespace.gauges[event["gauge"].to_sym], t)
|
10
|
+
|
11
|
+
{
|
12
|
+
:cmd => :values_for,
|
13
|
+
:gauge => event["gauge"],
|
14
|
+
:values => vals,
|
15
|
+
:count => vals.inject(0){ |m, (k,c)| m + c }
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
return false unless resp
|
20
|
+
|
21
|
+
resp.merge(
|
22
|
+
:type => "widget_response",
|
23
|
+
:widget_key => event["widget_key"]
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.execute_values_for(gauge, time)
|
28
|
+
gauge.field_values_at(time).sort do |a,b|
|
29
|
+
a.first.to_i <=> b.first.to_i
|
30
|
+
end.map do |a|
|
31
|
+
[a.first, a.second.to_i]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def data
|
36
|
+
super.merge(
|
37
|
+
:gauges => data_gauges,
|
38
|
+
:autoupdate => (@opts[:autoupdate] || 0),
|
39
|
+
:render_target => @opts[:render_target],
|
40
|
+
:ticks => @opts[:ticks],
|
41
|
+
:click_callback => @opts[:click_callback],
|
42
|
+
:async_chart => true,
|
43
|
+
:tick => tick,
|
44
|
+
:limit => @opts[:limit],
|
45
|
+
:no_min_height => @opts[:no_min_height]
|
46
|
+
).tap do |dat|
|
47
|
+
dat.merge!(
|
48
|
+
:gauges => @opts[:_gauges]
|
49
|
+
) if dat[:ticks]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def data_gauges
|
54
|
+
Hash.new.tap do |hash|
|
55
|
+
gauges.each do |g|
|
56
|
+
hash[g.name] = {
|
57
|
+
:tick => g.tick,
|
58
|
+
:title => g.title
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def has_tick?
|
65
|
+
false
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
class FnordMetric::Worker
|
2
|
+
|
3
|
+
def initialize(opts = {})
|
4
|
+
@namespaces = FnordMetric.namespaces
|
5
|
+
@opts = FnordMetric.options(opts)
|
6
|
+
|
7
|
+
FnordMetric.register(self)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialized
|
11
|
+
FnordMetric.log("worker started")
|
12
|
+
EM.next_tick(&method(:tick))
|
13
|
+
end
|
14
|
+
|
15
|
+
def tick
|
16
|
+
redis.blpop(queue_key, 1).callback do |list, event_id|
|
17
|
+
EM.next_tick(&method(:tick))
|
18
|
+
if event_id
|
19
|
+
redis.get(event_key(event_id)).callback do |event_data|
|
20
|
+
process_event(event_id, event_data) if event_data
|
21
|
+
FnordMetric.log("event_lost: event_data not found for event-id '#{event_id}' - maybe expired?") unless event_data
|
22
|
+
redis.hincrby(stats_key, :events_processed, 1)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def process_event(event_id, event_data)
|
29
|
+
EM.next_tick do
|
30
|
+
event = parse_json(event_data)
|
31
|
+
if event
|
32
|
+
event[:_time] ||= Time.now.to_i
|
33
|
+
event[:_eid] = event_id
|
34
|
+
announce_event(event)
|
35
|
+
publish_event(event)
|
36
|
+
expire_event(event_id)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def pubsub_key
|
42
|
+
[@opts[:redis_prefix], 'announce'].join("-")
|
43
|
+
end
|
44
|
+
|
45
|
+
def queue_key
|
46
|
+
[@opts[:redis_prefix], 'queue'].join("-")
|
47
|
+
end
|
48
|
+
|
49
|
+
def event_key(event_id)
|
50
|
+
[@opts[:redis_prefix], 'event', event_id].join("-")
|
51
|
+
end
|
52
|
+
|
53
|
+
def stats_key
|
54
|
+
[@opts[:redis_prefix], 'stats'].join("-")
|
55
|
+
end
|
56
|
+
|
57
|
+
def announce_event(event)
|
58
|
+
namespace(event[:_namespace]).ready!(redis, sync_redis).announce(event)
|
59
|
+
end
|
60
|
+
|
61
|
+
def expire_event(event_id)
|
62
|
+
redis.expire(event_key(event_id), @opts[:event_data_ttl])
|
63
|
+
end
|
64
|
+
|
65
|
+
def publish_event(event)
|
66
|
+
redis.publish(pubsub_key, event.to_json)
|
67
|
+
end
|
68
|
+
|
69
|
+
def namespace(key)
|
70
|
+
(@namespaces[key] || @namespaces.first.last).clone
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_json(data)
|
74
|
+
event = Yajl::Parser.new(:symbolize_keys => true).parse(data)
|
75
|
+
event[:_namespace] = event[:_namespace].to_sym if event[:_namespace]
|
76
|
+
event
|
77
|
+
rescue Yajl::ParseError => e
|
78
|
+
FnordMetric.error "invalid json: #{e.to_s}"; false
|
79
|
+
end
|
80
|
+
|
81
|
+
def redis
|
82
|
+
@redis ||= EM::Hiredis.connect(FnordMetric.options[:redis_url]) # FIXPAUL
|
83
|
+
end
|
84
|
+
|
85
|
+
def sync_redis
|
86
|
+
@sync_redis ||= FnordMetric.mk_redis
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
class FnordMetric::ZeroConfigGauge
|
2
|
+
|
3
|
+
TYPES = [:_incr, :_decr, :_avg, :_min, :_max, :_set]
|
4
|
+
|
5
|
+
Handler = proc do
|
6
|
+
if data[:gauge]
|
7
|
+
gauge_key = data[:gauge].to_sym
|
8
|
+
else
|
9
|
+
FnordMetric.error("missing key for zero config event: gauge")
|
10
|
+
next
|
11
|
+
end
|
12
|
+
|
13
|
+
unless data[:value]
|
14
|
+
FnordMetric.error("missing key for zero config event: value")
|
15
|
+
next
|
16
|
+
end
|
17
|
+
|
18
|
+
gauge = if namespace.gauges.has_key?(gauge_key)
|
19
|
+
namespace.gauges[gauge_key]
|
20
|
+
else
|
21
|
+
namespace.opt_gauge(gauge_key,
|
22
|
+
:flush_interval => data[:flush_interval],
|
23
|
+
:average => (type == :_avg),
|
24
|
+
:zero_config => true)
|
25
|
+
end
|
26
|
+
|
27
|
+
case type
|
28
|
+
|
29
|
+
when :_set
|
30
|
+
set_value gauge, data[:value].to_i
|
31
|
+
|
32
|
+
when :_incr
|
33
|
+
incr_tick gauge, data[:value].to_i
|
34
|
+
|
35
|
+
when :_decr
|
36
|
+
FnordMetric.error("_decr is not yet implemented")
|
37
|
+
|
38
|
+
when :_avg
|
39
|
+
incr_avg gauge, data[:value].to_i
|
40
|
+
|
41
|
+
when :_min, :_max
|
42
|
+
FnordMetric.error("_min/_max is not yet implemented")
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class EmtpyGauge
|
48
|
+
|
49
|
+
def self.tick
|
50
|
+
FnordMetric.options[:default_flush_interval]
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.retention
|
54
|
+
tick * 10
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.tick_at(time, _tick=tick)
|
58
|
+
(time/_tick.to_f).floor*_tick
|
59
|
+
end
|
60
|
+
|
61
|
+
def group
|
62
|
+
"Gauges"
|
63
|
+
end
|
64
|
+
|
65
|
+
def unit
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
def key_nouns
|
70
|
+
["Key", "Keys"]
|
71
|
+
end
|
72
|
+
|
73
|
+
def key(_append=nil)
|
74
|
+
"----empty-gauge----"
|
75
|
+
end
|
76
|
+
|
77
|
+
def tick_key(_time, _append=nil)
|
78
|
+
"----empty-gauge----"
|
79
|
+
end
|
80
|
+
|
81
|
+
def tick_keys(_range, _append=nil)
|
82
|
+
["----empty-gauge----"]
|
83
|
+
end
|
84
|
+
|
85
|
+
def retention_key(_time, _append=nil)
|
86
|
+
"----empty-gauge----"
|
87
|
+
end
|
88
|
+
|
89
|
+
def two_dimensional?
|
90
|
+
true
|
91
|
+
end
|
92
|
+
|
93
|
+
def three_dimensional?
|
94
|
+
false
|
95
|
+
end
|
96
|
+
|
97
|
+
def progressive?
|
98
|
+
false
|
99
|
+
end
|
100
|
+
|
101
|
+
def unique?
|
102
|
+
false
|
103
|
+
end
|
104
|
+
|
105
|
+
def average?
|
106
|
+
false
|
107
|
+
end
|
108
|
+
|
109
|
+
def has_series?
|
110
|
+
false
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
def initialize(key, namespace)
|
116
|
+
@key = key
|
117
|
+
@namespace = namespace
|
118
|
+
end
|
119
|
+
|
120
|
+
def name
|
121
|
+
@key
|
122
|
+
end
|
123
|
+
|
124
|
+
def title
|
125
|
+
@key
|
126
|
+
end
|
127
|
+
|
128
|
+
def method_missing(*msg)
|
129
|
+
gauge = @namespace.gauges[@key]
|
130
|
+
|
131
|
+
if gauge
|
132
|
+
gauge.send(*msg)
|
133
|
+
else
|
134
|
+
EmtpyGauge.send(*msg)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
data/lib/fnordmetric.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
require "eventmachine"
|
2
|
+
require 'em-hiredis'
|
3
|
+
require 'redis'
|
4
|
+
require "active_support/core_ext"
|
5
|
+
require 'yajl'
|
6
|
+
require 'sinatra/base'
|
7
|
+
require 'haml'
|
8
|
+
require 'json'
|
9
|
+
require "thin"
|
10
|
+
require 'rack/server'
|
11
|
+
require 'rack/websocket'
|
12
|
+
|
13
|
+
require "fnordmetric/ext"
|
14
|
+
require "fnordmetric/version"
|
15
|
+
|
16
|
+
module FnordMetric
|
17
|
+
|
18
|
+
@@options = nil
|
19
|
+
@@pool = []
|
20
|
+
|
21
|
+
@@namespaces = {}
|
22
|
+
|
23
|
+
def self.namespace(key=nil, &block)
|
24
|
+
@@namespaces[key] = block
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.namespaces
|
28
|
+
{}.tap do |_namespaces|
|
29
|
+
@@namespaces.each do |key, block|
|
30
|
+
_namespaces[key] = FnordMetric::Namespace.new(key, options.clone)
|
31
|
+
_namespaces[key].instance_eval(&block)
|
32
|
+
_namespaces[key].instance_eval(&FnordMetric::DEFAULT_PROC)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.options(opts = {})
|
38
|
+
default_options(@@options || {}).merge(opts)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.options=(opts)
|
42
|
+
@@options = opts
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.register(obj)
|
46
|
+
@@pool.push(obj)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.mk_redis
|
50
|
+
Redis.new(:url => options[:redis_url])
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.default_options(opts = {})
|
54
|
+
FnordMetric::DEFAULT_OPTIONS.merge(opts)
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.log(msg)
|
58
|
+
puts "[#{Time.now.strftime("%y-%m-%d %H:%M:%S")}] #{msg}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.error(msg)
|
62
|
+
log "[ERROR] #{msg}"; nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.error!(msg)
|
66
|
+
raise msg if ENV['FNORDMETRIC_ENV'] == 'test'
|
67
|
+
puts(msg); exit!
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.run
|
71
|
+
start_em
|
72
|
+
rescue Exception => e
|
73
|
+
raise e
|
74
|
+
log "!!! eventmachine died, restarting... #{e.message}"
|
75
|
+
sleep(1); run
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.shutdown(fnord=nil)
|
79
|
+
log "shutting down, byebye"
|
80
|
+
EM.stop
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.start_em
|
84
|
+
EM.run do
|
85
|
+
|
86
|
+
trap("TERM", &method(:shutdown))
|
87
|
+
trap("INT", &method(:shutdown))
|
88
|
+
|
89
|
+
EM.next_tick do
|
90
|
+
(@@pool || []).map(&:initialized)
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.server_configuration=(configuration)
|
97
|
+
puts "DEPRECATION WARNING - FIXPAUL"
|
98
|
+
self.options=(configuration)
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.standalone
|
102
|
+
puts "DEPRECATION WARNING - FIXPAUL"
|
103
|
+
require "fnordmetric/standalone"
|
104
|
+
start_em
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
require "fnordmetric/gauge_calculations"
|
110
|
+
require "fnordmetric/gauge_modifiers"
|
111
|
+
require "fnordmetric/gauge_validations"
|
112
|
+
require "fnordmetric/gauge_rendering"
|
113
|
+
require "fnordmetric/gauge"
|
114
|
+
require "fnordmetric/zero_config_gauge"
|
115
|
+
require "fnordmetric/gauges/timeseries_gauge"
|
116
|
+
require "fnordmetric/gauges/toplist_gauge"
|
117
|
+
require "fnordmetric/gauges/distribution_gauge"
|
118
|
+
require "fnordmetric/context"
|
119
|
+
require "fnordmetric/histogram"
|
120
|
+
require "fnordmetric/timeseries"
|
121
|
+
require "fnordmetric/toplist"
|
122
|
+
require "fnordmetric/namespace"
|
123
|
+
require "fnordmetric/session"
|
124
|
+
require "fnordmetric/api"
|
125
|
+
require "fnordmetric/worker"
|
126
|
+
require "fnordmetric/logger"
|
127
|
+
require "fnordmetric/defaults"
|
128
|
+
require "fnordmetric/util"
|
129
|
+
require "fnordmetric/web/web"
|
130
|
+
require "fnordmetric/web/app_helpers"
|
131
|
+
require "fnordmetric/web/app"
|
132
|
+
require "fnordmetric/web/websocket"
|
133
|
+
require "fnordmetric/web/reactor"
|
134
|
+
require "fnordmetric/web/event"
|
135
|
+
require "fnordmetric/web/dashboard"
|
136
|
+
require "fnordmetric/acceptors/acceptor"
|
137
|
+
require "fnordmetric/acceptors/tcp_acceptor"
|
138
|
+
require "fnordmetric/acceptors/udp_acceptor"
|
139
|
+
require "fnordmetric/acceptors/fyrehose_acceptor"
|
140
|
+
require "fnordmetric/acceptors/amqp_acceptor"
|
141
|
+
require "fnordmetric/acceptors/stomp_acceptor"
|
142
|
+
require "fnordmetric/widget"
|
143
|
+
require "fnordmetric/widgets/timeseries_widget"
|
144
|
+
require "fnordmetric/widgets/numbers_widget"
|
145
|
+
require "fnordmetric/widgets/bars_widget"
|
146
|
+
require "fnordmetric/widgets/toplist_widget"
|
147
|
+
require "fnordmetric/widgets/pie_widget"
|
148
|
+
require "fnordmetric/widgets/html_widget"
|
149
|
+
require "fnordmetric/enterprise/compatibility_handler"
|
data/run_specs.sh
ADDED
data/spec/api_spec.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require ::File.expand_path('../spec_helper.rb', __FILE__)
|
2
|
+
|
3
|
+
describe FnordMetric::Event do
|
4
|
+
|
5
|
+
include FnordMetric
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
@now = Time.utc(1992,01,13,5,23,23).to_i
|
9
|
+
@redis = Redis.new
|
10
|
+
@redis_wrap = RedisWrap.new(@redis)
|
11
|
+
|
12
|
+
@namespace = "fnordmetric-test-ns1234-api"
|
13
|
+
@timeline = "#{@namespace}-timeline"
|
14
|
+
|
15
|
+
@opts = {
|
16
|
+
:namespace_prefix => "#{@namespace}",
|
17
|
+
:redis_prefix => "fnordmetric-test",
|
18
|
+
:redis => @redis
|
19
|
+
}
|
20
|
+
@api = FnordMetric::API.new @opts
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "creating events using API" do
|
24
|
+
|
25
|
+
before(:each) do
|
26
|
+
@redis.keys("fnordmetric-test-*").each { |k| @redis.del(k) }
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should create an event from a (json-)string" do
|
30
|
+
json_string = {
|
31
|
+
:_type => "Fn0rd123",
|
32
|
+
:_time => @now
|
33
|
+
}.to_json
|
34
|
+
event_id = @api.event(json_string)
|
35
|
+
event = FnordMetric::Event.find(event_id, @opts)
|
36
|
+
event.type.should == "Fn0rd123"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should create an event from a hash" do
|
40
|
+
event_id = @api.event(
|
41
|
+
:_type => "Fn0rd234",
|
42
|
+
:_time => @now
|
43
|
+
)
|
44
|
+
event = FnordMetric::Event.find(event_id, @opts)
|
45
|
+
event.type.should == "Fn0rd234"
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require ::File.expand_path('../spec_helper.rb', __FILE__)
|
2
|
+
|
3
|
+
describe FnordMetric::Context do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
@redis = Redis.new
|
7
|
+
@redis_wrap = RedisWrap.new(@redis)
|
8
|
+
end
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
@redis.keys("fnordmetrictest*").each { |k| @redis.del(k) }
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should fetch a gauge by key"
|
15
|
+
it "should fetch a gauge by gauge"
|
16
|
+
it "should raise an error if unable to fetch a gauge"
|
17
|
+
|
18
|
+
it "should expose the current session_key" do
|
19
|
+
ns = FnordMetric::Namespace.new(
|
20
|
+
:myns_253,
|
21
|
+
:redis_prefix => "fnordmetrictest"
|
22
|
+
)
|
23
|
+
ns.opt_event(:fnordbar, {}) do
|
24
|
+
session_key.should == "145d3f6dee1a770e3a3c550b3993dc81"
|
25
|
+
end
|
26
|
+
ns.ready!(@redis_wrap, @redis).announce(
|
27
|
+
:_eid => "35r2423",
|
28
|
+
:_time => Time.now.to_i,
|
29
|
+
:_type => "fnordbar",
|
30
|
+
:_session => "sess213"
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should instance-eval the handler on call" do
|
35
|
+
Thread.current["fnord_123"] = false
|
36
|
+
my_block = proc{ Thread.current["fnord_123"] = "35r25" }
|
37
|
+
context = FnordMetric::Context.new({}, my_block)
|
38
|
+
context.call({}, nil, nil)
|
39
|
+
Thread.current["fnord_123"].should == "35r25"
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require ::File.expand_path('../spec_helper.rb', __FILE__)
|
3
|
+
|
4
|
+
describe FnordMetric::Dashboard do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should remember it's title" do
|
10
|
+
dashboard = FnordMetric::Dashboard.new(:title => 'My Foobar Dashboard')
|
11
|
+
dashboard.title.should == 'My Foobar Dashboard'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should build a token" do
|
15
|
+
dashboard = FnordMetric::Dashboard.new(:title => 'My!F00bar-.Dash_board'){ |dash| }
|
16
|
+
dashboard.token.should == 'MyF00barDash_board'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should build the correct token if the dashboard name contains whitespaces" do
|
20
|
+
dashboard = FnordMetric::Dashboard.new(:title => 'My!F00bar Dash_board'){ |dash| }
|
21
|
+
dashboard.token.should == 'MyF00barDash_board'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should build the correct token if the dashboard name contains non-english characters" do
|
25
|
+
dashboard = FnordMetric::Dashboard.new(:title => 'Новая статистика!'){ |dash| }
|
26
|
+
dashboard.token.should_not be_empty
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should add a widget" do
|
30
|
+
pending("fix this")
|
31
|
+
#dashboard = FnordMetric::Dashboard.new(:title => 'My!F00bar-.Dash_board'){ |dash| }
|
32
|
+
#FnordMetric.metric(:my_metric, :sum => :my_field)
|
33
|
+
#idget = FnordMetric.widget(:my_widget, :metrics => :my_metric, :title => "My Widget", :type => :timeline)
|
34
|
+
#dashboard.add_widget(widget)
|
35
|
+
#dashboard.widgets.first.should == widget
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|