parent
aaf01e52e2
commit
e4da771b21
@ -0,0 +1,3 @@ |
||||
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode |
||||
0: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 2740 1 ffff88003d3af3c0 100 0 0 10 0 |
||||
1: 0F02000A:0016 0202000A:8B6B 01 00000000:00000000 02:000AC99B 00000000 0 0 3652 4 ffff88003d3ae040 21 4 31 47 46 |
||||
@ -0,0 +1,150 @@ |
||||
// +build !notcpstat
|
||||
|
||||
package collector |
||||
|
||||
import ( |
||||
"bufio" |
||||
"fmt" |
||||
"io" |
||||
"os" |
||||
"strconv" |
||||
"strings" |
||||
|
||||
"github.com/prometheus/client_golang/prometheus" |
||||
) |
||||
|
||||
const ( |
||||
procTCPStat = "/proc/net/tcp" |
||||
procTCP6Stat = "/proc/net/tcp6" |
||||
) |
||||
|
||||
type TCPConnectionState int |
||||
|
||||
const ( |
||||
TCP_ESTABLISHED TCPConnectionState = iota + 1 |
||||
TCP_SYN_SENT |
||||
TCP_SYN_RECV |
||||
TCP_FIN_WAIT1 |
||||
TCP_FIN_WAIT2 |
||||
TCP_TIME_WAIT |
||||
TCP_CLOSE |
||||
TCP_CLOSE_WAIT |
||||
TCP_LAST_ACK |
||||
TCP_LISTEN |
||||
TCP_CLOSING |
||||
) |
||||
|
||||
type tcpStatCollector struct { |
||||
config Config |
||||
metric *prometheus.GaugeVec |
||||
} |
||||
|
||||
func init() { |
||||
Factories["tcpstat"] = NewTCPStatCollector |
||||
} |
||||
|
||||
// NewTCPStatCollector takes a config struct and returns
|
||||
// a new Collector exposing network stats.
|
||||
func NewTCPStatCollector(config Config) (Collector, error) { |
||||
return &tcpStatCollector{ |
||||
config: config, |
||||
metric: prometheus.NewGaugeVec( |
||||
prometheus.GaugeOpts{ |
||||
Namespace: Namespace, |
||||
Name: "tcp_connection_states", |
||||
Help: "Number of connection states.", |
||||
}, |
||||
[]string{"state"}, |
||||
), |
||||
}, nil |
||||
} |
||||
|
||||
func (c *tcpStatCollector) Update(ch chan<- prometheus.Metric) (err error) { |
||||
tcpStats, err := getTCPStats(procTCPStat) |
||||
if err != nil { |
||||
return fmt.Errorf("couldn't get tcpstats: %s", err) |
||||
} |
||||
|
||||
// if enabled ipv6 system
|
||||
if _, hasIPv6 := os.Stat(procTCP6Stat); hasIPv6 == nil { |
||||
tcp6Stats, err := getTCPStats(procTCP6Stat) |
||||
if err != nil { |
||||
return fmt.Errorf("couldn't get tcp6stats: %s", err) |
||||
} |
||||
|
||||
for st, value := range tcp6Stats { |
||||
tcpStats[st] += value |
||||
} |
||||
} |
||||
|
||||
for st, value := range tcpStats { |
||||
c.metric.WithLabelValues(st.String()).Set(value) |
||||
} |
||||
|
||||
c.metric.Collect(ch) |
||||
return err |
||||
} |
||||
|
||||
func getTCPStats(statsFile string) (map[TCPConnectionState]float64, error) { |
||||
file, err := os.Open(statsFile) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
defer file.Close() |
||||
|
||||
return parseTCPStats(file) |
||||
} |
||||
|
||||
func parseTCPStats(r io.Reader) (map[TCPConnectionState]float64, error) { |
||||
var ( |
||||
tcpStats = map[TCPConnectionState]float64{} |
||||
scanner = bufio.NewScanner(r) |
||||
) |
||||
|
||||
for scanner.Scan() { |
||||
parts := strings.Fields(scanner.Text()) |
||||
if len(parts) == 0 { |
||||
continue |
||||
} |
||||
if strings.HasPrefix(parts[0], "sl") { |
||||
continue |
||||
} |
||||
st, err := strconv.ParseInt(parts[3], 16, 8) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
tcpStats[TCPConnectionState(st)]++ |
||||
} |
||||
|
||||
return tcpStats, nil |
||||
} |
||||
|
||||
func (st TCPConnectionState) String() string { |
||||
switch st { |
||||
case TCP_ESTABLISHED: |
||||
return "established" |
||||
case TCP_SYN_SENT: |
||||
return "syn_sent" |
||||
case TCP_SYN_RECV: |
||||
return "syn_recv" |
||||
case TCP_FIN_WAIT1: |
||||
return "fin_wait1" |
||||
case TCP_FIN_WAIT2: |
||||
return "fin_wait2" |
||||
case TCP_TIME_WAIT: |
||||
return "time_wait" |
||||
case TCP_CLOSE: |
||||
return "close" |
||||
case TCP_CLOSE_WAIT: |
||||
return "close_wait" |
||||
case TCP_LAST_ACK: |
||||
return "last_ack" |
||||
case TCP_LISTEN: |
||||
return "listen" |
||||
case TCP_CLOSING: |
||||
return "closing" |
||||
default: |
||||
return "unknown" |
||||
} |
||||
} |
||||
@ -0,0 +1,27 @@ |
||||
package collector |
||||
|
||||
import ( |
||||
"os" |
||||
"testing" |
||||
) |
||||
|
||||
func TestTCPStat(t *testing.T) { |
||||
file, err := os.Open("fixtures/tcpstat") |
||||
if err != nil { |
||||
t.Fatal(err) |
||||
} |
||||
defer file.Close() |
||||
|
||||
tcpStats, err := parseTCPStats(file) |
||||
if err != nil { |
||||
t.Fatal(err) |
||||
} |
||||
|
||||
if want, got := 1, int(tcpStats[TCP_ESTABLISHED]); want != got { |
||||
t.Errorf("want tcpstat number of established state %d, got %d", want, got) |
||||
} |
||||
|
||||
if want, got := 1, int(tcpStats[TCP_LISTEN]); want != got { |
||||
t.Errorf("want tcpstat number of listen state %d, got %d", want, got) |
||||
} |
||||
} |
||||
Loading…
Reference in new issue