Run custom collectors in container housekeeping.

This will allow us to register and run custom collectors for each
container.
This commit is contained in:
Victor Marmol 2015-05-04 15:16:18 -07:00
parent 5b39a77318
commit bce54ce3f5
4 changed files with 35 additions and 9 deletions

View File

@ -24,6 +24,7 @@ import (
"github.com/docker/docker/pkg/units" "github.com/docker/docker/pkg/units"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/google/cadvisor/collector"
"github.com/google/cadvisor/container" "github.com/google/cadvisor/container"
info "github.com/google/cadvisor/info/v1" info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/info/v2" "github.com/google/cadvisor/info/v2"
@ -63,6 +64,9 @@ type containerData struct {
// Tells the container to stop. // Tells the container to stop.
stop chan bool stop chan bool
// Runs custom metric collectors.
collectorManager collector.CollectorManager
} }
func (c *containerData) Start() error { func (c *containerData) Start() error {
@ -109,7 +113,7 @@ func (c *containerData) DerivedStats() (v2.DerivedStats, error) {
return c.summaryReader.DerivedStats() return c.summaryReader.DerivedStats()
} }
func newContainerData(containerName string, memoryStorage *memory.InMemoryStorage, handler container.ContainerHandler, loadReader cpuload.CpuLoadReader, logUsage bool) (*containerData, error) { func newContainerData(containerName string, memoryStorage *memory.InMemoryStorage, handler container.ContainerHandler, loadReader cpuload.CpuLoadReader, logUsage bool, collectorManager collector.CollectorManager) (*containerData, error) {
if memoryStorage == nil { if memoryStorage == nil {
return nil, fmt.Errorf("nil memory storage") return nil, fmt.Errorf("nil memory storage")
} }
@ -129,6 +133,7 @@ func newContainerData(containerName string, memoryStorage *memory.InMemoryStorag
logUsage: logUsage, logUsage: logUsage,
loadAvg: -1.0, // negative value indicates uninitialized. loadAvg: -1.0, // negative value indicates uninitialized.
stop: make(chan bool, 1), stop: make(chan bool, 1),
collectorManager: collectorManager,
} }
cont.info.ContainerReference = ref cont.info.ContainerReference = ref
@ -172,6 +177,7 @@ func (self *containerData) nextHousekeeping(lastHousekeeping time.Time) time.Tim
return lastHousekeeping.Add(self.housekeepingInterval) return lastHousekeeping.Add(self.housekeepingInterval)
} }
// TODO(vmarmol): Implement stats collecting as a custom collector.
func (c *containerData) housekeeping() { func (c *containerData) housekeeping() {
// Long housekeeping is either 100ms or half of the housekeeping interval. // Long housekeeping is either 100ms or half of the housekeeping interval.
longHousekeeping := 100 * time.Millisecond longHousekeeping := 100 * time.Millisecond
@ -226,12 +232,24 @@ func (c *containerData) housekeeping() {
} }
} }
// Schedule the next housekeeping. Sleep until that time. // Run custom collectors.
nextHousekeeping := c.nextHousekeeping(lastHousekeeping) nextCollectionTime, err := c.collectorManager.Collect()
if time.Now().Before(nextHousekeeping) { if err != nil && c.allowErrorLogging() {
time.Sleep(nextHousekeeping.Sub(time.Now())) glog.Warningf("[%s] Collection failed: %v", c.info.Name, err)
} }
lastHousekeeping = nextHousekeeping
// Next housekeeping is the first of the stats or the custom collector's housekeeping.
nextHousekeeping := c.nextHousekeeping(lastHousekeeping)
next := nextHousekeeping
if !nextCollectionTime.IsZero() && nextCollectionTime.Before(nextHousekeeping) {
next = nextCollectionTime
}
// Schedule the next housekeeping. Sleep until that time.
if time.Now().Before(next) {
time.Sleep(next.Sub(time.Now()))
}
lastHousekeeping = next
} }
} }

View File

@ -22,6 +22,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/google/cadvisor/collector"
"github.com/google/cadvisor/container" "github.com/google/cadvisor/container"
info "github.com/google/cadvisor/info/v1" info "github.com/google/cadvisor/info/v1"
itest "github.com/google/cadvisor/info/v1/test" itest "github.com/google/cadvisor/info/v1/test"
@ -40,7 +41,7 @@ func setupContainerData(t *testing.T, spec info.ContainerSpec) (*containerData,
nil, nil,
) )
memoryStorage := memory.New(60, nil) memoryStorage := memory.New(60, nil)
ret, err := newContainerData(containerName, memoryStorage, mockHandler, nil, false) ret, err := newContainerData(containerName, memoryStorage, mockHandler, nil, false, &collector.FakeCollectorManager{})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -27,6 +27,7 @@ import (
"github.com/docker/libcontainer/cgroups" "github.com/docker/libcontainer/cgroups"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/google/cadvisor/collector"
"github.com/google/cadvisor/container" "github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/docker" "github.com/google/cadvisor/container/docker"
"github.com/google/cadvisor/container/raw" "github.com/google/cadvisor/container/raw"
@ -650,8 +651,13 @@ func (m *manager) createContainer(containerName string) error {
glog.V(4).Infof("ignoring container %q", containerName) glog.V(4).Infof("ignoring container %q", containerName)
return nil return nil
} }
// TODO(vmarmol): Register collectors.
collectorManager, err := collector.NewCollectorManager()
if err != nil {
return err
}
logUsage := *logCadvisorUsage && containerName == m.cadvisorContainer logUsage := *logCadvisorUsage && containerName == m.cadvisorContainer
cont, err := newContainerData(containerName, m.memoryStorage, handler, m.loadReader, logUsage) cont, err := newContainerData(containerName, m.memoryStorage, handler, m.loadReader, logUsage, collectorManager)
if err != nil { if err != nil {
return err return err
} }

View File

@ -22,6 +22,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/google/cadvisor/collector"
"github.com/google/cadvisor/container" "github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/docker" "github.com/google/cadvisor/container/docker"
info "github.com/google/cadvisor/info/v1" info "github.com/google/cadvisor/info/v1"
@ -52,7 +53,7 @@ func createManagerAndAddContainers(
spec, spec,
nil, nil,
).Once() ).Once()
cont, err := newContainerData(name, memoryStorage, mockHandler, nil, false) cont, err := newContainerData(name, memoryStorage, mockHandler, nil, false, &collector.FakeCollectorManager{})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }