Merge branch 'master' into patch-2
This commit is contained in:
commit
69e0ad3806
4
.gitignore
vendored
4
.gitignore
vendored
@ -4,3 +4,7 @@ cadvisor
|
||||
|
||||
# Go test binaries
|
||||
*.test
|
||||
|
||||
# Files generated by JetBrains IDEs, e.g. IntelliJ IDEA
|
||||
.idea/
|
||||
*.iml
|
||||
|
@ -33,6 +33,7 @@ import (
|
||||
"github.com/google/cadvisor/version"
|
||||
|
||||
"crypto/tls"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
@ -60,13 +61,17 @@ var collectorKey = flag.String("collector_key", "", "Key for the collector's cer
|
||||
var (
|
||||
// Metrics to be ignored.
|
||||
// Tcp metrics are ignored by default.
|
||||
ignoreMetrics metricSetValue = metricSetValue{container.MetricSet{container.NetworkTcpUsageMetrics: struct{}{}}}
|
||||
ignoreMetrics metricSetValue = metricSetValue{container.MetricSet{
|
||||
container.NetworkTcpUsageMetrics: struct{}{},
|
||||
container.NetworkUdpUsageMetrics: struct{}{},
|
||||
}}
|
||||
|
||||
// List of metrics that can be ignored.
|
||||
ignoreWhitelist = container.MetricSet{
|
||||
container.DiskUsageMetrics: struct{}{},
|
||||
container.NetworkUsageMetrics: struct{}{},
|
||||
container.NetworkTcpUsageMetrics: struct{}{},
|
||||
container.NetworkUdpUsageMetrics: struct{}{},
|
||||
}
|
||||
)
|
||||
|
||||
@ -98,7 +103,7 @@ func (ml *metricSetValue) Set(value string) error {
|
||||
}
|
||||
|
||||
func init() {
|
||||
flag.Var(&ignoreMetrics, "disable_metrics", "comma-separated list of `metrics` to be disabled. Options are 'disk', 'network', 'tcp'. Note: tcp is disabled by default due to high CPU usage.")
|
||||
flag.Var(&ignoreMetrics, "disable_metrics", "comma-separated list of `metrics` to be disabled. Options are 'disk', 'network', 'tcp', 'udp'. Note: tcp and udp are disabled by default due to high CPU usage.")
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@ -28,6 +28,12 @@ func TestTcpMetricsAreDisabledByDefault(t *testing.T) {
|
||||
assert.True(t, ignoreMetrics.Has(container.NetworkTcpUsageMetrics))
|
||||
}
|
||||
|
||||
func TestUdpMetricsAreDisabledByDefault(t *testing.T) {
|
||||
assert.True(t, ignoreMetrics.Has(container.NetworkUdpUsageMetrics))
|
||||
flag.Parse()
|
||||
assert.True(t, ignoreMetrics.Has(container.NetworkUdpUsageMetrics))
|
||||
}
|
||||
|
||||
func TestIgnoreMetrics(t *testing.T) {
|
||||
tests := []struct {
|
||||
value string
|
||||
|
@ -31,21 +31,35 @@ import (
|
||||
"github.com/google/cadvisor/info/v1"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Client represents the base URL for a cAdvisor client.
|
||||
type Client struct {
|
||||
baseUrl string
|
||||
baseUrl string
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
// NewClient returns a new v1.3 client with the specified base URL.
|
||||
func NewClient(url string) (*Client, error) {
|
||||
return newClient(url, http.DefaultClient)
|
||||
}
|
||||
|
||||
// NewClientWithTimeout returns a new v1.3 client with the specified base URL and http client timeout.
|
||||
func NewClientWithTimeout(url string, timeout time.Duration) (*Client, error) {
|
||||
return newClient(url, &http.Client{
|
||||
Timeout: timeout,
|
||||
})
|
||||
}
|
||||
|
||||
func newClient(url string, client *http.Client) (*Client, error) {
|
||||
if !strings.HasSuffix(url, "/") {
|
||||
url += "/"
|
||||
}
|
||||
|
||||
return &Client{
|
||||
baseUrl: fmt.Sprintf("%sapi/v1.3/", url),
|
||||
baseUrl: fmt.Sprintf("%sapi/v1.3/", url),
|
||||
httpClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -168,9 +182,9 @@ func (self *Client) httpGetJsonData(data, postData interface{}, url, infoName st
|
||||
if marshalErr != nil {
|
||||
return fmt.Errorf("unable to marshal data: %v", marshalErr)
|
||||
}
|
||||
resp, err = http.Post(url, "application/json", bytes.NewBuffer(data))
|
||||
resp, err = self.httpClient.Post(url, "application/json", bytes.NewBuffer(data))
|
||||
} else {
|
||||
resp, err = http.Get(url)
|
||||
resp, err = self.httpClient.Get(url)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get %q from %q: %v", infoName, url, err)
|
||||
@ -199,7 +213,7 @@ func (self *Client) getEventStreamingData(url string, einfo chan *v1.Event) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
resp, err := self.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@ -39,6 +40,7 @@ func Status() (v1.DockerStatus, error) {
|
||||
|
||||
out := v1.DockerStatus{}
|
||||
out.Version = VersionString()
|
||||
out.APIVersion = APIVersionString()
|
||||
out.KernelVersion = machine.KernelVersion()
|
||||
out.OS = dockerInfo.OperatingSystem
|
||||
out.Hostname = dockerInfo.Name
|
||||
@ -105,7 +107,7 @@ func ValidateInfo() (*dockertypes.Info, error) {
|
||||
}
|
||||
dockerInfo.ServerVersion = version.Version
|
||||
}
|
||||
version, err := parseDockerVersion(dockerInfo.ServerVersion)
|
||||
version, err := parseVersion(dockerInfo.ServerVersion, version_re, 3)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -129,7 +131,11 @@ func ValidateInfo() (*dockertypes.Info, error) {
|
||||
}
|
||||
|
||||
func Version() ([]int, error) {
|
||||
return parseDockerVersion(VersionString())
|
||||
return parseVersion(VersionString(), version_re, 3)
|
||||
}
|
||||
|
||||
func APIVersion() ([]int, error) {
|
||||
return parseVersion(APIVersionString(), apiversion_re, 2)
|
||||
}
|
||||
|
||||
func VersionString() string {
|
||||
@ -144,18 +150,29 @@ func VersionString() string {
|
||||
return docker_version
|
||||
}
|
||||
|
||||
// TODO: switch to a semantic versioning library.
|
||||
func parseDockerVersion(full_version_string string) ([]int, error) {
|
||||
matches := version_re.FindAllStringSubmatch(full_version_string, -1)
|
||||
func APIVersionString() string {
|
||||
docker_api_version := "Unknown"
|
||||
client, err := Client()
|
||||
if err == nil {
|
||||
version, err := client.ServerVersion(context.Background())
|
||||
if err == nil {
|
||||
docker_api_version = version.APIVersion
|
||||
}
|
||||
}
|
||||
return docker_api_version
|
||||
}
|
||||
|
||||
func parseVersion(version_string string, regex *regexp.Regexp, length int) ([]int, error) {
|
||||
matches := regex.FindAllStringSubmatch(version_string, -1)
|
||||
if len(matches) != 1 {
|
||||
return nil, fmt.Errorf("version string \"%v\" doesn't match expected regular expression: \"%v\"", full_version_string, version_regexp_string)
|
||||
return nil, fmt.Errorf("version string \"%v\" doesn't match expected regular expression: \"%v\"", version_string, regex.String())
|
||||
}
|
||||
version_string_array := matches[0][1:]
|
||||
version_array := make([]int, 3)
|
||||
for index, version_string := range version_string_array {
|
||||
version, err := strconv.Atoi(version_string)
|
||||
version_array := make([]int, length)
|
||||
for index, version_str := range version_string_array {
|
||||
version, err := strconv.Atoi(version_str)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while parsing \"%v\" in \"%v\"", version_string, full_version_string)
|
||||
return nil, fmt.Errorf("error while parsing \"%v\" in \"%v\"", version_str, version_string)
|
||||
}
|
||||
version_array[index] = version
|
||||
}
|
||||
|
51
container/docker/docker_test.go
Normal file
51
container/docker/docker_test.go
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package docker
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseDockerAPIVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
version string
|
||||
regex *regexp.Regexp
|
||||
length int
|
||||
expected []int
|
||||
expectedError string
|
||||
}{
|
||||
{"17.03.0", version_re, 3, []int{17, 03, 0}, ""},
|
||||
{"17.a3.0", version_re, 3, []int{}, `version string "17.a3.0" doesn't match expected regular expression: "(\d+)\.(\d+)\.(\d+)"`},
|
||||
{"1.20", apiversion_re, 2, []int{1, 20}, ""},
|
||||
{"1.a", apiversion_re, 2, []int{}, `version string "1.a" doesn't match expected regular expression: "(\d+)\.(\d+)"`},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
actual, err := parseVersion(test.version, test.regex, test.length)
|
||||
if err != nil {
|
||||
if len(test.expectedError) == 0 {
|
||||
t.Errorf("%s: expected no error, got %v", test.version, err)
|
||||
} else if err.Error() != test.expectedError {
|
||||
t.Errorf("%s: expected error %v, got %v", test.version, test.expectedError, err)
|
||||
}
|
||||
} else {
|
||||
if !reflect.DeepEqual(actual, test.expected) {
|
||||
t.Errorf("%s: expected array %v, got %v", test.version, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -103,6 +103,8 @@ type dockerFactory struct {
|
||||
|
||||
dockerVersion []int
|
||||
|
||||
dockerAPIVersion []int
|
||||
|
||||
ignoreMetrics container.MetricSet
|
||||
|
||||
thinPoolWatcher *devicemapper.ThinPoolWatcher
|
||||
@ -185,8 +187,10 @@ func (self *dockerFactory) DebugInfo() map[string][]string {
|
||||
}
|
||||
|
||||
var (
|
||||
version_regexp_string = `(\d+)\.(\d+)\.(\d+)`
|
||||
version_re = regexp.MustCompile(version_regexp_string)
|
||||
version_regexp_string = `(\d+)\.(\d+)\.(\d+)`
|
||||
version_re = regexp.MustCompile(version_regexp_string)
|
||||
apiversion_regexp_string = `(\d+)\.(\d+)`
|
||||
apiversion_re = regexp.MustCompile(apiversion_regexp_string)
|
||||
)
|
||||
|
||||
func startThinPoolWatcher(dockerInfo *dockertypes.Info) (*devicemapper.ThinPoolWatcher, error) {
|
||||
@ -310,7 +314,9 @@ func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics c
|
||||
}
|
||||
|
||||
// Version already validated above, assume no error here.
|
||||
dockerVersion, _ := parseDockerVersion(dockerInfo.ServerVersion)
|
||||
dockerVersion, _ := parseVersion(dockerInfo.ServerVersion, version_re, 3)
|
||||
|
||||
dockerAPIVersion, _ := APIVersion()
|
||||
|
||||
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems()
|
||||
if err != nil {
|
||||
@ -338,6 +344,7 @@ func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics c
|
||||
cgroupSubsystems: cgroupSubsystems,
|
||||
client: client,
|
||||
dockerVersion: dockerVersion,
|
||||
dockerAPIVersion: dockerAPIVersion,
|
||||
fsInfo: fsInfo,
|
||||
machineInfoFactory: factory,
|
||||
storageDriver: storageDriver(dockerInfo.Driver),
|
||||
|
@ -48,6 +48,7 @@ const (
|
||||
DiskUsageMetrics MetricKind = "disk"
|
||||
NetworkUsageMetrics MetricKind = "network"
|
||||
NetworkTcpUsageMetrics MetricKind = "tcp"
|
||||
NetworkUdpUsageMetrics MetricKind = "udp"
|
||||
AppMetrics MetricKind = "app"
|
||||
)
|
||||
|
||||
|
@ -17,6 +17,7 @@ package libcontainer
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
@ -118,6 +119,21 @@ func GetStats(cgroupManager cgroups.Manager, rootFs string, pid int, ignoreMetri
|
||||
stats.Network.Tcp6 = t6
|
||||
}
|
||||
}
|
||||
if !ignoreMetrics.Has(container.NetworkUdpUsageMetrics) {
|
||||
u, err := udpStatsFromProc(rootFs, pid, "net/udp")
|
||||
if err != nil {
|
||||
glog.V(2).Infof("Unable to get udp stats from pid %d: %v", pid, err)
|
||||
} else {
|
||||
stats.Network.Udp = u
|
||||
}
|
||||
|
||||
u6, err := udpStatsFromProc(rootFs, pid, "net/udp6")
|
||||
if err != nil {
|
||||
glog.V(2).Infof("Unable to get udp6 stats from pid %d: %v", pid, err)
|
||||
} else {
|
||||
stats.Network.Udp6 = u6
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility.
|
||||
if len(stats.Network.Interfaces) > 0 {
|
||||
@ -291,6 +307,74 @@ func scanTcpStats(tcpStatsFile string) (info.TcpStat, error) {
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func udpStatsFromProc(rootFs string, pid int, file string) (info.UdpStat, error) {
|
||||
var err error
|
||||
var udpStats info.UdpStat
|
||||
|
||||
udpStatsFile := path.Join(rootFs, "proc", strconv.Itoa(pid), file)
|
||||
|
||||
r, err := os.Open(udpStatsFile)
|
||||
if err != nil {
|
||||
return udpStats, fmt.Errorf("failure opening %s: %v", udpStatsFile, err)
|
||||
}
|
||||
|
||||
udpStats, err = scanUdpStats(r)
|
||||
if err != nil {
|
||||
return udpStats, fmt.Errorf("couldn't read udp stats: %v", err)
|
||||
}
|
||||
|
||||
return udpStats, nil
|
||||
}
|
||||
|
||||
func scanUdpStats(r io.Reader) (info.UdpStat, error) {
|
||||
var stats info.UdpStat
|
||||
|
||||
scanner := bufio.NewScanner(r)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
|
||||
// Discard header line
|
||||
if b := scanner.Scan(); !b {
|
||||
return stats, scanner.Err()
|
||||
}
|
||||
|
||||
listening := uint64(0)
|
||||
dropped := uint64(0)
|
||||
rxQueued := uint64(0)
|
||||
txQueued := uint64(0)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
// Format: sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops
|
||||
|
||||
listening++
|
||||
|
||||
fs := strings.Fields(line)
|
||||
if len(fs) != 13 {
|
||||
continue
|
||||
}
|
||||
|
||||
rx, tx := uint64(0), uint64(0)
|
||||
fmt.Sscanf(fs[4], "%X:%X", &rx, &tx)
|
||||
rxQueued += rx
|
||||
txQueued += tx
|
||||
|
||||
d, err := strconv.Atoi(string(fs[12]))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
dropped += uint64(d)
|
||||
}
|
||||
|
||||
stats = info.UdpStat{
|
||||
Listen: listening,
|
||||
Dropped: dropped,
|
||||
RxQueued: rxQueued,
|
||||
TxQueued: txQueued,
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func GetProcesses(cgroupManager cgroups.Manager) ([]int, error) {
|
||||
pids, err := cgroupManager.GetPids()
|
||||
if err != nil {
|
||||
|
@ -15,6 +15,7 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
@ -61,3 +62,27 @@ func TestScanInterfaceStats(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestScanUDPStats(t *testing.T) {
|
||||
udpStatsFile := "testdata/procnetudp"
|
||||
r, err := os.Open(udpStatsFile)
|
||||
if err != nil {
|
||||
t.Errorf("failure opening %s: %v", udpStatsFile, err)
|
||||
}
|
||||
|
||||
stats, err := scanUdpStats(r)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var udpstats = info.UdpStat{
|
||||
Listen: 2,
|
||||
Dropped: 4,
|
||||
RxQueued: 10,
|
||||
TxQueued: 11,
|
||||
}
|
||||
|
||||
if stats != udpstats {
|
||||
t.Errorf("Expected %#v, got %#v", udpstats, stats)
|
||||
}
|
||||
}
|
||||
|
3
container/libcontainer/testdata/procnetudp
vendored
Normal file
3
container/libcontainer/testdata/procnetudp
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops
|
||||
1: 00000000:07D3 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 16583 2 ffff8800b4549400 0
|
||||
21: 00000000:A841 00000000:0000 07 0000000A:0000000B 00:00000000 00000000 1000 0 114299623 2 ffff880338477800 4
|
@ -386,6 +386,10 @@ type NetworkStats struct {
|
||||
Tcp TcpStat `json:"tcp"`
|
||||
// TCP6 connection stats (Established, Listen...)
|
||||
Tcp6 TcpStat `json:"tcp6"`
|
||||
// UDP connection stats
|
||||
Udp UdpStat `json:"udp"`
|
||||
// UDP6 connection stats
|
||||
Udp6 UdpStat `json:"udp6"`
|
||||
}
|
||||
|
||||
type TcpStat struct {
|
||||
@ -413,6 +417,20 @@ type TcpStat struct {
|
||||
Closing uint64
|
||||
}
|
||||
|
||||
type UdpStat struct {
|
||||
// Count of UDP sockets in state "Listen"
|
||||
Listen uint64
|
||||
|
||||
// Count of UDP packets dropped by the IP stack
|
||||
Dropped uint64
|
||||
|
||||
// Count of packets Queued for Receieve
|
||||
RxQueued uint64
|
||||
|
||||
// Count of packets Queued for Transmit
|
||||
TxQueued uint64
|
||||
}
|
||||
|
||||
type FsStats struct {
|
||||
// The block device name associated with the filesystem.
|
||||
Device string `json:"device,omitempty"`
|
||||
|
@ -17,6 +17,7 @@ package v1
|
||||
|
||||
type DockerStatus struct {
|
||||
Version string `json:"version"`
|
||||
APIVersion string `json:"api_version"`
|
||||
KernelVersion string `json:"kernel_version"`
|
||||
OS string `json:"os"`
|
||||
Hostname string `json:"hostname"`
|
||||
|
@ -196,6 +196,9 @@ type VersionInfo struct {
|
||||
// Docker version.
|
||||
DockerVersion string `json:"docker_version"`
|
||||
|
||||
// Docker API Version
|
||||
DockerAPIVersion string `json:"docker_api_version"`
|
||||
|
||||
// cAdvisor version.
|
||||
CadvisorVersion string `json:"cadvisor_version"`
|
||||
// cAdvisor git revision.
|
||||
|
@ -269,6 +269,10 @@ type NetworkStats struct {
|
||||
Tcp TcpStat `json:"tcp"`
|
||||
// TCP6 connection stats (Established, Listen...)
|
||||
Tcp6 TcpStat `json:"tcp6"`
|
||||
// UDP connection stats
|
||||
Udp v1.UdpStat `json:"udp"`
|
||||
// UDP6 connection stats
|
||||
Udp6 v1.UdpStat `json:"udp6"`
|
||||
}
|
||||
|
||||
// Instantaneous CPU stats
|
||||
|
@ -133,7 +133,7 @@ func ContainerStatsFromV1(containerName string, spec *v1.ContainerSpec, stats []
|
||||
}
|
||||
} else if len(val.Filesystem) > 1 && containerName != "/" {
|
||||
// Cannot handle multiple devices per container.
|
||||
glog.V(2).Infof("failed to handle multiple devices for container %s. Skipping Filesystem stats", containerName)
|
||||
glog.V(4).Infof("failed to handle multiple devices for container %s. Skipping Filesystem stats", containerName)
|
||||
}
|
||||
}
|
||||
if spec.HasDiskIo {
|
||||
@ -259,6 +259,7 @@ func ContainerSpecFromV1(specV1 *v1.ContainerSpec, aliases []string, namespace s
|
||||
HasCustomMetrics: specV1.HasCustomMetrics,
|
||||
Image: specV1.Image,
|
||||
Labels: specV1.Labels,
|
||||
Envs: specV1.Envs,
|
||||
}
|
||||
if specV1.HasCpu {
|
||||
specV2.Cpu.Limit = specV1.Cpu.Limit
|
||||
|
@ -26,12 +26,14 @@ import (
|
||||
var (
|
||||
timestamp = time.Date(1987, time.August, 10, 0, 0, 0, 0, time.UTC)
|
||||
labels = map[string]string{"foo": "bar"}
|
||||
envs = map[string]string{"foo": "bar"}
|
||||
)
|
||||
|
||||
func TestContanierSpecFromV1(t *testing.T) {
|
||||
v1Spec := v1.ContainerSpec{
|
||||
CreationTime: timestamp,
|
||||
Labels: labels,
|
||||
Envs: envs,
|
||||
HasCpu: true,
|
||||
Cpu: v1.CpuSpec{
|
||||
Limit: 2048,
|
||||
@ -63,6 +65,7 @@ func TestContanierSpecFromV1(t *testing.T) {
|
||||
expectedV2Spec := ContainerSpec{
|
||||
CreationTime: timestamp,
|
||||
Labels: labels,
|
||||
Envs: envs,
|
||||
HasCpu: true,
|
||||
Cpu: CpuSpec{
|
||||
Limit: 2048,
|
||||
|
@ -31,6 +31,9 @@ type Attributes struct {
|
||||
// Docker version.
|
||||
DockerVersion string `json:"docker_version"`
|
||||
|
||||
// Docker API version.
|
||||
DockerAPIVersion string `json:"docker_api_version"`
|
||||
|
||||
// cAdvisor version.
|
||||
CadvisorVersion string `json:"cadvisor_version"`
|
||||
|
||||
@ -74,6 +77,7 @@ func GetAttributes(mi *v1.MachineInfo, vi *v1.VersionInfo) Attributes {
|
||||
KernelVersion: vi.KernelVersion,
|
||||
ContainerOsVersion: vi.ContainerOsVersion,
|
||||
DockerVersion: vi.DockerVersion,
|
||||
DockerAPIVersion: vi.DockerAPIVersion,
|
||||
CadvisorVersion: vi.CadvisorVersion,
|
||||
NumCores: mi.NumCores,
|
||||
CpuFrequency: mi.CpuFrequency,
|
||||
|
@ -1255,11 +1255,13 @@ func getVersionInfo() (*info.VersionInfo, error) {
|
||||
kernel_version := machine.KernelVersion()
|
||||
container_os := machine.ContainerOsVersion()
|
||||
docker_version := docker.VersionString()
|
||||
docker_api_version := docker.APIVersionString()
|
||||
|
||||
return &info.VersionInfo{
|
||||
KernelVersion: kernel_version,
|
||||
ContainerOsVersion: container_os,
|
||||
DockerVersion: docker_version,
|
||||
DockerAPIVersion: docker_api_version,
|
||||
CadvisorVersion: version.Info["version"],
|
||||
CadvisorRevision: version.Info["revision"],
|
||||
}, nil
|
||||
|
@ -130,10 +130,12 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
|
||||
getValues: func(s *info.ContainerStats) metricValues {
|
||||
values := make(metricValues, 0, len(s.Cpu.Usage.PerCpu))
|
||||
for i, value := range s.Cpu.Usage.PerCpu {
|
||||
values = append(values, metricValue{
|
||||
value: float64(value) / float64(time.Second),
|
||||
labels: []string{fmt.Sprintf("cpu%02d", i)},
|
||||
})
|
||||
if value > 0 {
|
||||
values = append(values, metricValue{
|
||||
value: float64(value) / float64(time.Second),
|
||||
labels: []string{fmt.Sprintf("cpu%02d", i)},
|
||||
})
|
||||
}
|
||||
}
|
||||
return values
|
||||
},
|
||||
|
@ -40,6 +40,7 @@ func toStatusKV(status info.DockerStatus) ([]keyVal, []keyVal) {
|
||||
}
|
||||
return []keyVal{
|
||||
{Key: "Docker Version", Value: status.Version},
|
||||
{Key: "Docker API Version", Value: status.APIVersion},
|
||||
{Key: "Kernel Version", Value: status.KernelVersion},
|
||||
{Key: "OS Version", Value: status.OS},
|
||||
{Key: "Host Name", Value: status.Hostname},
|
||||
|
Loading…
Reference in New Issue
Block a user