Skip to content

Commit 2e2a31b

Browse files
committed
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.
1 parent a0a4196 commit 2e2a31b

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

api/versions.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package api
1717
import (
1818
"fmt"
1919
"net/http"
20+
"strconv"
2021

2122
"github.com/golang/glog"
2223
"github.com/google/cadvisor/events"
@@ -31,6 +32,7 @@ const (
3132
machineApi = "machine"
3233
dockerApi = "docker"
3334
summaryApi = "summary"
35+
statsApi = "stats"
3436
specApi = "spec"
3537
eventsApi = "events"
3638
storageApi = "storage"
@@ -314,6 +316,22 @@ func (self *version2_0) HandleRequest(requestType string, request []string, m ma
314316
}
315317

316318
return writeResult(stats, w)
319+
case statsApi:
320+
name := getContainerName(request)
321+
sr, err := getStatsRequest(name, r)
322+
if err != nil {
323+
return err
324+
}
325+
glog.V(2).Infof("Api - Stats: Looking for stats for container %q, options %+v", name, sr)
326+
query := info.ContainerInfoRequest{
327+
NumStats: sr.Count,
328+
}
329+
cont, err := m.GetContainerInfo(name, &query)
330+
if err != nil {
331+
return fmt.Errorf("failed to get container %q: %v", name, err)
332+
}
333+
contStats := convertStats(cont)
334+
return writeResult(contStats, w)
317335
case specApi:
318336
containerName := getContainerName(request)
319337
glog.V(2).Infof("Api - Spec(%v)", containerName)
@@ -365,3 +383,59 @@ func convertSpec(specV1 info.ContainerSpec) v2.ContainerSpec {
365383
}
366384
return specV2
367385
}
386+
387+
func convertStats(cont *info.ContainerInfo) []v2.ContainerStats {
388+
stats := []v2.ContainerStats{}
389+
for _, val := range cont.Stats {
390+
stat := v2.ContainerStats{
391+
Timestamp: val.Timestamp,
392+
HasCpu: cont.Spec.HasCpu,
393+
HasMemory: cont.Spec.HasMemory,
394+
HasNetwork: cont.Spec.HasNetwork,
395+
HasFilesystem: cont.Spec.HasFilesystem,
396+
HasDiskIo: cont.Spec.HasDiskIo,
397+
}
398+
if stat.HasCpu {
399+
stat.Cpu = val.Cpu
400+
}
401+
if stat.HasMemory {
402+
stat.Memory = val.Memory
403+
}
404+
if stat.HasNetwork {
405+
// TODO(rjnagal): Return stats about all network interfaces.
406+
stat.Network = append(stat.Network, val.Network)
407+
}
408+
if stat.HasFilesystem {
409+
stat.Filesystem = val.Filesystem
410+
}
411+
if stat.HasDiskIo {
412+
stat.DiskIo = val.DiskIo
413+
}
414+
// TODO(rjnagal): Handle load stats.
415+
stats = append(stats, stat)
416+
}
417+
return stats
418+
}
419+
420+
func getStatsRequest(id string, r *http.Request) (v2.StatsRequest, error) {
421+
// fill in the defaults.
422+
sr := v2.StatsRequest{
423+
IdType: "name",
424+
Count: 64,
425+
Recursive: false,
426+
}
427+
idType := r.URL.Query().Get("type")
428+
if len(idType) != 0 && idType != "name" {
429+
return sr, fmt.Errorf("unknown 'type' %q for container name %q", idType, id)
430+
}
431+
count := r.URL.Query().Get("count")
432+
if len(count) != 0 {
433+
n, err := strconv.ParseUint(count, 10, 32)
434+
if err != nil {
435+
return sr, fmt.Errorf("failed to parse 'count' option: %v", count)
436+
}
437+
sr.Count = int(n)
438+
}
439+
// TODO(rjnagal): Add option to specify recursive.
440+
return sr, nil
441+
}

info/v2/container.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ package v2
1616

1717
import (
1818
"time"
19+
20+
// TODO(rjnagal): Remove dependency after moving all stats structs from v1.
21+
// using v1 now for easy conversion.
22+
"github.com/google/cadvisor/info/v1"
1923
)
2024

2125
type CpuSpec struct {
@@ -54,6 +58,29 @@ type ContainerSpec struct {
5458
Memory MemorySpec `json:"memory,omitempty"`
5559
}
5660

61+
type ContainerStats struct {
62+
// The time of this stat point.
63+
Timestamp time.Time `json:"timestamp"`
64+
// CPU statistics
65+
HasCpu bool `json:"has_cpu"`
66+
Cpu v1.CpuStats `json:"cpu,omitempty"`
67+
// Disk IO statistics
68+
HasDiskIo bool `json:"has_diskio"`
69+
DiskIo v1.DiskIoStats `json:"diskio,omitempty"`
70+
// Memory statistics
71+
HasMemory bool `json:"has_memory"`
72+
Memory v1.MemoryStats `json:"memory,omitempty"`
73+
// Network statistics
74+
HasNetwork bool `json:"has_network"`
75+
Network []v1.NetworkStats `json:"network,omitempty"`
76+
// Filesystem statistics
77+
HasFilesystem bool `json:"has_filesystem"`
78+
Filesystem []v1.FsStats `json:"filesystem,omitempty"`
79+
// Task load statistics
80+
HasLoad bool `json:"has_load"`
81+
Load v1.LoadStats `json:"load_stats,omitempty"`
82+
}
83+
5784
type Percentiles struct {
5885
// Indicates whether the stats are present or not.
5986
// If true, values below do not have any data.
@@ -114,3 +141,12 @@ type FsInfo struct {
114141
// Labels associated with this filesystem.
115142
Labels []string `json:"labels"`
116143
}
144+
145+
type StatsRequest struct {
146+
// Type of container identifier specified - "name", "dockerid", dockeralias"
147+
IdType string `json:"type"`
148+
// Number of stats to return
149+
Count int `json:"count"`
150+
// Whether to include stats for child subcontainers.
151+
Recursive bool `json:"recursive"`
152+
}

0 commit comments

Comments
 (0)