fnordmetric 0.3.2 → 0.5.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.
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
+