Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,11 @@ Usage: ./pwru [options] [pcap-filter]
--kernel-btf string specify kernel BTF file
--kmods strings list of kernel modules names to attach to
--output-caller print caller function name
--output-file string write traces to file
--output-file string write traces to file (rotates at 100MB by default)
--output-file-max-size int max size in MB per file before rotation (default 100)
--output-file-max-age int max age in days to keep rotated files (default 0, no limit)
--output-file-max-backups int max number of rotated files to keep (default 0, no limit)
--output-file-compress compress rotated files with gzip (default false)
--output-json output traces in JSON format
--output-limit-lines uint exit the program after the number of events has been received/printed
--output-meta print skb metadata (default true)
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
golang.org/x/net v0.48.0
golang.org/x/sync v0.19.0
golang.org/x/sys v0.40.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,7 @@ golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
rsc.io/c2go v0.0.0-20170620140410-520c22818a08 h1:AAIN5uzUq20OU2cNoPTVljUm7JDaD0Z/+Xl/uMBHJgU=
rsc.io/c2go v0.0.0-20170620140410-520c22818a08/go.mod h1:hE73EMCiJ3lIDPgEDEK781LZrVhFDxT+I+ziQRoLVNE=
40 changes: 30 additions & 10 deletions internal/pwru/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"log/slog"
"net"
"os"
Expand All @@ -26,12 +27,18 @@ import (
"github.com/tklauser/ps"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
"gopkg.in/natefinch/lumberjack.v2"

"github.com/cilium/pwru/internal/byteorder"
)

const absoluteTS string = "15:04:05.000"

type WriteSyncer interface {
io.Writer
Sync() error
}

const (
eventTypeKprobe = iota
eventTypeKprobeMulti
Expand All @@ -49,7 +56,8 @@ type output struct {
addr2name Addr2Name
skbMetadata []*SkbMetadata
xdpMetadata []*SkbMetadata
writer *os.File
writer io.Writer
closer io.Closer
kprobeMulti bool
kfreeReasons map[uint64]string
ifaceCache map[uint64]map[uint32]string
Expand Down Expand Up @@ -97,14 +105,20 @@ func centerAlignString(s string, width int) string {
}

func NewOutput(flags *Flags, printSkbMap, printShinfoMap, printStackMap, printBpfmapMap *ebpf.Map, addr2Name Addr2Name, skbMds, xdpMds []*SkbMetadata, kprobeMulti bool, btfSpec *btf.Spec) (*output, error) {
writer := os.Stdout
var writer io.Writer = os.Stdout
var closer io.Closer

if flags.OutputFile != "" {
file, err := os.Create(flags.OutputFile)
if err != nil {
return nil, err
lj := &lumberjack.Logger{
Filename: flags.OutputFile,
MaxSize: flags.OutputFileMaxSize,
MaxAge: flags.OutputFileMaxAge,
MaxBackups: flags.OutputFileMaxBackups,
Compress: flags.OutputFileCompress,
LocalTime: true,
}
writer = file
writer = lj
closer = lj
}

reasons, err := getKFreeSKBReasons(btfSpec)
Expand All @@ -131,18 +145,24 @@ func NewOutput(flags *Flags, printSkbMap, printShinfoMap, printStackMap, printBp
skbMetadata: skbMds,
xdpMetadata: xdpMds,
writer: writer,
closer: closer,
kprobeMulti: kprobeMulti,
kfreeReasons: reasons,
ifaceCache: ifs,
procCache: map[int]string{},
}, nil
}

func (o *output) Close() {
if o.writer != os.Stdout {
_ = o.writer.Sync()
_ = o.writer.Close()
func (o *output) Close() error {
if o.closer == nil {
return nil
}
if syncer, ok := o.closer.(WriteSyncer); ok {
if err := syncer.Sync(); err != nil {
slog.Warn("Failed to sync output file", "error", err)
}
}
return o.closer.Close()
}

func (o *output) PrintHeader() {
Expand Down
75 changes: 61 additions & 14 deletions internal/pwru/output_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,17 @@
package pwru

import (
"io"
"os"
"path/filepath"
"syscall"
"testing"
)

func BenchmarkOutputPrint(b *testing.B) {
devNull, err := os.OpenFile("/dev/null", os.O_WRONLY, 0)
if err != nil {
b.Fatal(err)
}
defer devNull.Close()
"gopkg.in/natefinch/lumberjack.v2"
)

output := &output{
func newBenchmarkOutput(writer io.Writer) *output {
return &output{
flags: &Flags{
OutputTS: "none",
OutputMeta: true,
Expand All @@ -38,16 +36,18 @@ func BenchmarkOutputPrint(b *testing.B) {
{addr: 0xffffffff81000000, name: "test_function"},
},
},
writer: devNull,
writer: writer,
ifaceCache: map[uint64]map[uint32]string{
4026531840: {1: "lo", 2: "eth0"},
},
procCache: map[int]string{
1234: "test-process:1234",
},
}
}

event := &Event{
func newBenchmarkEvent() *Event {
return &Event{
PID: 1234,
Type: eventTypeKprobe,
Addr: 0xffffffff81000000,
Expand All @@ -72,9 +72,56 @@ func BenchmarkOutputPrint(b *testing.B) {
TCPFlag: 0x12,
},
}
}

b.ResetTimer()
for i := 0; i < b.N; i++ {
output.Print(event)
}
func BenchmarkOutputPrint(b *testing.B) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❯ go test --bench=. ./internal/pwru/
goos: linux
goarch: arm64
pkg: github.com/cilium/pwru/internal/pwru
BenchmarkOutputPrint/DevNull-8         	  723668	      1519 ns/op
BenchmarkOutputPrint/RegularFile-8     	  656631	      1804 ns/op
BenchmarkOutputPrint/Lumberjack-8      	  613897	      1833 ns/op

event := newBenchmarkEvent()

b.Run("DevNull", func(b *testing.B) {
devNull, err := os.OpenFile("/dev/null", os.O_WRONLY, 0)
if err != nil {
b.Fatal(err)
}
defer devNull.Close()

out := newBenchmarkOutput(devNull)
b.ResetTimer()
for i := 0; i < b.N; i++ {
out.Print(event)
}
})

b.Run("RegularFile", func(b *testing.B) {
tmpDir := b.TempDir()
file, err := os.Create(filepath.Join(tmpDir, "bench.log"))
if err != nil {
b.Fatal(err)
}
defer file.Close()

out := newBenchmarkOutput(file)
b.ResetTimer()
for i := 0; i < b.N; i++ {
out.Print(event)
}
})

b.Run("Lumberjack", func(b *testing.B) {
tmpDir := b.TempDir()
lj := &lumberjack.Logger{
Filename: filepath.Join(tmpDir, "bench.log"),
MaxSize: 100,
MaxBackups: 0,
MaxAge: 0,
Compress: false,
LocalTime: true,
}
defer lj.Close()

out := newBenchmarkOutput(lj)
b.ResetTimer()
for i := 0; i < b.N; i++ {
out.Print(event)
}
})
}
38 changes: 23 additions & 15 deletions internal/pwru/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,24 @@ type Flags struct {
FilterSkbExpr string
FilterXdpExpr string

OutputTS string
OutputMeta bool
OutputTuple bool
OutputSkb bool
OutputShinfo bool
OutputStack bool
OutputBpfmap bool
OutputCaller bool
OutputLimitLines uint64
OutputSkbCB bool
OutputFile string
OutputJson bool
OutputTCPFlags bool
OutputTunnel bool
OutputTS string
OutputMeta bool
OutputTuple bool
OutputSkb bool
OutputShinfo bool
OutputStack bool
OutputBpfmap bool
OutputCaller bool
OutputLimitLines uint64
OutputSkbCB bool
OutputFile string
OutputFileMaxSize int
OutputFileMaxBackups int
OutputFileMaxAge int
OutputFileCompress bool
OutputJson bool
OutputTCPFlags bool
OutputTunnel bool

OutputSkbMetadata []string
OutputXdpMetadata []string
Expand Down Expand Up @@ -110,7 +114,11 @@ func (f *Flags) SetFlags() {
flag.BoolVar(&f.OutputTCPFlags, "output-tcp-flags", false, "print TCP flags")
flag.StringSliceVar(&f.OutputSkbMetadata, "output-skb-metadata", nil, fmt.Sprintf("print skb metadata (e.g., \"skb->mark\", \"skb->hash\"), %d at most", maxSkbMetadata))
flag.StringSliceVar(&f.OutputXdpMetadata, "output-xdp-metadata", nil, fmt.Sprintf("print xdp metadata (e.g., \"xdp->rxq->queue_index\"), %d at most", maxSkbMetadata))
flag.StringVar(&f.OutputFile, "output-file", "", "write traces to file")
flag.StringVar(&f.OutputFile, "output-file", "", "write traces to file (rotates at 100MB by default)")
flag.IntVar(&f.OutputFileMaxSize, "output-file-max-size", 100, "max size in MB per file before rotation")
flag.IntVar(&f.OutputFileMaxBackups, "output-file-max-backups", 0, "max number of rotated files to keep (0, no limit)")
flag.IntVar(&f.OutputFileMaxAge, "output-file-max-age", 0, "max age in days to keep rotated files (0, no limit)")
flag.BoolVar(&f.OutputFileCompress, "output-file-compress", false, "compress rotated files with gzip")

flag.BoolVar(&f.OutputJson, "output-json", false, "output traces in JSON format")

Expand Down
6 changes: 5 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,11 @@ func run(flags pwru.Flags) error {
if err != nil {
return fmt.Errorf("Failed to create outputer: %w", err)
}
defer output.Close()
defer func() {
if err := output.Close(); err != nil {
slog.Warn("Failed to close output", "error", err)
}
}()

if !flags.OutputJson {
output.PrintHeader()
Expand Down
23 changes: 23 additions & 0 deletions vendor/gopkg.in/natefinch/lumberjack.v2/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions vendor/gopkg.in/natefinch/lumberjack.v2/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions vendor/gopkg.in/natefinch/lumberjack.v2/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading