diff --git a/experimental/tracer/main/store.go b/experimental/tracer/main/store.go index 2fe0a6b93..aecee9e02 100644 --- a/experimental/tracer/main/store.go +++ b/experimental/tracer/main/store.go @@ -21,8 +21,10 @@ type key struct { type trace struct { PID int - Root *ptrace.Fd + ServerDetails *ptrace.ConnectionDetails + ClientDetails *ptrace.ConnectionDetails Children []*trace + Level int } type store struct { @@ -63,10 +65,18 @@ func (s *store) RecordConnection(pid int, connection *ptrace.Fd) { s.Lock() defer s.Unlock() - newTrace := &trace{PID: pid, Root: connection} - newTraceKey := newKey(connection) + newTrace := &trace{ + PID: pid, + ServerDetails: &connection.ConnectionDetails, + } + for _, child := range connection.Children { + newTrace.Children = append(newTrace.Children, &trace{ + Level: 1, + ClientDetails: &child.ConnectionDetails, + }) + } - log.Printf("Recording trace: %+v", newTrace) + newTraceKey := newKey(connection) // First, see if this new conneciton is a child of an existing connection. // This indicates we have a parent connection to attach to. @@ -75,6 +85,7 @@ func (s *store) RecordConnection(pid int, connection *ptrace.Fd) { parentNode.Remove() parentTrace := parentNode.Value.(*trace) log.Printf(" Found parent trace: %+v", parentTrace) + newTrace.Level = parentTrace.Level + 1 parentTrace.Children = append(parentTrace.Children, newTrace) } else { s.traces.Insert(newTraceKey, newTrace) @@ -89,6 +100,7 @@ func (s *store) RecordConnection(pid int, connection *ptrace.Fd) { childNode.Remove() childTrace := childNode.Value.(*trace) log.Printf(" Found child trace: %+v", childTrace) + IncrementLevel(childTrace, newTrace.Level) newTrace.Children = append(newTrace.Children, childTrace) } else { s.traces.Insert(childTraceKey, newTrace) @@ -96,11 +108,18 @@ func (s *store) RecordConnection(pid int, connection *ptrace.Fd) { } } +func IncrementLevel(trace *trace, increment int) { + trace.Level += increment + for _, child := range trace.Children { + IncrementLevel(child, increment) + } +} + func (s *store) Traces() []*trace { s.RLock() defer s.RUnlock() - var traces []*trace + traces := []*trace{} var cur = s.traces.First() for cur != nil { traces = append(traces, cur.Value.(*trace)) diff --git a/experimental/tracer/ptrace/fd.go b/experimental/tracer/ptrace/fd.go index b5f842fa5..ffea4b11d 100644 --- a/experimental/tracer/ptrace/fd.go +++ b/experimental/tracer/ptrace/fd.go @@ -29,10 +29,8 @@ var ( tcpRegexp = regexp.MustCompile(tcpPattern) ) -// Fd represents a connect and subsequent connections caused by it. -type Fd struct { +type ConnectionDetails struct { direction int - fd int Start int64 Stop int64 @@ -43,6 +41,14 @@ type Fd struct { FromPort uint16 ToAddr net.IP ToPort uint16 +} + +// Fd represents a connect and subsequent connections caused by it. +type Fd struct { + fd int + closed bool + + ConnectionDetails // Fds are connections, and can have a causal-link to other Fds Children []*Fd @@ -133,8 +139,14 @@ func newListeningFd(pid, fd int) (*Fd, error) { } return &Fd{ - direction: listening, fd: fd, Start: now(), - ToAddr: localAddr, ToPort: uint16(localPort), + fd: fd, + + ConnectionDetails: ConnectionDetails{ + direction: listening, + Start: now(), + ToAddr: localAddr, + ToPort: uint16(localPort), + }, }, nil } @@ -146,9 +158,16 @@ func newConnectionFd(pid, fd int, remoteAddr net.IP, remotePort uint16) (*Fd, er } return &Fd{ - direction: outgoing, fd: fd, Start: now(), - FromAddr: localAddr, FromPort: uint16(localPort), - ToAddr: remoteAddr, ToPort: remotePort, + fd: fd, + + ConnectionDetails: ConnectionDetails{ + direction: outgoing, + Start: now(), + FromAddr: localAddr, + FromPort: uint16(localPort), + ToAddr: remoteAddr, + ToPort: remotePort, + }, }, nil } @@ -159,12 +178,20 @@ func (fd *Fd) newConnection(addr net.IP, port uint16, newFd int) (*Fd, error) { } return &Fd{ - direction: incoming, fd: newFd, Start: now(), - ToAddr: fd.ToAddr, ToPort: fd.ToPort, - FromAddr: addr, FromPort: port, + fd: newFd, + + ConnectionDetails: ConnectionDetails{ + direction: incoming, + Start: now(), + ToAddr: fd.ToAddr, + ToPort: fd.ToPort, + FromAddr: addr, + FromPort: port, + }, }, nil } func (fd *Fd) close() { + fd.closed = true fd.Stop = now() } diff --git a/experimental/tracer/ptrace/thread.go b/experimental/tracer/ptrace/thread.go index 038f7050c..09c6eb715 100644 --- a/experimental/tracer/ptrace/thread.go +++ b/experimental/tracer/ptrace/thread.go @@ -204,28 +204,26 @@ func (t *thread) handleClose(call, result *syscall.PtraceRegs) { return } + t.logf("Closing fd %d", fdNum) fd.close() // if this connection was incoming, add it to 'the registry' if fd.direction == incoming { + // collect all the outgoing connections this thread has made + // and treat them as caused by this incoming connections for _, outgoing := range t.currentOutgoing { - t.logf("Fd %d caused %d", fd.fd, outgoing.fd) + t.logf("Fd %d caused %d", fdNum, outgoing.fd) fd.Children = append(fd.Children, outgoing) } + t.currentOutgoing = map[int]*Fd{} t.tracer.store.RecordConnection(t.process.pid, fd) - } else { - for _, incoming := range t.currentIncoming { - t.logf("Fd %d caused %d", incoming.fd, fd.fd) - incoming.Children = append(incoming.Children, fd) - } } // now make sure we've remove it from everywhere delete(t.process.fds, fdNum) for _, thread := range t.process.threads { delete(thread.currentIncoming, fdNum) - delete(t.currentOutgoing, fdNum) } } @@ -241,6 +239,7 @@ func (t *thread) handleIO(call, result *syscall.PtraceRegs) { t.logf("IO on incoming connection %d; setting affinity", fdNum) t.currentIncoming[fdNum] = fd } else { + t.logf("IO on outgoing connection %d; setting affinity", fdNum) t.currentOutgoing[fdNum] = fd } } diff --git a/experimental/tracer/ui/index.html b/experimental/tracer/ui/index.html index 4eeaa0e5d..938f9a728 100644 --- a/experimental/tracer/ui/index.html +++ b/experimental/tracer/ui/index.html @@ -24,6 +24,10 @@ var containers = []; var traces = []; + Handlebars.registerHelper('spaces', function(input) { + return new Array(input + 1).join("> "); + }); + Handlebars.registerHelper('ts', function(input) { var ts = moment(input).format("LTS") return new Handlebars.SafeString(ts); @@ -39,9 +43,11 @@ }); Handlebars.registerHelper('count', function(input) { - return new Handlebars.SafeString(input === null ? '0' : sprintf("%d", input.len)); + return new Handlebars.SafeString(input === null ? '0' : sprintf("%d", input.length)); }); + Handlebars.registerPartial('traces', $("#traces").html()); + function render() { var template = $('script#process-template').text(); template = Handlebars.compile(template); @@ -115,6 +121,27 @@ width: 100%; } + +