metrics-netstat-tcp.rb
3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#! /usr/bin/env ruby
#
# metrics-netstat-tcp
#
# DESCRIPTION:
# Fetch metrics on TCP socket states from netstat. This is particularly useful
# on high-traffic web or proxy servers with large numbers of short-lived TCP
# connections coming and going.
#
# OUTPUT:
# metric data
#
# PLATFORMS:
# Linux
#
# DEPENDENCIES:
# gem: sensu-plugin
#
# USAGE:
# $ ./metrics-netstat-tcp.rb --scheme servers.hostname
# servers.hostname.UNKNOWN 0 1350496466
# servers.hostname.ESTABLISHED 235 1350496466
# servers.hostname.SYN_SENT 0 1350496466
# servers.hostname.SYN_RECV 1 1350496466
# servers.hostname.FIN_WAIT1 0 1350496466
# servers.hostname.FIN_WAIT2 53 1350496466
# servers.hostname.TIME_WAIT 10640 1350496466
# servers.hostname.CLOSE 0 1350496466
# servers.hostname.CLOSE_WAIT 7 1350496466
# servers.hostname.LAST_ACK 1 1350496466
# servers.hostname.LISTEN 16 1350496466
# servers.hostname.CLOSING 0 1350496466
#
# NOTES:
# - Code for parsing Linux /proc/net/tcp from Anthony Goddard's ruby-netstat:
# https://github.com/agoddard/ruby-netstat
#
# LICENSE:
# Copyright 2012 Joe Miller <https://github.com/joemiller>
# Released under the same terms as Sensu (the MIT license); see LICENSE
# for details.
#
require 'sensu-plugin/metric/cli'
require 'socket'
TCP_STATES = {
'00' => 'UNKNOWN', # Bad state ... Impossible to achieve ...
'FF' => 'UNKNOWN', # Bad state ... Impossible to achieve ...
'01' => 'ESTABLISHED',
'02' => 'SYN_SENT',
'03' => 'SYN_RECV',
'04' => 'FIN_WAIT1',
'05' => 'FIN_WAIT2',
'06' => 'TIME_WAIT',
'07' => 'CLOSE',
'08' => 'CLOSE_WAIT',
'09' => 'LAST_ACK',
'0A' => 'LISTEN',
'0B' => 'CLOSING'
}.freeze
#
# Netstat TCP Metrics
#
class NetstatTCPMetrics < Sensu::Plugin::Metric::CLI::Graphite
option :scheme,
description: 'Metric naming scheme, text to prepend to metric',
short: '-s SCHEME',
long: '--scheme SCHEME',
default: "#{Socket.gethostname}.tcp"
option :port,
description: 'Port you wish to get metrics for',
short: '-p PORT',
long: '--port PORT',
proc: proc(&:to_i)
option :disabletcp6,
description: 'Disable tcp6 check',
short: '-d',
long: '--disabletcp6',
boolean: true
def netstat(protocol, pattern, state_counts)
File.open('/proc/net/' + protocol).each do |line|
line.strip!
if m = line.match(pattern) # rubocop:disable AssignmentInCondition
connection_state = m[5]
connection_port = m[2].to_i(16)
connection_state = TCP_STATES[connection_state]
if config[:port] && config[:port] == connection_port
state_counts[connection_state] += 1
elsif !config[:port]
state_counts[connection_state] += 1
end
end
end
state_counts
end
def run
timestamp = Time.now.to_i
state_counts = Hash.new(0)
TCP_STATES.each_pair { |_hex, name| state_counts[name] = 0 }
tcp4_pattern = /^\s*\d+:\s+(.{8}):(.{4})\s+(.{8}):(.{4})\s+(.{2})/
state_counts = netstat('tcp', tcp4_pattern, state_counts)
unless config[:disabletcp6]
tcp6_pattern = /^\s*\d+:\s+(.{32}):(.{4})\s+(.{32}):(.{4})\s+(.{2})/
state_counts = netstat('tcp6', tcp6_pattern, state_counts)
end
state_counts.each do |state, count|
graphite_name = config[:port] ? "#{config[:scheme]}.#{config[:port]}.#{state}" :
"#{config[:scheme]}.#{state}"
output graphite_name.to_s, count, timestamp
end
ok
end
end