circonus 1.0.1
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/bin/circonus-cli +31 -0
- data/bin/circonus-data-cli +25 -0
- data/examples/add_apache_node.rb +100 -0
- data/examples/add_dns_monitor.rb +115 -0
- data/examples/add_http_check.rb +88 -0
- data/examples/add_nginx_alerts.rb +132 -0
- data/examples/add_nginx_graphs.rb +131 -0
- data/examples/add_nginx_node.rb +87 -0
- data/examples/add_snmp_node.rb +142 -0
- data/examples/cache_copy.rb +21 -0
- data/examples/update_nginx_graph.rb +131 -0
- data/examples/util.rb +173 -0
- data/lib/circonus.rb +196 -0
- data/lib/circonus/values.rb +160 -0
- metadata +108 -0
@@ -0,0 +1,131 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Update an nginx graph from a list of hosts attached to a template *HACK*
|
4
|
+
# update_nginx_graph.rb template_name graphid
|
5
|
+
# --FIXME probably not the best way to get a list of hosts.. working on a better way
|
6
|
+
#
|
7
|
+
# -- David Nicklay
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'rubygems'
|
11
|
+
require 'circonus'
|
12
|
+
require "#{ENV['HOME']}/.circonus.rb"
|
13
|
+
@c = Circonus.new(@apitoken,@appname,@agent)
|
14
|
+
|
15
|
+
if ((ARGV.length < 1) or ARGV[0].match('^-')) then
|
16
|
+
print "Usage: update_nginx_graph.rb template_name [graphid]\n"
|
17
|
+
exit(-1)
|
18
|
+
end
|
19
|
+
template_name = ARGV[0]
|
20
|
+
graphid = ARGV[1]
|
21
|
+
|
22
|
+
agents = @c.list_broker
|
23
|
+
agentid = agents.select { |a| a['_name'] == @agent }.first['_cid']
|
24
|
+
|
25
|
+
title = "#{template_name} - requests"
|
26
|
+
data = {
|
27
|
+
"title"=>"nginx #{title}",
|
28
|
+
"style"=>"area",
|
29
|
+
"max_right_y"=>nil,
|
30
|
+
"min_right_y"=>nil,
|
31
|
+
"min_left_y"=>nil,
|
32
|
+
"max_left_y"=>nil,
|
33
|
+
"guides"=>[],
|
34
|
+
"datapoints"=> [],
|
35
|
+
"composites"=> []
|
36
|
+
}
|
37
|
+
|
38
|
+
dpstub = {
|
39
|
+
"axis"=>"l",
|
40
|
+
"stack"=>nil,
|
41
|
+
"metric_type"=>"numeric",
|
42
|
+
"data_formula"=>nil,
|
43
|
+
"name"=>nil,
|
44
|
+
"derive"=>"counter",
|
45
|
+
"metric_name"=>nil,
|
46
|
+
"color"=>"#33aa33",
|
47
|
+
"check_id"=>nil,
|
48
|
+
"legend_formula"=>nil,
|
49
|
+
"hidden"=>false
|
50
|
+
}
|
51
|
+
|
52
|
+
# No SUM(*) is available, so we have to generate a formula ourselves:
|
53
|
+
# Generate a total formula =A+B+C...... using the number of datapoints
|
54
|
+
def get_total_formula(npoints)
|
55
|
+
i = 0
|
56
|
+
formula = "="
|
57
|
+
a = 'A'..'ZZZZ'
|
58
|
+
a.each do |x|
|
59
|
+
i += 1
|
60
|
+
formula += x
|
61
|
+
break if i == npoints
|
62
|
+
formula += "+"
|
63
|
+
end
|
64
|
+
return formula
|
65
|
+
end
|
66
|
+
|
67
|
+
# get unique values from an array of hashes given an index to compare on
|
68
|
+
def get_unique(array,index)
|
69
|
+
a = array.sort_by { |x| x[index] }
|
70
|
+
return a.inject([]) do |result,item|
|
71
|
+
result << item if !result.last||result.last[index]!=item[index]
|
72
|
+
result
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Get list of hosts on template
|
77
|
+
hosts = @c.list_template.select { |t| t['name'] == template_name }.first['hosts']
|
78
|
+
# Get list of check ids to use:
|
79
|
+
bundles = @c.list_check_bundle().select { |b| hosts.include? b['target'] }
|
80
|
+
checkids = get_unique(bundles,'target').map { |j| j['_checks'].first }
|
81
|
+
checkids.each do |checkid|
|
82
|
+
cid = checkid.to_a.first.gsub(/^.*\//,'')
|
83
|
+
%w{ requests }.each do |metric|
|
84
|
+
dp = dpstub.clone
|
85
|
+
dp['name'] = "nginx #{title} - #{metric}"
|
86
|
+
dp['metric_name'] = metric
|
87
|
+
if %w{ accepted handled requests }.include? metric then
|
88
|
+
dp['derive'] = "counter"
|
89
|
+
end
|
90
|
+
dp['color'] = nil
|
91
|
+
|
92
|
+
dp['stack'] = 0
|
93
|
+
dp['check_id'] = cid
|
94
|
+
dp['hidden'] = true
|
95
|
+
|
96
|
+
data['datapoints'] << dp
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
# Do composite total:
|
103
|
+
formula = get_total_formula(data['datapoints'].length)
|
104
|
+
totaldp = {
|
105
|
+
"name"=>"Total Reqs/s",
|
106
|
+
"axis"=>"l",
|
107
|
+
"stack"=>nil,
|
108
|
+
"legend_formula"=>"=ceil(VAL)",
|
109
|
+
"color"=>"#33aa33",
|
110
|
+
"data_formula"=>formula,
|
111
|
+
"hidden"=>false
|
112
|
+
}
|
113
|
+
data['composites'] << totaldp
|
114
|
+
|
115
|
+
|
116
|
+
guidepct = {
|
117
|
+
"data_formula"=>"99%",
|
118
|
+
"name"=>"99th Percentile",
|
119
|
+
"color"=>"#ea3a92",
|
120
|
+
"hidden"=>false,
|
121
|
+
"legend_formula"=>"=ceil(VAL)"
|
122
|
+
}
|
123
|
+
data['guides'] << guidepct
|
124
|
+
|
125
|
+
if graphid.nil? then
|
126
|
+
r = @c.add_graph(data)
|
127
|
+
else
|
128
|
+
r = @c.update_graph(graphid,data)
|
129
|
+
end
|
130
|
+
pp r
|
131
|
+
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Add a single nginx host to circonus
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'circonus'
|
6
|
+
require 'optparse'
|
7
|
+
require "#{ENV['HOME']}/.circonus.rb"
|
8
|
+
|
9
|
+
def do_update_check_bundle(data)
|
10
|
+
search_check_bundle = @c.list_check_bundle({'display_name' => data['display_name']})
|
11
|
+
existing = false
|
12
|
+
if search_check_bundle.any? # already exists...
|
13
|
+
existing = true
|
14
|
+
r = @c.update_check_bundle(search_check_bundle.first['_cid'],data)
|
15
|
+
else
|
16
|
+
r = @c.add_check_bundle(data)
|
17
|
+
end
|
18
|
+
if not r.nil? then
|
19
|
+
pp r
|
20
|
+
print "Success (#{existing ? 'updating' : 'adding'} #{data['display_name']})\n"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
options = {}
|
26
|
+
options[:tags] = []
|
27
|
+
OptionParser.new { |opts|
|
28
|
+
opts.banner = "Usage: #{File.basename($0)} [-h] hostname [-t tag1,tag2,...]\n"
|
29
|
+
opts.on( '-h', '--help', "This usage menu") do
|
30
|
+
puts opts
|
31
|
+
exit
|
32
|
+
end
|
33
|
+
opts.on( '-t','--tags TAGLIST',"Apply comma separated list of tags" ) do |t|
|
34
|
+
options[:tags] += t.split(/,/)
|
35
|
+
end
|
36
|
+
}.parse!
|
37
|
+
|
38
|
+
def usage()
|
39
|
+
print <<EOF
|
40
|
+
Usage: #{File.basename($0)} hostname [-t tag1,tag2,... ]
|
41
|
+
-h,--help This usage menu
|
42
|
+
-t,--tags Comma separated list of tag names to apply (default is an empty list)
|
43
|
+
EOF
|
44
|
+
end
|
45
|
+
|
46
|
+
host = ARGV[0]
|
47
|
+
if host.nil? then
|
48
|
+
usage()
|
49
|
+
exit -1
|
50
|
+
end
|
51
|
+
|
52
|
+
@c = Circonus.new(@apitoken,@appname,@agent)
|
53
|
+
|
54
|
+
agents = @c.list_broker
|
55
|
+
agentid = agents.select { |a| a['_name'] == @agent }.first['_cid']
|
56
|
+
|
57
|
+
print "Adding nginx for host #{host}\n"
|
58
|
+
data = {
|
59
|
+
:agent_id => agentid,
|
60
|
+
:target => host,
|
61
|
+
:module => "nginx",
|
62
|
+
}
|
63
|
+
bundle = {
|
64
|
+
"type" => "nginx",
|
65
|
+
"target" => host,
|
66
|
+
"tags" => options[:tags],
|
67
|
+
"timeout" => 10,
|
68
|
+
"period" => 60,
|
69
|
+
"display_name" => "#{host} nginx",
|
70
|
+
"brokers" => [
|
71
|
+
agentid
|
72
|
+
],
|
73
|
+
"metrics" => [
|
74
|
+
],
|
75
|
+
"config" => {
|
76
|
+
"url" => "http://#{host}/server-status"
|
77
|
+
}
|
78
|
+
}
|
79
|
+
%w{ handled waiting requests accepted active duration reading writing }.each do |metric|
|
80
|
+
bundle['metrics'] << {
|
81
|
+
'type' => 'numeric',
|
82
|
+
'name' => metric
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
do_update_check_bundle(bundle)
|
87
|
+
|
@@ -0,0 +1,142 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Add a single snmp based host to circonus
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'circonus'
|
6
|
+
require 'snmp'
|
7
|
+
require 'pp'
|
8
|
+
require 'optparse'
|
9
|
+
|
10
|
+
|
11
|
+
options = {}
|
12
|
+
options[:tags] = []
|
13
|
+
OptionParser.new { |opts|
|
14
|
+
opts.banner = "Usage: #{File.basename($0)} [-h] hostname [-t tag1,tag2,...]\n"
|
15
|
+
opts.on( '-h', '--help', "This usage menu") do
|
16
|
+
puts opts
|
17
|
+
exit
|
18
|
+
end
|
19
|
+
opts.on( '-t','--tags TAGLIST',"Apply comma separated list of tags" ) do |t|
|
20
|
+
options[:tags] += t.split(/,/)
|
21
|
+
end
|
22
|
+
}.parse!
|
23
|
+
|
24
|
+
|
25
|
+
def usage()
|
26
|
+
print <<EOF
|
27
|
+
Usage: add_snmp_node.rb hostname [-t tag1,tag2,... ]
|
28
|
+
-h,--help This usage menu
|
29
|
+
-t,--tags Comma separated list of tag names to apply (default is an empty list)
|
30
|
+
EOF
|
31
|
+
end
|
32
|
+
|
33
|
+
host = ARGV[0]
|
34
|
+
if host.nil? then
|
35
|
+
usage()
|
36
|
+
exit -1
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Make a guess as to what ethernet interface to query for data
|
41
|
+
def get_ethernet_oids(host)
|
42
|
+
ifTable_columns = ["ifDescr", "ifOutOctets","ifIndex"]
|
43
|
+
eth_name = nil
|
44
|
+
eth_octets = nil
|
45
|
+
eth_index = nil
|
46
|
+
SNMP::Manager.open(:Host => host) do |manager|
|
47
|
+
manager.walk(ifTable_columns) do |row|
|
48
|
+
next if row[0].value.to_s.match('^lo')
|
49
|
+
if eth_name.nil? then
|
50
|
+
eth_name = row[0].value
|
51
|
+
eth_octets = row[1].value
|
52
|
+
eth_index = row[2].value
|
53
|
+
end
|
54
|
+
if row[1].value > eth_octets then
|
55
|
+
eth_name = row[0].value
|
56
|
+
eth_octets = row[1].value
|
57
|
+
eth_index = row[2].value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
if eth_index.nil?
|
62
|
+
eth_index = 0
|
63
|
+
end
|
64
|
+
return {
|
65
|
+
"ifOutOctets" => ".1.3.6.1.2.1.2.2.1.16.#{eth_index}",
|
66
|
+
"ifInOctets" => ".1.3.6.1.2.1.2.2.1.10.#{eth_index}"
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
require "#{ENV['HOME']}/.circonus.rb"
|
71
|
+
@c = Circonus.new(@apitoken,@appname,@agent)
|
72
|
+
|
73
|
+
agentid = @c.search_broker(@agent,'_name').first['_cid']
|
74
|
+
|
75
|
+
print "Adding snmp check for host #{host}\n"
|
76
|
+
data_stub = {
|
77
|
+
"type" => nil,
|
78
|
+
"target" => nil,
|
79
|
+
"timeout" => 10,
|
80
|
+
"period" => 60,
|
81
|
+
"display_name" => nil,
|
82
|
+
"brokers" => [],
|
83
|
+
"metrics" => [],
|
84
|
+
"config" => {}
|
85
|
+
}
|
86
|
+
bundle = data_stub.clone()
|
87
|
+
bundle['tags'] = options[:tags]
|
88
|
+
bundle['target'] = host
|
89
|
+
bundle['type'] = 'snmp'
|
90
|
+
bundle['display_name'] = "#{host} snmp"
|
91
|
+
bundle['brokers'] << agentid
|
92
|
+
bundle['config'] = {
|
93
|
+
"community" => "public",
|
94
|
+
"version" => "2c",
|
95
|
+
"port" => "161",
|
96
|
+
}
|
97
|
+
oids = {
|
98
|
+
"memAvailSwap"=> ".1.3.6.1.4.1.2021.4.4.0",
|
99
|
+
"memAvailReal"=> ".1.3.6.1.4.1.2021.4.6.0",
|
100
|
+
"memTotalSwap"=> ".1.3.6.1.4.1.2021.4.3.0",
|
101
|
+
"memTotalReal"=> ".1.3.6.1.4.1.2021.4.5.0",
|
102
|
+
"memTotalFree"=> ".1.3.6.1.4.1.2021.4.11.0",
|
103
|
+
"memShared"=> ".1.3.6.1.4.1.2021.4.13.0",
|
104
|
+
"memBuffer"=> ".1.3.6.1.4.1.2021.4.14.0",
|
105
|
+
"memCached"=> ".1.3.6.1.4.1.2021.4.15.0",
|
106
|
+
"ssCpuRawUser"=> ".1.3.6.1.4.1.2021.11.50.0",
|
107
|
+
"ssCpuRawNice"=> ".1.3.6.1.4.1.2021.11.51.0",
|
108
|
+
"ssCpuRawSystem"=> ".1.3.6.1.4.1.2021.11.52.0",
|
109
|
+
"ssCpuRawIdle"=> ".1.3.6.1.4.1.2021.11.53.0",
|
110
|
+
"ssCpuRawWait"=> ".1.3.6.1.4.1.2021.11.54.0",
|
111
|
+
"ssCpuRawKernel"=> ".1.3.6.1.4.1.2021.11.55.0",
|
112
|
+
"ssCpuRawInterrupt"=> ".1.3.6.1.4.1.2021.11.56.0",
|
113
|
+
"ssCpuRawSoftIRQ"=> ".1.3.6.1.4.1.2021.11.61.0",
|
114
|
+
"ssCpuIdle"=> ".1.3.6.1.4.1.2021.11.11.0"
|
115
|
+
}
|
116
|
+
|
117
|
+
begin
|
118
|
+
eth_oids = get_ethernet_oids(host)
|
119
|
+
rescue
|
120
|
+
eth_oids = {}
|
121
|
+
end
|
122
|
+
oids.merge!(eth_oids)
|
123
|
+
|
124
|
+
oids.each do |name,oid|
|
125
|
+
bundle['config']["oid_#{name}"] = oid
|
126
|
+
bundle['metrics'] << {
|
127
|
+
'type' => 'numeric',
|
128
|
+
'name' => name
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
search_bundles = @c.search_check_bundle(bundle['display_name'],'display_name')
|
133
|
+
if search_bundles.any? # already exists...
|
134
|
+
r = @c.update_check_bundle(search_bundles.first['_cid'],bundle)
|
135
|
+
else
|
136
|
+
r = @c.add_check_bundle(bundle)
|
137
|
+
end
|
138
|
+
if not r.nil? then
|
139
|
+
print "Success\n"
|
140
|
+
#pp r
|
141
|
+
end
|
142
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Make a cached copy of all of what is in circonus API
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'circonus'
|
6
|
+
require 'json'
|
7
|
+
require "#{ENV['HOME']}/.circonus.rb"
|
8
|
+
@c = Circonus.new(@apitoken,@appname,@agent)
|
9
|
+
|
10
|
+
@c.methods.select { |m| m.match('^list_') }.each do |m|
|
11
|
+
begin
|
12
|
+
data = @c.send m.to_sym
|
13
|
+
type = m.sub('list_','')
|
14
|
+
Dir.mkdir 'cache' unless File.directory?('cache')
|
15
|
+
f = File.open File.join('cache',"#{type}.json"), "w"
|
16
|
+
f.write JSON.pretty_generate(data)
|
17
|
+
f.close
|
18
|
+
rescue RestClient::ResourceNotFound => e
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,131 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Update an nginx graph from a list of hosts attached to a template *HACK*
|
4
|
+
# update_nginx_graph.rb template_name graphid
|
5
|
+
# --FIXME probably not the best way to get a list of hosts.. working on a better way
|
6
|
+
#
|
7
|
+
# -- David Nicklay
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'rubygems'
|
11
|
+
require 'circonus'
|
12
|
+
require "#{ENV['HOME']}/.circonus.rb"
|
13
|
+
@c = Circonus.new(@apitoken,@appname,@agent)
|
14
|
+
|
15
|
+
if ((ARGV.length < 1) or ARGV[0].match('^-')) then
|
16
|
+
print "Usage: update_nginx_graph.rb template_name [graphid]\n"
|
17
|
+
exit(-1)
|
18
|
+
end
|
19
|
+
template_name = ARGV[0]
|
20
|
+
graphid = ARGV[1]
|
21
|
+
|
22
|
+
agents = @c.list_broker
|
23
|
+
agentid = agents.select { |a| a['_name'] == @agent }.first['_cid']
|
24
|
+
|
25
|
+
title = "#{template_name} - requests"
|
26
|
+
data = {
|
27
|
+
"title"=>"nginx #{title}",
|
28
|
+
"style"=>"area",
|
29
|
+
"max_right_y"=>nil,
|
30
|
+
"min_right_y"=>nil,
|
31
|
+
"min_left_y"=>nil,
|
32
|
+
"max_left_y"=>nil,
|
33
|
+
"guides"=>[],
|
34
|
+
"datapoints"=> [],
|
35
|
+
"composites"=> []
|
36
|
+
}
|
37
|
+
|
38
|
+
dpstub = {
|
39
|
+
"axis"=>"l",
|
40
|
+
"stack"=>nil,
|
41
|
+
"metric_type"=>"numeric",
|
42
|
+
"data_formula"=>nil,
|
43
|
+
"name"=>nil,
|
44
|
+
"derive"=>"counter",
|
45
|
+
"metric_name"=>nil,
|
46
|
+
"color"=>"#33aa33",
|
47
|
+
"check_id"=>nil,
|
48
|
+
"legend_formula"=>nil,
|
49
|
+
"hidden"=>false
|
50
|
+
}
|
51
|
+
|
52
|
+
# No SUM(*) is available, so we have to generate a formula ourselves:
|
53
|
+
# Generate a total formula =A+B+C...... using the number of datapoints
|
54
|
+
def get_total_formula(npoints)
|
55
|
+
i = 0
|
56
|
+
formula = "="
|
57
|
+
a = 'A'..'ZZZZ'
|
58
|
+
a.each do |x|
|
59
|
+
i += 1
|
60
|
+
formula += x
|
61
|
+
break if i == npoints
|
62
|
+
formula += "+"
|
63
|
+
end
|
64
|
+
return formula
|
65
|
+
end
|
66
|
+
|
67
|
+
# get unique values from an array of hashes given an index to compare on
|
68
|
+
def get_unique(array,index)
|
69
|
+
a = array.sort_by { |x| x[index] }
|
70
|
+
return a.inject([]) do |result,item|
|
71
|
+
result << item if !result.last||result.last[index]!=item[index]
|
72
|
+
result
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Get list of hosts on template
|
77
|
+
hosts = @c.list_template.select { |t| t['name'] == template_name }.first['hosts']
|
78
|
+
# Get list of check ids to use:
|
79
|
+
bundles = @c.list_check_bundle().select { |b| hosts.include? b['target'] }
|
80
|
+
checkids = get_unique(bundles,'target').map { |j| j['_checks'].first }
|
81
|
+
checkids.each do |checkid|
|
82
|
+
cid = checkid.to_a.first.gsub(/^.*\//,'')
|
83
|
+
%w{ requests }.each do |metric|
|
84
|
+
dp = dpstub.clone
|
85
|
+
dp['name'] = "nginx #{title} - #{metric}"
|
86
|
+
dp['metric_name'] = metric
|
87
|
+
if %w{ accepted handled requests }.include? metric then
|
88
|
+
dp['derive'] = "counter"
|
89
|
+
end
|
90
|
+
dp['color'] = nil
|
91
|
+
|
92
|
+
dp['stack'] = 0
|
93
|
+
dp['check_id'] = cid
|
94
|
+
dp['hidden'] = true
|
95
|
+
|
96
|
+
data['datapoints'] << dp
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
# Do composite total:
|
103
|
+
formula = get_total_formula(data['datapoints'].length)
|
104
|
+
totaldp = {
|
105
|
+
"name"=>"Total Reqs/s",
|
106
|
+
"axis"=>"l",
|
107
|
+
"stack"=>nil,
|
108
|
+
"legend_formula"=>"=ceil(VAL)",
|
109
|
+
"color"=>"#33aa33",
|
110
|
+
"data_formula"=>formula,
|
111
|
+
"hidden"=>false
|
112
|
+
}
|
113
|
+
data['composites'] << totaldp
|
114
|
+
|
115
|
+
|
116
|
+
guidepct = {
|
117
|
+
"data_formula"=>"99%",
|
118
|
+
"name"=>"99th Percentile",
|
119
|
+
"color"=>"#ea3a92",
|
120
|
+
"hidden"=>false,
|
121
|
+
"legend_formula"=>"=ceil(VAL)"
|
122
|
+
}
|
123
|
+
data['guides'] << guidepct
|
124
|
+
|
125
|
+
if graphid.nil? then
|
126
|
+
r = @c.add_graph(data)
|
127
|
+
else
|
128
|
+
r = @c.update_graph(graphid,data)
|
129
|
+
end
|
130
|
+
pp r
|
131
|
+
|