mirror of
				https://github.com/prometheus/node_exporter.git
				synced 2025-08-20 18:33:52 -07:00 
			
		
		
		
	Add collector for /proc/net/tcp
This commit is contained in:
		
							parent
							
								
									aaf01e52e2
								
							
						
					
					
						commit
						e4da771b21
					
				|  | @ -46,6 +46,7 @@ lastlogin | Exposes the last time there was a login. | ||||||
| megacli | Exposes RAID statistics from MegaCLI. | megacli | Exposes RAID statistics from MegaCLI. | ||||||
| ntp | Exposes time drift from an NTP server. | ntp | Exposes time drift from an NTP server. | ||||||
| runit | Exposes service status from [runit](http://smarden.org/runit/). | runit | Exposes service status from [runit](http://smarden.org/runit/). | ||||||
|  | tcpstat | Exposes TCP connection status information from /proc/net/tcp and /proc/net/tcp6. (Warning: the current version has potential performance issues in high load situations.) | ||||||
| 
 | 
 | ||||||
| ## Textfile Collector | ## Textfile Collector | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								collector/fixtures/tcpstat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								collector/fixtures/tcpstat
									
									
									
									
									
										Normal file
									
								
							|  | @ -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                      | ||||||
							
								
								
									
										150
									
								
								collector/tcpstat.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								collector/tcpstat.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -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" | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								collector/tcpstat_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								collector/tcpstat_test.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -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 a new issue