multiforecast-client 0.62.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.pryrc +5 -0
- data/.rdebugrc +4 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +5 -0
- data/LICENSE +22 -0
- data/README.md +96 -0
- data/Rakefile +15 -0
- data/VERSION +1 -0
- data/bin/multiforecast +5 -0
- data/examples/example.rb +161 -0
- data/lib/multiforecast/cli.rb +69 -0
- data/lib/multiforecast/client.rb +326 -0
- data/lib/multiforecast/conversion_rule.rb +42 -0
- data/lib/multiforecast/shared_context/mock.rb +163 -0
- data/lib/multiforecast/shared_context/setup.rb +62 -0
- data/lib/multiforecast/shared_context.rb +22 -0
- data/lib/multiforecast/shared_examples.rb +30 -0
- data/lib/multiforecast-client.rb +2 -0
- data/multiforecast-client.gemspec +29 -0
- data/spec/multiforecast/client_spec.rb +170 -0
- data/spec/multiforecast/conversion_rule_spec.rb +152 -0
- data/spec/spec_helper.rb +18 -0
- metadata +170 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1316eee0e12243629951f3a621150271e5df2a3f
|
4
|
+
data.tar.gz: f4cb9e1be15332f4f7cf51036f2d509ef93926c6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 61b291a15bbf7ce71c80783ef984ac3b56cc2a10862a8ccce2ae05034848dabf72bc6926f3bbd9fed495adcf0c8d5f4494636e29f250c0c723256564118ebb6f
|
7
|
+
data.tar.gz: 0cc4d55285915ff7334b047076c52efa49a3b5dc52d9fcddef604804260da1a5f33ccc9efdcbf37f6da602ad0c1849e100b362fc0d9ccbbcf78181bdffd89e0e
|
data/.gitignore
ADDED
data/.pryrc
ADDED
data/.rdebugrc
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Naotoshi SEO
|
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,96 @@
|
|
1
|
+
# multiforecast-client
|
2
|
+
|
3
|
+
testing ruby: 1.9.2, 1.9.3, 2.0.0; GrowthForecast: >= 0.62 (Jun 27, 2013 released)
|
4
|
+
|
5
|
+
## About multiforecast-client
|
6
|
+
|
7
|
+
`multiforecast-client` is a Multiple GrowthForecast Client, aimed to be used for [Yohoushi](https://github.com/yohoushi/yohoushi) visualization tool.
|
8
|
+
|
9
|
+
Features
|
10
|
+
|
11
|
+
- Possible to send http requests to multiple growthforecasts seemlessly
|
12
|
+
- Enables to create graphs whose levels are more than 3.
|
13
|
+
- CRUD graphs
|
14
|
+
- Get graph image uri
|
15
|
+
|
16
|
+
## USAGE
|
17
|
+
|
18
|
+
### Library
|
19
|
+
|
20
|
+
Create a client.
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
require 'multiforecast-client'
|
24
|
+
client = MultiForecast::Client.new('mapping' => {
|
25
|
+
'foo/' => 'http://localhost:5125',
|
26
|
+
'' => 'http://localhost:5000'
|
27
|
+
})
|
28
|
+
```
|
29
|
+
|
30
|
+
The first `post_graph` posts a number to the first GrowthForecast.
|
31
|
+
The second `post_graph` posts a number to the second GrowthForecast because the specified path did not match with the first mapping rule 'foo/'.
|
32
|
+
Notice that the pattern matching is processed from top as ruby's hash is an ordered hash.
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
client.post_graph('foo/b/c/d', { 'number' => 0 })
|
36
|
+
client.post_graph('bar/b/c/d', { 'number' => 0 })
|
37
|
+
```
|
38
|
+
|
39
|
+
See [examples](./examples) for more.
|
40
|
+
|
41
|
+
### CLI
|
42
|
+
|
43
|
+
`multiforecast-client` also provides a CLI named `multiforecast`.
|
44
|
+
|
45
|
+
Generate a config file template to store a mapping rule:
|
46
|
+
|
47
|
+
```
|
48
|
+
$ multiforecast genearte config
|
49
|
+
Generated multiforecast.yml
|
50
|
+
$ cat multiforecast.yml
|
51
|
+
---
|
52
|
+
mapping:
|
53
|
+
'': http://localhost:5125
|
54
|
+
short_metrics: true
|
55
|
+
```
|
56
|
+
|
57
|
+
Post a number and create a graph:
|
58
|
+
|
59
|
+
```
|
60
|
+
$ multiforecast post '{"number":0}' 'foo/a/b/c' -c multiforecast.yml
|
61
|
+
```
|
62
|
+
|
63
|
+
Delete a graph or graphs under a path:
|
64
|
+
|
65
|
+
```
|
66
|
+
$ multiforecast delete 'foo/' -c multiforecast.yml
|
67
|
+
```
|
68
|
+
|
69
|
+
See help for more:
|
70
|
+
|
71
|
+
```
|
72
|
+
$ multiforecast help
|
73
|
+
```
|
74
|
+
|
75
|
+
## INSIDE: How to treat graphs of more than 3 levels
|
76
|
+
|
77
|
+
Although GrowthForecast can treat only graphs of 3 leveled path, MultiForecast can handle graphs of more than 3 levels.
|
78
|
+
This feature is achieved by converting a given path to GrowthForecast's `service_name/section_name/graph_name` path as follows:
|
79
|
+
|
80
|
+
service_name = 'multiforecast'
|
81
|
+
section_name = CGI.escape(File.dirname(path)).gsub('+', '%20').gsub('.', '%2E')
|
82
|
+
graph_name = File.basename(path)
|
83
|
+
|
84
|
+
As a viewer for these converted path, [Yohoushi](https://github.com/yohoushi/yohoushi) is ready for you.
|
85
|
+
|
86
|
+
## Contributing
|
87
|
+
|
88
|
+
1. Fork it
|
89
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
90
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
91
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
92
|
+
5. Create new [Pull Request](../../pull/new/master)
|
93
|
+
|
94
|
+
## Copyright
|
95
|
+
|
96
|
+
Copyright (c) 2013 Naotoshi SEO. See [LICENSE](LICENSE) for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
require 'rspec/core'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
7
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
8
|
+
end
|
9
|
+
task :default => :spec
|
10
|
+
|
11
|
+
desc 'Open an irb session preloaded with the gem library'
|
12
|
+
task :console do
|
13
|
+
sh 'irb -rubygems -I lib -r multiforecast-client.rb'
|
14
|
+
end
|
15
|
+
task :c => :console
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.62.0.2
|
data/bin/multiforecast
ADDED
data/examples/example.rb
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'multiforecast-client'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
### Create a Multi GrowthForecast Client
|
6
|
+
client = MultiForecast::Client.new('mapping' => {
|
7
|
+
'app1/' => 'http://localhost:5125',
|
8
|
+
'app2/' => 'http://localhost:5000'
|
9
|
+
})
|
10
|
+
# client.debug_dev = STDOUT # print out HTTP requests and responses
|
11
|
+
|
12
|
+
pp 'Create a graph (Post a number)'
|
13
|
+
client.post_graph('app1/2xx_count', { 'number' => 0 })
|
14
|
+
client.post_graph('app1/3xx_count', { 'number' => 0 })
|
15
|
+
pp client.post_graph('app2/2xx_count', { 'number' => 0 }) #=>
|
16
|
+
# {"error"=>0,
|
17
|
+
# "data"=>
|
18
|
+
# {"number"=>0,
|
19
|
+
# "llimit"=>-1000000000,
|
20
|
+
# "mode"=>"gauge",
|
21
|
+
# "stype"=>"AREA",
|
22
|
+
# "adjustval"=>"1",
|
23
|
+
# "meta"=>"",
|
24
|
+
# "service_name"=>"multiforecast",
|
25
|
+
# "gmode"=>"gauge",
|
26
|
+
# "color"=>"#33cc99",
|
27
|
+
# "created_at"=>"2013/05/20 17:57:57",
|
28
|
+
# "section_name"=>"multiforecast",
|
29
|
+
# "ulimit"=>1000000000,
|
30
|
+
# "id"=>2,
|
31
|
+
# "graph_name"=>"app2%2F2xx_count",
|
32
|
+
# "description"=>"",
|
33
|
+
# "sulimit"=>100000,
|
34
|
+
# "unit"=>"",
|
35
|
+
# "sort"=>0,
|
36
|
+
# "updated_at"=>"2013/05/20 17:57:57",
|
37
|
+
# "adjust"=>"*",
|
38
|
+
# "type"=>"AREA",
|
39
|
+
# "sllimit"=>-100000,
|
40
|
+
# "md5"=>"c81e728d9d4c2f636f067f89cc14862c"}}
|
41
|
+
|
42
|
+
pp 'List graphs. All graphs from multiple growthforecasts are shown'
|
43
|
+
pp client.list_graph #=>
|
44
|
+
# [{"graph_name"=>"app1%2F3xx_count",
|
45
|
+
# "service_name"=>"multiforecast",
|
46
|
+
# "section_name"=>"multiforecast",
|
47
|
+
# "id"=>2,
|
48
|
+
# "base_uri"=>"http://localhost:5125",
|
49
|
+
# "path"=>"app1/3xx_count"},
|
50
|
+
# {"graph_name"=>"app1%2F2xx_count",
|
51
|
+
# "service_name"=>"multiforecast",
|
52
|
+
# "section_name"=>"multiforecast",
|
53
|
+
# "id"=>1,
|
54
|
+
# "base_uri"=>"http://localhost:5125",
|
55
|
+
# "path"=>"app1/2xx_count"},
|
56
|
+
# {"service_name"=>"multiforecast",
|
57
|
+
# "graph_name"=>"app2%2F2xx_count",
|
58
|
+
# "section_name"=>"multiforecast",
|
59
|
+
# "id"=>2,
|
60
|
+
# "base_uri"=>"http://localhost:5000",
|
61
|
+
# "path"=>"app2/2xx_count"}]
|
62
|
+
|
63
|
+
pp 'List graphs by filtering by dirpath app1/'
|
64
|
+
pp client.list_graph('app1/') #=>
|
65
|
+
# [{"graph_name"=>"app1%2F3xx_count",
|
66
|
+
# "service_name"=>"multiforecast",
|
67
|
+
# "section_name"=>"multiforecast",
|
68
|
+
# "id"=>2,
|
69
|
+
# "base_uri"=>"http://localhost:5125",
|
70
|
+
# "path"=>"app1/3xx_count"},
|
71
|
+
# {"graph_name"=>"app1%2F2xx_count",
|
72
|
+
# "service_name"=>"multiforecast",
|
73
|
+
# "section_name"=>"multiforecast",
|
74
|
+
# "id"=>1,
|
75
|
+
# "base_uri"=>"http://localhost:5125",
|
76
|
+
# "path"=>"app1/2xx_count"}]
|
77
|
+
|
78
|
+
pp 'Get a graph property'
|
79
|
+
pp client.get_graph('app2/2xx_count') #=>
|
80
|
+
# {"number"=>0,
|
81
|
+
# "llimit"=>-1000000000,
|
82
|
+
# "mode"=>"gauge",
|
83
|
+
# "stype"=>"AREA",
|
84
|
+
# "adjustval"=>"1",
|
85
|
+
# "meta"=>"",
|
86
|
+
# "service_name"=>"multiforecast",
|
87
|
+
# "gmode"=>"gauge",
|
88
|
+
# "color"=>"#33cc99",
|
89
|
+
# "created_at"=>"2013/05/20 17:57:57",
|
90
|
+
# "section_name"=>"multiforecast",
|
91
|
+
# "ulimit"=>1000000000,
|
92
|
+
# "id"=>2,
|
93
|
+
# "graph_name"=>"app2%2F2xx_count",
|
94
|
+
# "description"=>"",
|
95
|
+
# "sulimit"=>100000,
|
96
|
+
# "unit"=>"",
|
97
|
+
# "sort"=>0,
|
98
|
+
# "updated_at"=>"2013/05/20 17:57:57",
|
99
|
+
# "adjust"=>"*",
|
100
|
+
# "type"=>"AREA",
|
101
|
+
# "sllimit"=>-100000,
|
102
|
+
# "md5"=>"c81e728d9d4c2f636f067f89cc14862c",
|
103
|
+
# "base_uri"=>"http://localhost:5000",
|
104
|
+
# "path"=>"app2/2xx_count"}
|
105
|
+
|
106
|
+
pp 'Get a graph image uri'
|
107
|
+
pp client.get_graph_uri('app2/2xx_count', term: '3h') #=>
|
108
|
+
# "http://localhost:5125/graph/multiforecast/multiforecast/app1%2F2xx_count?t=3h"
|
109
|
+
|
110
|
+
pp 'Delete a complex graph'
|
111
|
+
pp client.delete_graph('app2/2xx_count') #=>
|
112
|
+
# {"location"=>"http://localhost:5000/list/multiforecast/multiforecast", "error"=>0}
|
113
|
+
|
114
|
+
pp 'Create a complex graph'
|
115
|
+
# Source graphs of a complex graph must exist on *a* GrowthForecast
|
116
|
+
from_graphs= [
|
117
|
+
{"path"=>'app1/2xx_count', "gmode" => 'gauge', "stack" => true, "type" => 'AREA'},
|
118
|
+
{"path"=>'app1/3xx_count', "gmode" => 'gauge', "stack" => true, "type" => 'AREA'},
|
119
|
+
]
|
120
|
+
to_complex = {
|
121
|
+
'path' => 'app1/complex',
|
122
|
+
"description" => "response time count",
|
123
|
+
"sort" => 10,
|
124
|
+
}
|
125
|
+
pp client.create_complex(from_graphs, to_complex) #=>
|
126
|
+
# {"location"=>"http://localhost:5125/list/multiforecast/multiforecast", "error"=>0}
|
127
|
+
|
128
|
+
pp 'Get a complex graph'
|
129
|
+
pp client.get_complex(to_complex['path']) #=>
|
130
|
+
# {"number"=>0,
|
131
|
+
# "complex"=>true,
|
132
|
+
# "created_at"=>"2013/05/20 18:00:09",
|
133
|
+
# "service_name"=>"multiforecast",
|
134
|
+
# "section_name"=>"multiforecast",
|
135
|
+
# "id"=>1,
|
136
|
+
# "graph_name"=>"app1%2Fcomplex",
|
137
|
+
# "data"=>
|
138
|
+
# [{"gmode"=>"gauge", "stack"=>false, "type"=>"AREA", "graph_id"=>1},
|
139
|
+
# {"gmode"=>"gauge", "stack"=>true, "type"=>"AREA", "graph_id"=>2}],
|
140
|
+
# "sumup"=>false,
|
141
|
+
# "description"=>"response time count",
|
142
|
+
# "sort"=>10,
|
143
|
+
# "updated_at"=>"2013/05/20 18:00:09",
|
144
|
+
# "base_uri"=>"http://localhost:5125",
|
145
|
+
# "path"=>"app1/complex"}
|
146
|
+
|
147
|
+
pp 'Get a complex graph image uri'
|
148
|
+
pp client.get_complex_uri(to_complex['path'], term: '3h') #=>
|
149
|
+
# "http://localhost:5125/complex/graph/multiforecast/multiforecast/app1%2Fcomplex?t=3h"
|
150
|
+
|
151
|
+
pp 'List complex graphs'
|
152
|
+
pp client.list_complex #=>
|
153
|
+
# [{"service_name"=>"multiforecast", "graph_name"=>"app1%2Fcomplex", "section_name"=>"multiforecast", "id"=>1, "base_uri"=>"http://localhost:5125", "path"=>"app1/complex"}]
|
154
|
+
|
155
|
+
pp 'List complex graphs by filetering by dirpath app1/'
|
156
|
+
pp client.list_complex('app1/')
|
157
|
+
|
158
|
+
pp 'Delete a complex graph'
|
159
|
+
pp client.delete_complex(to_complex['path']) #=>
|
160
|
+
# {"location"=>"http://localhost:5125/list/multiforecast/multiforecast", "error"=>0}
|
161
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'thor'
|
3
|
+
require 'yaml'
|
4
|
+
require 'multiforecast-client'
|
5
|
+
|
6
|
+
class MultiForecast::CLI < Thor
|
7
|
+
class_option :config, :aliases => ["-c"], :type => :string
|
8
|
+
class_option :silent, :aliases => ["-S"], :type => :boolean
|
9
|
+
|
10
|
+
def initialize(args = [], opts = [], config = {})
|
11
|
+
super(args, opts, config)
|
12
|
+
|
13
|
+
if options['config'] && File.exists?(options['config'])
|
14
|
+
@options = YAML.load_file(options['config']).merge(@options)
|
15
|
+
end
|
16
|
+
@client = MultiForecast::Client.new(@options)
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'generate config', 'Generate a sample config file'
|
20
|
+
def generate(target)
|
21
|
+
config = {
|
22
|
+
'mapping' => { '' => 'http://localhost:5125' },
|
23
|
+
}
|
24
|
+
File.open("multiforecast.yml", "w") do |file|
|
25
|
+
YAML.dump(config, file)
|
26
|
+
$stdout.puts "Generated #{file.path}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'post <json> <path>', 'Post a parameter to a path'
|
31
|
+
long_desc <<-LONGDESC
|
32
|
+
Post a parameter to a path
|
33
|
+
|
34
|
+
ex)
|
35
|
+
$ multiforecast post '{"number":0}' 'test/test' -c multiforecast.yml
|
36
|
+
LONGDESC
|
37
|
+
def post(json, path)
|
38
|
+
begin
|
39
|
+
res = @client.post_graph(path, JSON.parse(json))
|
40
|
+
$stdout.puts res unless @options['silent']
|
41
|
+
rescue => e
|
42
|
+
$stderr.puts "\tclass:#{e.class}\t#{e.message}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
desc 'delete <base_path>', 'Delete a graph or graphs under a path'
|
47
|
+
def delete(base_path)
|
48
|
+
graphs = @client.list_graph(base_path)
|
49
|
+
graphs.each do |graph|
|
50
|
+
begin
|
51
|
+
@client.delete_graph(graph['path'])
|
52
|
+
$stdout.puts "Deleted #{graph['path']}" unless @options['silent']
|
53
|
+
rescue => e
|
54
|
+
$stderr.puts "\tclass:#{e.class}\t#{e.message}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
complexes = @client.list_complex(base_path)
|
58
|
+
complexes.each do |graph|
|
59
|
+
begin
|
60
|
+
@client.delete_complex(graph['path'])
|
61
|
+
$stdout.puts "Deleted #{graph['path']}" unless @options['silent']
|
62
|
+
rescue => e
|
63
|
+
puts "\tclass:#{e.class}\t#{e.message}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
$stderr.puts "Not found" if graphs.empty? and complexes.empty? unless @options['silent']
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|