circonus 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|