fnordmetric 0.6.1 → 0.6.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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.1
1
+ 0.6.2
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.6.1"
8
+ s.version = "0.6.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{2012-01-12}
12
+ s.date = %q{2012-01-13}
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.extra_rdoc_files = [
@@ -30,6 +30,7 @@ Gem::Specification.new do |s|
30
30
  "haml/app.haml",
31
31
  "haml/widget.haml",
32
32
  "lib/fnordmetric.rb",
33
+ "lib/fnordmetric/api.rb",
33
34
  "lib/fnordmetric/app.rb",
34
35
  "lib/fnordmetric/average_metric.rb",
35
36
  "lib/fnordmetric/bars_widget.rb",
@@ -64,6 +65,7 @@ Gem::Specification.new do |s|
64
65
  "pub/sprite.png",
65
66
  "pub/vendor/highcharts.js",
66
67
  "pub/vendor/jquery-1.6.1.min.js",
68
+ "spec/api_spec.rb",
67
69
  "spec/app_spec.rb",
68
70
  "spec/context_spec.rb",
69
71
  "spec/dashboard_spec.rb",
@@ -79,9 +81,10 @@ Gem::Specification.new do |s|
79
81
  s.homepage = %q{http://github.com/paulasmuth/fnordmetric}
80
82
  s.licenses = ["MIT"]
81
83
  s.require_paths = ["lib"]
82
- s.rubygems_version = %q{1.5.2}
84
+ s.rubygems_version = %q{1.6.2}
83
85
  s.summary = %q{FnordMetric is a Ruby Event-Tracking gem on steroids}
84
86
  s.test_files = [
87
+ "spec/api_spec.rb",
85
88
  "spec/app_spec.rb",
86
89
  "spec/context_spec.rb",
87
90
  "spec/dashboard_spec.rb",
data/lib/fnordmetric.rb CHANGED
@@ -12,8 +12,8 @@ module FnordMetric
12
12
 
13
13
  @@namespaces = {}
14
14
 
15
- def self.namespace(key=nil, &block)
16
- @@namespaces[key] = block
15
+ def self.namespace(key=nil, &block)
16
+ @@namespaces[key] = block
17
17
  end
18
18
 
19
19
  def self.server_configuration=(configuration)
@@ -23,7 +23,7 @@ module FnordMetric
23
23
  def self.default_options(opts)
24
24
 
25
25
  opts[:redis_url] ||= "redis://localhost:6379"
26
- opts[:redis_prefix] ||= "fnordmetric"
26
+ opts[:redis_prefix] ||= "fnordmetric"
27
27
 
28
28
  opts[:inbound_stream] ||= ["0.0.0.0", "1337"]
29
29
  opts[:web_interface] ||= ["0.0.0.0", "4242"]
@@ -38,8 +38,8 @@ module FnordMetric
38
38
  opts[:event_data_ttl] ||= 3600*24*30
39
39
 
40
40
  # session data is kept for one month
41
- opts[:session_data_ttl] ||= 3600*24*30
42
-
41
+ opts[:session_data_ttl] ||= 3600*24*30
42
+
43
43
  opts
44
44
  end
45
45
 
@@ -49,25 +49,10 @@ module FnordMetric
49
49
  trap("TERM", &method(:shutdown))
50
50
  trap("INT", &method(:shutdown))
51
51
 
52
- opts = default_options(opts)
53
-
54
- if opts[:start_worker]
55
- worker = Worker.new(@@namespaces.clone, opts)
56
- worker.ready!
57
- end
58
-
59
- if opts[:inbound_stream]
60
- begin
61
- inbound_stream = InboundStream.start(opts)
62
- log "listening on tcp##{opts[:inbound_stream].join(":")}"
63
- rescue
64
- log "cant start FnordMetric::InboundStream. port in use?"
65
- end
66
- end
52
+ app = embedded(opts)
67
53
 
68
54
  if opts[:web_interface]
69
- begin
70
- app = FnordMetric::App.new(@@namespaces.clone, opts)
55
+ begin
71
56
  Thin::Server.start(*opts[:web_interface], app)
72
57
  log "listening on http##{opts[:web_interface].join(":")}"
73
58
  rescue Exception => e
@@ -75,14 +60,7 @@ module FnordMetric
75
60
  end
76
61
  end
77
62
 
78
- if opts[:print_stats]
79
- redis = connect_redis(opts[:redis_url])
80
- EM::PeriodicTimer.new(opts[:print_stats]) do
81
- print_stats(opts, redis)
82
- end
83
- end
84
-
85
- end
63
+ end
86
64
  end
87
65
 
88
66
  def self.log(msg)
@@ -113,21 +91,60 @@ module FnordMetric
113
91
 
114
92
  def self.print_stats(opts, redis) # FIXME: refactor this mess
115
93
  keys = [:events_received, :events_processed]
116
- redis.llen("#{opts[:redis_prefix]}-queue") do |queue_length|
94
+ redis.llen("#{opts[:redis_prefix]}-queue") do |queue_length|
117
95
  redis.hmget("#{opts[:redis_prefix]}-stats", *keys) do |data|
118
96
  data_human = keys.size.times.map{|n|"#{keys[n]}: #{data[n]}"}
119
97
  log "#{data_human.join(", ")}, queue_length: #{queue_length}"
120
- end
98
+ end
121
99
  end
122
100
  end
123
101
 
124
- def self.standalone
102
+ def self.standalone
125
103
  require "fnordmetric/logger"
126
104
  require "fnordmetric/standalone"
127
105
  end
128
106
 
107
+ # returns a Rack app which can be mounted under any path.
108
+ # `:start_worker` starts a worker
109
+ # `:inbound_stream` starts the TCP interface
110
+ # `:print_stats` periodicaly prints worker stats
111
+ def self.embedded(opts={})
112
+ opts = default_options(opts)
113
+ app = nil
114
+
115
+ if opts[:rack_app] or opts[:web_interface]
116
+ app = FnordMetric::App.new(@@namespaces.clone, opts)
117
+ end
118
+
119
+ EM.next_tick do
120
+ if opts[:start_worker]
121
+ worker = Worker.new(@@namespaces.clone, opts)
122
+ worker.ready!
123
+ end
124
+
125
+ if opts[:inbound_stream]
126
+ begin
127
+ inbound_stream = InboundStream.start(opts)
128
+ log "listening on tcp##{opts[:inbound_stream].join(":")}"
129
+ rescue
130
+ log "cant start FnordMetric::InboundStream. port in use?"
131
+ end
132
+ end
133
+
134
+ if opts[:print_stats]
135
+ redis = connect_redis(opts[:redis_url])
136
+ EM::PeriodicTimer.new(opts[:print_stats]) do
137
+ print_stats(opts, redis)
138
+ end
139
+ end
140
+ end
141
+
142
+ app
143
+ end
144
+
129
145
  end
130
146
 
147
+ require "fnordmetric/api"
131
148
  require "fnordmetric/inbound_stream"
132
149
  require "fnordmetric/worker"
133
150
  require "fnordmetric/widget"
@@ -0,0 +1,38 @@
1
+ require 'securerandom'
2
+ class FnordMetric::API
3
+ @@opts = nil
4
+ def initialize opts
5
+ @@opts = FnordMetric.default_options(opts)
6
+ connect
7
+ end
8
+
9
+ def connect
10
+ @redis = @@opts[:redis] if @@opts[:redis]
11
+ @redis = Redis.connect(:url => @@opts[:redis_url])
12
+ end
13
+
14
+ def event(event_data)
15
+ event_data = event_data.to_json if event_data.is_a?(Hash)
16
+ push_event(get_next_uuid, event_data)
17
+ end
18
+
19
+ def disconnect
20
+ @redis.quit
21
+ end
22
+
23
+ private
24
+
25
+ def push_event(event_id, event_data)
26
+ prefix = @@opts[:redis_prefix]
27
+ @redis.hincrby "#{prefix}-testdata", "events_received", 1
28
+ @redis.hincrby "#{prefix}-stats", "events_received", 1
29
+ @redis.set "#{prefix}-event-#{event_id}", event_data
30
+ @redis.lpush "#{prefix}-queue", event_id
31
+ @redis.expire "#{prefix}-event-#{event_id}", @@opts[:event_queue_ttl]
32
+ event_id
33
+ end
34
+
35
+ def get_next_uuid
36
+ SecureRandom.uuid
37
+ end
38
+ end
@@ -1,18 +1,18 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  class FnordMetric::App < Sinatra::Base
4
-
4
+
5
5
  @@sessions = Hash.new
6
-
6
+
7
7
  Encoding.default_external = Encoding::UTF_8
8
8
 
9
9
  #use Rack::Reloader, 0
10
-
10
+
11
11
  enable :session
12
12
 
13
- set :haml, :format => :html5
13
+ set :haml, :format => :html5
14
14
  set :views, ::File.expand_path('../../../haml', __FILE__)
15
- set :public, ::File.expand_path('../../../pub', __FILE__)
15
+ set :public_folder, ::File.expand_path('../../../pub', __FILE__)
16
16
 
17
17
  def initialize(namespaces, opts)
18
18
  @namespaces = {}
@@ -25,7 +25,7 @@ class FnordMetric::App < Sinatra::Base
25
25
  end
26
26
  super(nil)
27
27
  end
28
-
28
+
29
29
  helpers do
30
30
  include Rack::Utils
31
31
  alias_method :h, :escape_html
@@ -38,7 +38,7 @@ class FnordMetric::App < Sinatra::Base
38
38
  @namespaces
39
39
  end
40
40
 
41
- def current_namespace
41
+ def current_namespace
42
42
  @namespaces[@namespaces.keys.detect{ |k|
43
43
  k.to_s == params[:namespace]
44
44
  }.try(:intern)]
@@ -47,7 +47,7 @@ class FnordMetric::App < Sinatra::Base
47
47
  end
48
48
 
49
49
  if ENV['RACK_ENV'] == "test"
50
- set :raise_errors, true
50
+ set :raise_errors, true
51
51
  end
52
52
 
53
53
  get '/' do
@@ -78,7 +78,7 @@ class FnordMetric::App < Sinatra::Base
78
78
  params[:sum] ? { :sum => _values.values.compact.map(&:to_i).sum } : _values
79
79
  else
80
80
  { (_t = gauge.tick_at(Time.now.to_i-gauge.tick)) => gauge.value_at(_t) }
81
- end
81
+ end
82
82
 
83
83
  data.to_json
84
84
  end
@@ -88,14 +88,14 @@ class FnordMetric::App < Sinatra::Base
88
88
  sessions = current_namespace.sessions(:all, :limit => 100).map do |session|
89
89
  session.fetch_data!
90
90
  session.to_json
91
- end
91
+ end
92
92
 
93
93
  { :sessions => sessions }.to_json
94
94
  end
95
95
 
96
96
  get '/:namespace/events' do
97
97
 
98
- events = if params[:type]
98
+ events = if params[:type]
99
99
  current_namespace.events(:by_type, :type => params[:type])
100
100
  elsif params[:session_key]
101
101
  current_namespace.events(:by_session_key, :session_key => params[:session_key])
@@ -122,7 +122,7 @@ class FnordMetric::App < Sinatra::Base
122
122
  end
123
123
 
124
124
  post '/events' do
125
- halt 400, 'please specify the event_type (_type)' unless params["_type"]
125
+ halt 400, 'please specify the event_type (_type)' unless params["_type"]
126
126
  track_event((8**32).to_s(36), parse_params(params))
127
127
  end
128
128
 
@@ -130,7 +130,7 @@ private
130
130
 
131
131
  def parse_params(hash)
132
132
  hash.tap do |h|
133
- h.keys.each{ |k| h[k] = parse_param(h[k]) }
133
+ h.keys.each{ |k| h[k] = parse_param(h[k]) }
134
134
  end
135
135
  end
136
136
 
@@ -1,6 +1,4 @@
1
- require 'securerandom'
2
1
  class FnordMetric::InboundStream < EventMachine::Connection
3
-
4
2
  @@opts = nil
5
3
 
6
4
  def self.start(opts)
@@ -13,18 +11,6 @@ class FnordMetric::InboundStream < EventMachine::Connection
13
11
  EM.defer{ next_event }
14
12
  end
15
13
 
16
- def push_event(event_id, event_data)
17
- prefix = @@opts[:redis_prefix]
18
-
19
- @redis.hincrby "#{prefix}-stats", "events_received", 1
20
- @redis.set "#{prefix}-event-#{event_id}", event_data
21
- @redis.lpush "#{prefix}-queue", event_id
22
- @redis.expire "#{prefix}-event-#{event_id}", @@opts[:event_queue_ttl]
23
-
24
- @events_buffered -= 1
25
- close_connection?
26
- end
27
-
28
14
  def next_event
29
15
  read_next_event
30
16
  push_next_event
@@ -39,20 +25,18 @@ class FnordMetric::InboundStream < EventMachine::Connection
39
25
 
40
26
  def push_next_event
41
27
  return true if @events.empty?
42
- push_event(get_next_uuid, @events.pop)
28
+ @events_buffered -= 1
29
+ @api.event(@events.pop)
30
+ close_connection?
43
31
  EM.next_tick(&method(:push_next_event))
44
32
  end
45
33
 
46
- def get_next_uuid
47
- SecureRandom.uuid
48
- end
49
-
50
34
  def close_connection?
51
- @redis.quit unless @streaming || (@events_buffered!=0)
35
+ @api.disconnect unless @streaming || (@events_buffered!=0)
52
36
  end
53
37
 
54
38
  def post_init
55
- @redis = Redis.connect(:url => @@opts[:redis_url])
39
+ @api = FnordMetric::API.new(@@opts)
56
40
  @events_buffered = 0
57
41
  @streaming = true
58
42
  @buffer = ""
@@ -63,5 +47,4 @@ class FnordMetric::InboundStream < EventMachine::Connection
63
47
  @streaming = false
64
48
  close_connection?
65
49
  end
66
-
67
50
  end
data/pub/fnordmetric.css CHANGED
@@ -4,7 +4,7 @@ body{ background:#3b3e45; color:#333; margin:0; padding:0; overflow-y:scroll; fo
4
4
  .shown{ display: block; }
5
5
  .hidden{ display: none; }
6
6
 
7
- .topbar{ height:38px; background:#24272c; position:fixed; top:0px; width:100%;}
7
+ .topbar{ height:38px; background:#24272c; position:fixed; top:0px; width:100%; z-index: 1}
8
8
  .topbar ul { list-style-type:none; margin:0; }
9
9
  .topbar ul li { padding: 5px 10px 5px 10px; background-color:#3b3e45; display:inline; height:38px; line-height:38px; border-radius:3px; margin-right:5px;}
10
10
  .topbar ul li a { color:#ccc; font-size:13px; text-decoration:none; }
@@ -122,7 +122,7 @@ ul.session_list li .history:hover{ color:#333; text-decoration:underline; }
122
122
  .sessions_feed ul.feed_inner li .message{ font-size:12px; line-height:19px; padding-top:9px; display:block; }
123
123
  .sessions_feed ul.feed_inner li .properties{ margin-left:50px; font-size:10px; display:block; color:#555; }
124
124
  .sessions_feed ul.feed_inner li .time{ font-size:10px; line-height:20px; padding-top:19px; padding-right:10px; display:block; color:#999; float:right; font-style:italic; }
125
- .sessions_feed ul.feed_inner li .picture{ height:40px; overflow:hidden; width:40px; float:left; background:#333; margin:7px 10px 0 0; }
125
+ .sessions_feed ul.feed_inner li .picture{ height:40px; overflow:hidden; width:40px; float:left; background:#333; margin:7px 10px 0 0; cursor:pointer; }
126
126
  .sessions_sidebar{ min-height:1200px; float:right; width:250px; border-left:1px solid #C7C9CC; }
127
127
  .events_sidebar{ min-height:1200px; float:left; width:200px; border-right:1px solid #C7C9CC; }
128
128
 
data/pub/fnordmetric.js CHANGED
@@ -959,8 +959,6 @@ var FnordMetric = (function(){
959
959
 
960
960
  listElem.append(
961
961
  $('<li class="session"></li>').append(
962
- $('<input type="checkbox" />').click(function(){ updateEventFilter(); })
963
- ).append(
964
962
  $('<div class="picture"></div>').html(session_picture)
965
963
  ).append(
966
964
  $('<span class="name"></span>').html(session_name)
@@ -969,9 +967,9 @@ var FnordMetric = (function(){
969
967
  ).append(
970
968
  $('<span class="history"></span>').html('history')
971
969
  .click(function(){
972
- setCheckboxesCheckedState(true, false);
973
- $('input', $(this).parent()).attr('checked', true);
974
- updateEventFilter(); loadEventHistory({session_key: session_data["session_key"]});
970
+ setCheckboxesCheckedState(true, false);
971
+ updateEventFilter();
972
+ loadEventHistory({session_key: session_data["session_key"]});
975
973
  })
976
974
  ).attr('data-session', session_data["session_key"])
977
975
  );
@@ -1002,16 +1000,22 @@ var FnordMetric = (function(){
1002
1000
  event_time.html(formatTimeOfDay(event_data._time));
1003
1001
 
1004
1002
  if(event_data._session_key && event_data._session_key.length > 0){
1003
+ var __session_key = event_data._session_key;
1004
+ var load_usersession = (function(){
1005
+ loadEventHistory({session_key: __session_key});
1006
+ });
1005
1007
  if(session_data=sessionData[event_data._session_key]){
1006
1008
  if(session_data._name){
1007
1009
  event_props.append(
1008
- $('<strong></strong>').html(session_data._name)
1010
+ $('<strong></strong>').html(session_data._name).css({
1011
+ 'cursor': 'pointer'
1012
+ }).click(load_usersession)
1009
1013
  );
1010
1014
  }
1011
1015
  if(session_data._picture){
1012
1016
  event_picture.append(
1013
1017
  $('<img width="40" />').attr('src', session_data._picture)
1014
- )
1018
+ ).click(load_usersession);
1015
1019
  }
1016
1020
  }
1017
1021
  }
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 = 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 = 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 = Event.find(event_id, @opts)
45
+ event.type.should == "Fn0rd234"
46
+ end
47
+
48
+ end
49
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: fnordmetric
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.6.1
5
+ version: 0.6.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Paul Asmuth
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-01-12 00:00:00 +01:00
13
+ date: 2012-01-13 00:00:00 +01:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -234,6 +234,7 @@ files:
234
234
  - haml/app.haml
235
235
  - haml/widget.haml
236
236
  - lib/fnordmetric.rb
237
+ - lib/fnordmetric/api.rb
237
238
  - lib/fnordmetric/app.rb
238
239
  - lib/fnordmetric/average_metric.rb
239
240
  - lib/fnordmetric/bars_widget.rb
@@ -268,6 +269,7 @@ files:
268
269
  - pub/sprite.png
269
270
  - pub/vendor/highcharts.js
270
271
  - pub/vendor/jquery-1.6.1.min.js
272
+ - spec/api_spec.rb
271
273
  - spec/app_spec.rb
272
274
  - spec/context_spec.rb
273
275
  - spec/dashboard_spec.rb
@@ -303,11 +305,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
303
305
  requirements: []
304
306
 
305
307
  rubyforge_project:
306
- rubygems_version: 1.5.2
308
+ rubygems_version: 1.6.2
307
309
  signing_key:
308
310
  specification_version: 3
309
311
  summary: FnordMetric is a Ruby Event-Tracking gem on steroids
310
312
  test_files:
313
+ - spec/api_spec.rb
311
314
  - spec/app_spec.rb
312
315
  - spec/context_spec.rb
313
316
  - spec/dashboard_spec.rb