johnf-fnordmetric 1.2.7

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 (119) hide show
  1. data/Gemfile +6 -0
  2. data/Rakefile +9 -0
  3. data/fnordmetric.gemspec +41 -0
  4. data/lib/fnordmetric/acceptors/acceptor.rb +42 -0
  5. data/lib/fnordmetric/acceptors/amqp_acceptor.rb +56 -0
  6. data/lib/fnordmetric/acceptors/fyrehose_acceptor.rb +43 -0
  7. data/lib/fnordmetric/acceptors/stomp_acceptor.rb +71 -0
  8. data/lib/fnordmetric/acceptors/tcp_acceptor.rb +58 -0
  9. data/lib/fnordmetric/acceptors/udp_acceptor.rb +37 -0
  10. data/lib/fnordmetric/api.rb +46 -0
  11. data/lib/fnordmetric/cache.rb +20 -0
  12. data/lib/fnordmetric/context.rb +96 -0
  13. data/lib/fnordmetric/defaults.rb +22 -0
  14. data/lib/fnordmetric/enterprise/compatibility_handler.rb +42 -0
  15. data/lib/fnordmetric/ext.rb +75 -0
  16. data/lib/fnordmetric/gauge.rb +98 -0
  17. data/lib/fnordmetric/gauge_calculations.rb +106 -0
  18. data/lib/fnordmetric/gauge_modifiers.rb +144 -0
  19. data/lib/fnordmetric/gauge_rendering.rb +40 -0
  20. data/lib/fnordmetric/gauge_validations.rb +15 -0
  21. data/lib/fnordmetric/gauges/distribution_gauge.rb +87 -0
  22. data/lib/fnordmetric/gauges/server_health_gauge.rb +13 -0
  23. data/lib/fnordmetric/gauges/timeseries_gauge.rb +138 -0
  24. data/lib/fnordmetric/gauges/toplist_gauge.rb +44 -0
  25. data/lib/fnordmetric/histogram.rb +64 -0
  26. data/lib/fnordmetric/logger.rb +63 -0
  27. data/lib/fnordmetric/namespace.rb +208 -0
  28. data/lib/fnordmetric/session.rb +139 -0
  29. data/lib/fnordmetric/standalone.rb +20 -0
  30. data/lib/fnordmetric/timeseries.rb +79 -0
  31. data/lib/fnordmetric/toplist.rb +61 -0
  32. data/lib/fnordmetric/udp_client.rb +22 -0
  33. data/lib/fnordmetric/util.rb +25 -0
  34. data/lib/fnordmetric/version.rb +3 -0
  35. data/lib/fnordmetric/web/app.rb +63 -0
  36. data/lib/fnordmetric/web/app_helpers.rb +42 -0
  37. data/lib/fnordmetric/web/dashboard.rb +40 -0
  38. data/lib/fnordmetric/web/event.rb +99 -0
  39. data/lib/fnordmetric/web/reactor.rb +127 -0
  40. data/lib/fnordmetric/web/web.rb +59 -0
  41. data/lib/fnordmetric/web/websocket.rb +41 -0
  42. data/lib/fnordmetric/widget.rb +82 -0
  43. data/lib/fnordmetric/widgets/bars_widget.rb +44 -0
  44. data/lib/fnordmetric/widgets/html_widget.rb +28 -0
  45. data/lib/fnordmetric/widgets/numbers_widget.rb +80 -0
  46. data/lib/fnordmetric/widgets/pie_widget.rb +23 -0
  47. data/lib/fnordmetric/widgets/timeseries_widget.rb +65 -0
  48. data/lib/fnordmetric/widgets/toplist_widget.rb +68 -0
  49. data/lib/fnordmetric/worker.rb +89 -0
  50. data/lib/fnordmetric/zero_config_gauge.rb +138 -0
  51. data/lib/fnordmetric.rb +149 -0
  52. data/run_specs.sh +11 -0
  53. data/spec/api_spec.rb +49 -0
  54. data/spec/context_spec.rb +42 -0
  55. data/spec/dashboard_spec.rb +38 -0
  56. data/spec/event_spec.rb +170 -0
  57. data/spec/ext_spec.rb +14 -0
  58. data/spec/fnordmetric_spec.rb +56 -0
  59. data/spec/gauge_like_shared.rb +56 -0
  60. data/spec/gauge_modifiers_spec.rb +583 -0
  61. data/spec/gauge_spec.rb +230 -0
  62. data/spec/namespace_spec.rb +114 -0
  63. data/spec/session_spec.rb +231 -0
  64. data/spec/spec_helper.rb +49 -0
  65. data/spec/tcp_acceptor_spec.rb +35 -0
  66. data/spec/timeseries_gauge_spec.rb +56 -0
  67. data/spec/udp_acceptor_spec.rb +35 -0
  68. data/spec/util_spec.rb +46 -0
  69. data/spec/widget_spec.rb +113 -0
  70. data/spec/worker_spec.rb +40 -0
  71. data/web/.gitignore +4 -0
  72. data/web/build.sh +34 -0
  73. data/web/css/fnordmetric.core.css +868 -0
  74. data/web/fnordmetric-core.css +1409 -0
  75. data/web/fnordmetric-core.js +3420 -0
  76. data/web/fnordmetric-ui.css +282 -0
  77. data/web/fnordmetric-ui.js +12032 -0
  78. data/web/haml/app.haml +20 -0
  79. data/web/haml/distribution_gauge.haml +118 -0
  80. data/web/haml/timeseries_gauge.haml +80 -0
  81. data/web/haml/toplist_gauge.haml +194 -0
  82. data/web/img/head.png +0 -0
  83. data/web/img/list.png +0 -0
  84. data/web/img/list_active.png +0 -0
  85. data/web/img/list_hover.png +0 -0
  86. data/web/img/loader.gif +0 -0
  87. data/web/img/loader_white.gif +0 -0
  88. data/web/img/navbar.png +0 -0
  89. data/web/img/navbar_btn.png +0 -0
  90. data/web/img/picto_gauge.png +0 -0
  91. data/web/js/fnordmetric.bars_widget.js +178 -0
  92. data/web/js/fnordmetric.dashboard_view.js +99 -0
  93. data/web/js/fnordmetric.gauge_explorer.js +173 -0
  94. data/web/js/fnordmetric.gauge_view.js +260 -0
  95. data/web/js/fnordmetric.html_widget.js +21 -0
  96. data/web/js/fnordmetric.js +315 -0
  97. data/web/js/fnordmetric.numbers_widget.js +122 -0
  98. data/web/js/fnordmetric.overview_view.js +35 -0
  99. data/web/js/fnordmetric.pie_widget.js +118 -0
  100. data/web/js/fnordmetric.realtime_timeline_widget.js +175 -0
  101. data/web/js/fnordmetric.session_view.js +342 -0
  102. data/web/js/fnordmetric.timeline_widget.js +333 -0
  103. data/web/js/fnordmetric.timeseries_widget.js +405 -0
  104. data/web/js/fnordmetric.toplist_widget.js +119 -0
  105. data/web/js/fnordmetric.ui.js +91 -0
  106. data/web/js/fnordmetric.util.js +248 -0
  107. data/web/vendor/font-awesome/css/font-awesome-ie7.min.css +22 -0
  108. data/web/vendor/font-awesome/css/font-awesome.css +540 -0
  109. data/web/vendor/font-awesome/css/font-awesome.min.css +33 -0
  110. data/web/vendor/font-awesome/font/FontAwesome.otf +0 -0
  111. data/web/vendor/font-awesome/font/fontawesome-webfont.eot +0 -0
  112. data/web/vendor/font-awesome/font/fontawesome-webfont.svg +284 -0
  113. data/web/vendor/font-awesome/font/fontawesome-webfont.ttf +0 -0
  114. data/web/vendor/font-awesome/font/fontawesome-webfont.woff +0 -0
  115. data/web/vendor/jquery-1.6.2.min.js +18 -0
  116. data/web/vendor/jquery-ui.min.js +6 -0
  117. data/web/vendor/jquery.combobox.js +129 -0
  118. data/web/vendor/jquery.maskedinput.js +252 -0
  119. metadata +444 -0
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem "rake"
6
+ gem "yajl-ruby", :git => "git://github.com/brianmario/yajl-ruby.git"
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'rspec'
2
+ require 'rspec/core/rake_task'
3
+ desc "Run all examples"
4
+ task RSpec::Core::RakeTask.new('fnordmetric-core/spec')
5
+
6
+ task :default => "spec"
7
+
8
+ require "bundler/gem_tasks"
9
+
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "date"
4
+ require "fnordmetric/version"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "johnf-fnordmetric"
8
+ s.version = FnordMetric::VERSION
9
+ s.date = Date.today.to_s
10
+ s.platform = Gem::Platform::RUBY
11
+ s.authors = ["Paul Asmuth"]
12
+ s.email = ["paul@paulasmuth.com"]
13
+ s.homepage = "http://github.com/paulasmuth/fnordmetric"
14
+ s.summary = %q{FnordMetric is a Ruby Event-Tracking gem on steroids}
15
+ s.description = %q{FnordMetric is a Ruby Event-Tracking gem on steroids}
16
+ s.licenses = ["MIT"]
17
+
18
+ s.add_dependency "sinatra", ">= 1.2.6"
19
+ s.add_dependency "redis", ">= 2.2.2"
20
+ s.add_dependency "eventmachine"
21
+ s.add_dependency "websocket-rack", "0.4.0"
22
+ s.add_dependency "em-hiredis", ">= 0.1.1"
23
+ s.add_dependency "json"
24
+ s.add_dependency "i18n"
25
+ s.add_dependency "haml"
26
+ s.add_dependency "rack"
27
+ s.add_dependency "rack-test"
28
+ s.add_dependency "yajl-ruby"
29
+ s.add_dependency "thin", ">= 1.3.0"
30
+ s.add_dependency "activesupport"
31
+
32
+ s.add_development_dependency "delorean"
33
+ s.add_development_dependency "rspec", "~> 2.8.0"
34
+ s.add_development_dependency "shoulda"
35
+
36
+ s.files = `git ls-files`.split("\n") - [".gitignore", ".rspec", ".travis.yml"]
37
+ s.files += ["web/fnordmetric-ui.js", "web/fnordmetric-ui.css", "web/fnordmetric-core.js", "web/fnordmetric-core.css"]
38
+ s.test_files = `git ls-files -- spec/*`.split("\n")
39
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
40
+ s.require_paths = ["lib"]
41
+ end
@@ -0,0 +1,42 @@
1
+ class FnordMetric::Acceptor
2
+
3
+ def initialize(opts)
4
+ @opts = opts
5
+
6
+ FnordMetric.register(self)
7
+ end
8
+
9
+ def initialized
10
+ inbound_class = if @opts[:protocol] == :udp
11
+ FnordMetric::UDPAcceptor
12
+ elsif @opts[:protocol] == :tcp
13
+ FnordMetric::TCPAcceptor
14
+ elsif @opts[:protocol] == :fyrehose
15
+ FnordMetric::FyrehoseAcceptor
16
+ elsif @opts[:protocol] == :amqp
17
+ FnordMetric::AMQPAcceptor
18
+ elsif @opts[:protocol] == :stomp
19
+ FnordMetric::STOMPAcceptor
20
+ else
21
+ raise "unknown protocol: #{@opts[:protocol]}"
22
+ end
23
+
24
+ @opts[:listen] = [
25
+ @opts[:host] || "0.0.0.0",
26
+ @opts[:port] || 2323
27
+ ]
28
+
29
+ begin
30
+ inbound_stream = inbound_class.start(@opts)
31
+ if inbound_class.respond_to?(:outbound?) && inbound_class.outbound?
32
+ FnordMetric.log "connected to #{@opts[:protocol]}://#{@opts[:listen][0..1].join(":")}"
33
+ else
34
+ FnordMetric.log "listening on #{@opts[:protocol]}://#{@opts[:listen][0..1].join(":")}"
35
+ end
36
+ rescue Exception => e
37
+ raise e if ENV["FNORDMETRIC_ENV"] == "dev"
38
+ FnordMetric.log "cant start #{inbound_class.name} on #{@opts[:protocol]}://#{@opts[:listen][0..1].join(":")}. port in use?"
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,56 @@
1
+ class FnordMetric::AMQPAcceptor
2
+
3
+ def self.start(opts)
4
+ begin
5
+ require "amqp"
6
+ rescue LoadError
7
+ FnordMetric.error("require 'amqp' failed, you need the amqp gem")
8
+ exit 1
9
+ end
10
+
11
+ new(opts)
12
+ end
13
+
14
+ def initialize(opts)
15
+ amqp = AMQP.connect(:host => 'firehose')
16
+ amqp_channel = AMQP::Channel.new(amqp)
17
+
18
+ msg_handler = lambda do |channel, data|
19
+ event = begin
20
+ JSON.parse(data)
21
+ rescue
22
+ FnordMetric.log("[AMQP] received invalid JSON: #{data[0..60]}")
23
+ end
24
+
25
+ if event
26
+ event["_type"] ||= channel
27
+ events << event
28
+ push_next_event
29
+ end
30
+ end
31
+
32
+ opts[:channels].each do |channel|
33
+ queue = amqp_channel.queue(channel, :auto_delete => true)
34
+ queue.subscribe{ |data| msg_handler[channel, data] }
35
+ end
36
+ end
37
+
38
+ def push_next_event
39
+ return true if events.empty?
40
+ api.event(@events.pop)
41
+ EM.next_tick(&method(:push_next_event))
42
+ end
43
+
44
+ def events
45
+ @events ||= []
46
+ end
47
+
48
+ def api
49
+ @api ||= FnordMetric::API.new(FnordMetric.options)
50
+ end
51
+
52
+ def self.outbound?
53
+ true
54
+ end
55
+
56
+ end
@@ -0,0 +1,43 @@
1
+ class FnordMetric::FyrehoseAcceptor
2
+
3
+ def self.start(opts)
4
+ require "fyrehose"
5
+ require "fyrehose/reactor"
6
+
7
+ new(opts)
8
+ end
9
+
10
+ def initialize(opts)
11
+ reactor = EM.connect(opts[:host], opts[:port], Fyrehose::Reactor)
12
+
13
+ reactor.on_message do |channel, data|
14
+ event = JSON.parse(data)
15
+ event["_type"] ||= channel
16
+ events << event
17
+ push_next_event
18
+ end
19
+
20
+ opts[:channels].each do |channel|
21
+ reactor.subscribe(channel)
22
+ end
23
+ end
24
+
25
+ def push_next_event
26
+ return true if events.empty?
27
+ api.event(@events.pop)
28
+ EM.next_tick(&method(:push_next_event))
29
+ end
30
+
31
+ def events
32
+ @events ||= []
33
+ end
34
+
35
+ def api
36
+ @api ||= FnordMetric::API.new(FnordMetric.options)
37
+ end
38
+
39
+ def self.outboud?
40
+ true
41
+ end
42
+
43
+ end
@@ -0,0 +1,71 @@
1
+ class FnordMetric::STOMPAcceptor
2
+
3
+ def self.start(opts)
4
+ begin
5
+ require "stomp"
6
+ rescue LoadError
7
+ FnordMetric.error("require 'stomp' failed, you need the stomp gem")
8
+ exit 1
9
+ end
10
+
11
+ new(opts)
12
+ end
13
+
14
+ def initialize(opts)
15
+ @mutex = Mutex.new
16
+
17
+ client = Stomp::Client.new(:hosts => [{
18
+ :host => opts[:host],
19
+ :port => opts[:port],
20
+ :passcode => opts[:password],
21
+ :login => opts[:username]}])
22
+
23
+ msg_handler = lambda do |topic, msg|
24
+ data = msg.body
25
+
26
+ event = begin
27
+ JSON.parse(data)
28
+ rescue
29
+ FnordMetric.log("[STOMP] received invalid JSON: #{data[0..60]}")
30
+ end
31
+
32
+ if event
33
+ event["_type"] ||= topic.gsub(/^\/topic\//, '')
34
+ @mutex.synchronize{ events << event }
35
+ end
36
+ end
37
+
38
+ opts[:topics].each do |topic|
39
+ client.subscribe(topic){ |data| msg_handler[topic, data] }
40
+ end
41
+
42
+ Thread.new do
43
+ client.join
44
+ end
45
+
46
+ EM.next_tick(&method(:push_next_event))
47
+ end
48
+
49
+ def push_next_event
50
+ nxt = @mutex.synchronize{ events.pop }
51
+ unless nxt
52
+ EM::Timer.new(0.01, &method(:push_next_event))
53
+ return true
54
+ end
55
+ api.event(nxt)
56
+ EM.next_tick(&method(:push_next_event))
57
+ end
58
+
59
+ def events
60
+ @events ||= []
61
+ end
62
+
63
+ def api
64
+ @api ||= FnordMetric::API.new(FnordMetric.options)
65
+ end
66
+
67
+ def self.outbound?
68
+ true
69
+ end
70
+
71
+ end
@@ -0,0 +1,58 @@
1
+ class FnordMetric::TCPAcceptor < EventMachine::Connection
2
+ @@opts = nil
3
+
4
+ def self.start(opts)
5
+ @@opts = opts
6
+ EM.start_server(*(opts[:listen] + [self]))
7
+ end
8
+
9
+ def self.options(opts)
10
+ @@opts = opts
11
+ end
12
+
13
+ def receive_data(chunk)
14
+ @buffer << chunk
15
+ next_event
16
+ end
17
+
18
+ def next_event
19
+ read_next_event
20
+ push_next_event
21
+ end
22
+
23
+ def read_next_event
24
+ while (event = @buffer.slice!(/^(.*)\n/))
25
+ @events_buffered += 1
26
+ @events << event
27
+ end
28
+ end
29
+
30
+ def push_next_event
31
+ return true if @events.empty?
32
+ @events_buffered -= 1
33
+ api.event(@events.pop)
34
+ close_connection?
35
+ EM.next_tick(&method(:push_next_event))
36
+ end
37
+
38
+ def close_connection?
39
+ #@backend.hangup unless @streaming || (@events_buffered!=0)
40
+ end
41
+
42
+ def post_init
43
+ @events_buffered = 0
44
+ @streaming = true
45
+ @buffer = ""
46
+ @events = []
47
+ end
48
+
49
+ def unbind
50
+ @streaming = false
51
+ close_connection?
52
+ end
53
+
54
+ def api
55
+ @api ||= FnordMetric::API.new(FnordMetric.options)
56
+ end
57
+
58
+ end
@@ -0,0 +1,37 @@
1
+ class FnordMetric::UDPAcceptor < EventMachine::Connection
2
+
3
+ class << self
4
+ attr_accessor :opts
5
+ end
6
+
7
+ def self.start(opts)
8
+ self.opts = opts
9
+
10
+ EM.open_datagram_socket(*(opts[:listen] << self << opts))
11
+ end
12
+
13
+ def receive_data(event)
14
+ events << event
15
+ push_next_event
16
+ end
17
+
18
+ def push_next_event
19
+ return true if events.empty?
20
+ ev = @events.pop
21
+ api.event(ev)
22
+ EM.next_tick(&method(:push_next_event))
23
+ end
24
+
25
+ def unbind
26
+ #backend.hangup
27
+ end
28
+
29
+ def events
30
+ @events ||= []
31
+ end
32
+
33
+ def api
34
+ @api ||= FnordMetric::API.new(FnordMetric.options)
35
+ end
36
+
37
+ end
@@ -0,0 +1,46 @@
1
+ class FnordMetric::API
2
+
3
+ @@opts = nil
4
+
5
+ def initialize(opts={})
6
+ @@opts = FnordMetric.default_options(opts)
7
+ connect
8
+ end
9
+
10
+ def connect
11
+ @redis = Redis.connect(:url => @@opts[:redis_url])
12
+ end
13
+
14
+ def event(event_data)
15
+ begin
16
+ if event_data.is_a?(Hash)
17
+ event_data = event_data.to_json
18
+ else
19
+ JSON.parse(event_data) # void ;)
20
+ end
21
+ rescue JSON::ParserError
22
+ FnordMetric.log("event_lost: can't parse json")
23
+ else
24
+ push_event(get_next_uuid, event_data)
25
+ end
26
+ end
27
+
28
+ def disconnect
29
+ @redis.quit
30
+ end
31
+
32
+ private
33
+
34
+ def push_event(event_id, event_data)
35
+ prefix = @@opts[:redis_prefix]
36
+ @redis.hincrby "#{prefix}-stats", "events_received", 1
37
+ @redis.set "#{prefix}-event-#{event_id}", event_data
38
+ @redis.lpush "#{prefix}-queue", event_id
39
+ @redis.expire "#{prefix}-event-#{event_id}", @@opts[:event_queue_ttl]
40
+ event_id
41
+ end
42
+
43
+ def get_next_uuid
44
+ rand(8**32).to_s(36)
45
+ end
46
+ end
@@ -0,0 +1,20 @@
1
+ class FnordMetric::Cache
2
+ # include Mongoid::Document
3
+
4
+ # self.collection_name = 'fnordmetric_cache'
5
+
6
+ # field :cache_key, :type => String
7
+ # field :data, :type => Hash
8
+
9
+ def self.store!(cache_key, data)
10
+ data = { :value => data } unless data.is_a?(Hash)
11
+ self.create(:cache_key => cache_key, :data => data)
12
+ end
13
+
14
+ def self.get(cache_key)
15
+ item = self.where(:cache_key => cache_key).last
16
+ return nil unless item
17
+ item.data.keys == ["value"] ? item.data["value"] : item.data
18
+ end
19
+
20
+ end
@@ -0,0 +1,96 @@
1
+ class FnordMetric::Context
2
+
3
+ include FnordMetric::GaugeModifiers
4
+
5
+ class Proxy
6
+
7
+ def initialize(_ref)
8
+ @ref = _ref
9
+ end
10
+
11
+ def method_missing(method, *args, &block)
12
+ @ref.dispatch(method, *args, &block)
13
+ end
14
+
15
+ end
16
+
17
+ def initialize(opts, block)
18
+ @block = block
19
+ @opts = opts
20
+ end
21
+
22
+ def call(event, redis, namespace)
23
+ @redis = redis
24
+ @event = event
25
+ @namespace = namespace
26
+ proxy.instance_eval(&@block)
27
+ rescue Exception => e
28
+ raise e if ENV['FNORDMETRIC_ENV'] == 'test'
29
+ puts "error: #{e.message}"
30
+ puts e.backtrace.push("").join("\n") if ENV['FNORDMETRIC_ENV'] == 'dev'
31
+ end
32
+
33
+ def proxy
34
+ @proxy ||= Proxy.new(self)
35
+ end
36
+
37
+ def namespace
38
+ @namespace
39
+ end
40
+
41
+ def dispatch(method, *args, &block)
42
+ if args.size > 0 && gauges[args[0]].try(:renderable?)
43
+ gauges[args.delete_at(0)].execute(method, *args.unshift(self), &block)
44
+ else
45
+ send(method, *args, &block)
46
+ end
47
+ rescue Exception => e
48
+ raise e if ENV['FNORDMETRIC_ENV'] == 'test'
49
+ puts "error: #{e.message}"
50
+ puts e.backtrace.push("\n").join("\n") if ENV['FNORDMETRIC_ENV'] == 'dev'
51
+ end
52
+
53
+ def redis_exec(*args)
54
+ @redis.send(*args)
55
+ end
56
+
57
+ private
58
+
59
+ def session_key
60
+ @event[:_session_key]
61
+ end
62
+
63
+ def data
64
+ @event
65
+ end
66
+
67
+ def key(gauge)
68
+ fetch_gauge(gauge).key
69
+ end
70
+
71
+ def time
72
+ @event[:_time].to_i
73
+ end
74
+
75
+ def type
76
+ @event[:_type].to_sym
77
+ end
78
+
79
+ def gauges
80
+ @namespace.gauges
81
+ end
82
+
83
+ protected
84
+
85
+ def fetch_gauge(_gauge)
86
+ _gauge.is_a?(FnordMetric::Gauge) ? _gauge : gauges.fetch(_gauge)
87
+ rescue
88
+ error! "error: gauge '#{_gauge}' is undefined"
89
+ end
90
+
91
+ def error!(msg)
92
+ FnordMetric.error(msg)
93
+ end
94
+
95
+
96
+ end
@@ -0,0 +1,22 @@
1
+ FnordMetric::COLORS = ["#4572a7", "#aa4643", "#89a54e", "#80699b", "#3d96ae", "#db843d"].reverse
2
+
3
+ FnordMetric::DEFAULT_PROC = lambda{ |arg| }
4
+
5
+ FnordMetric::TICKS = lambda{ |tick, span| [tick, 60, 300, 1200, 3600, 86400]
6
+ .select{ |t| (t >= tick) && ((span/t) > 5) }
7
+ .uniq }
8
+
9
+ FnordMetric::DEFAULT_OPTIONS = {
10
+ :redis_url => "redis://localhost:6379",
11
+ :redis_prefix => "fnordmetric",
12
+ :inbound_stream => nil,
13
+ :inbound_protocol => nil,
14
+ :web_interface => ["0.0.0.0", "4242"],
15
+ :web_interface_server => "thin",
16
+ :start_worker => true,
17
+ :print_stats => 3,
18
+ :event_queue_ttl => 120,
19
+ :event_data_ttl => 3600*24*30,
20
+ :session_data_ttl => 3600*24*30,
21
+ :default_flush_interval => 10
22
+ }
@@ -0,0 +1,42 @@
1
+ module FnordMetric::Enterprise
2
+
3
+ CompatibilityHandler = proc do
4
+ if data[:_cmd]
5
+ cmd = data[:_cmd].to_s
6
+ else
7
+ FnordMetric.error("missing key: _cmd")
8
+ next
9
+ end
10
+
11
+ if m = cmd.match(/^SAMPLE (.*)(delta|mean|sum)-([0-9]+) ([0-9]+)$/)
12
+ gauge_type = m[2].to_sym
13
+ gauge_tick = m[3].to_i
14
+ gauge_key = :"#{m[1]}#{gauge_type}-#{gauge_tick}"
15
+ op_value = m[4].to_i
16
+ else
17
+ FnordMetric.error("invalid _cmd")
18
+ next
19
+ end
20
+
21
+ gauge = if namespace.gauges.has_key?(gauge_key)
22
+ namespace.gauges[gauge_key]
23
+ else
24
+ namespace.opt_gauge(gauge_key,
25
+ :flush_interval => gauge_tick,
26
+ :average => (gauge_type == :mean),
27
+ :zero_config => true)
28
+ end
29
+
30
+ case gauge_type
31
+
32
+ when :delta, :sum
33
+ incr gauge, op_value
34
+
35
+ when :mean
36
+ incr_avg gauge, op_value
37
+
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,75 @@
1
+ module Enumerable
2
+
3
+ def each_with_log(total = nil, &block)
4
+ log_every = ((total ||= self.count) / 150)
5
+ self.each_with_index do |item, index|
6
+ if index % log_every == 0
7
+ STDOUT.puts "#{index}/#{total} (#{((index/total.to_f)*100).to_i}%)"
8
+ end
9
+ block.call(item, index)
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+ module Haml::Filters::Gaugejs
16
+ include Haml::Filters::Base
17
+
18
+ def render(text)
19
+ "<FNORDMETRIC-GAUGEJS>#{text}</FNORDMETRIC-GAUGEJS>"
20
+ end
21
+ end
22
+
23
+ class Symbol
24
+ alias :intern :to_sym
25
+ end
26
+
27
+ class Range
28
+
29
+ def size
30
+ self.last - self.first
31
+ end
32
+
33
+ end
34
+
35
+ class Array
36
+
37
+ def mean
38
+ return 0 if empty?
39
+ inject(&:+).to_f / size
40
+ end
41
+
42
+ alias :average :mean
43
+
44
+ def median
45
+ return 0 if empty?
46
+ (_sorted = self.dup.sort)[_sorted.size/2]
47
+ end
48
+
49
+ def range
50
+ return 0 if empty?
51
+ max - min
52
+ end
53
+
54
+ def mode
55
+ return 0 if empty?
56
+ inject({}){ |h,v| h[v] = h[v].to_i+1; h }.to_a
57
+ .sort{ |a,b| b.last <=> a.last }[0][0]
58
+ end
59
+
60
+ def emtpy
61
+ self.size == 0
62
+ end
63
+
64
+ end
65
+
66
+ class Thin::Connection
67
+
68
+ alias :pre_process_orig :pre_process
69
+
70
+ def pre_process
71
+ @request.env['async.connection'] = self
72
+ pre_process_orig
73
+ end
74
+
75
+ end