expri 0.1.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.
- data/lib/expri.rb +10 -0
- data/lib/expri/dumper.rb +52 -0
- data/lib/expri/metric.rb +91 -0
- data/lib/expri/metric_set.rb +39 -0
- metadata +81 -0
data/lib/expri.rb
ADDED
data/lib/expri/dumper.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Expri
|
2
|
+
class Dumper
|
3
|
+
def initialize(options={})
|
4
|
+
@options = options
|
5
|
+
end
|
6
|
+
|
7
|
+
def run
|
8
|
+
str = ""
|
9
|
+
str << header
|
10
|
+
metrics = Metric.list
|
11
|
+
metrics.each do |metric|
|
12
|
+
metric = Metric.new(metric, {}, @options)
|
13
|
+
metric.get
|
14
|
+
str << dump_metric(metric)
|
15
|
+
end
|
16
|
+
str << footer
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
NUMERICAL_ATTRIBUTES = %w{divisor frequency precentile window}.
|
22
|
+
map { |x| x.to_sym }.freeze
|
23
|
+
|
24
|
+
def dump_metric(metric)
|
25
|
+
attributes = metric.attributes_without_defaults.dup
|
26
|
+
|
27
|
+
type = attributes.delete(:type)
|
28
|
+
predicate = attributes.delete(:predicate)
|
29
|
+
|
30
|
+
# at bare minimum, window is required, so attributes size should always
|
31
|
+
# be > 0 even after type and predicate are removed
|
32
|
+
attributes_str = attributes.to_a.
|
33
|
+
sort_by { |a| a[0] }.
|
34
|
+
map { |a| "#{a[0]}: #{NUMERICAL_ATTRIBUTES.include?(a[0]) ? a[1] : %{"#{a[1]}"}}" }.
|
35
|
+
join(",\n ")
|
36
|
+
|
37
|
+
# predicate is important, but optional
|
38
|
+
str = %{ metric "#{metric.name}",\n}
|
39
|
+
str << %{ type: :#{type},\n}
|
40
|
+
str << %{ predicate: #{predicate},\n} if predicate
|
41
|
+
str << %{ #{attributes_str}\n\n}
|
42
|
+
end
|
43
|
+
|
44
|
+
def footer
|
45
|
+
"end"
|
46
|
+
end
|
47
|
+
|
48
|
+
def header
|
49
|
+
"Expri.metrics do\n\n"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/expri/metric.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
module Expri
|
2
|
+
class Metric
|
3
|
+
ATTRIBUTE_DEFAULTS = { :frequency => 3 }.freeze
|
4
|
+
VALID_ATTRIBUTES = %w{divisor frequency key percentile predicate predicate2
|
5
|
+
type window value}.map { |x| x.to_sym }.freeze
|
6
|
+
|
7
|
+
attr_accessor :attributes, :name, :options
|
8
|
+
|
9
|
+
def self.list(options={})
|
10
|
+
metric = Metric.new(nil, {}, {})
|
11
|
+
MultiJson.decode(metric.api.get(path: "/metrics", expects: 200).body)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(name, attributes={}, options={})
|
15
|
+
@name = name
|
16
|
+
@options = options
|
17
|
+
self.attributes = attributes
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
attributes_without_defaults == other.attributes_without_defaults
|
22
|
+
end
|
23
|
+
|
24
|
+
def api
|
25
|
+
@api ||= Excon.new(api_url)
|
26
|
+
end
|
27
|
+
|
28
|
+
def attributes=(attributes)
|
29
|
+
# symbolize keys
|
30
|
+
attributes.keys.each do |key|
|
31
|
+
attributes[(key.to_sym rescue key) || key] = attributes.delete(key)
|
32
|
+
end
|
33
|
+
|
34
|
+
attributes.delete_if { |k, v| !VALID_ATTRIBUTES.include?(k) }
|
35
|
+
attributes.delete_if { |k, v| v == nil }
|
36
|
+
|
37
|
+
# manual normalization
|
38
|
+
attributes[:type] = attributes[:type].to_sym if attributes[:type]
|
39
|
+
|
40
|
+
@attributes = attributes
|
41
|
+
end
|
42
|
+
|
43
|
+
# only the attributes that are not at their default value
|
44
|
+
def attributes_without_defaults
|
45
|
+
attributes = @attributes.dup
|
46
|
+
attributes.delete_if { |k, v| ATTRIBUTE_DEFAULTS[k] == v }
|
47
|
+
end
|
48
|
+
|
49
|
+
def destroy
|
50
|
+
puts "destroy name=#{name}" if @options[:verbose]
|
51
|
+
api.delete(path: "/metrics/#{name}", body: MultiJson.encode(@attributes),
|
52
|
+
expects: 200)
|
53
|
+
end
|
54
|
+
|
55
|
+
def get
|
56
|
+
puts "show name=#{name}" if @options[:verbose]
|
57
|
+
self.attributes =
|
58
|
+
MultiJson.decode(api.get(path: "/metrics/#{name}", expects: 200).body)
|
59
|
+
end
|
60
|
+
|
61
|
+
def post
|
62
|
+
puts "create name=#{name}" if @options[:verbose]
|
63
|
+
# exprd's put is like most api's post
|
64
|
+
api.put(path: "/metrics/#{name}", body: MultiJson.encode(@attributes),
|
65
|
+
expects: 200)
|
66
|
+
rescue Excon::Errors::BadRequest => e
|
67
|
+
message = MultiJson.decode(e.response.body)["message"]
|
68
|
+
raise(message)
|
69
|
+
end
|
70
|
+
|
71
|
+
def put
|
72
|
+
begin
|
73
|
+
existing = Metric.new(name, {}, @options)
|
74
|
+
existing.get
|
75
|
+
if self != existing
|
76
|
+
existing.destroy
|
77
|
+
post
|
78
|
+
end
|
79
|
+
rescue Excon::Errors::NotFound
|
80
|
+
post
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def api_url
|
87
|
+
@options[:exprd_api_url] || ENV["EXPRD_API_URL"] ||
|
88
|
+
raise("need EXPRD_API")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Expri
|
2
|
+
class MetricSet
|
3
|
+
def metric(name, attributes={}, options={})
|
4
|
+
@metrics << Metric.new(name, attributes, @options.merge(options))
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
@options = { :destroy_extras => true }.merge(options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def run(&block)
|
12
|
+
puts "run options=#{@options}" if @options[:verbose]
|
13
|
+
cache_current if @options[:destroy_extras]
|
14
|
+
|
15
|
+
@metrics = []
|
16
|
+
instance_eval(&block)
|
17
|
+
@metrics.each do |metric|
|
18
|
+
metric.put
|
19
|
+
end
|
20
|
+
|
21
|
+
destroy_extras if @options[:destroy_extras]
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def cache_current
|
27
|
+
@current_metrics = Metric.list
|
28
|
+
end
|
29
|
+
|
30
|
+
def destroy_extras
|
31
|
+
puts "check_extras" if @options[:verbose]
|
32
|
+
extra_metrics = @current_metrics - @metrics.map(&:name)
|
33
|
+
extra_metrics.each do |metric|
|
34
|
+
metric = Metric.new(metric, {}, @options)
|
35
|
+
metric.destroy
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: expri
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Brandur
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: excon
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - '='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.16.4
|
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: 0.16.4
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: multi_json
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - '='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.3.6
|
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.3.6
|
46
|
+
description:
|
47
|
+
email: brandur@mutelight.org
|
48
|
+
executables: []
|
49
|
+
extensions: []
|
50
|
+
extra_rdoc_files: []
|
51
|
+
files:
|
52
|
+
- lib/expri/dumper.rb
|
53
|
+
- lib/expri/metric.rb
|
54
|
+
- lib/expri/metric_set.rb
|
55
|
+
- lib/expri.rb
|
56
|
+
homepage: https://github.com/heroku/expri
|
57
|
+
licenses:
|
58
|
+
- MIT
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.8.23
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: Versionable metrics recipes for exprd.
|
81
|
+
test_files: []
|