fnordmetric 0.5.1 → 0.5.2

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 (65) hide show
  1. data/.travis.yml +1 -0
  2. data/VERSION +1 -1
  3. data/doc/preview1.png +0 -0
  4. data/doc/preview2.png +0 -0
  5. data/doc/ulm_stats.rb +622 -0
  6. data/doc/version +1 -0
  7. data/fnordmetric.gemspec +16 -38
  8. data/haml/app.haml +12 -5
  9. data/lib/fnordmetric.rb +3 -0
  10. data/lib/fnordmetric/app.rb +19 -10
  11. data/lib/fnordmetric/bars_widget.rb +26 -0
  12. data/lib/fnordmetric/context.rb +3 -3
  13. data/lib/fnordmetric/gauge.rb +20 -0
  14. data/lib/fnordmetric/gauge_calculations.rb +28 -4
  15. data/lib/fnordmetric/gauge_modifiers.rb +39 -6
  16. data/lib/fnordmetric/logger.rb +19 -0
  17. data/lib/fnordmetric/numbers_widget.rb +5 -15
  18. data/lib/fnordmetric/pie_widget.rb +23 -0
  19. data/lib/fnordmetric/standalone.rb +1 -1
  20. data/lib/fnordmetric/timeline_widget.rb +16 -23
  21. data/lib/fnordmetric/toplist_widget.rb +25 -0
  22. data/lib/fnordmetric/widget.rb +3 -3
  23. data/pub/{fnordmetric/fnordmetric.css → fnordmetric.css} +46 -36
  24. data/pub/fnordmetric.js +1069 -0
  25. data/pub/loader.gif +0 -0
  26. data/pub/{highcharts → vendor}/highcharts.js +0 -0
  27. data/pub/{jquery-1.6.1.min.js → vendor/jquery-1.6.1.min.js} +0 -0
  28. data/readme.rdoc +228 -311
  29. data/spec/app_spec.rb +63 -3
  30. data/spec/gauge_modifiers_spec.rb +157 -2
  31. data/spec/gauge_spec.rb +143 -12
  32. data/spec/widget_spec.rb +18 -18
  33. metadata +33 -58
  34. data/.document +0 -5
  35. data/_spec/app_spec.rb +0 -178
  36. data/_spec/cache_spec.rb +0 -53
  37. data/_spec/combine_metric_spec.rb +0 -19
  38. data/_spec/core_spec.rb +0 -50
  39. data/_spec/count_metric_spec.rb +0 -32
  40. data/_spec/dashboard_spec.rb +0 -67
  41. data/_spec/event_spec.rb +0 -46
  42. data/_spec/metric_spec.rb +0 -118
  43. data/_spec/report_spec.rb +0 -87
  44. data/_spec/sum_metric_spec.rb +0 -33
  45. data/_spec/widget_spec.rb +0 -107
  46. data/doc/example_server.rb +0 -56
  47. data/doc/import_dump.rb +0 -26
  48. data/pub/fnordmetric/fnordmetric.js +0 -543
  49. data/pub/fnordmetric/widget_numbers.js +0 -71
  50. data/pub/fnordmetric/widget_timeline.css +0 -0
  51. data/pub/fnordmetric/widget_timeline.js +0 -110
  52. data/pub/highcharts/adapters/mootools-adapter.js +0 -12
  53. data/pub/highcharts/adapters/mootools-adapter.src.js +0 -243
  54. data/pub/highcharts/adapters/prototype-adapter.js +0 -14
  55. data/pub/highcharts/adapters/prototype-adapter.src.js +0 -284
  56. data/pub/highcharts/highcharts.src.js +0 -11103
  57. data/pub/highcharts/modules/exporting.js +0 -22
  58. data/pub/highcharts/modules/exporting.src.js +0 -703
  59. data/pub/highcharts/themes/dark-blue.js +0 -268
  60. data/pub/highcharts/themes/dark-green.js +0 -268
  61. data/pub/highcharts/themes/gray.js +0 -262
  62. data/pub/highcharts/themes/grid.js +0 -97
  63. data/pub/raphael-min.js +0 -8
  64. data/pub/raphael-utils.js +0 -221
  65. data/ulm_stats.rb +0 -198
@@ -0,0 +1 @@
1
+ 0.5.2
@@ -5,38 +5,30 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{fnordmetric}
8
- s.version = "0.5.1"
8
+ s.version = "0.5.2"
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-12-10}
12
+ s.date = %q{2011-12-26}
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 = [
16
- ".document",
16
+ ".travis.yml",
17
17
  "Gemfile",
18
18
  "Gemfile.lock",
19
19
  "Rakefile",
20
20
  "VERSION",
21
- "_spec/app_spec.rb",
22
- "_spec/cache_spec.rb",
23
- "_spec/combine_metric_spec.rb",
24
- "_spec/core_spec.rb",
25
- "_spec/count_metric_spec.rb",
26
- "_spec/dashboard_spec.rb",
27
- "_spec/event_spec.rb",
28
- "_spec/metric_spec.rb",
29
- "_spec/report_spec.rb",
30
- "_spec/sum_metric_spec.rb",
31
- "_spec/widget_spec.rb",
32
- "doc/example_server.rb",
33
- "doc/import_dump.rb",
21
+ "doc/preview1.png",
22
+ "doc/preview2.png",
23
+ "doc/ulm_stats.rb",
24
+ "doc/version",
34
25
  "fnordmetric.gemspec",
35
26
  "haml/app.haml",
36
27
  "haml/widget.haml",
37
28
  "lib/fnordmetric.rb",
38
29
  "lib/fnordmetric/app.rb",
39
30
  "lib/fnordmetric/average_metric.rb",
31
+ "lib/fnordmetric/bars_widget.rb",
40
32
  "lib/fnordmetric/cache.rb",
41
33
  "lib/fnordmetric/combine_metric.rb",
42
34
  "lib/fnordmetric/context.rb",
@@ -53,34 +45,21 @@ Gem::Specification.new do |s|
53
45
  "lib/fnordmetric/metric_api.rb",
54
46
  "lib/fnordmetric/namespace.rb",
55
47
  "lib/fnordmetric/numbers_widget.rb",
48
+ "lib/fnordmetric/pie_widget.rb",
56
49
  "lib/fnordmetric/report.rb",
57
50
  "lib/fnordmetric/session.rb",
58
51
  "lib/fnordmetric/standalone.rb",
59
52
  "lib/fnordmetric/sum_metric.rb",
60
53
  "lib/fnordmetric/timeline_widget.rb",
54
+ "lib/fnordmetric/toplist_widget.rb",
61
55
  "lib/fnordmetric/widget.rb",
62
56
  "lib/fnordmetric/worker.rb",
63
- "pub/fnordmetric/fnordmetric.css",
64
- "pub/fnordmetric/fnordmetric.js",
65
- "pub/fnordmetric/widget_numbers.js",
66
- "pub/fnordmetric/widget_timeline.css",
67
- "pub/fnordmetric/widget_timeline.js",
68
- "pub/highcharts/adapters/mootools-adapter.js",
69
- "pub/highcharts/adapters/mootools-adapter.src.js",
70
- "pub/highcharts/adapters/prototype-adapter.js",
71
- "pub/highcharts/adapters/prototype-adapter.src.js",
72
- "pub/highcharts/highcharts.js",
73
- "pub/highcharts/highcharts.src.js",
74
- "pub/highcharts/modules/exporting.js",
75
- "pub/highcharts/modules/exporting.src.js",
76
- "pub/highcharts/themes/dark-blue.js",
77
- "pub/highcharts/themes/dark-green.js",
78
- "pub/highcharts/themes/gray.js",
79
- "pub/highcharts/themes/grid.js",
80
- "pub/jquery-1.6.1.min.js",
81
- "pub/raphael-min.js",
82
- "pub/raphael-utils.js",
57
+ "pub/fnordmetric.css",
58
+ "pub/fnordmetric.js",
59
+ "pub/loader.gif",
83
60
  "pub/sprite.png",
61
+ "pub/vendor/highcharts.js",
62
+ "pub/vendor/jquery-1.6.1.min.js",
84
63
  "readme.rdoc",
85
64
  "spec/app_spec.rb",
86
65
  "spec/context_spec.rb",
@@ -92,8 +71,7 @@ Gem::Specification.new do |s|
92
71
  "spec/session_spec.rb",
93
72
  "spec/spec_helper.rb",
94
73
  "spec/widget_spec.rb",
95
- "spec/worker_spec.rb",
96
- "ulm_stats.rb"
74
+ "spec/worker_spec.rb"
97
75
  ]
98
76
  s.homepage = %q{http://github.com/paulasmuth/fnordmetric}
99
77
  s.licenses = ["MIT"]
@@ -3,11 +3,13 @@
3
3
 
4
4
  %head
5
5
  %title Fnordmetric Dashboard
6
- %script(type="text/javascript" src="#{path_prefix}/jquery-1.6.1.min.js")
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")
10
- %script(type="text/javascript" src="#{path_prefix}/fnordmetric/fnordmetric.js")
6
+
7
+ %script(type="text/javascript" src="#{path_prefix}/vendor/jquery-1.6.1.min.js")
8
+ %script(type="text/javascript" src="#{path_prefix}/vendor/highcharts.js")
9
+
10
+ %script(type="text/javascript" src="#{path_prefix}/fnordmetric.js")
11
+ %link(type="text/css" rel="stylesheet" href="#{path_prefix}/fnordmetric.css")
12
+
11
13
  :javascript
12
14
  FnordMetric.p = '#{path_prefix}';
13
15
 
@@ -37,6 +39,7 @@
37
39
 
38
40
  $('#tabs li.dashboard').click(function(){
39
41
  FnordMetric.renderDashboard($(this).attr('rel'));
42
+ window.location.hash = $(this).attr('rel');
40
43
  });
41
44
 
42
45
  $('#tabs li.sessions').click(function(){
@@ -56,6 +59,10 @@
56
59
  resizeViewport();
57
60
  $(window).resize(resizeViewport);
58
61
 
62
+ if(window.location.hash){
63
+ $('#tabs li.dashboard[rel="'+window.location.hash.slice(1)+'"]').trigger('click');
64
+ }
65
+
59
66
  });
60
67
 
61
68
 
@@ -128,6 +128,9 @@ require "fnordmetric/worker"
128
128
  require "fnordmetric/widget"
129
129
  require "fnordmetric/timeline_widget"
130
130
  require "fnordmetric/numbers_widget"
131
+ require "fnordmetric/bars_widget"
132
+ require "fnordmetric/toplist_widget"
133
+ require "fnordmetric/pie_widget"
131
134
  require "fnordmetric/namespace"
132
135
  require "fnordmetric/gauge_modifiers"
133
136
  require "fnordmetric/gauge_calculations"
@@ -57,16 +57,25 @@ class FnordMetric::App < Sinatra::Base
57
57
  ""
58
58
  end
59
59
 
60
- #get '/metric/:name' do
61
- # content_type 'application/json'
62
- # FnordMetric::MetricAPI.new(params).render
63
- #end
64
-
65
- #get '/widget/:name' do
66
- # @dashboard = FnordMetric.dashboards.first
67
- # @widget = @dashboard.widgets.first
68
- # haml :widget
69
- #end
60
+ get '/:namespace/gauge/:name' do
61
+
62
+ gauge = current_namespace.gauges.fetch(params[:name].intern)
63
+
64
+ data = if gauge.three_dimensional?
65
+ _t = (params[:at] || Time.now).to_i
66
+ { :count => gauge.field_values_total(_t), :values => gauge.field_values_at(_t) }
67
+ elsif params[:at] && params[:at] =~ /^[0-9]+$/
68
+ { (_t = gauge.tick_at(params[:at].to_i)) => gauge.value_at(_t) }
69
+ elsif params[:at] && params[:at] =~ /^([0-9]+)-([0-9]+)$/
70
+ _range = params[:at].split("-").map(&:to_i)
71
+ _values = gauge.values_in(_range.first.._range.last)
72
+ params[:sum] ? { :sum => _values.values.compact.map(&:to_i).sum } : _values
73
+ else
74
+ { (_t = gauge.tick_at(Time.now.to_i-gauge.tick)) => gauge.value_at(_t) }
75
+ end
76
+
77
+ data.to_json
78
+ end
70
79
 
71
80
  get '/:namespace/sessions' do
72
81
 
@@ -0,0 +1,26 @@
1
+ class FnordMetric::BarsWidget < 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
+ :order_by => (@opts[:order_by] || 'value'),
9
+ :plot_style => (@opts[:plot_style] || 'vertical'),
10
+ :tick => tick
11
+ )
12
+ end
13
+
14
+ def gauge_titles
15
+ {}.tap do |_hash|
16
+ gauges.each do |gauge|
17
+ _hash.merge!(gauge.name => gauge.title)
18
+ end
19
+ end
20
+ end
21
+
22
+ def has_tick?
23
+ false
24
+ end
25
+
26
+ end
@@ -4,13 +4,13 @@ class FnordMetric::Context
4
4
 
5
5
  def initialize(opts, block)
6
6
  @block = block
7
- @opts = opts
7
+ @opts = opts
8
8
  end
9
9
 
10
10
  def call(event, redis)
11
11
  @redis = redis
12
- @event = event
13
- self.instance_eval(&@block)
12
+ @event = event
13
+ self.instance_eval(&@block)
14
14
  rescue Exception => e
15
15
  raise e if ENV['FNORDMETRIC_ENV'] == 'test'
16
16
  puts "error: #{e.message}"
@@ -18,6 +18,10 @@ class FnordMetric::Gauge
18
18
  def name
19
19
  @opts[:key]
20
20
  end
21
+
22
+ def title
23
+ @opts[:title] || name
24
+ end
21
25
 
22
26
  def key(_append=nil)
23
27
  [@opts[:key_prefix], "gauge", name, tick, _append].flatten.compact.join("-")
@@ -31,6 +35,10 @@ class FnordMetric::Gauge
31
35
  !@opts[:three_dimensional]
32
36
  end
33
37
 
38
+ def three_dimensional?
39
+ !!@opts[:three_dimensional]
40
+ end
41
+
34
42
  def progressive?
35
43
  !!@opts[:progressive]
36
44
  end
@@ -39,8 +47,20 @@ class FnordMetric::Gauge
39
47
  !!@opts[:unique]
40
48
  end
41
49
 
50
+ def average?
51
+ !!@opts[:average]
52
+ end
53
+
42
54
  def add_redis(_redis)
43
55
  @opts[:redis] = _redis
44
56
  end
45
57
 
58
+ def ticks_in(r)
59
+ (((r.last-r.first)/tick.to_f).ceil+1).times.map{ |n| tick_at(r.first + tick*(n-1)) }
60
+ end
61
+
62
+ def values_in(range)
63
+ values_at(ticks_in(range))
64
+ end
65
+
46
66
  end
@@ -1,8 +1,15 @@
1
1
  module FnordMetric::GaugeCalculations
2
2
 
3
3
  @@avg_per_session_proc = proc{ |_v, _t|
4
- #raise redis.get(tick_key(_t, :"sessions-count")).inspect
5
- (_v.to_f / (redis.get(tick_key(_t, :"sessions-count"))||0).to_i)
4
+ (_v.to_f / (redis.get(tick_key(_t, :"sessions-count"))||1).to_i)
5
+ }
6
+
7
+ @@count_per_session_proc = proc{ |_v, _t|
8
+ (redis.get(tick_key(_t, :"sessions-count"))||0).to_i
9
+ }
10
+
11
+ @@avg_per_count_proc = proc{ |_v, _t|
12
+ (_v.to_f / (redis.get(tick_key(_t, :"value-count"))||1).to_i)
6
13
  }
7
14
 
8
15
  def value_at(time, opts={}, &block)
@@ -27,8 +34,10 @@ module FnordMetric::GaugeCalculations
27
34
  end
28
35
 
29
36
  def calculate_value(_v, _t, opts, block)
30
- block = @@avg_per_session_proc if opts[:avg_per_session]
31
-
37
+ block = @@avg_per_count_proc if average?
38
+ #block = @@count_per_session_proc if unique?
39
+ block = @@avg_per_session_proc if unique? && average?
40
+
32
41
  if block
33
42
  instance_exec(_v, _t, &block)
34
43
  else
@@ -36,6 +45,21 @@ module FnordMetric::GaugeCalculations
36
45
  end
37
46
  end
38
47
 
48
+ def field_values_at(time, opts={}, &block)
49
+ opts[:max_fields] ||= 50
50
+ redis.zrevrange(
51
+ tick_key(time),
52
+ 0, opts[:max_fields]-1,
53
+ :withscores => true
54
+ ).in_groups_of(2).map do |key, val|
55
+ [key, calculate_value(val, time, opts, block)]
56
+ end
57
+ end
58
+
59
+ def field_values_total(time)
60
+ (redis.get(tick_key(time, :count))||0).to_i
61
+ end
62
+
39
63
  def redis
40
64
  @opts[:redis]
41
65
  end
@@ -5,6 +5,8 @@ module FnordMetric::GaugeModifiers
5
5
  assure_two_dimensional!(gauge)
6
6
  if gauge.unique?
7
7
  incr_uniq(gauge, value)
8
+ elsif gauge.average?
9
+ incr_avg(gauge, value)
8
10
  else
9
11
  incr_tick(gauge, value)
10
12
  end
@@ -18,26 +20,57 @@ module FnordMetric::GaugeModifiers
18
20
  end
19
21
  end
20
22
  else
21
- @redis.hincrby(gauge.key, gauge.tick_at(time), value)
23
+ @redis.hsetnx(gauge.key, gauge.tick_at(time), 0).callback do
24
+ @redis.hincrby(gauge.key, gauge.tick_at(time), value)
25
+ end
22
26
  end
23
27
  end
24
28
 
25
- def incr_uniq(gauge, value)
26
- return false unless session_key
29
+ def incr_uniq(gauge, value, field_name=nil)
30
+ return false if session_key.blank?
27
31
  @redis.sadd(gauge.tick_key(time, :sessions), session_key).callback do |_new|
28
32
  @redis.expire(gauge.tick_key(time, :sessions), gauge.tick)
29
- if _new
33
+ if (_new == 1) || (_new == true) #redis vs. em-redis
30
34
  @redis.incr(gauge.tick_key(time, :"sessions-count")).callback do |sc|
31
- incr_tick(gauge, value)
35
+ field_name ? incr_field_by(gauge, field_name, value) : incr_tick(gauge, value)
32
36
  end
33
37
  end
34
38
  end
35
39
  end
36
40
 
41
+ def incr_avg(gauge, value)
42
+ @redis.incr(gauge.tick_key(time, :"value-count")).callback do
43
+ incr_tick(gauge, value)
44
+ end
45
+ end
46
+
37
47
  def incr_field(gauge_name, field_name, value=1)
38
48
  gauge = fetch_gauge(gauge_name)
39
49
  assure_three_dimensional!(gauge)
40
- # here be dragons
50
+ if gauge.unique?
51
+ incr_uniq(gauge, value, field_name)
52
+ else
53
+ incr_field_by(gauge, field_name, value)
54
+ end
55
+ end
56
+
57
+ def incr_field_by(gauge, field_name, value)
58
+ @redis.zincrby(gauge.tick_key(time), value, field_name).callback do
59
+ @redis.incrby(gauge.tick_key(time, :count), 1)
60
+ end
61
+ end
62
+
63
+ def set_value(gauge_name, value)
64
+ gauge = fetch_gauge(gauge_name)
65
+ assure_two_dimensional!(gauge)
66
+ @redis.hset(gauge.key, gauge.tick_at(time), value)
67
+ end
68
+
69
+ def set_field(gauge_name, field_name, value)
70
+ gauge = fetch_gauge(gauge_name)
71
+ assure_three_dimensional!(gauge)
72
+ @redis.zadd(gauge.tick_key(time), value, field_name)
41
73
  end
42
74
 
75
+
43
76
  end
@@ -35,4 +35,23 @@ class FnordMetric::Logger
35
35
  fetcher.join
36
36
  end
37
37
 
38
+ def self.import(logfile_path)
39
+ redis = Redis.new
40
+ dump_file = File.open(logfile_path, 'r')
41
+
42
+ puts "reading #{logfile_path}..."
43
+ dump_lines = dump_file.read.split("\n")
44
+
45
+ puts "importing #{dump_lines.length} events..."
46
+ pre_uuid = rand(999999999999999999999)
47
+ log_every = (dump_lines.length / 150)
48
+ dump_lines.each_with_index do |line,n|
49
+ puts "#{n}/#{dump_lines.length} (#{((n/dump_lines.length.to_f)*100).to_i}%)" if n%log_every==0
50
+ my_uuid = "#{pre_uuid}-#{n}"
51
+ redis.set("fnordmetric-event-#{my_uuid}", line)
52
+ redis.lpush("fnordmetric-queue", my_uuid)
53
+ redis.expire("fnordmetric-event-#{my_uuid}", 3600*12)
54
+ end
55
+ end
56
+
38
57
  end
@@ -2,8 +2,9 @@ class FnordMetric::NumbersWidget < FnordMetric::Widget
2
2
 
3
3
  def data
4
4
  super.merge(
5
- :offsets => offsets,
6
- :gauges => data_gauges
5
+ :gauges => data_gauges,
6
+ :offsets => (@opts[:offsets] || [0, 1, "s30"]),
7
+ :autoupdate => (@opts[:autoupdate] || 0)
7
8
  )
8
9
  end
9
10
 
@@ -11,26 +12,15 @@ class FnordMetric::NumbersWidget < FnordMetric::Widget
11
12
  Hash.new.tap do |hash|
12
13
  gauges.each do |g|
13
14
  hash[g.name] = {
14
- :values => data_gauge(g),
15
- :title => g.name
15
+ :tick => g.tick,
16
+ :title => g.title
16
17
  }
17
18
  end
18
19
  end
19
20
  end
20
21
 
21
- def data_gauge(gauge)
22
- offsets.map do |offset|
23
- offset_time = Time.now.to_i - offset*gauge.tick
24
- [gauge.tick_at(offset_time), gauge.value_at(offset_time)]
25
- end
26
- end
27
-
28
22
  def has_tick?
29
23
  false
30
24
  end
31
25
 
32
- def offsets
33
- [0, 1, 30]
34
- end
35
-
36
26
  end