Skip to content

Commit 32a46d0

Browse files
committed
1. fix sysdig server bugs
todo: 1. modify json tag names for container model 2. return flatten connections in route getContainer
1 parent ceab617 commit 32a46d0

File tree

10 files changed

+196
-28
lines changed

10 files changed

+196
-28
lines changed

log/log.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ var L = logrus.New()
1111

1212
func init() {
1313
L.SetOutput(os.Stdout)
14-
L.SetLevel(logrus.InfoLevel)
14+
L.SetLevel(logrus.DebugLevel)
1515
}

main.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
package main
22

33
import (
4+
"context"
5+
"os"
6+
"os/signal"
7+
8+
"github.com/YLonely/sysdig-monitor/log"
9+
"github.com/YLonely/sysdig-monitor/server"
10+
411
"github.com/urfave/cli"
512
)
613

@@ -21,6 +28,16 @@ func main() {
2128
}
2229

2330
app.Action = func(c *cli.Context) error {
24-
31+
conf := server.Config{Port: ":" + port}
32+
signals := make(chan os.Signal, 2048)
33+
ctx, cancel := context.WithCancel(context.Background())
34+
serv := server.NewServer(conf)
35+
errorC := serv.Start(ctx)
36+
done := handleSignals(ctx, cancel, serv, signals, errorC)
37+
signal.Notify(signals, handledSignals...)
38+
log.L.Info("sysdig-monitor successfully booted")
39+
<-done
40+
return nil
2541
}
42+
app.Run(os.Args)
2643
}

server/controller/container/container.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,31 @@ type ContainerController struct {
1818
ec chan sysdig.Event
1919

2020
// containers use container id as key
21-
containers map[string]*model.Container
21+
containers map[string]*mutexContainer
2222
// container process channels
2323
containerCh map[string]chan containerEvent
2424

2525
//containers mutex
2626
cm sync.RWMutex
2727
}
2828

29-
const eventBufferLen = 512
29+
type mutexContainer struct {
30+
m sync.RWMutex
31+
*model.Container
32+
}
33+
34+
func newMutexContainer(id, name string) *mutexContainer {
35+
c := model.NewContainer(id, name)
36+
return &mutexContainer{Container: c}
37+
}
38+
39+
const eventBufferLen = 1024
40+
const unknownContainerName = "<unknown>"
41+
const incompleteContainerName = "incomplete"
3042

3143
func NewController(ctx context.Context, ec chan sysdig.Event) (controller.Controller, error) {
3244
r := router.NewGroupRouter("/container")
33-
res := &ContainerController{containerRouter: r, ec: ec, containers: map[string]*model.Container{}, containerCh: map[string]chan containerEvent{}}
45+
res := &ContainerController{containerRouter: r, ec: ec, containers: map[string]*mutexContainer{}, containerCh: map[string]chan containerEvent{}}
3446
res.initRouter()
3547
if err := res.start(ctx); err != nil {
3648
return res, err
@@ -46,24 +58,31 @@ func (cc *ContainerController) BindedRoutes() []router.Route {
4658

4759
func (cc *ContainerController) initRouter() {
4860
// TODO
61+
cc.containerRouter.AddRoute("/", router.MethodGet, cc.getAllContainers)
62+
cc.containerRouter.AddRoute("/:id", router.MethodGet, cc.getContainer)
4963
}
5064

5165
func (cc *ContainerController) start(ctx context.Context) error {
52-
func() {
66+
go func() {
5367
var e sysdig.Event
5468
for {
5569
select {
5670
case e = <-cc.ec:
5771
case <-ctx.Done():
5872
return
5973
}
60-
if e.ContainerName == "host" {
74+
if e.ContainerID == "host" || len(e.ContainerID) == 0 {
6175
continue
6276
}
6377
ce := convert(e)
6478
containerID := ce.containerID
79+
containerName := ce.containerName
80+
if containerName == incompleteContainerName {
81+
containerName = unknownContainerName
82+
}
83+
log.L.Debug(ce)
6584
if _, exists := cc.containers[containerID]; !exists {
66-
container := model.NewContainer(ce.containerID, ce.containerName)
85+
container := newMutexContainer(ce.containerID, containerName)
6786
ch := make(chan containerEvent, eventBufferLen)
6887
cc.cm.Lock()
6988
cc.containers[containerID] = container
@@ -77,9 +96,9 @@ func (cc *ContainerController) start(ctx context.Context) error {
7796
log.L.WithError(err).Error("")
7897
}
7998
cc.cm.Lock()
80-
cc.containers[container.ID] = nil
99+
delete(cc.containers, container.ID)
81100
cc.cm.Unlock()
82-
cc.containerCh[container.ID] = nil
101+
delete(cc.containerCh, container.ID)
83102
close(ch)
84103
}()
85104
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package container
2+
3+
import (
4+
"github.com/gin-gonic/gin"
5+
)
6+
7+
func (cc *ContainerController) getAllContainers(c *gin.Context) {
8+
res := map[string]string{}
9+
cc.cm.RLock()
10+
for id, container := range cc.containers {
11+
res[id] = container.Name
12+
}
13+
cc.cm.RUnlock()
14+
c.JSON(200, res)
15+
}
16+
17+
func (cc *ContainerController) getContainer(c *gin.Context) {
18+
cid := c.Param("id")
19+
cc.cm.RLock()
20+
container, exists := cc.containers[cid]
21+
cc.cm.RUnlock()
22+
if !exists {
23+
c.JSON(200, "no such container error")
24+
return
25+
}
26+
container.m.RLock()
27+
defer container.m.RUnlock()
28+
c.JSON(200, container.Container)
29+
}

server/controller/container/util.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ type containerEvent struct {
3131
virtualtid int
3232
}
3333

34-
func processLoop(ctx context.Context, c *model.Container, ch chan containerEvent) error {
34+
func processLoop(ctx context.Context, c *mutexContainer, ch chan containerEvent) error {
3535
var e containerEvent
3636
var err error
3737
for {
@@ -45,23 +45,29 @@ func processLoop(ctx context.Context, c *model.Container, ch chan containerEvent
4545
}
4646
// container exits
4747
if e.eventType == "procexit" && e.virtualtid == 1 {
48+
log.L.WithField("container-id", c.ID).Debug("container exits")
4849
return nil
4950
}
5051
if e.eventDir == "<" {
51-
if err = handleSysCall(c, e); err != nil {
52+
c.m.Lock()
53+
if e.containerName != incompleteContainerName && c.Name == unknownContainerName {
54+
c.Name = e.containerName
55+
}
56+
if err = handleSysCall(c.Container, e); err != nil {
5257
log.L.WithError(err).WithField("container-id", c.ID).Error("syscall handler error")
5358
}
5459
if e.rawRes >= 0 && (e.isIORead || e.isIOWrite) {
55-
if err = handleIO(c, e); err != nil {
60+
if err = handleIO(c.Container, e); err != nil {
5661
//if something wrong happens, just log it out
5762
log.L.WithField("container-id", c.ID).WithError(err).Error("io handle error")
5863
}
5964
} else {
6065
// may have some other handler?
61-
if err = handleNetwork(c, e); err != nil {
66+
if err = handleNetwork(c.Container, e); err != nil {
6267
log.L.WithField("container-id", c.ID).WithError(err).Error("network handler error")
6368
}
6469
}
70+
c.m.Unlock()
6571
}
6672
}
6773
}
@@ -161,7 +167,7 @@ func handleNetwork(c *model.Container, e containerEvent) error {
161167
}
162168
// should return nonexists error?
163169
if _, exists := c.ActiveConnections[meta]; exists {
164-
c.ActiveConnections[meta] = nil
170+
delete(c.ActiveConnections, meta)
165171
}
166172
}
167173
return nil

server/model/container.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package model
33
import "time"
44

55
type Container struct {
6-
ID string
6+
ID string
77
Name string
88

99
SystemCalls
@@ -40,19 +40,20 @@ type FileSystem struct {
4040
}
4141

4242
type Network struct {
43-
ActiveConnections map[ConnectionMeta]*Connection
43+
ActiveConnections map[ConnectionMeta]*Connection `json:"-"`
44+
FlattenConnections []*FlattenConnection `json:"active_connections"`
4445
TotalReadIn, TotalWriteOut int64
4546
}
4647

4748
type SystemCall struct {
48-
Name string
49+
Name string `json:"-"`
4950
// total number of times it is invoked
5051
Calls int64
5152
TotalTime time.Duration
5253
}
5354

5455
type File struct {
55-
Name string
56+
Name string `json:"-"`
5657
WriteOut int64
5758
ReadIn int64
5859
}
@@ -71,6 +72,11 @@ type ConnectionMeta struct {
7172
DestPort int
7273
}
7374

75+
type FlattenConnection struct {
76+
ConnectionMeta
77+
Connection
78+
}
79+
7480
type IOCall struct {
7581
FileName string
7682
Latency time.Duration

server/server.go

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,83 @@
11
package server
22

3-
import "context"
3+
import (
4+
"context"
5+
"net/http"
6+
"time"
7+
8+
"github.com/YLonely/sysdig-monitor/server/controller"
9+
10+
"github.com/gin-gonic/gin"
11+
12+
"github.com/YLonely/sysdig-monitor/server/controller/container"
13+
"github.com/YLonely/sysdig-monitor/sysdig"
14+
)
415

516
// Config containes params to start a server, only port now
617
type Config struct {
7-
port string
18+
Port string
819
}
920

1021
// Server is the interface of a monitor server
1122
type Server interface {
1223
Start(ctx context.Context) chan error
24+
Shutdown(ctx context.Context) error
1325
}
1426

1527
type server struct {
16-
conf Config
28+
conf Config
29+
httpServer *http.Server
1730
}
1831

1932
func NewServer(conf Config) Server {
2033
return &server{conf: conf}
2134
}
2235

2336
func (s *server) Start(ctx context.Context) chan error {
24-
37+
errch := make(chan error, 1)
38+
sysdigServer := sysdig.NewServer()
39+
containerContorller, err := container.NewController(ctx, sysdigServer.Subscribe())
40+
if err != nil {
41+
errch <- err
42+
return errch
43+
}
44+
err, sysdigErrorCh := sysdigServer.Start(ctx)
45+
if err != nil {
46+
errch <- err
47+
return errch
48+
}
49+
ginServer := gin.Default()
50+
initRoutes(ginServer, containerContorller) // may be more controller?
51+
s.httpServer = &http.Server{Addr: s.conf.Port, Handler: ginServer}
52+
httpServerErrorCh := make(chan error, 1)
53+
go func() {
54+
if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
55+
httpServerErrorCh <- err
56+
}
57+
}()
58+
go func() {
59+
var e error
60+
select {
61+
case e = <-sysdigErrorCh:
62+
case e = <-httpServerErrorCh:
63+
errch <- e
64+
}
65+
}()
66+
return errch
67+
}
68+
69+
func (s *server) Shutdown(ctx context.Context) error {
70+
cctx, cancel := context.WithTimeout(ctx, time.Second*3)
71+
defer cancel()
72+
err := s.httpServer.Shutdown(cctx)
73+
return err
74+
}
75+
76+
func initRoutes(ginServer *gin.Engine, controllers ...controller.Controller) {
77+
for _, controller := range controllers {
78+
routes := controller.BindedRoutes()
79+
for _, route := range routes {
80+
ginServer.Handle(route.Method(), route.Path(), gin.HandlerFunc(route.Handler()))
81+
}
82+
}
2583
}

signals.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"os"
6+
"syscall"
7+
8+
"github.com/YLonely/sysdig-monitor/server"
9+
10+
"github.com/YLonely/sysdig-monitor/log"
11+
)
12+
13+
var handledSignals = []os.Signal{
14+
syscall.SIGTERM,
15+
syscall.SIGINT,
16+
}
17+
18+
func handleSignals(ctx context.Context, cancel context.CancelFunc, server server.Server, signals chan os.Signal, serverErrorC chan error) chan bool {
19+
done := make(chan bool, 1)
20+
go func() {
21+
select {
22+
case s := <-signals:
23+
log.L.WithField("signal", s).Debug("get signal")
24+
case err := <-serverErrorC:
25+
log.L.WithError(err).Error("server error")
26+
}
27+
// ignore the shutdown error
28+
server.Shutdown(ctx)
29+
cancel()
30+
close(done)
31+
}()
32+
return done
33+
}

sysdig/event.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type Event struct {
2020
EventBuflen int `json:"evt.buflen"`
2121
ProcName string `json:"proc.name"`
2222
ThreadID int `json:"thread.tid"`
23-
ThreadVirtualID int `json:"thread.vid"`
23+
ThreadVirtualID int `json:"thread.vtid"`
2424
EventLatency time.Duration `json:"evt.latency"`
2525
RawRes int `json:"evt.rawres"`
2626
SyscallType string `json:"syscall.type"`

0 commit comments

Comments
 (0)