WIP: Add stats API for 2.0.

First cut on 2.0 stats API. Main change in returned stats is that presence checks (eg. HasCPU) are embedded in each stat.
Added support to handle querying container with name.

Current syntax:
/stats?name=/&count=1,
/stats?name=docker/928c058ce260ac2a55972b18cb991fa0475fbbb7bc15bd295e62b76964d05fe6 [default count: 64]

Other handlers to include: dockerid, dockeralias. We can make subcontainers inclusion as an option too.
This commit is contained in:
Rohit Jnagal 2015-03-12 06:01:57 +00:00
parent a0a419614f
commit 2e2a31bea2
2 changed files with 110 additions and 0 deletions

View File

@ -17,6 +17,7 @@ package api
import (
"fmt"
"net/http"
"strconv"
"github.com/golang/glog"
"github.com/google/cadvisor/events"
@ -31,6 +32,7 @@ const (
machineApi = "machine"
dockerApi = "docker"
summaryApi = "summary"
statsApi = "stats"
specApi = "spec"
eventsApi = "events"
storageApi = "storage"
@ -314,6 +316,22 @@ func (self *version2_0) HandleRequest(requestType string, request []string, m ma
}
return writeResult(stats, w)
case statsApi:
name := getContainerName(request)
sr, err := getStatsRequest(name, r)
if err != nil {
return err
}
glog.V(2).Infof("Api - Stats: Looking for stats for container %q, options %+v", name, sr)
query := info.ContainerInfoRequest{
NumStats: sr.Count,
}
cont, err := m.GetContainerInfo(name, &query)
if err != nil {
return fmt.Errorf("failed to get container %q: %v", name, err)
}
contStats := convertStats(cont)
return writeResult(contStats, w)
case specApi:
containerName := getContainerName(request)
glog.V(2).Infof("Api - Spec(%v)", containerName)
@ -365,3 +383,59 @@ func convertSpec(specV1 info.ContainerSpec) v2.ContainerSpec {
}
return specV2
}
func convertStats(cont *info.ContainerInfo) []v2.ContainerStats {
stats := []v2.ContainerStats{}
for _, val := range cont.Stats {
stat := v2.ContainerStats{
Timestamp: val.Timestamp,
HasCpu: cont.Spec.HasCpu,
HasMemory: cont.Spec.HasMemory,
HasNetwork: cont.Spec.HasNetwork,
HasFilesystem: cont.Spec.HasFilesystem,
HasDiskIo: cont.Spec.HasDiskIo,
}
if stat.HasCpu {
stat.Cpu = val.Cpu
}
if stat.HasMemory {
stat.Memory = val.Memory
}
if stat.HasNetwork {
// TODO(rjnagal): Return stats about all network interfaces.
stat.Network = append(stat.Network, val.Network)
}
if stat.HasFilesystem {
stat.Filesystem = val.Filesystem
}
if stat.HasDiskIo {
stat.DiskIo = val.DiskIo
}
// TODO(rjnagal): Handle load stats.
stats = append(stats, stat)
}
return stats
}
func getStatsRequest(id string, r *http.Request) (v2.StatsRequest, error) {
// fill in the defaults.
sr := v2.StatsRequest{
IdType: "name",
Count: 64,
Recursive: false,
}
idType := r.URL.Query().Get("type")
if len(idType) != 0 && idType != "name" {
return sr, fmt.Errorf("unknown 'type' %q for container name %q", idType, id)
}
count := r.URL.Query().Get("count")
if len(count) != 0 {
n, err := strconv.ParseUint(count, 10, 32)
if err != nil {
return sr, fmt.Errorf("failed to parse 'count' option: %v", count)
}
sr.Count = int(n)
}
// TODO(rjnagal): Add option to specify recursive.
return sr, nil
}

View File

@ -16,6 +16,10 @@ package v2
import (
"time"
// TODO(rjnagal): Remove dependency after moving all stats structs from v1.
// using v1 now for easy conversion.
"github.com/google/cadvisor/info/v1"
)
type CpuSpec struct {
@ -54,6 +58,29 @@ type ContainerSpec struct {
Memory MemorySpec `json:"memory,omitempty"`
}
type ContainerStats struct {
// The time of this stat point.
Timestamp time.Time `json:"timestamp"`
// CPU statistics
HasCpu bool `json:"has_cpu"`
Cpu v1.CpuStats `json:"cpu,omitempty"`
// Disk IO statistics
HasDiskIo bool `json:"has_diskio"`
DiskIo v1.DiskIoStats `json:"diskio,omitempty"`
// Memory statistics
HasMemory bool `json:"has_memory"`
Memory v1.MemoryStats `json:"memory,omitempty"`
// Network statistics
HasNetwork bool `json:"has_network"`
Network []v1.NetworkStats `json:"network,omitempty"`
// Filesystem statistics
HasFilesystem bool `json:"has_filesystem"`
Filesystem []v1.FsStats `json:"filesystem,omitempty"`
// Task load statistics
HasLoad bool `json:"has_load"`
Load v1.LoadStats `json:"load_stats,omitempty"`
}
type Percentiles struct {
// Indicates whether the stats are present or not.
// If true, values below do not have any data.
@ -114,3 +141,12 @@ type FsInfo struct {
// Labels associated with this filesystem.
Labels []string `json:"labels"`
}
type StatsRequest struct {
// Type of container identifier specified - "name", "dockerid", dockeralias"
IdType string `json:"type"`
// Number of stats to return
Count int `json:"count"`
// Whether to include stats for child subcontainers.
Recursive bool `json:"recursive"`
}