Skip to content

Docker Stats Receiver #495

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Sep 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ updates:
directory: "/receiver/collectdreceiver"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/receiver/dockerstatsreceiver"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/receiver/k8sclusterreceiver"
schedule:
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ OTEL_VERSION=master
# Modules to run integration tests on.
# XXX: Find a way to automatically populate this. Too slow to run across all modules when there are just a few.
INTEGRATION_TEST_MODULES := \
receiver/dockerstatsreceiver \
receiver/redisreceiver \
internal/common

Expand Down
1 change: 1 addition & 0 deletions receiver/dockerstatsreceiver/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../../Makefile.Common
53 changes: 53 additions & 0 deletions receiver/dockerstatsreceiver/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Docker Stats Receiver

The Docker Stats receiver queries the local Docker daemon's container stats API for
all desired running containers on a configured interval. These stats are for container
resource usage of cpu, memory, network, and the
[blkio controller](https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt).

Requires Docker API version 1.22+. At this time only Linux is supported.

## Configuration

The following settings are required:

* `endpoint` (default = `unix:///var/run/docker.sock`): Address to reach the desired Docker daemon.

The following settings are optional:

* `collection_interval`: (default = `10s`) The interval at which to gather container stats.
* `timeout` (default = `5s`): The request timeout for any docker daemon query.
* `container_labels_to_metric_labels` (no default): A map of Docker container label names whose label values to use
as the specified metric label key.
* `env_vars_to_metric_labels` (no default): A map of Docker container environment variables whose values to use
as the specified metric label key.
* `excluded_images` (no default, all running containers monitored): A list of strings,
[regexes](https://golang.org/pkg/regexp/), or [globs](https://github.com/gobwas/glob) whose referent container image
names will not be among the queried containers. `!`-prefixed negations are possible for all item types to signify that
only unmatched container image names should be monitored.
* Regexes must be placed between `/` characters: `/my?egex/`. Negations are to be outside the forward slashes:
`!/my?egex/` will monitor all containers whose name doesn't match the compiled regex `my?egex`.
* Globs are non-regex items (e.g. `/items/`) containing any of the following: `*[]{}?`. Negations are supported:
`!my*container` will monitor all containers whose image name doesn't match the blob `my*container`.
* `provide_per_core_cpu_metrics` (default = `false`): Whether to report `cpu.usage.percpu` metrics.

Example:

```yaml
receivers:
docker_stats:
endpoint: http://example.com/
collection_interval: 2s
timeout: 20s
container_labels_to_metric_labels:
my.container.label: my-metric-label
my.other.container.label: my-other-metric-label
env_vars_to_metric_labels:
MY_ENVIRONMENT_VARIABLE: my-metric-label
MY_OTHER_ENVIRONMENT_VARIABLE: my-other-metric-label
excluded_images:
- undesired-container
- /.*undesired.*/
- another-*-container
provide_per_core_cpu_metrics: true
```
66 changes: 66 additions & 0 deletions receiver/dockerstatsreceiver/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2020, OpenTelemetry Authors
//
// 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 dockerstatsreceiver

import (
"errors"
"time"

"go.opentelemetry.io/collector/config/configmodels"
)

var _ configmodels.Receiver = (*Config)(nil)

type Config struct {
configmodels.ReceiverSettings `mapstructure:",squash"`
// The URL of the docker server. Default is "unix:///var/run/docker.sock"
Endpoint string `mapstructure:"endpoint"`
// The time between each collection event. Default is 10s.
CollectionInterval time.Duration `mapstructure:"collection_interval"`

// The maximum amount of time to wait for docker API responses. Default is 5s
Timeout time.Duration `mapstructure:"timeout"`

// A mapping of container label names to MetricDescriptor label keys.
// The corresponding container label value will become the DataPoint label value
// for the mapped name. E.g. `io.kubernetes.container.name: container_spec_name`
// would result in a MetricDescriptor label called `container_spec_name` whose
// Metric DataPoints have the value of the `io.kubernetes.container.name` container label.
ContainerLabelsToMetricLabels map[string]string `mapstructure:"container_labels_to_metric_labels"`

// A mapping of container environment variable names to MetricDescriptor label
// keys. The corresponding env var values become the DataPoint label value.
// E.g. `APP_VERSION: version` would result MetricDescriptors having a label
// key called `version` whose DataPoint label values are the value of the
// `APP_VERSION` environment variable configured for that particular container, if
// present.
EnvVarsToMetricLabels map[string]string `mapstructure:"env_vars_to_metric_labels"`

// A list of filters whose matching images are to be excluded. Supports literals, globs, and regex.
ExcludedImages []string `mapstructure:"excluded_images"`

// Whether to report all CPU metrics. Default is false
ProvidePerCoreCPUMetrics bool `mapstructure:"provide_per_core_cpu_metrics"`
}

func (config Config) Validate() error {
if config.Endpoint == "" {
return errors.New("config.Endpoint must be specified")
}
if config.CollectionInterval == 0 {
return errors.New("config.CollectionInterval must be specified")
}
return nil
}
80 changes: 80 additions & 0 deletions receiver/dockerstatsreceiver/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2020, OpenTelemetry Authors
//
// 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 dockerstatsreceiver

import (
"path"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/component/componenttest"
"go.opentelemetry.io/collector/config/configmodels"
"go.opentelemetry.io/collector/config/configtest"
)

func TestLoadConfig(t *testing.T) {
factories, err := componenttest.ExampleComponents()
assert.NoError(t, err)

factory := NewFactory()
factories.Receivers[configmodels.Type(typeStr)] = factory
config, err := configtest.LoadConfigFile(
t, path.Join(".", "testdata", "config.yaml"), factories,
)

require.NoError(t, err)
require.NotNil(t, config)
assert.Equal(t, 2, len(config.Receivers))

defaultConfig := config.Receivers["docker_stats"]
assert.Equal(t, factory.CreateDefaultConfig(), defaultConfig)

dcfg := defaultConfig.(*Config)
assert.Equal(t, "docker_stats", dcfg.Name())
assert.Equal(t, "unix:///var/run/docker.sock", dcfg.Endpoint)
assert.Equal(t, 10*time.Second, dcfg.CollectionInterval)
assert.Equal(t, 5*time.Second, dcfg.Timeout)

assert.Nil(t, dcfg.ExcludedImages)
assert.Nil(t, dcfg.ContainerLabelsToMetricLabels)
assert.Nil(t, dcfg.EnvVarsToMetricLabels)

assert.False(t, dcfg.ProvidePerCoreCPUMetrics)

ascfg := config.Receivers["docker_stats/allsettings"].(*Config)
assert.Equal(t, "docker_stats/allsettings", ascfg.Name())
assert.Equal(t, "http://example.com/", ascfg.Endpoint)
assert.Equal(t, 2*time.Second, ascfg.CollectionInterval)
assert.Equal(t, 20*time.Second, ascfg.Timeout)

assert.Equal(t, []string{
"undesired-container",
"another-*-container",
}, ascfg.ExcludedImages)

assert.Equal(t, map[string]string{
"my.container.label": "my-metric-label",
"my.other.container.label": "my-other-metric-label",
}, ascfg.ContainerLabelsToMetricLabels)

assert.Equal(t, map[string]string{
"my_environment_variable": "my-metric-label",
"my_other_environment_variable": "my-other-metric-label",
}, ascfg.EnvVarsToMetricLabels)

assert.True(t, ascfg.ProvidePerCoreCPUMetrics)
}
Loading