fnordmetric 0.3.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/Gemfile +6 -0
  2. data/Gemfile.lock +21 -0
  3. data/Procfile +1 -2
  4. data/VERSION +1 -1
  5. data/_spec/app_spec.rb +178 -0
  6. data/{spec → _spec}/cache_spec.rb +0 -0
  7. data/{spec → _spec}/combine_metric_spec.rb +0 -0
  8. data/{spec → _spec}/core_spec.rb +0 -0
  9. data/{spec → _spec}/count_metric_spec.rb +0 -0
  10. data/_spec/dashboard_spec.rb +67 -0
  11. data/_spec/event_spec.rb +46 -0
  12. data/{spec → _spec}/metric_spec.rb +0 -0
  13. data/{spec → _spec}/report_spec.rb +0 -0
  14. data/{spec → _spec}/sum_metric_spec.rb +0 -0
  15. data/_spec/widget_spec.rb +107 -0
  16. data/doc/import_dump.rb +26 -0
  17. data/em_runner.rb +33 -0
  18. data/fnordmetric.gemspec +59 -20
  19. data/haml/app.haml +26 -12
  20. data/lib/fnordmetric.rb +150 -15
  21. data/lib/fnordmetric/app.rb +70 -11
  22. data/lib/fnordmetric/cache.rb +4 -4
  23. data/lib/fnordmetric/context.rb +65 -0
  24. data/lib/fnordmetric/dashboard.rb +16 -12
  25. data/lib/fnordmetric/event.rb +65 -15
  26. data/lib/fnordmetric/gauge.rb +46 -0
  27. data/lib/fnordmetric/gauge_calculations.rb +43 -0
  28. data/lib/fnordmetric/gauge_modifiers.rb +43 -0
  29. data/lib/fnordmetric/inbound_stream.rb +66 -0
  30. data/lib/fnordmetric/logger.rb +38 -0
  31. data/lib/fnordmetric/namespace.rb +120 -0
  32. data/lib/fnordmetric/numbers_widget.rb +29 -11
  33. data/lib/fnordmetric/session.rb +131 -0
  34. data/lib/fnordmetric/standalone.rb +31 -0
  35. data/lib/fnordmetric/timeline_widget.rb +29 -9
  36. data/lib/fnordmetric/widget.rb +50 -45
  37. data/lib/fnordmetric/worker.rb +80 -0
  38. data/pub/fnordmetric/fnordmetric.css +76 -9
  39. data/pub/fnordmetric/fnordmetric.js +541 -42
  40. data/pub/raphael-min.js +8 -0
  41. data/pub/raphael-utils.js +221 -0
  42. data/readme.rdoc +172 -27
  43. data/server.rb +22 -0
  44. data/spec/app_spec.rb +359 -117
  45. data/spec/context_spec.rb +42 -0
  46. data/spec/dashboard_spec.rb +7 -47
  47. data/spec/event_spec.rb +114 -33
  48. data/spec/gauge_modifiers_spec.rb +276 -0
  49. data/spec/gauge_spec.rb +128 -0
  50. data/spec/namespace_spec.rb +104 -0
  51. data/spec/session_spec.rb +231 -0
  52. data/spec/spec_helper.rb +27 -4
  53. data/spec/widget_spec.rb +81 -75
  54. data/spec/worker_spec.rb +37 -0
  55. data/test_stream.sh +187 -0
  56. data/ulm_stats.rb +198 -0
  57. metadata +114 -35
  58. data/lib/fnordmetric/core.rb +0 -66
  59. data/lib/fnordmetric/engine.rb +0 -3
@@ -0,0 +1,26 @@
1
+ require "rubygems"
2
+ require "redis"
3
+ require "json"
4
+
5
+ if ARGV.length != 1
6
+ puts "usage: #{$0} /path/to/dump.json"
7
+ exit!
8
+ end
9
+
10
+ file_path = ARGV[0]
11
+
12
+ puts "opening #{file_path}"
13
+ file = File.open(file_path)
14
+
15
+ puts "reading file..."
16
+ events = file.read.split("\n")
17
+
18
+ puts "pushing #{events.length} events to redis"
19
+ redis = Redis.new
20
+ total_events = events.length
21
+ events.each_with_index do |event,n|
22
+ my_uuid = rand(9999999999999999999).to_s # generate a unique event id ;)
23
+ redis.lpush("fnordmetric-queue", my_uuid)
24
+ redis.set("fnordmetric-event-#{my_uuid}", event)
25
+ puts "#{n}/#{total_events}" if (n%100==0)
26
+ end
data/em_runner.rb ADDED
@@ -0,0 +1,33 @@
1
+ require "rubygems"
2
+ require "eventmachine"
3
+ require 'em-hiredis'
4
+
5
+ module Runner
6
+
7
+ def self.redis
8
+ @redis ||= EM::Hiredis.connect("redis://localhost:6379")
9
+ end
10
+
11
+ def self.next
12
+ redis.blpop('fnordmetric-queue', 0).callback do |list, data|
13
+ puts data
14
+ EM.next_tick(&method(:next))
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+
21
+ module Ticker
22
+
23
+ def self.tick
24
+ EM.defer(proc { print '.'; sleep 1; }, proc{ EM.next_tick(&method(:tick)) })
25
+ #EM.next_tick(&method(:next))
26
+ end
27
+
28
+ end
29
+
30
+ EM.run do
31
+ Ticker.tick
32
+ Runner.next
33
+ end
data/fnordmetric.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{fnordmetric}
8
- s.version = "0.3.2"
8
+ s.version = "0.5.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Paul Asmuth"]
12
- s.date = %q{2011-11-05}
12
+ s.date = %q{2011-12-10}
13
13
  s.description = %q{FnordMetric is a Ruby Event-Tracking gem on steroids}
14
14
  s.email = %q{paul@paulasmuth.com}
15
15
  s.files = [
@@ -19,7 +19,20 @@ Gem::Specification.new do |s|
19
19
  "Procfile",
20
20
  "Rakefile",
21
21
  "VERSION",
22
+ "_spec/app_spec.rb",
23
+ "_spec/cache_spec.rb",
24
+ "_spec/combine_metric_spec.rb",
25
+ "_spec/core_spec.rb",
26
+ "_spec/count_metric_spec.rb",
27
+ "_spec/dashboard_spec.rb",
28
+ "_spec/event_spec.rb",
29
+ "_spec/metric_spec.rb",
30
+ "_spec/report_spec.rb",
31
+ "_spec/sum_metric_spec.rb",
32
+ "_spec/widget_spec.rb",
22
33
  "doc/example_server.rb",
34
+ "doc/import_dump.rb",
35
+ "em_runner.rb",
23
36
  "fnordmetric.gemspec",
24
37
  "haml/app.haml",
25
38
  "haml/widget.haml",
@@ -28,19 +41,27 @@ Gem::Specification.new do |s|
28
41
  "lib/fnordmetric/average_metric.rb",
29
42
  "lib/fnordmetric/cache.rb",
30
43
  "lib/fnordmetric/combine_metric.rb",
31
- "lib/fnordmetric/core.rb",
44
+ "lib/fnordmetric/context.rb",
32
45
  "lib/fnordmetric/count_metric.rb",
33
46
  "lib/fnordmetric/dashboard.rb",
34
- "lib/fnordmetric/engine.rb",
35
47
  "lib/fnordmetric/event.rb",
36
48
  "lib/fnordmetric/funnel_widget.rb",
49
+ "lib/fnordmetric/gauge.rb",
50
+ "lib/fnordmetric/gauge_calculations.rb",
51
+ "lib/fnordmetric/gauge_modifiers.rb",
52
+ "lib/fnordmetric/inbound_stream.rb",
53
+ "lib/fnordmetric/logger.rb",
37
54
  "lib/fnordmetric/metric.rb",
38
55
  "lib/fnordmetric/metric_api.rb",
56
+ "lib/fnordmetric/namespace.rb",
39
57
  "lib/fnordmetric/numbers_widget.rb",
40
58
  "lib/fnordmetric/report.rb",
59
+ "lib/fnordmetric/session.rb",
60
+ "lib/fnordmetric/standalone.rb",
41
61
  "lib/fnordmetric/sum_metric.rb",
42
62
  "lib/fnordmetric/timeline_widget.rb",
43
63
  "lib/fnordmetric/widget.rb",
64
+ "lib/fnordmetric/worker.rb",
44
65
  "pub/fnordmetric/fnordmetric.css",
45
66
  "pub/fnordmetric/fnordmetric.js",
46
67
  "pub/fnordmetric/widget_numbers.js",
@@ -59,20 +80,24 @@ Gem::Specification.new do |s|
59
80
  "pub/highcharts/themes/gray.js",
60
81
  "pub/highcharts/themes/grid.js",
61
82
  "pub/jquery-1.6.1.min.js",
83
+ "pub/raphael-min.js",
84
+ "pub/raphael-utils.js",
62
85
  "pub/sprite.png",
63
86
  "readme.rdoc",
87
+ "server.rb",
64
88
  "spec/app_spec.rb",
65
- "spec/cache_spec.rb",
66
- "spec/combine_metric_spec.rb",
67
- "spec/core_spec.rb",
68
- "spec/count_metric_spec.rb",
89
+ "spec/context_spec.rb",
69
90
  "spec/dashboard_spec.rb",
70
91
  "spec/event_spec.rb",
71
- "spec/metric_spec.rb",
72
- "spec/report_spec.rb",
92
+ "spec/gauge_modifiers_spec.rb",
93
+ "spec/gauge_spec.rb",
94
+ "spec/namespace_spec.rb",
95
+ "spec/session_spec.rb",
73
96
  "spec/spec_helper.rb",
74
- "spec/sum_metric_spec.rb",
75
- "spec/widget_spec.rb"
97
+ "spec/widget_spec.rb",
98
+ "spec/worker_spec.rb",
99
+ "test_stream.sh",
100
+ "ulm_stats.rb"
76
101
  ]
77
102
  s.homepage = %q{http://github.com/paulasmuth/fnordmetric}
78
103
  s.licenses = ["MIT"]
@@ -81,17 +106,16 @@ Gem::Specification.new do |s|
81
106
  s.summary = %q{FnordMetric is a Ruby Event-Tracking gem on steroids}
82
107
  s.test_files = [
83
108
  "spec/app_spec.rb",
84
- "spec/cache_spec.rb",
85
- "spec/combine_metric_spec.rb",
86
- "spec/core_spec.rb",
87
- "spec/count_metric_spec.rb",
109
+ "spec/context_spec.rb",
88
110
  "spec/dashboard_spec.rb",
89
111
  "spec/event_spec.rb",
90
- "spec/metric_spec.rb",
91
- "spec/report_spec.rb",
112
+ "spec/gauge_modifiers_spec.rb",
113
+ "spec/gauge_spec.rb",
114
+ "spec/namespace_spec.rb",
115
+ "spec/session_spec.rb",
92
116
  "spec/spec_helper.rb",
93
- "spec/sum_metric_spec.rb",
94
- "spec/widget_spec.rb"
117
+ "spec/widget_spec.rb",
118
+ "spec/worker_spec.rb"
95
119
  ]
96
120
 
97
121
  if s.respond_to? :specification_version then
@@ -102,10 +126,15 @@ Gem::Specification.new do |s|
102
126
  s.add_runtime_dependency(%q<mongo>, ["~> 1.4.0"])
103
127
  s.add_runtime_dependency(%q<bson_ext>, ["~> 1.4.0"])
104
128
  s.add_runtime_dependency(%q<sinatra>, ["~> 1.2.6"])
129
+ s.add_runtime_dependency(%q<redis>, ["~> 2.2.2"])
130
+ s.add_runtime_dependency(%q<eventmachine>, [">= 0"])
131
+ s.add_runtime_dependency(%q<em-hiredis>, [">= 0"])
105
132
  s.add_runtime_dependency(%q<json>, [">= 0"])
106
133
  s.add_runtime_dependency(%q<haml>, [">= 0"])
107
134
  s.add_runtime_dependency(%q<rack>, [">= 0"])
108
135
  s.add_runtime_dependency(%q<rack-test>, [">= 0"])
136
+ s.add_runtime_dependency(%q<yajl-ruby>, [">= 0"])
137
+ s.add_runtime_dependency(%q<thin>, [">= 0"])
109
138
  s.add_development_dependency(%q<delorean>, [">= 0"])
110
139
  s.add_development_dependency(%q<rspec>, ["~> 2.6.0"])
111
140
  s.add_development_dependency(%q<shoulda>, [">= 0"])
@@ -116,10 +145,15 @@ Gem::Specification.new do |s|
116
145
  s.add_dependency(%q<mongo>, ["~> 1.4.0"])
117
146
  s.add_dependency(%q<bson_ext>, ["~> 1.4.0"])
118
147
  s.add_dependency(%q<sinatra>, ["~> 1.2.6"])
148
+ s.add_dependency(%q<redis>, ["~> 2.2.2"])
149
+ s.add_dependency(%q<eventmachine>, [">= 0"])
150
+ s.add_dependency(%q<em-hiredis>, [">= 0"])
119
151
  s.add_dependency(%q<json>, [">= 0"])
120
152
  s.add_dependency(%q<haml>, [">= 0"])
121
153
  s.add_dependency(%q<rack>, [">= 0"])
122
154
  s.add_dependency(%q<rack-test>, [">= 0"])
155
+ s.add_dependency(%q<yajl-ruby>, [">= 0"])
156
+ s.add_dependency(%q<thin>, [">= 0"])
123
157
  s.add_dependency(%q<delorean>, [">= 0"])
124
158
  s.add_dependency(%q<rspec>, ["~> 2.6.0"])
125
159
  s.add_dependency(%q<shoulda>, [">= 0"])
@@ -131,10 +165,15 @@ Gem::Specification.new do |s|
131
165
  s.add_dependency(%q<mongo>, ["~> 1.4.0"])
132
166
  s.add_dependency(%q<bson_ext>, ["~> 1.4.0"])
133
167
  s.add_dependency(%q<sinatra>, ["~> 1.2.6"])
168
+ s.add_dependency(%q<redis>, ["~> 2.2.2"])
169
+ s.add_dependency(%q<eventmachine>, [">= 0"])
170
+ s.add_dependency(%q<em-hiredis>, [">= 0"])
134
171
  s.add_dependency(%q<json>, [">= 0"])
135
172
  s.add_dependency(%q<haml>, [">= 0"])
136
173
  s.add_dependency(%q<rack>, [">= 0"])
137
174
  s.add_dependency(%q<rack-test>, [">= 0"])
175
+ s.add_dependency(%q<yajl-ruby>, [">= 0"])
176
+ s.add_dependency(%q<thin>, [">= 0"])
138
177
  s.add_dependency(%q<delorean>, [">= 0"])
139
178
  s.add_dependency(%q<rspec>, ["~> 2.6.0"])
140
179
  s.add_dependency(%q<shoulda>, [">= 0"])
data/haml/app.haml CHANGED
@@ -5,40 +5,54 @@
5
5
  %title Fnordmetric Dashboard
6
6
  %script(type="text/javascript" src="#{path_prefix}/jquery-1.6.1.min.js")
7
7
  %link(type="text/css" rel="stylesheet" href="#{path_prefix}/fnordmetric/fnordmetric.css")
8
+ %script(type="text/javascript" src="#{path_prefix}/raphael-min.js")
9
+ %script(type="text/javascript" src="#{path_prefix}/raphael-utils.js")
8
10
  %script(type="text/javascript" src="#{path_prefix}/fnordmetric/fnordmetric.js")
9
11
  :javascript
10
12
  FnordMetric.p = '#{path_prefix}';
11
13
 
12
14
  %body
15
+ .topbar
16
+
13
17
  #wrap
14
18
  #tabs
15
19
  %ul
16
- -FnordMetric.dashboards.each do |dashboard|
17
- %li{:rel => dashboard.token}
20
+ %li.active.sessions
21
+ .picto.piechart
22
+ Active Users
23
+
24
+ -current_namespace.dashboards.each do |key,dashboard|
25
+ %li.dashboard{:rel => dashboard.token}
18
26
  .picto.piechart
19
27
  =h dashboard.title
20
28
 
21
29
  #viewport
22
- -unless @dashboard
23
- no dashboard selected
24
-
25
- -@dashboard.widgets.each do |widget|
26
- -elem_id = "fw#{(rand*9999).to_i}"
27
- %div{:id => elem_id, :style => "margin-bottom:10px;"}
28
- =widget.render(elem_id)
29
-
30
+ .viewport_inner.clearfix
31
+
30
32
 
31
33
  :javascript
32
34
  $(document).ready(function(){
33
35
 
36
+ FnordMetric.init('#{current_namespace.token}', $('.viewport_inner'));
37
+
38
+ $('#tabs li.dashboard').click(function(){
39
+ FnordMetric.renderDashboard($(this).attr('rel'));
40
+ });
41
+
42
+ $('#tabs li.sessions').click(function(){
43
+ FnordMetric.renderSessionView();
44
+ });
45
+
34
46
  $('#tabs li').click(function(){
35
- document.location.href = '#{path_prefix}/dashboard/' + $(this).attr('rel');
47
+ $(this).addClass('active').siblings().removeClass('active');
36
48
  });
37
49
 
38
50
  function resizeViewport(){
39
- var viewport_width = window.innerWidth-310
51
+ var viewport_width = window.innerWidth-220
40
52
  $('#viewport').width(viewport_width);
53
+ FnordMetric.resizeView();
41
54
  }
55
+
42
56
  resizeViewport();
43
57
  $(window).resize(resizeViewport);
44
58
 
data/lib/fnordmetric.rb CHANGED
@@ -1,21 +1,156 @@
1
1
  require 'rubygems'
2
- require 'mongoid'
3
- require 'haml'
2
+ require "eventmachine"
3
+ require 'em-hiredis'
4
+ require 'redis'
5
+ require "active_support/core_ext"
6
+ require 'yajl'
4
7
  require 'sinatra/base'
8
+ require 'haml'
9
+ require 'thin'
10
+
11
+ module FnordMetric
12
+
13
+ @@namespaces = {}
14
+
15
+ def self.namespace(key=nil, &block)
16
+ @@namespaces[key] = block
17
+ end
18
+
19
+ def self.default_options(opts)
20
+
21
+ opts[:redis_uri] = "redis://localhost:6379"
22
+ opts[:redis_prefix] ||= "fnordmetric"
23
+
24
+ opts[:inbound_stream] ||= ["0.0.0.0", "1337"]
25
+ opts[:web_interface] ||= ["0.0.0.0", "4242"]
26
+
27
+ opts[:start_worker] ||= true
28
+ opts[:print_stats] ||= 3
29
+
30
+ # events that aren't processed after 2 min get dropped
31
+ opts[:event_queue_ttl] ||= 120
32
+
33
+ # event data is kept for one month
34
+ opts[:event_data_ttl] ||= 3600*24*30
35
+
36
+ # session data is kept for one month
37
+ opts[:session_data_ttl] ||= 3600*24*30
38
+
39
+ opts
40
+ end
41
+
42
+ def self.start_em(opts)
43
+ EM.run do
44
+
45
+ trap("TERM", &method(:shutdown))
46
+ trap("INT", &method(:shutdown))
47
+
48
+ opts = default_options(opts)
49
+
50
+ if opts[:start_worker]
51
+ worker = Worker.new(@@namespaces.clone, opts)
52
+ worker.ready!
53
+ end
54
+
55
+ if opts[:inbound_stream]
56
+ begin
57
+ inbound_stream = InboundStream.start(opts)
58
+ log "listening on tcp##{opts[:inbound_stream].join(":")}"
59
+ rescue
60
+ log "cant start FnordMetric::InboundStream. port in use?"
61
+ end
62
+ end
63
+
64
+ if opts[:web_interface]
65
+ begin
66
+ app = FnordMetric::App.new(@@namespaces.clone, opts)
67
+ Thin::Server.start(*opts[:web_interface], app)
68
+ log "listening on http##{opts[:web_interface].join(":")}"
69
+ rescue Exception => e
70
+ log "cant start FnordMetric::App. port in use?"
71
+ end
72
+ end
73
+
74
+ if opts[:print_stats]
75
+ redis = connect_redis(opts[:redis_url])
76
+ EM::PeriodicTimer.new(opts[:print_stats]) do
77
+ print_stats(opts, redis)
78
+ end
79
+ end
80
+
81
+ end
82
+ end
83
+
84
+ def self.log(msg)
85
+ puts "[#{Time.now.strftime("%y-%m-%d %H:%M:%S")}] #{msg}"
86
+ end
5
87
 
6
- require "fnordmetric/core"
88
+ def self.error!(msg)
89
+ raise msg if ENV['FNORDMETRIC_ENV'] == 'test'
90
+ puts(msg); exit!
91
+ end
92
+
93
+ def self.run(opts={})
94
+ start_em(opts)
95
+ rescue Exception => e
96
+ log "!!! eventmachine died, restarting... #{e.message}"
97
+ sleep(1); run(opts)
98
+ end
99
+
100
+ def self.shutdown
101
+ log "shutting down, byebye"
102
+ EM.stop
103
+ end
104
+
105
+ def self.connect_redis(redis_url)
106
+ EM::Hiredis.connect(redis_url)
107
+ end
108
+
109
+ def self.print_stats(opts, redis) # FIXME: refactor this mess
110
+ keys = [:events_received, :events_processed]
111
+ redis.llen("#{opts[:redis_prefix]}-queue") do |queue_length|
112
+ redis.hmget("#{opts[:redis_prefix]}-stats", *keys) do |data|
113
+ data_human = keys.size.times.map{|n|"#{keys[n]}: #{data[n]}"}
114
+ log "#{data_human.join(", ")}, queue_length: #{queue_length}"
115
+ end
116
+ end
117
+ end
118
+
119
+ def self.standalone
120
+ require "fnordmetric/logger"
121
+ require "fnordmetric/standalone"
122
+ end
123
+
124
+ end
125
+
126
+ require "fnordmetric/inbound_stream"
127
+ require "fnordmetric/worker"
128
+ require "fnordmetric/widget"
129
+ require "fnordmetric/timeline_widget"
130
+ require "fnordmetric/numbers_widget"
131
+ require "fnordmetric/namespace"
132
+ require "fnordmetric/gauge_modifiers"
133
+ require "fnordmetric/gauge_calculations"
134
+ require "fnordmetric/context"
135
+ require "fnordmetric/gauge"
136
+ require "fnordmetric/session"
7
137
  require "fnordmetric/app"
8
- require "fnordmetric/metric_api"
9
138
  require "fnordmetric/dashboard"
10
139
  require "fnordmetric/event"
11
- require "fnordmetric/cache"
12
- require "fnordmetric/report"
13
- require "fnordmetric/metric"
14
- require "fnordmetric/average_metric"
15
- require "fnordmetric/count_metric"
16
- require "fnordmetric/combine_metric"
17
- require "fnordmetric/sum_metric"
18
- require "fnordmetric/widget"
19
- require "fnordmetric/numbers_widget"
20
- require "fnordmetric/timeline_widget"
21
- require "fnordmetric/funnel_widget"
140
+
141
+
142
+ #require "fnordmetric/metric_api"
143
+
144
+
145
+ #require "fnordmetric/cache"
146
+ #require "fnordmetric/report"
147
+ #require "fnordmetric/metric"
148
+ #require "fnordmetric/average_metric"
149
+ #require "fnordmetric/count_metric"
150
+ #require "fnordmetric/combine_metric"
151
+ #require "fnordmetric/sum_metric"
152
+ #require "fnordmetric/widget"
153
+
154
+ #
155
+ #require "fnordmetric/funnel_widget"
156
+