55package pwru
66
77import (
8+ "encoding/json"
89 "errors"
910 "fmt"
1011 "io"
@@ -42,6 +43,32 @@ type output struct {
4243 ifaceCache map [uint64 ]map [uint32 ]string
4344}
4445
46+ // outputStructured is a struct to hold the data for the json output
47+ type jsonPrinter struct {
48+ Skb string `json:"skb,omitempty"`
49+ Cpu uint32 `json:"cpu,omitempty"`
50+ Process string `json:"process,omitempty"`
51+ Func string `json:"func,omitempty"`
52+ Time interface {} `json:"time,omitempty"`
53+ Netns uint32 `json:"netns,omitempty"`
54+ Mark uint32 `json:"mark,omitempty"`
55+ Iface string `json:"iface,omitempty"`
56+ Proto uint16 `json:"proto,omitempty"`
57+ Mtu uint32 `json:"mtu,omitempty"`
58+ Len uint32 `json:"len,omitempty"`
59+ Tuple * jsonTuple `json:"tuple,omitempty"`
60+ Stack interface {} `json:"stack,omitempty"`
61+ SkbMetadata interface {} `json:"skb_metadata,omitempty"`
62+ }
63+
64+ type jsonTuple struct {
65+ Saddr string `json:"saddr,omitempty"`
66+ Daddr string `json:"daddr,omitempty"`
67+ Sport uint16 `json:"sport,omitempty"`
68+ Dport uint16 `json:"dport,omitempty"`
69+ Proto uint8 `json:"proto,omitempty"`
70+ }
71+
4572func NewOutput (flags * Flags , printSkbMap * ebpf.Map , printStackMap * ebpf.Map ,
4673 addr2Name Addr2Name , kprobeMulti bool , btfSpec * btf.Spec ,
4774) (* output , error ) {
@@ -92,25 +119,93 @@ func (o *output) PrintHeader() {
92119 fmt .Fprintf (o .writer , "\n " )
93120}
94121
95- func (o * output ) Print (event * Event ) {
96- if o .flags .OutputTS == "absolute" {
97- fmt .Fprintf (o .writer , "%12s " , time .Now ().Format (absoluteTS ))
122+ // PrintJson prints the event in JSON format
123+ func (o * output ) PrintJson (event * Event ) {
124+ // crate an instance of the outputStructured struct to hold the data
125+ d := & jsonPrinter {}
126+
127+ // add the data to the struct
128+ d .Skb = fmt .Sprintf ("%#x" , event .SAddr )
129+ d .Cpu = event .CPU
130+ d .Process = getExecName (int (event .PID ))
131+ d .Func = getOutFuncName (o , event , event .Addr )
132+
133+ o .lastSeenSkb [event .SAddr ] = event .Timestamp
134+
135+ // add the timestamp to the struct if it is not set to none
136+ if o .flags .OutputTS != "none" {
137+ switch o .flags .OutputTS {
138+ case "absolute" :
139+ d .Time = getAbsoluteTs ()
140+ case "relative" :
141+ d .Time = getRelativeTs (event , o )
142+ case "current" :
143+ d .Time = event .Timestamp
144+ }
98145 }
99- p , err := ps .FindProcess (int (event .PID ))
100- execName := fmt .Sprintf ("<empty>(%d)" , event .PID )
101- if err == nil && p != nil {
102- execName = fmt .Sprintf ("%s(%d)" , p .ExecutablePath (), event .PID )
146+
147+ if o .flags .OutputMeta {
148+ d .Netns = event .Meta .Netns
149+ d .Mark = event .Meta .Mark
150+ d .Iface = o .getIfaceName (event .Meta .Netns , event .Meta .Ifindex )
151+ d .Proto = byteorder .NetworkToHost16 (event .Meta .Proto )
152+ d .Mtu = event .Meta .MTU
153+ d .Len = event .Meta .Len
154+ }
155+
156+ if o .flags .OutputTuple {
157+ t := & jsonTuple {}
158+ t .Saddr = addrToStr (event .Tuple .L3Proto , event .Tuple .Saddr )
159+ t .Daddr = addrToStr (event .Tuple .L3Proto , event .Tuple .Daddr )
160+ t .Sport = byteorder .NetworkToHost16 (event .Tuple .Sport )
161+ t .Dport = byteorder .NetworkToHost16 (event .Tuple .Dport )
162+ t .Proto = event .Tuple .L4Proto
163+ d .Tuple = t
164+ }
165+
166+ if o .flags .OutputStack && event .PrintStackId > 0 {
167+ d .Stack = getStackData (event , o )
168+ }
169+
170+ if o .flags .OutputSkb {
171+ d .SkbMetadata = getSkbData (event , o )
172+ }
173+
174+ // Create new encoder to write the json to stdout or file depending on the flags
175+ encoder := json .NewEncoder (o .writer )
176+ encoder .SetEscapeHTML (false )
177+
178+ err := encoder .Encode (d )
179+
180+ if err != nil {
181+ log .Fatalf ("Error encoding JSON: %s" , err )
103182 }
183+ }
184+
185+ func getAbsoluteTs () string {
186+ return time .Now ().Format (absoluteTS )
187+ }
188+
189+ func getRelativeTs (event * Event , o * output ) uint64 {
104190 ts := event .Timestamp
105- if o .flags .OutputTS == "relative" {
106- if last , found := o .lastSeenSkb [event .SAddr ]; found {
107- ts = ts - last
108- } else {
109- ts = 0
110- }
191+ if last , found := o .lastSeenSkb [event .SAddr ]; found {
192+ ts = ts - last
193+ } else {
194+ ts = 0
111195 }
112- var addr uint64
113- // XXX: not sure why the -1 offset is needed on x86 but not on arm64
196+ return ts
197+ }
198+
199+ func getExecName (pid int ) string {
200+ p , err := ps .FindProcess (pid )
201+ execName := fmt .Sprintf ("<empty>:(%d)" , pid )
202+ if err == nil && p != nil {
203+ return fmt .Sprintf ("%s:%d" , p .ExecutablePath (), pid )
204+ }
205+ return execName
206+ }
207+
208+ func getAddrByArch (event * Event , o * output ) (addr uint64 ) {
114209 switch runtime .GOARCH {
115210 case "amd64" :
116211 addr = event .Addr
@@ -120,7 +215,50 @@ func (o *output) Print(event *Event) {
120215 case "arm64" :
121216 addr = event .Addr
122217 }
218+ return addr
219+ }
220+
221+ func getTupleData (event * Event ) (tupleData string ) {
222+ tupleData = fmt .Sprintf ("%s:%d->%s:%d(%s)" ,
223+ addrToStr (event .Tuple .L3Proto , event .Tuple .Saddr ), byteorder .NetworkToHost16 (event .Tuple .Sport ),
224+ addrToStr (event .Tuple .L3Proto , event .Tuple .Daddr ), byteorder .NetworkToHost16 (event .Tuple .Dport ),
225+ protoToStr (event .Tuple .L4Proto ))
226+ return tupleData
227+ }
228+
229+ func getStackData (event * Event , o * output ) (stackData string ) {
230+ var stack StackData
231+ id := uint32 (event .PrintStackId )
232+ if err := o .printStackMap .Lookup (& id , & stack ); err == nil {
233+ for _ , ip := range stack .IPs {
234+ if ip > 0 {
235+ stackData += fmt .Sprintf ("\n %s" , o .addr2name .findNearestSym (ip ))
236+ }
237+ }
238+ }
239+ _ = o .printStackMap .Delete (& id )
240+ return stackData
241+ }
242+
243+ func getSkbData (event * Event , o * output ) (skbData string ) {
244+ id := uint32 (event .PrintSkbId )
245+ if str , err := o .printSkbMap .LookupBytes (& id ); err == nil {
246+ skbData = string (str )
247+ }
248+ return skbData
249+ }
250+
251+ func getMetaData (event * Event , o * output ) (metaData string ) {
252+ metaData = fmt .Sprintf ("netns=%d mark=%#x iface=%s proto=%#04x mtu=%d len=%d" ,
253+ event .Meta .Netns , event .Meta .Mark ,
254+ o .getIfaceName (event .Meta .Netns , event .Meta .Ifindex ),
255+ byteorder .NetworkToHost16 (event .Meta .Proto ), event .Meta .MTU , event .Meta .Len )
256+ return metaData
257+ }
258+
259+ func getOutFuncName (o * output , event * Event , addr uint64 ) string {
123260 var funcName string
261+
124262 if ksym , ok := o .addr2name .Addr2NameMap [addr ]; ok {
125263 funcName = ksym .name
126264 } else if ksym , ok := o .addr2name .Addr2NameMap [addr - 4 ]; runtime .GOARCH == "amd64" && ok {
@@ -151,6 +289,26 @@ func (o *output) Print(event *Event) {
151289 }
152290 }
153291
292+ return outFuncName
293+ }
294+
295+ func (o * output ) Print (event * Event ) {
296+ if o .flags .OutputTS == "absolute" {
297+ fmt .Fprintf (o .writer , "%12s " , getAbsoluteTs ())
298+ }
299+
300+ execName := getExecName (int (event .PID ))
301+
302+ ts := event .Timestamp
303+ if o .flags .OutputTS == "relative" {
304+ ts = getRelativeTs (event , o )
305+ }
306+
307+ // XXX: not sure why the -1 offset is needed on x86 but not on arm64
308+ addr := getAddrByArch (event , o )
309+
310+ outFuncName := getOutFuncName (o , event , addr )
311+
154312 fmt .Fprintf (o .writer , "%18s %6s %16s %24s" , fmt .Sprintf ("%#x" , event .SAddr ),
155313 fmt .Sprintf ("%d" , event .CPU ), fmt .Sprintf ("[%s]" , execName ), outFuncName )
156314 if o .flags .OutputTS != "none" {
@@ -159,37 +317,19 @@ func (o *output) Print(event *Event) {
159317 o .lastSeenSkb [event .SAddr ] = event .Timestamp
160318
161319 if o .flags .OutputMeta {
162- fmt .Fprintf (o .writer , " netns=%d mark=%#x iface=%s proto=%#04x mtu=%d len=%d" ,
163- event .Meta .Netns , event .Meta .Mark ,
164- o .getIfaceName (event .Meta .Netns , event .Meta .Ifindex ),
165- byteorder .NetworkToHost16 (event .Meta .Proto ), event .Meta .MTU , event .Meta .Len )
320+ fmt .Fprintf (o .writer , "%s" , getMetaData (event , o ))
166321 }
167322
168323 if o .flags .OutputTuple {
169- fmt .Fprintf (o .writer , " %s:%d->%s:%d(%s)" ,
170- addrToStr (event .Tuple .L3Proto , event .Tuple .Saddr ), byteorder .NetworkToHost16 (event .Tuple .Sport ),
171- addrToStr (event .Tuple .L3Proto , event .Tuple .Daddr ), byteorder .NetworkToHost16 (event .Tuple .Dport ),
172- protoToStr (event .Tuple .L4Proto ))
324+ fmt .Fprintf (o .writer , "%s" , getTupleData (event ))
173325 }
174326
175327 if o .flags .OutputStack && event .PrintStackId > 0 {
176- var stack StackData
177- id := uint32 (event .PrintStackId )
178- if err := o .printStackMap .Lookup (& id , & stack ); err == nil {
179- for _ , ip := range stack .IPs {
180- if ip > 0 {
181- fmt .Fprintf (o .writer , "\n %s" , o .addr2name .findNearestSym (ip ))
182- }
183- }
184- }
185- _ = o .printStackMap .Delete (& id )
328+ fmt .Fprintf (o .writer , "%s" , getStackData (event , o ))
186329 }
187330
188331 if o .flags .OutputSkb {
189- id := uint32 (event .PrintSkbId )
190- if str , err := o .printSkbMap .LookupBytes (& id ); err == nil {
191- fmt .Fprintf (o .writer , "\n %s" , string (str ))
192- }
332+ fmt .Fprintf (o .writer , "%s" , getSkbData (event , o ))
193333 }
194334
195335 fmt .Fprintln (o .writer )
0 commit comments