Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: socketstat input plugin #3649

Merged
merged 127 commits into from
Dec 22, 2021
Merged
Show file tree
Hide file tree
Changes from 117 commits
Commits
Show all changes
127 commits
Select commit Hold shift + click to select a range
38a4921
WIP for socketstat input plugin
sajoupa Nov 7, 2017
c92a946
Merge branch 'master' of https://github.com/influxdb/telegraf into so…
sajoupa Nov 7, 2017
21b84c7
socketstat plugin working with tcp and udp, README update. Needs unit…
sajoupa Nov 14, 2017
459231d
socketstat: add support for sctp, dtcp, raw, unix... and factorize code
sajoupa Nov 28, 2017
eb27dac
Merge branch 'master' of https://github.com/influxdb/telegraf into so…
sajoupa Nov 28, 2017
569be61
add unit tests, README updates and gofmt run
sajoupa Jan 1, 2018
6a246c0
Merge branch 'master' of https://github.com/influxdb/telegraf into so…
sajoupa Jan 9, 2018
a28526b
Comments and rewordings, update test data. Passes 'make test'.
sajoupa Jan 9, 2018
d49f375
Merge branch 'master' of https://github.com/influxdb/telegraf into so…
sajoupa Jan 9, 2018
f497e8d
Merge branch 'socketstat' of /home/sajoupa/git/dev/telegraf into sock…
sajoupa Jan 9, 2018
fdb13a4
gofmt run
sajoupa Jan 9, 2018
357d8c3
Merge branch 'master' of https://github.com/influxdata/telegraf into …
sajoupa Jan 23, 2018
cf7f6e8
socketstat plugin: Add warning about data cardinality in README
sajoupa Jan 30, 2018
a242634
Merge branch 'master' of https://github.com/influxdata/telegraf into …
sajoupa Jan 30, 2018
74b777e
rework socketstat plugin with remarks from ipset PR (WIP)
sajoupa Feb 2, 2018
76b380b
Merge branch 'master' of https://github.com/influxdata/telegraf into …
sajoupa Feb 13, 2018
3d7669f
Merge branch 'socketstat' of github.com:sajoupa/telegraf into socketstat
sajoupa Feb 13, 2018
44b70f4
Merge branch 'master' of https://github.com/influxdata/telegraf into …
sajoupa Feb 13, 2018
ae57878
Merge branch 'socketstat' of github.com:sajoupa/telegraf into socketstat
sajoupa Feb 13, 2018
2c8a087
start updating sockestat tests (WIP)
sajoupa Feb 13, 2018
8e6b40d
Merge branch 'socketstat' of github.com:sajoupa/telegraf into socketstat
sajoupa Feb 13, 2018
9cb5b33
socketstat test: small fixes
sajoupa Feb 13, 2018
3a981af
socketstat: misc fixes
sajoupa Feb 13, 2018
49b1808
socketstat input plugin: gofmt fixes
sajoupa Feb 13, 2018
4ceb8bb
Merge branch 'master' of https://github.com/influxdata/telegraf into …
sajoupa Jul 12, 2018
2f70f93
Merge branch 'master' of https://github.com/influxdata/telegraf into …
sajoupa Aug 19, 2018
7fbebcc
Merge branch 'master' of https://github.com/influxdata/telegraf into …
sajoupa Sep 11, 2018
9459b94
Merge branch 'master' of github.com:influxdata/telegraf into socketstat
sajoupa Nov 27, 2020
d89a764
socketstat: README updates, small code improvements, add config snipp…
sajoupa Nov 27, 2020
258f826
Merge branch 'master' of github.com:influxdata/telegraf into socketstat
sajoupa Dec 3, 2021
a197586
Merge branch 'master' of github.com:influxdata/telegraf into socketstat
sajoupa Dec 4, 2021
7ade521
revert changes to telegraf.conf (they'll be auto-generated at release…
sajoupa Dec 4, 2021
dd97878
socketstat: handle initialization login in an Init() function, update…
sajoupa Dec 4, 2021
2421436
socketstat: tabs/spaces fix
sajoupa Dec 4, 2021
21f2291
socketstat: improve comments, fix formatting
sajoupa Dec 4, 2021
155b9a5
socketstat: remove an unneeded case handling and fix an error catchin…
sajoupa Dec 4, 2021
3651e83
socketstat: fix regexp for lines starting with whitespace (following …
sajoupa Dec 4, 2021
e96b4d5
Merge branch 'master' of github.com:influxdata/telegraf into socketstat
sajoupa Dec 7, 2021
d02eecf
socketstat: reorder Struct items, add toml-tags and make all possible…
sajoupa Dec 7, 2021
01881dc
Merge branch 'socketstat' of github.com:sajoupa/telegraf into socketstat
sajoupa Dec 7, 2021
aa64386
socketstat: rename the 'socket_proto' config item to 'protocols'
sajoupa Dec 7, 2021
5d6cb59
socketstat: rename variable following previous commit, and move input…
sajoupa Dec 7, 2021
39d4005
socketstat: fix a log message
sajoupa Dec 7, 2021
3946e7d
socketstat: variable renaming for more clarity
sajoupa Dec 7, 2021
9b454c8
Merge branch 'socketstat' of github.com:sajoupa/telegraf into socketstat
sajoupa Dec 7, 2021
b3a56a4
socketstat: make failures to read send_q and recv_q warning instead o…
sajoupa Dec 12, 2021
3956c9e
socketstat: only move lister = socketList out of init(), to keep inpu…
sajoupa Dec 12, 2021
dc3c3ec
socketstat: small code simplification
sajoupa Dec 12, 2021
89aafff
socketstat: move testdata to a dedicated file, and drive-by indentati…
sajoupa Dec 13, 2021
c0df468
socketstat: gofmt fixes
sajoupa Dec 13, 2021
98bce79
socketstat: fixes in README for superlinter
sajoupa Dec 13, 2021
f64385f
warning update in plugins/inputs/socketstat/README.md
sajoupa Dec 14, 2021
6d4595a
socketstat: small code simplification in socketstat_test.go
sajoupa Dec 20, 2021
b0c99c0
socketstat: in tests, replace reflect.DeepEqual with require.Equal (a…
sajoupa Dec 20, 2021
5b14fdb
socketstat: move only testdata from `ss` output to dedicated files
sajoupa Dec 20, 2021
7d9f949
Merge branch 'master' of github.com:influxdata/telegraf into socketstat
sajoupa Dec 20, 2021
b28d021
socketstat input plugin: small indentation fix
sajoupa Dec 21, 2021
276374a
socketstat input plugin: set the lister unconditionally, and modify i…
sajoupa Dec 21, 2021
f506fbe
Merge branch 'socketstat' of github.com:sajoupa/telegraf into socketstat
sajoupa Dec 21, 2021
23c1e9e
socketstat input plugin: make "measurement" a const
sajoupa Dec 21, 2021
addf4d7
socketstat input plugin: replace a manual test with a require.Equalf
sajoupa Dec 21, 2021
35d23e0
socketstat input plugin: make fmt fixes
sajoupa Dec 21, 2021
eb948aa
WIP for socketstat input plugin
sajoupa Nov 7, 2017
05b9758
socketstat plugin working with tcp and udp, README update. Needs unit…
sajoupa Nov 14, 2017
fd615d7
socketstat: add support for sctp, dtcp, raw, unix... and factorize code
sajoupa Nov 28, 2017
39e6e74
add unit tests, README updates and gofmt run
sajoupa Jan 1, 2018
8513c86
Comments and rewordings, update test data. Passes 'make test'.
sajoupa Jan 9, 2018
ddfd744
gofmt run
sajoupa Jan 9, 2018
70ff228
socketstat plugin: Add warning about data cardinality in README
sajoupa Jan 30, 2018
c36e433
start updating sockestat tests (WIP)
sajoupa Feb 13, 2018
e88e72d
rework socketstat plugin with remarks from ipset PR (WIP)
sajoupa Feb 2, 2018
2bd4c04
socketstat test: small fixes
sajoupa Feb 13, 2018
e923988
socketstat: misc fixes
sajoupa Feb 13, 2018
ae65f0e
socketstat input plugin: gofmt fixes
sajoupa Feb 13, 2018
c40da1b
socketstat: README updates, small code improvements, add config snipp…
sajoupa Nov 27, 2020
1076c6e
socketstat: handle initialization login in an Init() function, update…
sajoupa Dec 4, 2021
eb7fa8c
socketstat: tabs/spaces fix
sajoupa Dec 4, 2021
2305a2e
socketstat: improve comments, fix formatting
sajoupa Dec 4, 2021
dc567f4
socketstat: remove an unneeded case handling and fix an error catchin…
sajoupa Dec 4, 2021
acbe944
socketstat: fix regexp for lines starting with whitespace (following …
sajoupa Dec 4, 2021
3107fbb
socketstat: reorder Struct items, add toml-tags and make all possible…
sajoupa Dec 7, 2021
8f25e86
socketstat: rename the 'socket_proto' config item to 'protocols'
sajoupa Dec 7, 2021
bd9da99
socketstat: rename variable following previous commit, and move input…
sajoupa Dec 7, 2021
579d54f
socketstat: variable renaming for more clarity
sajoupa Dec 7, 2021
a1b16e4
socketstat: fix a log message
sajoupa Dec 7, 2021
86dd548
socketstat: make failures to read send_q and recv_q warning instead o…
sajoupa Dec 12, 2021
104572f
socketstat: only move lister = socketList out of init(), to keep inpu…
sajoupa Dec 12, 2021
132e004
socketstat: small code simplification
sajoupa Dec 12, 2021
5727bf7
socketstat: move testdata to a dedicated file, and drive-by indentati…
sajoupa Dec 13, 2021
c7acec9
socketstat: gofmt fixes
sajoupa Dec 13, 2021
63d305a
socketstat: fixes in README for superlinter
sajoupa Dec 13, 2021
ff2c796
warning update in plugins/inputs/socketstat/README.md
sajoupa Dec 14, 2021
8bd2157
socketstat: small code simplification in socketstat_test.go
sajoupa Dec 20, 2021
31037c5
socketstat: in tests, replace reflect.DeepEqual with require.Equal (a…
sajoupa Dec 20, 2021
44fd1f0
socketstat: move only testdata from `ss` output to dedicated files
sajoupa Dec 20, 2021
0d24922
socketstat input plugin: set the lister unconditionally, and modify i…
sajoupa Dec 21, 2021
953d283
socketstat input plugin: small indentation fix
sajoupa Dec 21, 2021
651a631
socketstat input plugin: make "measurement" a const
sajoupa Dec 21, 2021
bb6a8d4
socketstat input plugin: replace a manual test with a require.Equalf
sajoupa Dec 21, 2021
54222cb
socketstat input plugin: make fmt fixes
sajoupa Dec 21, 2021
e65f52a
Merge branch 'influxdata:master' into socketstat
sajoupa Dec 21, 2021
c7fee91
Merge branch 'socketstat' of github.com:sajoupa/telegraf into socketstat
sajoupa Dec 21, 2021
33cf0b7
socketstat input plugin: remove duplicate entry in all.go
sajoupa Dec 21, 2021
bd6f1e7
socketstat input plugin: don't error during tests if `ss` isn't insta…
sajoupa Dec 21, 2021
31bdaaa
socketstat input plugin: small go fmt fix
sajoupa Dec 21, 2021
9cadf61
Merge branch 'master' of github.com:influxdata/telegraf into socketstat
sajoupa Dec 21, 2021
772944b
socketstat input plugin: small code readability improvement
sajoupa Dec 21, 2021
7bf18b5
socketstat input plugin: small code optimization
sajoupa Dec 21, 2021
af1d04f
Merge branch 'socketstat' of github.com:sajoupa/telegraf into socketstat
sajoupa Dec 21, 2021
c79db78
socketstat input plugin: display the error if recv_q and send_q could…
sajoupa Dec 21, 2021
276e1c3
socketstat input plugin: allow disabling the execution timeout
sajoupa Dec 22, 2021
8957bc3
socketstat input plugin: simplify one of the tests
sajoupa Dec 22, 2021
38b1298
socketstat input plugin: be more strict in testing errors
sajoupa Dec 22, 2021
3610d8a
socketstat input plugin: fix defautl timeout setting, and lister erro…
sajoupa Dec 22, 2021
cf6b6da
socketstat input plugin: variable renaming for golangci-lint
sajoupa Dec 22, 2021
c5f82b5
socketstat input plugin: small variable name fix
sajoupa Dec 22, 2021
46dfa2f
Merge branch 'master' of github.com:influxdata/telegraf into socketstat
sajoupa Dec 22, 2021
7e3ebdb
socketstat input plugin: use Log.Warn instead of Warnf where relevant
sajoupa Dec 22, 2021
0ae3695
socketstat input plugin: rename a variable for more consistency
sajoupa Dec 22, 2021
7ac8acb
socketstat input plugin: change the return type of parseAndGather, wh…
sajoupa Dec 22, 2021
c8abe68
socketstat input plugin: small code simplification
sajoupa Dec 22, 2021
cea3533
socketstat input plugin: don't set recv_q or send_q if there was an e…
sajoupa Dec 22, 2021
ca22aa1
socketstat input plugin: fix test when `ss` isn't installed
sajoupa Dec 22, 2021
9a4a22a
Merge branch 'master' of github.com:influxdata/telegraf into socketstat
sajoupa Dec 22, 2021
46a9b95
Merge branch 'socketstat' of github.com:sajoupa/telegraf into socketstat
sajoupa Dec 22, 2021
6a8290d
socketstat input plugin: in Init(), test if `ss` is available last, b…
sajoupa Dec 22, 2021
6c73dd3
socketstat input plugin: don't build for windows
sajoupa Dec 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions plugins/inputs/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ import (
_ "github.com/influxdata/telegraf/plugins/inputs/snmp_legacy"
_ "github.com/influxdata/telegraf/plugins/inputs/snmp_trap"
_ "github.com/influxdata/telegraf/plugins/inputs/socket_listener"
_ "github.com/influxdata/telegraf/plugins/inputs/socketstat"
_ "github.com/influxdata/telegraf/plugins/inputs/solr"
_ "github.com/influxdata/telegraf/plugins/inputs/sql"
_ "github.com/influxdata/telegraf/plugins/inputs/sqlserver"
Expand Down
55 changes: 55 additions & 0 deletions plugins/inputs/socketstat/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# SocketStat plugin

The socketstat plugin gathers indicators from established connections, using iproute2's `ss` command.

The `ss` command does not require specific privileges.

**WARNING: The output format will produce series with very high cardinality.** You should either store those by an engine which doesn't suffer from it, use a short retention policy or do appropriate filtering.

## Configuration

```toml
[[inputs.socketstat]]
## ss can display information about tcp, udp, raw, unix, packet, dccp and sctp sockets
## Specify here the types you want to gather
socket_types = [ "tcp", "udp" ]
## The default timeout of 1s for ss execution can be overridden here:
# timeout = "1s"
```

## Measurements & Fields

- socketstat
- state (string) (for tcp, dccp and sctp protocols)
- If ss provides it (it depends on the protocol and ss version):
- bytes_acked (integer, bytes)
- bytes_received (integer, bytes)
- segs_out (integer, count)
- segs_in (integer, count)
- data_segs_out (integer, count)
- data_segs_in (integer, count)

## Tags

- All measurements have the following tags:
- proto
- local_addr
- local_port
- remote_addr
- remote_port

## Example Output

### recent ss version (iproute2 4.3.0 here)

```sh
./telegraf --config telegraf.conf --input-filter socketstat --test
> socketstat,host=ubuntu-xenial,local_addr=10.6.231.226,local_port=42716,proto=tcp,remote_addr=192.168.2.21,remote_port=80 bytes_acked=184i,bytes_received=2624519595i,recv_q=4344i,segs_in=1812580i,segs_out=661642i,send_q=0i,state="ESTAB" 1606457205000000000
```

### older ss version (iproute2 3.12.0 here)

```sh
./telegraf --config telegraf.conf --input-filter socketstat --test
> socketstat,host=ubuntu-trusty,local_addr=10.6.231.163,local_port=35890,proto=tcp,remote_addr=192.168.2.21,remote_port=80 recv_q=0i,send_q=0i,state="ESTAB" 1606456977000000000
```
216 changes: 216 additions & 0 deletions plugins/inputs/socketstat/socketstat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package socketstat

import (
"bufio"
"bytes"
"fmt"
"os/exec"
"regexp"
"strconv"
"strings"
"time"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/inputs"
)

const measurement = "socketstat"

// Socketstat is a telegraf plugin to gather indicators from established connections, using iproute2's `ss` command.
type Socketstat struct {
SocketProto []string `toml:"protocols"`
Timeout config.Duration `toml:"timeout"`
Log telegraf.Logger `toml:"-"`

isNewConnection *regexp.Regexp
validValues *regexp.Regexp
cmdName string
lister socketLister
}

type socketLister func(cmdName string, proto string, timeout config.Duration) (*bytes.Buffer, error)

// Description returns a short description of the plugin
func (ss *Socketstat) Description() string {
return "Gather indicators from established connections, using iproute2's `ss` command."
}

// SampleConfig returns sample configuration options
func (ss *Socketstat) SampleConfig() string {
return `
## ss can display information about tcp, udp, raw, unix, packet, dccp and sctp sockets
## List of protocol types to collect
# protocols = [ "tcp", "udp" ]
## The default timeout of 1s for ss execution can be overridden here:
# timeout = "1s"
`
}

// Gather gathers indicators from established connections
func (ss *Socketstat) Gather(acc telegraf.Accumulator) error {
// best effort : we continue through the protocols even if an error is encountered,
// but we keep track of the last error.
for _, proto := range ss.SocketProto {
out, e := ss.lister(ss.cmdName, proto, ss.Timeout)
if e != nil {
acc.AddError(e)
continue
}
e = ss.parseAndGather(acc, out, proto)
if e != nil {
acc.AddError(e)
continue
}
sajoupa marked this conversation as resolved.
Show resolved Hide resolved
}
return nil
}

func socketList(cmdName string, proto string, timeout config.Duration) (*bytes.Buffer, error) {
// Run ss for the given protocol, return the output as bytes.Buffer
args := []string{"-in", "--" + proto}
cmd := exec.Command(cmdName, args...)
var out bytes.Buffer
cmd.Stdout = &out
err := internal.RunTimeout(cmd, time.Duration(timeout))
if err != nil {
return &out, fmt.Errorf("error running ss -in --%s: %v", proto, err)
}
return &out, nil
}

func (ss *Socketstat) parseAndGather(acc telegraf.Accumulator, data *bytes.Buffer, proto string) error {
sajoupa marked this conversation as resolved.
Show resolved Hide resolved
scanner := bufio.NewScanner(data)
tags := map[string]string{}
fields := make(map[string]interface{})

// ss output can have blank lines, and/or socket basic info lines and more advanced
// statistics lines, in turns.
// In all non-empty lines, we can have metrics, so we need to group those relevant to
// the same connection.
// To achieve this, we're using the flushData variable which indicates if we should add
// a new measurement or postpone it to a later line.

// The first line is only headers
scanner.Scan()

flushData := false
for scanner.Scan() {
line := scanner.Text()
if line == "" {
continue
}
words := strings.Fields(line)

if ss.isNewConnection.MatchString(line) {
// A line with starting whitespace means metrics about the current connection.
// We should never get 2 consecutive such lines. If we do, log a warning and in
// a best effort, extend the metrics from the 1st line with the metrics of the 2nd
// one, possibly overwriting.
for _, word := range words {
if !ss.validValues.MatchString(word) {
continue
}
// kv will have 2 fields because it matched the regexp
kv := strings.Split(word, ":")
v, err := strconv.ParseUint(kv[1], 10, 64)
if err != nil {
ss.Log.Infof("Couldn't parse metric %q: %v", word, err)
continue
}
fields[kv[0]] = v
}
if !flushData {
ss.Log.Warnf("Found orphaned metrics: %s", words)
ss.Log.Warnf("Added them to the last known connection.")
sajoupa marked this conversation as resolved.
Show resolved Hide resolved
}
acc.AddFields(measurement, fields, tags)
flushData = false
continue
}
// A line with no starting whitespace means we're going to parse a new connection.
// Flush what we gathered about the previous one, if any.
if flushData {
acc.AddFields(measurement, fields, tags)
}

// Delegate the real parsing to getTagsAndState, which manages various
// formats depending on the protocol.
tags, fields = getTagsAndState(proto, words, ss.Log)

// This line containted metrics, so record that.
flushData = true
}
if flushData {
acc.AddFields(measurement, fields, tags)
}
return nil
}

func getTagsAndState(proto string, words []string, log telegraf.Logger) (map[string]string, map[string]interface{}) {
tags := map[string]string{}
fields := make(map[string]interface{})
tags["proto"] = proto
sajoupa marked this conversation as resolved.
Show resolved Hide resolved
switch proto {
case "udp", "raw":
words = append([]string{"dummy"}, words...)
case "tcp", "dccp", "sctp":
fields["state"] = words[0]
}
switch proto {
case "tcp", "udp", "raw", "dccp", "sctp":
// Local and remote addresses are fields 3 and 4
// Separate addresses and ports with the last ':'
localIndex := strings.LastIndex(words[3], ":")
remoteIndex := strings.LastIndex(words[4], ":")
tags["local_addr"] = words[3][:localIndex]
tags["local_port"] = words[3][localIndex+1:]
tags["remote_addr"] = words[4][:remoteIndex]
tags["remote_port"] = words[4][remoteIndex+1:]
case "unix", "packet":
fields["netid"] = words[0]
tags["local_addr"] = words[4]
tags["local_port"] = words[5]
tags["remote_addr"] = words[6]
tags["remote_port"] = words[7]
}
sajoupa marked this conversation as resolved.
Show resolved Hide resolved
var err error
fields["recv_q"], err = strconv.ParseUint(words[1], 10, 64)
sajoupa marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
log.Warnf("Couldn't read recv_q in %q: %v", words, err)
}
fields["send_q"], err = strconv.ParseUint(words[2], 10, 64)
if err != nil {
log.Warnf("Couldn't read send_q in %q: %v", words, err)
}
sajoupa marked this conversation as resolved.
Show resolved Hide resolved
return tags, fields
}

func (ss *Socketstat) Init() error {
if len(ss.SocketProto) == 0 {
ss.SocketProto = []string{"tcp", "udp"}
}

// Check that ss is installed, get its path
ssPath, err := exec.LookPath("ss")
if err != nil {
return err
}
ss.cmdName = ssPath

// Initialize regexps to validate input data
validFields := "(bytes_acked|bytes_received|segs_out|segs_in|data_segs_in|data_segs_out)"
ss.validValues = regexp.MustCompile("^" + validFields + ":[0-9]+$")
ss.isNewConnection = regexp.MustCompile(`^\s+.*$`)

ss.lister = socketList

return nil
}

func init() {
inputs.Add("socketstat", func() telegraf.Input {
return &Socketstat{Timeout: config.Duration(time.Second)}
})
}