// GetMetricTypes returns list of available metrics func (d *docker) GetMetricTypes(_ plugin.ConfigType) ([]plugin.MetricType, error) { var metricTypes []plugin.MetricType var err error // initialize containerData struct data := containerData{ Stats: wrapper.NewStatistics(), } // generate available namespace for data container structure dockerMetrics := []string{} utils.FromCompositeObject(data, "", &dockerMetrics) nscreator := nsCreator{dynamicElements: definedDynamicElements} for _, metricName := range dockerMetrics { ns := core.NewNamespace(NS_VENDOR, NS_PLUGIN). AddDynamicElement("docker_id", "an id of docker container") if ns, err = nscreator.createMetricNamespace(ns, metricName); err != nil { // skip this metric name which is not supported // fmt.Fprintf(os.Stderr, "Error in creating metric namespace: %v\n", err) continue } metricType := plugin.MetricType{ Namespace_: ns, Version_: VERSION, } metricTypes = append(metricTypes, metricType) } return metricTypes, nil }
func CreateMockStats() *wrapper.Statistics { stats := wrapper.NewStatistics() stats.Connection.Tcp.Close = 1 stats.Connection.Tcp.Established = 1 stats.Connection.Tcp6.Close = 2 stats.Connection.Tcp6.Established = 2 stats.Network = []wrapper.NetworkInterface{ wrapper.NetworkInterface{ Name: "eth0", RxBytes: 1024, RxPackets: 1, TxBytes: 4096, TxPackets: 4, TxErrors: 0, }, wrapper.NetworkInterface{ Name: "eth1", RxBytes: 2048, RxPackets: 2, TxBytes: 0, TxPackets: 0, TxErrors: 10, }, } stats.Filesystem["dev1"] = wrapper.FilesystemInterface{ Device: "dev1", Type: "vfs", Limit: 0, Usage: 0, BaseUsage: 0, Available: 0, InodesFree: 0, ReadsCompleted: 0, } stats.Filesystem["dev2"] = wrapper.FilesystemInterface{ Device: "dev2", Type: "vfs", Limit: 0, Usage: 0, BaseUsage: 0, Available: 0, InodesFree: 0, ReadsCompleted: 0, } stats.CgroupStats.CpuStats.CpuUsage.PercpuUsage = []uint64{1000, 2000, 3000, 4000} return stats }
// GetStatsFromContainer returns docker containers stats: cgroups stats (cpu usage, memory usage, etc.) and network stats (tx_bytes, rx_bytes etc.); // notes that incoming container id has to be full-length to be able to inspect container func (dc *DockerClient) GetStatsFromContainer(id string, collectFs bool) (*wrapper.Statistics, error) { var ( err error pid int workingSet uint64 container = &docker.Container{} groupWrap = wrapper.CgroupsToStats // wrapper for cgroup name and interface for stats extraction stats = wrapper.NewStatistics() ) if !isHost(id) { if !isFullLengthID(id) { return nil, fmt.Errorf("Container id %+v is not fully-length - cannot inspect container", id) } // inspect container based only on fully-length container id. container, err = dc.InspectContainer(id) if err != nil { return nil, err } // take docker container PID pid = container.State.Pid } for cg, stat := range groupWrap { groupPath, err := getSubsystemPath(cg, id) if err != nil { fmt.Fprintln(os.Stderr, "Cannot found subsystem path for cgroup=", cg, " for container id=", container) continue } switch cg { case "cpuset": cpuset := wrapper.CpuSet{} // get cpuset group stats err = cpuset.GetExtendedStats(groupPath, stats.CgroupsExtended) case "shares": // get cpu.shares stats shares := wrapper.Shares{} err = shares.GetExtendedStats(groupPath, stats.CgroupsExtended) default: // get cgroup stats for given docker err = stat.GetStats(groupPath, stats.CgroupStats) } if err != nil { // just log about it if isHost(id) { fmt.Fprintln(os.Stderr, "Cannot obtain cgroups statistics for host, err=", err) } else { fmt.Fprintln(os.Stderr, "Cannot obtain cgroups statistics for container: id=", id, ", image=", container.Image, ", name=", container.Name, ", err=", err) } continue } } // calculate additional stats memory:working_set based on memory_stats if totalInactiveAnon, ok := stats.CgroupStats.MemoryStats.Stats["total_inactive_anon"]; ok { workingSet = stats.CgroupStats.MemoryStats.Usage.Usage if workingSet < totalInactiveAnon { workingSet = 0 } else { workingSet -= totalInactiveAnon } if totalInactiveFile, ok := stats.CgroupStats.MemoryStats.Stats["total_inactive_file"]; ok { if workingSet < totalInactiveFile { workingSet = 0 } else { workingSet -= totalInactiveFile } } } stats.CgroupStats.MemoryStats.Stats["working_set"] = workingSet if !isHost(id) { rootFs := "/" stats.Network, err = network.NetworkStatsFromProc(rootFs, pid) if err != nil { // only log error message fmt.Fprintf(os.Stderr, "Unable to get network stats, containerID=%+v, pid %d: %v", container.ID, pid, err) } stats.Connection.Tcp, err = network.TcpStatsFromProc(rootFs, pid) if err != nil { // only log error message fmt.Fprintf(os.Stderr, "Unable to get tcp stats from pid %d: %v", pid, err) } stats.Connection.Tcp6, err = network.Tcp6StatsFromProc(rootFs, pid) if err != nil { // only log error message fmt.Fprintf(os.Stderr, "Unable to get tcp6 stats from pid %d: %v", pid, err) } } else { stats.Network, err = network.NetworkStatsFromRoot() if err != nil { // only log error message fmt.Fprintf(os.Stderr, "Unable to get network stats, containerID=%v, %v", id, err) } } if collectFs { stats.Filesystem, err = fs.GetFsStats(container) if err != nil { // only log error message fmt.Fprintf(os.Stderr, "Unable to get filesystem stats for docker: %v, err=%v", id, err) } } return stats, nil }