Skip to content

Commit

Permalink
tetra: add stack traces human output to compact mode
Browse files Browse the repository at this point in the history
It looks similar to this with the new stack trace encoder:
syscall  /usr/bin/curl kfree_skb_reason
  0xffffbcdee5bf4840: skb_release_head_state+0x110
  0xffffbcdee5be3678: __sys_connect_file+0x88
  0xffffbcdee5be376c: __sys_connect+0xbc
  0xffffbcdee5be37bc: __arm64_sys_connect+0x28
  0xffffbcdee4dfcd68: invoke_syscall+0x78
  0xffffbcdee4dfcf70: el0_svc_common.constprop.0+0x180
  0xffffbcdee4dfcfa4: do_el0_svc+0x30
  0xffffbcdee5e861e8: el0_svc+0x48
  0xffffbcdee5e881b4: el0t_64_sync_handler+0xa4
  0xffffbcdee4de1e38: el0t_64_sync+0x1a4

Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
  • Loading branch information
mtardy committed Sep 5, 2023
1 parent fec71d4 commit 60bd1a7
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 22 deletions.
8 changes: 5 additions & 3 deletions cmd/tetra/getevents/getevents.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,18 @@ type Opts struct {
Host bool
Timestamps bool
TTYEncode string
StackTraces bool
}

var Options Opts

// GetEncoder returns an encoder for an event stream based on configuration options.
var GetEncoder = func(w io.Writer, colorMode encoder.ColorMode, timestamps bool, compact bool, tty string) encoder.EventEncoder {
var GetEncoder = func(w io.Writer, colorMode encoder.ColorMode, timestamps bool, compact bool, tty string, stackTraces bool) encoder.EventEncoder {
if tty != "" {
return encoder.NewTtyEncoder(w, tty)
}
if compact {
return encoder.NewCompactEncoder(w, colorMode, timestamps)
return encoder.NewCompactEncoder(w, colorMode, timestamps, stackTraces)
}
return encoder.NewProtojsonEncoder(w)
}
Expand Down Expand Up @@ -123,7 +124,7 @@ func getEvents(ctx context.Context, client tetragon.FineGuidanceSensorsClient) {
if err != nil {
logger.GetLogger().WithError(err).Fatal("Failed to call GetEvents")
}
eventEncoder := GetEncoder(os.Stdout, encoder.ColorMode(Options.Color), Options.Timestamps, Options.Output == "compact", Options.TTYEncode)
eventEncoder := GetEncoder(os.Stdout, encoder.ColorMode(Options.Color), Options.Timestamps, Options.Output == "compact", Options.TTYEncode, Options.StackTraces)
for {
res, err := stream.Recv()
if err != nil {
Expand Down Expand Up @@ -191,5 +192,6 @@ func New() *cobra.Command {
flags.BoolVar(&Options.Host, "host", false, "Get host events")
flags.BoolVar(&Options.Timestamps, "timestamps", false, "Include timestamps in compact output")
flags.StringVarP(&Options.TTYEncode, "tty-encode", "t", "", "Encode terminal data by file path (all other events will be ignored)")
flags.BoolVar(&Options.StackTraces, "stack-traces", true, "Include stack traces in compact output")
return &cmd
}
39 changes: 32 additions & 7 deletions pkg/encoder/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"io"
"os"
"strings"

"github.com/cilium/tetragon/api/v1/tetragon"
"github.com/cilium/tetragon/pkg/arch"
Expand Down Expand Up @@ -83,17 +84,19 @@ func (p *TtyEncoder) Encode(v interface{}) error {

// CompactEncoder encodes tetragon.GetEventsResponse in a short format with emojis and colors.
type CompactEncoder struct {
Writer io.Writer
Colorer *Colorer
Timestamps bool
Writer io.Writer
Colorer *Colorer
Timestamps bool
StackTraces bool
}

// NewCompactEncoder initializes and returns a pointer to CompactEncoder.
func NewCompactEncoder(w io.Writer, colorMode ColorMode, timestamps bool) *CompactEncoder {
func NewCompactEncoder(w io.Writer, colorMode ColorMode, timestamps bool, stackTraces bool) *CompactEncoder {
return &CompactEncoder{
Writer: w,
Colorer: NewColorer(colorMode),
Timestamps: timestamps,
Writer: w,
Colorer: NewColorer(colorMode),
Timestamps: timestamps,
StackTraces: stackTraces,
}
}

Expand All @@ -113,6 +116,13 @@ func (p *CompactEncoder) Encode(v interface{}) error {
str = fmt.Sprintf("%s %s", ts, str)
}
fmt.Fprintln(p.Writer, str)

// print stack trace if available
if p.StackTraces {
st := HumanStackTrace(event, p.Colorer)
fmt.Fprint(p.Writer, st)
}

return nil
}

Expand Down Expand Up @@ -188,6 +198,21 @@ func PrintNS(ns int32) string {
return nsId[ns]
}

func HumanStackTrace(response *tetragon.GetEventsResponse, colorer *Colorer) string {
out := new(strings.Builder)
if ev, ok := response.Event.(*tetragon.GetEventsResponse_ProcessKprobe); ok {
if ev.ProcessKprobe.StackTrace != nil {
for _, st := range ev.ProcessKprobe.StackTrace {
colorer.Green.Fprintf(out, " 0x%x:", st.Address)
colorer.Blue.Fprintf(out, " %s", st.Symbol)
fmt.Fprintf(out, "+")
colorer.Yellow.Fprintf(out, "0x%x\n", st.Offset)
}
}
}
return out.String()
}

func (p *CompactEncoder) EventToString(response *tetragon.GetEventsResponse) (string, error) {
switch response.Event.(type) {
case *tetragon.GetEventsResponse_ProcessExec:
Expand Down
24 changes: 12 additions & 12 deletions pkg/encoder/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ import (
)

func TestCompactEncoder_InvalidEventToString(t *testing.T) {
p := NewCompactEncoder(os.Stdout, Never, false)
p := NewCompactEncoder(os.Stdout, Never, false, false)

// should fail if the event field is nil.
_, err := p.EventToString(&tetragon.GetEventsResponse{})
assert.Error(t, err)
}

func TestCompactEncoder_ExecEventToString(t *testing.T) {
p := NewCompactEncoder(os.Stdout, Never, false)
p := NewCompactEncoder(os.Stdout, Never, false, false)

// should fail if the process field is nil.
_, err := p.EventToString(&tetragon.GetEventsResponse{
Expand Down Expand Up @@ -73,7 +73,7 @@ func TestCompactEncoder_ExecEventToString(t *testing.T) {
}

func TestCompactEncoder_ExitEventToString(t *testing.T) {
p := NewCompactEncoder(os.Stdout, Never, false)
p := NewCompactEncoder(os.Stdout, Never, false, false)

// should fail if the process field is nil.
_, err := p.EventToString(&tetragon.GetEventsResponse{
Expand Down Expand Up @@ -123,7 +123,7 @@ func TestCompactEncoder_ExitEventToString(t *testing.T) {
}

func TestCompactEncoder_KprobeEventToString(t *testing.T) {
p := NewCompactEncoder(os.Stdout, Never, false)
p := NewCompactEncoder(os.Stdout, Never, false, false)

// should fail without process field
_, err := p.EventToString(&tetragon.GetEventsResponse{
Expand Down Expand Up @@ -156,7 +156,7 @@ func TestCompactEncoder_KprobeEventToString(t *testing.T) {
}

func TestCompactEncoder_KprobeOpenEventToString(t *testing.T) {
p := NewCompactEncoder(os.Stdout, Never, false)
p := NewCompactEncoder(os.Stdout, Never, false, false)

// open without args
result, err := p.EventToString(&tetragon.GetEventsResponse{
Expand Down Expand Up @@ -200,7 +200,7 @@ func TestCompactEncoder_KprobeOpenEventToString(t *testing.T) {
}

func TestCompactEncoder_KprobeWriteEventToString(t *testing.T) {
p := NewCompactEncoder(os.Stdout, Never, false)
p := NewCompactEncoder(os.Stdout, Never, false, false)

// write without args
result, err := p.EventToString(&tetragon.GetEventsResponse{
Expand Down Expand Up @@ -245,7 +245,7 @@ func TestCompactEncoder_KprobeWriteEventToString(t *testing.T) {
}

func TestCompactEncoder_KprobeCloseEventToString(t *testing.T) {
p := NewCompactEncoder(os.Stdout, Never, false)
p := NewCompactEncoder(os.Stdout, Never, false, false)

// open without args
result, err := p.EventToString(&tetragon.GetEventsResponse{
Expand Down Expand Up @@ -288,7 +288,7 @@ func TestCompactEncoder_KprobeCloseEventToString(t *testing.T) {
}

func TestCompactEncoder_KprobeBPFEventToString(t *testing.T) {
p := NewCompactEncoder(os.Stdout, Never, false)
p := NewCompactEncoder(os.Stdout, Never, false, false)

// bpf with no args
result, err := p.EventToString(&tetragon.GetEventsResponse{
Expand Down Expand Up @@ -336,7 +336,7 @@ func TestCompactEncoder_KprobeBPFEventToString(t *testing.T) {
}

func TestCompactEncoder_KprobePerfEventAllocEventToString(t *testing.T) {
p := NewCompactEncoder(os.Stdout, Never, false)
p := NewCompactEncoder(os.Stdout, Never, false, false)

// perf event alloc with no args
result, err := p.EventToString(&tetragon.GetEventsResponse{
Expand Down Expand Up @@ -383,7 +383,7 @@ func TestCompactEncoder_KprobePerfEventAllocEventToString(t *testing.T) {
}

func TestCompactEncoder_KprobeBPFMapAllocEventToString(t *testing.T) {
p := NewCompactEncoder(os.Stdout, Never, false)
p := NewCompactEncoder(os.Stdout, Never, false, false)

// bpf map with no args
result, err := p.EventToString(&tetragon.GetEventsResponse{
Expand Down Expand Up @@ -434,7 +434,7 @@ func TestCompactEncoder_KprobeBPFMapAllocEventToString(t *testing.T) {

func TestCompactEncoder_Encode(t *testing.T) {
var b bytes.Buffer
p := NewCompactEncoder(&b, Never, false)
p := NewCompactEncoder(&b, Never, false, false)

// invalid event
err := p.Encode(nil)
Expand Down Expand Up @@ -465,7 +465,7 @@ func TestCompactEncoder_Encode(t *testing.T) {

func TestCompactEncoder_EncodeWithTimestamp(t *testing.T) {
var b bytes.Buffer
p := NewCompactEncoder(&b, Never, true)
p := NewCompactEncoder(&b, Never, true, false)

// invalid event
err := p.Encode(nil)
Expand Down

0 comments on commit 60bd1a7

Please sign in to comment.