slate 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.sw*
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - jruby-18mode # JRuby in 1.8 mode
5
+ - jruby-19mode # JRuby in 1.9 mode
6
+ - rbx-18mode
7
+ - rbx-19mode
8
+ - 1.8.7
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in graphite.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Trae Robrock
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # Slate
2
+ [![Build Status](https://secure.travis-ci.org/trobrock/slate.png)](http://travis-ci.org/trobrock/slate)
3
+
4
+ Simple wrapper to the Graphite render api
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'slate'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install slate
19
+
20
+ ## Usage
21
+
22
+ TODO: Write usage instructions here
23
+
24
+ ## Contributing
25
+
26
+ 1. Fork it
27
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
28
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
29
+ 4. Push to the branch (`git push origin my-new-feature`)
30
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/lib/slate.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "slate/version"
2
+ require "slate/configuration"
3
+ require "slate/render"
4
+ require "slate/calculation"
5
+
6
+ require "slate/calculation/mean"
7
+
8
+ module Slate
9
+ def self.configure
10
+ yield Configuration.instance
11
+ end
12
+
13
+ def self.configuration
14
+ Configuration.instance
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ require 'json'
2
+
3
+ module Slate
4
+ module Calculation
5
+ class Base
6
+ def initialize(graph)
7
+ @graph = graph
8
+ end
9
+
10
+ def result
11
+ nil # Override this
12
+ end
13
+
14
+ protected
15
+
16
+ def data
17
+ @data ||= JSON.parse(@graph.download(:json)).first["datapoints"].map(&:first).compact
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ module Slate
2
+ module Calculation
3
+ class Mean < Base
4
+ def result
5
+ data.inject(0.0, :+) / data.size.to_f
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'singleton'
2
+
3
+ module Slate
4
+ class Configuration
5
+ include Singleton
6
+
7
+ attr_accessor :endpoint
8
+ end
9
+ end
@@ -0,0 +1,77 @@
1
+ require 'cgi'
2
+ require 'rest_client'
3
+
4
+ module Slate
5
+ class Render
6
+ def initialize(options={})
7
+ @target = options[:target]
8
+ @from = options[:from]
9
+ @until = options[:until]
10
+ @functions = []
11
+ end
12
+
13
+ def url(format=:png)
14
+ options = url_options.merge("format" => format.to_s)
15
+ "#{Configuration.instance.endpoint}/render?#{params(options)}"
16
+ end
17
+
18
+ def download(format=:png)
19
+ RestClient.get url(format)
20
+ end
21
+
22
+ def add_function(*function)
23
+ if function.size > 1
24
+ arguments = function[1..-1]
25
+ @functions << [function.first.to_sym, arguments]
26
+ else
27
+ @functions << function.first.to_sym
28
+ end
29
+
30
+ target
31
+ end
32
+
33
+ def target
34
+ target = @target
35
+ @functions.each do |function|
36
+ if function.is_a? Symbol
37
+ target = %Q{#{function}(#{target})}
38
+ else
39
+ args = arguments(function.last).join(",")
40
+ target = %Q{#{function.first}(#{target},#{args})}
41
+ end
42
+ end
43
+
44
+ target
45
+ end
46
+
47
+ private
48
+
49
+ def arguments(args=[])
50
+ args.map do |arg|
51
+ if arg.is_a?(Numeric)
52
+ arg.to_s
53
+ elsif arg.is_a?(Slate::Render)
54
+ arg.send(:target)
55
+ else
56
+ %Q{"#{arg}"}
57
+ end
58
+ end
59
+ end
60
+
61
+ def url_options
62
+ options = {
63
+ "target" => target
64
+ }
65
+ options["from"] = @from if @from
66
+ options["until"] = @until if @until
67
+
68
+ options
69
+ end
70
+
71
+ def params(options={})
72
+ options.map do |key,value|
73
+ "#{CGI.escape(key)}=#{CGI.escape(value)}"
74
+ end.join("&")
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,3 @@
1
+ module Slate
2
+ VERSION = "0.0.1"
3
+ end
data/script.rb ADDED
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'slate'
6
+
7
+ WINDOW = ARGV[0] || "-1w"
8
+
9
+ def log(title, value)
10
+ format = "[%17s] %01.2f\n"
11
+ printf format, title, value
12
+ end
13
+
14
+ Slate.configure do |c|
15
+ c.endpoint = "http://statsd.outright.com"
16
+ end
17
+
18
+ graph = Slate::Render.new(target: "stats.timers.rack.*.response_time.upper_90", from: WINDOW)
19
+ graph.add_function :avg
20
+ graph.add_function :summarize, "1h", "avg"
21
+
22
+ app_response_time = Slate::Calculation::Mean.new(graph).result
23
+
24
+ graph = Slate::Render.new(target: "stats.rack.*.status_code.success", from: WINDOW)
25
+ graph.add_function :sum
26
+
27
+ total_graph = Slate::Render.new(target: "stats.rack.*.status_code.*", from: WINDOW)
28
+ total_graph.add_function :exclude, "missing"
29
+ total_graph.add_function :sum
30
+
31
+ graph.add_function :asPercent, total_graph
32
+
33
+ app_success_rate = Slate::Calculation::Mean.new(graph).result
34
+
35
+
36
+
37
+ graph = Slate::Render.new(target: "stats.timers.agg.thrift.*.response_time.upper_90", from: WINDOW)
38
+ graph.add_function :avg
39
+ graph.add_function :summarize, "1h", "avg"
40
+
41
+ agg_response_time = Slate::Calculation::Mean.new(graph).result
42
+
43
+
44
+ graph = Slate::Render.new(target: "stats.agg.thrift.*.status_code.success", from: WINDOW)
45
+ graph.add_function :sum
46
+
47
+ total_graph = Slate::Render.new(target: "stats.agg.thrift.*.status_code.*", from: WINDOW)
48
+ total_graph.add_function :exclude, "missing"
49
+ total_graph.add_function :sum
50
+
51
+ graph.add_function :asPercent, total_graph
52
+
53
+ agg_success_rate = Slate::Calculation::Mean.new(graph).result
54
+
55
+ log "App Response Time", app_response_time
56
+ log "App Success Rate" , app_success_rate
57
+ log "App Uptime" , 0
58
+ print "\n"
59
+ log "Agg Response Time", agg_response_time
60
+ log "Agg Success Rate" , agg_success_rate
61
+ log "Agg Uptime" , 0
data/slate.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'slate/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "slate"
8
+ gem.version = Slate::VERSION
9
+ gem.authors = ["Trae Robrock"]
10
+ gem.email = ["trobrock@gmail.com"]
11
+ gem.description = %q{Simple api on top of the graphite render api}
12
+ gem.summary = %q{Simple wrapper on top of the graphite render api}
13
+ gem.homepage = "https://github.com/trobrock/slate"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "rest-client", "~> 1.6.7"
21
+ gem.add_dependency "json", "~> 1.7.5"
22
+ gem.add_dependency "jruby-openssl" if RUBY_PLATFORM == 'java'
23
+
24
+ gem.add_development_dependency "rake"
25
+ gem.add_development_dependency "rspec"
26
+ gem.add_development_dependency "mocha"
27
+ gem.add_development_dependency "webmock"
28
+ end
@@ -0,0 +1,24 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
+
3
+ describe Slate::Calculation::Mean do
4
+ before do
5
+ @graph = Slate::Render.new(:target => "some.stat")
6
+ data = [
7
+ {
8
+ "target" => "some.stat",
9
+ "datapoints" => [
10
+ [1.0, 1352143990],
11
+ [0.0, 1352144000],
12
+ [2.0, 1352145000],
13
+ [3.0, 1352146000]
14
+ ]
15
+ }
16
+ ]
17
+ @graph.stubs(:download).with(:json).returns(JSON.generate(data))
18
+ end
19
+
20
+ it "should calculate the mean of the series" do
21
+ calculation = Slate::Calculation::Mean.new(@graph)
22
+ calculation.result.should == 1.5
23
+ end
24
+ end
@@ -0,0 +1,89 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper')
2
+
3
+ describe Slate::Render do
4
+ before(:each) do
5
+ Slate.configure { |c| c.endpoint = "http://graphite" }
6
+
7
+ @png_stub = "PNG Image Data"
8
+ @raw_stub = "RAW Image Data"
9
+ @csv_stub = "CSV,Image,Data"
10
+ @json_stub = "{ \"JSON\": \"Image Data\" }"
11
+ @svg_stub = "SVG Image Data"
12
+
13
+ stub_download :png , @png_stub
14
+ stub_download :raw , @raw_stub
15
+ stub_download :csv , @csv_stub
16
+ stub_download :json, @json_stub
17
+ stub_download :svg , @svg_stub
18
+ end
19
+
20
+ it "should be able to get a single target" do
21
+ graph = Slate::Render.new(:target => "app.server01.load")
22
+ query(graph.url).should include("target" => "app.server01.load", "format" => "png")
23
+ end
24
+
25
+ it "should be able to apply functions" do
26
+ graph = Slate::Render.new(:target => "app.server01.load")
27
+ graph.add_function :cumulative
28
+ graph.url.should include(CGI.escape("cumulative(app.server01.load)"))
29
+
30
+ graph = Slate::Render.new(:target => "app.server01.load")
31
+ graph.add_function :cumulative
32
+ graph.add_function :alias, "load"
33
+ graph.url.should include(CGI.escape("alias(cumulative(app.server01.load),\"load\""))
34
+
35
+ graph = Slate::Render.new(:target => "app.server01.load")
36
+ graph.add_function :summarize, "1s", "sum"
37
+ graph.url.should include(CGI.escape("summarize(app.server01.load,\"1s\",\"sum\")"))
38
+
39
+ graph = Slate::Render.new(:target => "app.server01.load")
40
+ graph.add_function :movingAverage, 10
41
+ graph.url.should include(CGI.escape("movingAverage(app.server01.load,10)"))
42
+ end
43
+
44
+ it "should be able to accept other graphs as options to a function" do
45
+ graph = Slate::Render.new(:target => "app.server01.load")
46
+
47
+ other_graph = Slate::Render.new(:target => "app.server*.load")
48
+ other_graph.add_function :sum
49
+
50
+ graph.add_function :asPercent, other_graph
51
+
52
+ graph.url.should include(CGI.escape("asPercent(app.server01.load,sum(app.server*.load))"))
53
+ end
54
+
55
+ it "should be able to specify start and end times" do
56
+ graph = Slate::Render.new(:target => "app.server01.load", :from => "-1d")
57
+ graph.url.should match(/from=-1d/)
58
+
59
+ graph = Slate::Render.new(:target => "app.server01.load", :until => "-1d")
60
+ graph.url.should match(/until=-1d/)
61
+
62
+ graph = Slate::Render.new(:target => "app.server01.load", :from => "-1d", :until => "-6h")
63
+ graph.url.should match(/from=-1d/)
64
+ graph.url.should match(/until=-6h/)
65
+ end
66
+
67
+ it "should provide methods for retrieving formats" do
68
+ graph = Slate::Render.new(:target => "app.server01.load")
69
+ graph.url(:png).should match(/format=png/)
70
+ graph.url(:raw).should match(/format=raw/)
71
+ graph.url(:csv).should match(/format=csv/)
72
+ graph.url(:json).should match(/format=json/)
73
+ graph.url(:svg).should match(/format=svg/)
74
+ end
75
+
76
+ it "should retrieve the graph" do
77
+ graph = Slate::Render.new(:target => "app.server01.load")
78
+ graph.download(:png).should eq(@png_stub)
79
+ graph.download(:raw).should eq(@raw_stub)
80
+ graph.download(:csv).should eq(@csv_stub)
81
+ graph.download(:json).should eq(@json_stub)
82
+ graph.download(:svg).should eq(@svg_stub)
83
+ end
84
+ end
85
+
86
+ def stub_download(format, body="")
87
+ stub_request(:get, "http://graphite/render?format=#{format}&target=app.server01.load").
88
+ to_return(:status => 200, :body => body, :headers => {})
89
+ end
@@ -0,0 +1,11 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Slate do
4
+ it "should be able to configure the graphite host" do
5
+ Slate.configure do |c|
6
+ c.endpoint = "http://graphite"
7
+ end
8
+
9
+ Slate.configuration.endpoint.should == "http://graphite"
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ require "slate"
2
+ require "webmock/rspec"
3
+ require "mocha_standalone"
4
+ require "uri"
5
+ require "cgi"
6
+
7
+ RSpec.configure do |config|
8
+ # Use color in STDOUT
9
+ config.color_enabled = true
10
+
11
+ # Use color not only in STDOUT but also in pagers and files
12
+ config.tty = true
13
+
14
+ # Use the specified formatter
15
+ config.formatter = :documentation # :progress, :html, :textmate
16
+
17
+ config.mock_framework = :mocha
18
+ end
19
+
20
+ def query(url)
21
+ CGI.parse(URI.parse(url).query).inject({}) do |h, x|
22
+ key = x.first
23
+ val = x.last
24
+ h[key] = val.size == 1 ? val.first : val
25
+
26
+ h
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,169 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: slate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Trae Robrock
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.6.7
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 1.6.7
30
+ - !ruby/object:Gem::Dependency
31
+ name: json
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.7.5
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.7.5
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: mocha
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: webmock
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Simple api on top of the graphite render api
111
+ email:
112
+ - trobrock@gmail.com
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - .gitignore
118
+ - .travis.yml
119
+ - Gemfile
120
+ - LICENSE.txt
121
+ - README.md
122
+ - Rakefile
123
+ - lib/slate.rb
124
+ - lib/slate/calculation.rb
125
+ - lib/slate/calculation/mean.rb
126
+ - lib/slate/configuration.rb
127
+ - lib/slate/render.rb
128
+ - lib/slate/version.rb
129
+ - script.rb
130
+ - slate.gemspec
131
+ - spec/slate/calculation/mean_spec.rb
132
+ - spec/slate/render_spec.rb
133
+ - spec/slate_spec.rb
134
+ - spec/spec_helper.rb
135
+ homepage: https://github.com/trobrock/slate
136
+ licenses: []
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ none: false
143
+ requirements:
144
+ - - ! '>='
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ segments:
148
+ - 0
149
+ hash: -1369003764169049016
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ none: false
152
+ requirements:
153
+ - - ! '>='
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ segments:
157
+ - 0
158
+ hash: -1369003764169049016
159
+ requirements: []
160
+ rubyforge_project:
161
+ rubygems_version: 1.8.24
162
+ signing_key:
163
+ specification_version: 3
164
+ summary: Simple wrapper on top of the graphite render api
165
+ test_files:
166
+ - spec/slate/calculation/mean_spec.rb
167
+ - spec/slate/render_spec.rb
168
+ - spec/slate_spec.rb
169
+ - spec/spec_helper.rb