Browse code

Add the possibility to log event with specific attributes

Signed-off-by: Vincent Demeester <vincent@sbr.pm>

Vincent Demeester authored on 2016/01/08 07:14:05
Showing 7 changed files
... ...
@@ -204,7 +204,10 @@ func (daemon *Daemon) Commit(name string, c *types.ContainerCommitConfig) (strin
204 204
 		}
205 205
 	}
206 206
 
207
-	daemon.LogContainerEvent(container, "commit")
207
+	attributes := map[string]string{
208
+		"comment": c.Comment,
209
+	}
210
+	daemon.LogContainerEventWithAttributes(container, "commit", attributes)
208 211
 	return id.String(), nil
209 212
 }
210 213
 
... ...
@@ -8,9 +8,14 @@ import (
8 8
 	"github.com/docker/libnetwork"
9 9
 )
10 10
 
11
-// LogContainerEvent generates an event related to a container.
11
+// LogContainerEvent generates an event related to a container with only the default attributes.
12 12
 func (daemon *Daemon) LogContainerEvent(container *container.Container, action string) {
13
-	attributes := copyAttributes(container.Config.Labels)
13
+	daemon.LogContainerEventWithAttributes(container, action, map[string]string{})
14
+}
15
+
16
+// LogContainerEventWithAttributes generates an event related to a container with specific given attributes.
17
+func (daemon *Daemon) LogContainerEventWithAttributes(container *container.Container, action string, attributes map[string]string) {
18
+	copyAttributes(attributes, container.Config.Labels)
14 19
 	if container.Config.Image != "" {
15 20
 		attributes["image"] = container.Config.Image
16 21
 	}
... ...
@@ -23,14 +28,18 @@ func (daemon *Daemon) LogContainerEvent(container *container.Container, action s
23 23
 	daemon.EventsService.Log(action, events.ContainerEventType, actor)
24 24
 }
25 25
 
26
-// LogImageEvent generates an event related to a container.
26
+// LogImageEvent generates an event related to a container with only the default attributes.
27 27
 func (daemon *Daemon) LogImageEvent(imageID, refName, action string) {
28
-	attributes := map[string]string{}
28
+	daemon.LogImageEventWithAttributes(imageID, refName, action, map[string]string{})
29
+}
30
+
31
+// LogImageEventWithAttributes generates an event related to a container with specific given attributes.
32
+func (daemon *Daemon) LogImageEventWithAttributes(imageID, refName, action string, attributes map[string]string) {
29 33
 	img, err := daemon.GetImage(imageID)
30 34
 	if err == nil && img.Config != nil {
31 35
 		// image has not been removed yet.
32 36
 		// it could be missing if the event is `delete`.
33
-		attributes = copyAttributes(img.Config.Labels)
37
+		copyAttributes(attributes, img.Config.Labels)
34 38
 	}
35 39
 	if refName != "" {
36 40
 		attributes["name"] = refName
... ...
@@ -69,13 +78,11 @@ func (daemon *Daemon) LogNetworkEventWithAttributes(nw libnetwork.Network, actio
69 69
 }
70 70
 
71 71
 // copyAttributes guarantees that labels are not mutated by event triggers.
72
-func copyAttributes(labels map[string]string) map[string]string {
73
-	attributes := map[string]string{}
72
+func copyAttributes(attributes, labels map[string]string) {
74 73
 	if labels == nil {
75
-		return attributes
74
+		return
76 75
 	}
77 76
 	for k, v := range labels {
78 77
 		attributes[k] = v
79 78
 	}
80
-	return attributes
81 79
 }
... ...
@@ -2,13 +2,15 @@ package daemon
2 2
 
3 3
 import (
4 4
 	"testing"
5
+	"time"
5 6
 
6 7
 	"github.com/docker/docker/container"
7 8
 	"github.com/docker/docker/daemon/events"
8 9
 	containertypes "github.com/docker/engine-api/types/container"
10
+	eventtypes "github.com/docker/engine-api/types/events"
9 11
 )
10 12
 
11
-func TestLogContainerCopyLabels(t *testing.T) {
13
+func TestLogContainerEventCopyLabels(t *testing.T) {
12 14
 	e := events.New()
13 15
 	_, l, _ := e.Subscribe()
14 16
 	defer e.Evict(l)
... ...
@@ -18,6 +20,7 @@ func TestLogContainerCopyLabels(t *testing.T) {
18 18
 			ID:   "container_id",
19 19
 			Name: "container_name",
20 20
 			Config: &containertypes.Config{
21
+				Image: "image_name",
21 22
 				Labels: map[string]string{
22 23
 					"node": "1",
23 24
 					"os":   "alpine",
... ...
@@ -33,4 +36,59 @@ func TestLogContainerCopyLabels(t *testing.T) {
33 33
 	if _, mutated := container.Config.Labels["image"]; mutated {
34 34
 		t.Fatalf("Expected to not mutate the container labels, got %q", container.Config.Labels)
35 35
 	}
36
+
37
+	validateTestAttributes(t, l, map[string]string{
38
+		"node": "1",
39
+		"os":   "alpine",
40
+	})
41
+}
42
+
43
+func TestLogContainerEventWithAttributes(t *testing.T) {
44
+	e := events.New()
45
+	_, l, _ := e.Subscribe()
46
+	defer e.Evict(l)
47
+
48
+	container := &container.Container{
49
+		CommonContainer: container.CommonContainer{
50
+			ID:   "container_id",
51
+			Name: "container_name",
52
+			Config: &containertypes.Config{
53
+				Labels: map[string]string{
54
+					"node": "1",
55
+					"os":   "alpine",
56
+				},
57
+			},
58
+		},
59
+	}
60
+	daemon := &Daemon{
61
+		EventsService: e,
62
+	}
63
+	attributes := map[string]string{
64
+		"node": "2",
65
+		"foo":  "bar",
66
+	}
67
+	daemon.LogContainerEventWithAttributes(container, "create", attributes)
68
+
69
+	validateTestAttributes(t, l, map[string]string{
70
+		"node": "1",
71
+		"foo":  "bar",
72
+	})
73
+}
74
+
75
+func validateTestAttributes(t *testing.T, l chan interface{}, expectedAttributesToTest map[string]string) {
76
+	select {
77
+	case ev := <-l:
78
+		event, ok := ev.(eventtypes.Message)
79
+		if !ok {
80
+			t.Fatalf("Unexpected event message: %q", ev)
81
+		}
82
+		for key, expected := range expectedAttributesToTest {
83
+			actual, ok := event.Actor.Attributes[key]
84
+			if !ok || actual != expected {
85
+				t.Fatalf("Expected value for key %s to be %s, but was %s (event:%v)", key, expected, actual, event)
86
+			}
87
+		}
88
+	case <-time.After(10 * time.Second):
89
+		t.Fatalf("LogEvent test timed out")
90
+	}
36 91
 }
... ...
@@ -65,7 +65,10 @@ func (daemon *Daemon) killWithSignal(container *container.Container, sig int) er
65 65
 		return err
66 66
 	}
67 67
 
68
-	daemon.LogContainerEvent(container, "kill")
68
+	attributes := map[string]string{
69
+		"signal": fmt.Sprintf("%d", sig),
70
+	}
71
+	daemon.LogContainerEventWithAttributes(container, "kill", attributes)
69 72
 	return nil
70 73
 }
71 74
 
... ...
@@ -49,8 +49,12 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
49 49
 		return err
50 50
 	}
51 51
 
52
+	attributes := map[string]string{
53
+		"oldName": oldName,
54
+	}
55
+
52 56
 	if !container.Running {
53
-		daemon.LogContainerEvent(container, "rename")
57
+		daemon.LogContainerEventWithAttributes(container, "rename", attributes)
54 58
 		return nil
55 59
 	}
56 60
 
... ...
@@ -73,6 +77,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
73 73
 	if err != nil {
74 74
 		return err
75 75
 	}
76
-	daemon.LogContainerEvent(container, "rename")
76
+
77
+	daemon.LogContainerEventWithAttributes(container, "rename", attributes)
77 78
 	return nil
78 79
 }
... ...
@@ -1,6 +1,10 @@
1 1
 package daemon
2 2
 
3
-import derr "github.com/docker/docker/errors"
3
+import (
4
+	"fmt"
5
+
6
+	derr "github.com/docker/docker/errors"
7
+)
4 8
 
5 9
 // ContainerResize changes the size of the TTY of the process running
6 10
 // in the container with the given name to the given height and width.
... ...
@@ -15,7 +19,11 @@ func (daemon *Daemon) ContainerResize(name string, height, width int) error {
15 15
 	}
16 16
 
17 17
 	if err = container.Resize(height, width); err == nil {
18
-		daemon.LogContainerEvent(container, "resize")
18
+		attributes := map[string]string{
19
+			"height": fmt.Sprintf("%d", height),
20
+			"width":  fmt.Sprintf("%d", width),
21
+		}
22
+		daemon.LogContainerEventWithAttributes(container, "resize", attributes)
19 23
 	}
20 24
 	return err
21 25
 }
... ...
@@ -1,6 +1,7 @@
1 1
 package daemon
2 2
 
3 3
 import (
4
+	"fmt"
4 5
 	"runtime"
5 6
 
6 7
 	"github.com/Sirupsen/logrus"
... ...
@@ -101,7 +102,10 @@ func (daemon *Daemon) containerStart(container *container.Container) (err error)
101 101
 			}
102 102
 			container.ToDisk()
103 103
 			daemon.Cleanup(container)
104
-			daemon.LogContainerEvent(container, "die")
104
+			attributes := map[string]string{
105
+				"exitCode": fmt.Sprintf("%d", container.ExitCode),
106
+			}
107
+			daemon.LogContainerEventWithAttributes(container, "die", attributes)
105 108
 		}
106 109
 	}()
107 110