Skip to content

Commit 1648e31

Browse files
committed
Implement interval output (closes #1)
1 parent 15ed146 commit 1648e31

File tree

6 files changed

+66
-30
lines changed

6 files changed

+66
-30
lines changed

README.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,16 @@ NAME
3030
pktstat
3131

3232
FLAGS
33-
-?, --help display help
34-
-v, --add_vlan if true, add VLAN header
35-
-j, --json if true, output in JSON format
36-
--version display program version
37-
-s, --snaplen INT snaplen (if <= 0 uses 65535) (default: 0)
38-
-b, --bufsize INT interface buffersize in MB (default: 8)
39-
-f, --filter STRING BPF filter
40-
-i, --iface STRING interface to read from (default: any)
41-
-t, --timeout DURATION timeout for packet capture (default: 0s)
33+
-?, --help display help
34+
-v, --add_vlan if true, add VLAN header
35+
-j, --json if true, output in JSON format
36+
--version display program version
37+
-s, --snaplen INT snaplen (if <= 0 uses 65535) (default: 0)
38+
-b, --bufsize INT interface buffersize in MB (default: 8)
39+
-f, --filter STRING BPF filter
40+
-i, --iface STRING interface to read from (default: en0)
41+
-t, --timeout DURATION timeout for packet capture (default: 10m0s)
42+
-l, --interval DURATION interval between packet capture output (default: 0s)
4243
```
4344
4445
By default pktstat listens to all interfaces without any BPF filter. It is possible to specify interface with `--iface` and specify a BPF filter either including or excluding needed traffic, for instance `--filter "not port 22"`.
@@ -47,6 +48,8 @@ Timeout `--timeout` will stop execution after a specified time, but it is also p
4748
4849
With `--json` it is possible to get traffic statistics in JSON format.
4950
51+
Interval `--interval` when it is greater than zero (and less than timeout duration) will make program output statistics for every such duration until program exit.
52+
5053
## Star History
5154
5255
[![Star History Chart](https://api.star-history.com/svg?repos=dkorunic/pktstat,dkorunic/pktstat-bpf&type=Date)](https://star-history.com/#dkorunic/pktstat&dkorunic/pktstat-bpf&Date)

flags.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ var (
4242
iface, filter *string
4343
snaplen, bufferSize *int
4444
addVLAN, version, help, jsonOutput *bool
45-
timeout *time.Duration
45+
timeout, interval *time.Duration
4646
)
4747

4848
func parseFags() {
@@ -61,6 +61,7 @@ func parseFags() {
6161
iface = fs.String('i', "iface", findFirstEtherIface(), "interface to read from")
6262

6363
timeout = fs.Duration('t', "timeout", defaultTimeout, "timeout for packet capture")
64+
interval = fs.Duration('l', "interval", 0, "interval between packet capture output")
6465

6566
var err error
6667

@@ -86,4 +87,8 @@ func parseFags() {
8687
if *snaplen <= 0 {
8788
*snaplen = 65535
8889
}
90+
91+
if *timeout > 0 && *interval > 0 && *interval >= *timeout {
92+
*interval = 0
93+
}
8994
}

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ go 1.24
55
toolchain go1.24.0
66

77
require (
8-
github.com/KimMachineGun/automemlimit v0.7.2
8+
github.com/KimMachineGun/automemlimit v0.7.4
99
github.com/goccy/go-json v0.10.5
1010
github.com/google/gopacket v1.1.19
1111
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b
1212
github.com/peterbourgon/ff/v4 v4.0.0-alpha.4
1313
go.uber.org/automaxprocs v1.6.0
14-
golang.org/x/net v0.41.0
14+
golang.org/x/net v0.42.0
1515
)
1616

1717
require (
1818
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
1919
github.com/stretchr/testify v1.8.4 // indirect
20-
golang.org/x/sys v0.33.0 // indirect
20+
golang.org/x/sys v0.34.0 // indirect
2121
)

go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
github.com/KimMachineGun/automemlimit v0.7.2 h1:DyfHI7zLWmZPn2Wqdy2AgTiUvrGPmnYWgwhHXtAegX4=
2-
github.com/KimMachineGun/automemlimit v0.7.2/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
1+
github.com/KimMachineGun/automemlimit v0.7.4 h1:UY7QYOIfrr3wjjOAqahFmC3IaQCLWvur9nmfIn6LnWk=
2+
github.com/KimMachineGun/automemlimit v0.7.4/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
33
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
44
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
55
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
@@ -28,13 +28,13 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPI
2828
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
2929
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
3030
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
31-
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
32-
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
31+
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
32+
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
3333
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
3434
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
3535
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
36-
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
37-
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
36+
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
37+
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
3838
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
3939
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
4040
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

main.go

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,16 @@ func main() {
124124
signalCh := make(chan os.Signal, 1)
125125
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
126126

127-
go func() {
128-
s := <-signalCh
129-
fmt.Fprintf(os.Stderr, "Received %v signal, trying to exit...\n", s)
130-
cancel()
131-
close(statCh)
132-
}()
127+
go func(ctx context.Context) {
128+
select {
129+
case <-ctx.Done():
130+
return
131+
case s := <-signalCh:
132+
fmt.Fprintf(os.Stderr, "Received %v signal, trying to exit...\n", s)
133+
cancel()
134+
close(statCh)
135+
}
136+
}(c1)
133137

134138
if *timeout > 0 {
135139
go func() {
@@ -139,11 +143,21 @@ func main() {
139143
}()
140144
}
141145

146+
if *interval > 0 {
147+
go func(ctx context.Context) {
148+
for {
149+
select {
150+
case <-ctx.Done():
151+
return
152+
default:
153+
time.Sleep(*interval)
154+
outputStats(startTime, statMap, totalPackets, totalBytes)
155+
}
156+
}
157+
}(c1)
158+
}
159+
142160
wg.Wait()
143161

144-
if *jsonOutput {
145-
outputJSON(startTime, statMap, totalPackets, totalBytes)
146-
} else {
147-
outputPlain(startTime, statMap, totalPackets, totalBytes)
148-
}
162+
outputStats(startTime, statMap, totalPackets, totalBytes)
149163
}

output.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,17 @@ func (s *statJSON) MarshalJSON() ([]byte, error) {
126126
Proto: s.Proto.String(),
127127
})
128128
}
129+
130+
// outputStats outputs the collected statistics in either plain text or JSON format.
131+
//
132+
// startTime: the start time of the statistics collection.
133+
// statMap: a map containing statistical data.
134+
// totalPackets: total number of packets.
135+
// totalBytes: total number of bytes.
136+
func outputStats(startTime time.Time, statMap StatMap, totalPackets uint64, totalBytes uint64) {
137+
if *jsonOutput {
138+
outputJSON(startTime, statMap, totalPackets, totalBytes)
139+
} else {
140+
outputPlain(startTime, statMap, totalPackets, totalBytes)
141+
}
142+
}

0 commit comments

Comments
 (0)