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
data/bin/circonus-cli
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# CLI for circonus API
|
3
|
+
# Most things can be accessed with list_*, get_*, add_*
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'circonus'
|
7
|
+
require 'pp'
|
8
|
+
require 'ripl'
|
9
|
+
|
10
|
+
# You need to have thse in a ~/.circonus.rb file
|
11
|
+
#@agent="mytestbroker"
|
12
|
+
#@apitoken="blahblahblah"
|
13
|
+
#@appname="curl"
|
14
|
+
|
15
|
+
require "#{ENV['HOME']}/.circonus.rb"
|
16
|
+
|
17
|
+
@c = Circonus.new(@apitoken,@appname,@agent)
|
18
|
+
|
19
|
+
def help()
|
20
|
+
return methods().select { |m| m.to_s.match('^(list|get|add|delete|update|search)_') }.sort.join(' ')
|
21
|
+
end
|
22
|
+
|
23
|
+
#def list(arg)
|
24
|
+
# self.send "list_#{arg}".to_sym
|
25
|
+
#end
|
26
|
+
|
27
|
+
Ripl.start :binding => @c.instance_eval{ binding }
|
28
|
+
#Ripl.start
|
29
|
+
|
30
|
+
|
31
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# CLI for circonus data API
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'circonus'
|
6
|
+
require 'circonus/values'
|
7
|
+
require 'pp'
|
8
|
+
require 'ripl'
|
9
|
+
|
10
|
+
# You need to have thse in a ~/.circonus.rb file
|
11
|
+
#@username="username"
|
12
|
+
#@password="password"
|
13
|
+
#@account="myaccountname"
|
14
|
+
|
15
|
+
require "#{ENV['HOME']}/.circonus.rb"
|
16
|
+
|
17
|
+
@d = Circonus::Values.new(@username,@password,@account)
|
18
|
+
@d.login()
|
19
|
+
|
20
|
+
def help()
|
21
|
+
return methods.select {|s| s.to_s.match('(data|graph|value)') }.sort.join(' ')
|
22
|
+
end
|
23
|
+
|
24
|
+
Ripl.start :binding => @d.instance_eval{ binding }
|
25
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Add a single apache 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 apache for host #{host}\n"
|
58
|
+
data = {
|
59
|
+
:agent_id => agentid,
|
60
|
+
:target => host,
|
61
|
+
:module => "apache",
|
62
|
+
}
|
63
|
+
bundle = {
|
64
|
+
"type" => "http",
|
65
|
+
"target" => host,
|
66
|
+
"tags" => options[:tags],
|
67
|
+
"timeout" => 10,
|
68
|
+
"period" => 60,
|
69
|
+
"display_name" => "#{host} http:apache",
|
70
|
+
"brokers" => [
|
71
|
+
agentid
|
72
|
+
],
|
73
|
+
"metrics" => [
|
74
|
+
],
|
75
|
+
"config" => {
|
76
|
+
"code"=>"^200$",
|
77
|
+
"extract"=>"^([\\w\\s]+):\\s*(\\S{1,30})\\r?\\n",
|
78
|
+
"header_Host"=>host,
|
79
|
+
"http_version"=>"1.1",
|
80
|
+
"method"=>"GET",
|
81
|
+
"read_limit"=>"1048576",
|
82
|
+
"redirects"=>"0",
|
83
|
+
"url"=>"http://#{host}/server-status?auto"
|
84
|
+
}
|
85
|
+
}
|
86
|
+
%w{ code }.each do |metric|
|
87
|
+
bundle['metrics'] << {
|
88
|
+
'type' => 'text',
|
89
|
+
'name' => metric
|
90
|
+
}
|
91
|
+
end
|
92
|
+
%w{ code truncated tt_firstbyte BusyWorkers bytes duration tt_connect IdleWorkers }.each do |metric|
|
93
|
+
bundle['metrics'] << {
|
94
|
+
'type' => 'numeric',
|
95
|
+
'name' => metric
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
do_update_check_bundle(bundle)
|
100
|
+
|
@@ -0,0 +1,115 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'circonus'
|
5
|
+
require 'optparse'
|
6
|
+
require 'pp'
|
7
|
+
require "#{ENV['HOME']}/.circonus.rb"
|
8
|
+
|
9
|
+
class CirconusUtility
|
10
|
+
attr_accessor :c, :args, :debug_flag, :template, :tags
|
11
|
+
|
12
|
+
def initialize(apitoken,appname)
|
13
|
+
@args = []
|
14
|
+
@c = Circonus.new(apitoken,appname,nil)
|
15
|
+
@debug_flag = true
|
16
|
+
@template = nil
|
17
|
+
@tags = []
|
18
|
+
options()
|
19
|
+
end
|
20
|
+
def debug(msg)
|
21
|
+
puts msg if @debug_flag
|
22
|
+
end
|
23
|
+
def options
|
24
|
+
options = {}
|
25
|
+
options[:tags] = []
|
26
|
+
OptionParser.new { |opts|
|
27
|
+
opts.banner = "Usage: #{File.basename($0)} [-h] argument [-t tag1,tag2,...]\n"
|
28
|
+
opts.on( '-h', '--help', "This usage menu") do
|
29
|
+
puts opts
|
30
|
+
exit
|
31
|
+
end
|
32
|
+
opts.on( '-t','--tags TAGLIST',"Apply comma separated list of tags" ) do |t|
|
33
|
+
options[:tags] += t.split(/,/)
|
34
|
+
end
|
35
|
+
}.parse!
|
36
|
+
@tags = options[:tags]
|
37
|
+
@args = ARGV
|
38
|
+
usage(-1) unless @args.any?
|
39
|
+
end
|
40
|
+
def usage(exitcode=nil)
|
41
|
+
print <<EOF
|
42
|
+
Usage: #{File.basename($0)} argument [-t tag1,tag2,... ]
|
43
|
+
-h,--help This usage menu
|
44
|
+
-t,--tags Comma separated list of tag names to apply (default is an empty list)
|
45
|
+
EOF
|
46
|
+
exit(exitcode) unless exitcode.nil?
|
47
|
+
end
|
48
|
+
|
49
|
+
def do_update_check_bundle
|
50
|
+
search_check_bundle = @c.list_check_bundle({'display_name' => @template['display_name']})
|
51
|
+
existing = false
|
52
|
+
if search_check_bundle.any? # already exists...
|
53
|
+
existing = true
|
54
|
+
r = @c.update_check_bundle(search_check_bundle.first['_cid'],@template)
|
55
|
+
else
|
56
|
+
r = @c.add_check_bundle(@template)
|
57
|
+
end
|
58
|
+
if not r.nil? then
|
59
|
+
#debug "Result: #{r.inspect}"
|
60
|
+
debug "Success (#{existing ? 'updating' : 'adding'} #{@template['display_name']})\n"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def update
|
65
|
+
do_update_check_bundle
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_nameservers(target)
|
71
|
+
list = `dig +short -t ns #{target} @8.8.8.8` # use Google public dns to look it up
|
72
|
+
nameservers = list.split().map { |m| m.sub(/\.$/,'') }
|
73
|
+
unless $?.to_i == 0
|
74
|
+
puts "nameservers lookup failed: #{list}"
|
75
|
+
exit($?.to_i)
|
76
|
+
end
|
77
|
+
return nameservers
|
78
|
+
end
|
79
|
+
|
80
|
+
cu = CirconusUtility.new(@apitoken,@appname)
|
81
|
+
template = {
|
82
|
+
"brokers"=>["/broker/1"],
|
83
|
+
"config"=>{ "ctype"=>"IN", "query"=>"www.hostname.com", "rtype"=>"NS" },
|
84
|
+
"display_name"=>"DNS - www.hostname.com @mydns.dns.com",
|
85
|
+
"metrics"=>
|
86
|
+
[
|
87
|
+
{"name"=>"answer", "status"=>"active", "type"=>"text"},
|
88
|
+
{"name"=>"cname", "status"=>"active", "type"=>"numeric"},
|
89
|
+
{"name"=>"rtt", "status"=>"active", "type"=>"histogram"}
|
90
|
+
],
|
91
|
+
"notes"=>nil,
|
92
|
+
"period"=>60,
|
93
|
+
"status"=>"active",
|
94
|
+
"tags"=>[],
|
95
|
+
"target"=>"mydns.dns.com",
|
96
|
+
"timeout"=>10,
|
97
|
+
"type"=>"dns"
|
98
|
+
}
|
99
|
+
|
100
|
+
cu.debug_flag = true
|
101
|
+
hostnames = cu.args
|
102
|
+
hostnames.each do |hostname|
|
103
|
+
nameservers = get_nameservers(hostname)
|
104
|
+
cu.debug "Updating nameserver monitors for hostname: #{hostname} nameservers: #{nameservers.join(',')}"
|
105
|
+
nameservers.each do |ns|
|
106
|
+
template['display_name'] = "DNS - #{hostname} @#{ns}"
|
107
|
+
template['target'] = ns
|
108
|
+
template['config']['query'] = hostname
|
109
|
+
template['tags'] = cu.tags
|
110
|
+
cu.template = template
|
111
|
+
#cu.debug "Template=#{template.inspect}"
|
112
|
+
cu.update
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Add an HTTP site check
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'optparse'
|
8
|
+
require 'circonus'
|
9
|
+
require "#{ENV['HOME']}/.circonus.rb"
|
10
|
+
@c = Circonus.new(@apitoken,@appname,@agent)
|
11
|
+
|
12
|
+
options = {}
|
13
|
+
options[:multi] = false
|
14
|
+
OptionParser.new { |opts|
|
15
|
+
opts.banner = "Usage: #{File.basename($0)} [-h] [-m] sitename URL"
|
16
|
+
opts.on( '-h', '--help', "This usage menu") do
|
17
|
+
puts opts
|
18
|
+
print "sitename = The site's hostname\n"
|
19
|
+
print "URL = The actual url to check on the site\n"
|
20
|
+
exit
|
21
|
+
end
|
22
|
+
opts.on( '-m','--multi',"Use multiple circonus brokers" ) do
|
23
|
+
options[:multi] = true
|
24
|
+
end
|
25
|
+
}.parse!
|
26
|
+
|
27
|
+
|
28
|
+
def usage()
|
29
|
+
print <<EOF
|
30
|
+
Usage: add_http_check.rb sitename URL
|
31
|
+
-h,--help This usage menu
|
32
|
+
-m,--multi Use multiple circonus brokers
|
33
|
+
EOF
|
34
|
+
end
|
35
|
+
|
36
|
+
sitename = ARGV[0]
|
37
|
+
url = ARGV[1]
|
38
|
+
|
39
|
+
circonus_brokers = @c.search_broker("circonus",'_type')
|
40
|
+
circonus_brokers = circonus_brokers.select {|a| a['_name'] != 'HTTPTrap'} # filter out http trap broker...
|
41
|
+
agentids = circonus_brokers.map { |m| m['_cid'] }
|
42
|
+
agentids = agentids[0,1] unless options[:multi]
|
43
|
+
|
44
|
+
bundle_stub = {
|
45
|
+
"brokers"=>[ ],
|
46
|
+
"display_name"=>nil,
|
47
|
+
"period"=>60,
|
48
|
+
"target"=>nil,
|
49
|
+
"timeout"=>10,
|
50
|
+
"type"=>"http",
|
51
|
+
"metrics"=> [
|
52
|
+
{"name"=>"body_match", "type"=>"text"},
|
53
|
+
{"name"=>"bytes", "type"=>"numeric"},
|
54
|
+
{"name"=>"code", "type"=>"text"},
|
55
|
+
{"name"=>"duration", "type"=>"numeric"},
|
56
|
+
{"name"=>"truncated", "type"=>"numeric"},
|
57
|
+
{"name"=>"tt_connect", "type"=>"numeric"},
|
58
|
+
{"name"=>"tt_firstbyte", "type"=>"numeric"}
|
59
|
+
],
|
60
|
+
"config" => {
|
61
|
+
"url"=>nil,
|
62
|
+
"http_version"=>"1.1",
|
63
|
+
"header_Host"=>nil,
|
64
|
+
"read_limit"=>"1048576",
|
65
|
+
"method"=>"GET",
|
66
|
+
"code"=>"^200$",
|
67
|
+
"redirects"=>"0"
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
bundle = bundle_stub.clone
|
72
|
+
bundle['brokers'] = agentids
|
73
|
+
bundle['target'] = sitename
|
74
|
+
bundle['display_name'] = "#{sitename} http"
|
75
|
+
bundle['config']['url'] = url
|
76
|
+
bundle['config']['header_Host'] = sitename
|
77
|
+
|
78
|
+
search_bundles = @c.search_check_bundle(bundle['display_name'],'display_name')
|
79
|
+
if search_bundles.any? # already exists...
|
80
|
+
r = @c.update_check_bundle(search_bundles.first['_cid'],bundle)
|
81
|
+
else
|
82
|
+
r = @c.add_check_bundle(bundle)
|
83
|
+
end
|
84
|
+
if not r.nil? then
|
85
|
+
print "Success\n"
|
86
|
+
#pp r
|
87
|
+
end
|
88
|
+
|
@@ -0,0 +1,132 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Add alerts for nginx based service
|
4
|
+
#
|
5
|
+
# -- David Nicklay
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'rubygems'
|
9
|
+
require 'circonus'
|
10
|
+
require "#{ENV['HOME']}/.circonus.rb"
|
11
|
+
@c = Circonus.new(@apitoken,@appname,@agent)
|
12
|
+
|
13
|
+
if ((ARGV.length < 1) or ARGV[0].match('^-')) then
|
14
|
+
print "Usage: add_nginx_alerts.rb template_name [alertid]\n"
|
15
|
+
exit(-1)
|
16
|
+
end
|
17
|
+
template_name = ARGV[0]
|
18
|
+
alertid = ARGV[1]
|
19
|
+
|
20
|
+
agents = @c.list_broker
|
21
|
+
agentid = agents.select { |a| a['_name'] == @agent }.first['_cid']
|
22
|
+
|
23
|
+
datapoints = 'requests'
|
24
|
+
|
25
|
+
title = "#{template_name} - #{datapoint}"
|
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
|
+
exit
|
126
|
+
if graphid.nil? then
|
127
|
+
r = @c.add_graph(data)
|
128
|
+
else
|
129
|
+
r = @c.update_graph(graphid,data)
|
130
|
+
end
|
131
|
+
pp r
|
132
|
+
|