Browse Source

Add the possibility to log event with specific attributes

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
Vincent Demeester 9 years ago
parent
commit
1d8ccc6ae7
7 changed files with 105 additions and 17 deletions
  1. 4 1
      daemon/commit.go
  2. 16 9
      daemon/events.go
  3. 59 1
      daemon/events_test.go
  4. 4 1
      daemon/kill.go
  5. 7 2
      daemon/rename.go
  6. 10 2
      daemon/resize.go
  7. 5 1
      daemon/start.go

+ 4 - 1
daemon/commit.go

@@ -204,7 +204,10 @@ func (daemon *Daemon) Commit(name string, c *types.ContainerCommitConfig) (strin
 		}
 		}
 	}
 	}
 
 
-	daemon.LogContainerEvent(container, "commit")
+	attributes := map[string]string{
+		"comment": c.Comment,
+	}
+	daemon.LogContainerEventWithAttributes(container, "commit", attributes)
 	return id.String(), nil
 	return id.String(), nil
 }
 }
 
 

+ 16 - 9
daemon/events.go

@@ -8,9 +8,14 @@ import (
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork"
 )
 )
 
 
-// LogContainerEvent generates an event related to a container.
+// LogContainerEvent generates an event related to a container with only the default attributes.
 func (daemon *Daemon) LogContainerEvent(container *container.Container, action string) {
 func (daemon *Daemon) LogContainerEvent(container *container.Container, action string) {
-	attributes := copyAttributes(container.Config.Labels)
+	daemon.LogContainerEventWithAttributes(container, action, map[string]string{})
+}
+
+// LogContainerEventWithAttributes generates an event related to a container with specific given attributes.
+func (daemon *Daemon) LogContainerEventWithAttributes(container *container.Container, action string, attributes map[string]string) {
+	copyAttributes(attributes, container.Config.Labels)
 	if container.Config.Image != "" {
 	if container.Config.Image != "" {
 		attributes["image"] = container.Config.Image
 		attributes["image"] = container.Config.Image
 	}
 	}
@@ -23,14 +28,18 @@ func (daemon *Daemon) LogContainerEvent(container *container.Container, action s
 	daemon.EventsService.Log(action, events.ContainerEventType, actor)
 	daemon.EventsService.Log(action, events.ContainerEventType, actor)
 }
 }
 
 
-// LogImageEvent generates an event related to a container.
+// LogImageEvent generates an event related to a container with only the default attributes.
 func (daemon *Daemon) LogImageEvent(imageID, refName, action string) {
 func (daemon *Daemon) LogImageEvent(imageID, refName, action string) {
-	attributes := map[string]string{}
+	daemon.LogImageEventWithAttributes(imageID, refName, action, map[string]string{})
+}
+
+// LogImageEventWithAttributes generates an event related to a container with specific given attributes.
+func (daemon *Daemon) LogImageEventWithAttributes(imageID, refName, action string, attributes map[string]string) {
 	img, err := daemon.GetImage(imageID)
 	img, err := daemon.GetImage(imageID)
 	if err == nil && img.Config != nil {
 	if err == nil && img.Config != nil {
 		// image has not been removed yet.
 		// image has not been removed yet.
 		// it could be missing if the event is `delete`.
 		// it could be missing if the event is `delete`.
-		attributes = copyAttributes(img.Config.Labels)
+		copyAttributes(attributes, img.Config.Labels)
 	}
 	}
 	if refName != "" {
 	if refName != "" {
 		attributes["name"] = refName
 		attributes["name"] = refName
@@ -69,13 +78,11 @@ func (daemon *Daemon) LogNetworkEventWithAttributes(nw libnetwork.Network, actio
 }
 }
 
 
 // copyAttributes guarantees that labels are not mutated by event triggers.
 // copyAttributes guarantees that labels are not mutated by event triggers.
-func copyAttributes(labels map[string]string) map[string]string {
-	attributes := map[string]string{}
+func copyAttributes(attributes, labels map[string]string) {
 	if labels == nil {
 	if labels == nil {
-		return attributes
+		return
 	}
 	}
 	for k, v := range labels {
 	for k, v := range labels {
 		attributes[k] = v
 		attributes[k] = v
 	}
 	}
-	return attributes
 }
 }

+ 59 - 1
daemon/events_test.go

@@ -2,13 +2,15 @@ package daemon
 
 
 import (
 import (
 	"testing"
 	"testing"
+	"time"
 
 
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/events"
 	"github.com/docker/docker/daemon/events"
 	containertypes "github.com/docker/engine-api/types/container"
 	containertypes "github.com/docker/engine-api/types/container"
+	eventtypes "github.com/docker/engine-api/types/events"
 )
 )
 
 
-func TestLogContainerCopyLabels(t *testing.T) {
+func TestLogContainerEventCopyLabels(t *testing.T) {
 	e := events.New()
 	e := events.New()
 	_, l, _ := e.Subscribe()
 	_, l, _ := e.Subscribe()
 	defer e.Evict(l)
 	defer e.Evict(l)
@@ -18,6 +20,7 @@ func TestLogContainerCopyLabels(t *testing.T) {
 			ID:   "container_id",
 			ID:   "container_id",
 			Name: "container_name",
 			Name: "container_name",
 			Config: &containertypes.Config{
 			Config: &containertypes.Config{
+				Image: "image_name",
 				Labels: map[string]string{
 				Labels: map[string]string{
 					"node": "1",
 					"node": "1",
 					"os":   "alpine",
 					"os":   "alpine",
@@ -33,4 +36,59 @@ func TestLogContainerCopyLabels(t *testing.T) {
 	if _, mutated := container.Config.Labels["image"]; mutated {
 	if _, mutated := container.Config.Labels["image"]; mutated {
 		t.Fatalf("Expected to not mutate the container labels, got %q", container.Config.Labels)
 		t.Fatalf("Expected to not mutate the container labels, got %q", container.Config.Labels)
 	}
 	}
+
+	validateTestAttributes(t, l, map[string]string{
+		"node": "1",
+		"os":   "alpine",
+	})
+}
+
+func TestLogContainerEventWithAttributes(t *testing.T) {
+	e := events.New()
+	_, l, _ := e.Subscribe()
+	defer e.Evict(l)
+
+	container := &container.Container{
+		CommonContainer: container.CommonContainer{
+			ID:   "container_id",
+			Name: "container_name",
+			Config: &containertypes.Config{
+				Labels: map[string]string{
+					"node": "1",
+					"os":   "alpine",
+				},
+			},
+		},
+	}
+	daemon := &Daemon{
+		EventsService: e,
+	}
+	attributes := map[string]string{
+		"node": "2",
+		"foo":  "bar",
+	}
+	daemon.LogContainerEventWithAttributes(container, "create", attributes)
+
+	validateTestAttributes(t, l, map[string]string{
+		"node": "1",
+		"foo":  "bar",
+	})
+}
+
+func validateTestAttributes(t *testing.T, l chan interface{}, expectedAttributesToTest map[string]string) {
+	select {
+	case ev := <-l:
+		event, ok := ev.(eventtypes.Message)
+		if !ok {
+			t.Fatalf("Unexpected event message: %q", ev)
+		}
+		for key, expected := range expectedAttributesToTest {
+			actual, ok := event.Actor.Attributes[key]
+			if !ok || actual != expected {
+				t.Fatalf("Expected value for key %s to be %s, but was %s (event:%v)", key, expected, actual, event)
+			}
+		}
+	case <-time.After(10 * time.Second):
+		t.Fatalf("LogEvent test timed out")
+	}
 }
 }

+ 4 - 1
daemon/kill.go

@@ -65,7 +65,10 @@ func (daemon *Daemon) killWithSignal(container *container.Container, sig int) er
 		return err
 		return err
 	}
 	}
 
 
-	daemon.LogContainerEvent(container, "kill")
+	attributes := map[string]string{
+		"signal": fmt.Sprintf("%d", sig),
+	}
+	daemon.LogContainerEventWithAttributes(container, "kill", attributes)
 	return nil
 	return nil
 }
 }
 
 

+ 7 - 2
daemon/rename.go

@@ -49,8 +49,12 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
 		return err
 		return err
 	}
 	}
 
 
+	attributes := map[string]string{
+		"oldName": oldName,
+	}
+
 	if !container.Running {
 	if !container.Running {
-		daemon.LogContainerEvent(container, "rename")
+		daemon.LogContainerEventWithAttributes(container, "rename", attributes)
 		return nil
 		return nil
 	}
 	}
 
 
@@ -73,6 +77,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	daemon.LogContainerEvent(container, "rename")
+
+	daemon.LogContainerEventWithAttributes(container, "rename", attributes)
 	return nil
 	return nil
 }
 }

+ 10 - 2
daemon/resize.go

@@ -1,6 +1,10 @@
 package daemon
 package daemon
 
 
-import derr "github.com/docker/docker/errors"
+import (
+	"fmt"
+
+	derr "github.com/docker/docker/errors"
+)
 
 
 // ContainerResize changes the size of the TTY of the process running
 // ContainerResize changes the size of the TTY of the process running
 // in the container with the given name to the given height and width.
 // 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 {
 	}
 	}
 
 
 	if err = container.Resize(height, width); err == nil {
 	if err = container.Resize(height, width); err == nil {
-		daemon.LogContainerEvent(container, "resize")
+		attributes := map[string]string{
+			"height": fmt.Sprintf("%d", height),
+			"width":  fmt.Sprintf("%d", width),
+		}
+		daemon.LogContainerEventWithAttributes(container, "resize", attributes)
 	}
 	}
 	return err
 	return err
 }
 }

+ 5 - 1
daemon/start.go

@@ -1,6 +1,7 @@
 package daemon
 package daemon
 
 
 import (
 import (
+	"fmt"
 	"runtime"
 	"runtime"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
@@ -101,7 +102,10 @@ func (daemon *Daemon) containerStart(container *container.Container) (err error)
 			}
 			}
 			container.ToDisk()
 			container.ToDisk()
 			daemon.Cleanup(container)
 			daemon.Cleanup(container)
-			daemon.LogContainerEvent(container, "die")
+			attributes := map[string]string{
+				"exitCode": fmt.Sprintf("%d", container.ExitCode),
+			}
+			daemon.LogContainerEventWithAttributes(container, "die", attributes)
 		}
 		}
 	}()
 	}()