Skip to content
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
1 change: 1 addition & 0 deletions receiver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Supported trace receivers (sorted alphabetically):
- [Zipkin Receiver](#zipkin)

Supported metric receivers (sorted alphabetically):
- [Host Metrics Receiver](#hostmetrics)
- [OpenCensus Receiver](#opencensus)
- [Prometheus Receiver](#prometheus)
- [VM Metrics Receiver](#vmmetrics)
Expand Down
22 changes: 22 additions & 0 deletions receiver/hostmetricsreceiver/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Host Metrics Receiver

The Host Metrics receiver generates metrics about the host system. This is intended to be used when the collector is
deployed as an agent.

The categories of metrics scraped can be configured under the `scrapers` key, e.g. to scrape cpu, memory and disk metrics
(note not all of these are implemented yet):

```
hostmetrics:
default_collection_interval: 10s
scrapers:
cpu:
report_per_process: true
memory:
disk:
```

## OS Support

The initial implementation of the Host Metrics receiver supports Windows only. It's intended that future iterations
of this receiver will support the collection of identical metrics (where possible) on other operating systems.
30 changes: 30 additions & 0 deletions receiver/hostmetricsreceiver/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// 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 hostmetricsreceiver

import (
"time"

"github.com/open-telemetry/opentelemetry-collector/config/configmodels"
"github.com/open-telemetry/opentelemetry-collector/receiver/hostmetricsreceiver/internal"
)

// Config defines configuration for HostMetrics receiver.
type Config struct {
configmodels.ReceiverSettings `mapstructure:",squash"`

DefaultCollectionInterval time.Duration `mapstructure:"default_collection_interval"`
Scrapers map[string]internal.Config `mapstructure:"-"`
}
35 changes: 35 additions & 0 deletions receiver/hostmetricsreceiver/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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 hostmetricsreceiver

import (
"path"
"testing"

"github.com/stretchr/testify/require"

"github.com/open-telemetry/opentelemetry-collector/config"
)

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

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

require.Error(t, err)
}
21 changes: 21 additions & 0 deletions receiver/hostmetricsreceiver/example_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
extensions:
zpages:
endpoint: 0.0.0.0:55679

receivers:
hostmetrics:
default_collection_interval: 10s
scrapers:

exporters:
logging:
prometheus:
endpoint: 0.0.0.0:8889

service:
pipelines:
metrics:
receivers: [hostmetrics]
exporters: [prometheus, logging]

extensions: [zpages]
147 changes: 147 additions & 0 deletions receiver/hostmetricsreceiver/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// 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 hostmetricsreceiver

import (
"context"
"errors"
"fmt"
"runtime"
"time"

"github.com/spf13/viper"

"github.com/open-telemetry/opentelemetry-collector/component"
"github.com/open-telemetry/opentelemetry-collector/config/configerror"
"github.com/open-telemetry/opentelemetry-collector/config/configmodels"
"github.com/open-telemetry/opentelemetry-collector/consumer"
"github.com/open-telemetry/opentelemetry-collector/receiver/hostmetricsreceiver/internal"
)

// This file implements Factory for HostMetrics receiver.

const (
// The value of "type" key in configuration.
typeStr = "hostmetrics"
scrapersKey = "scrapers"
)

// Factory is the Factory for receiver.
type Factory struct {
ScraperFactories map[string]internal.Factory
}

// NewFactory creates a new factory
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// NewFactory creates a new factory
// NewFactory creates a new factory for host metrics receiver.

func NewFactory() *Factory {
return &Factory{
ScraperFactories: map[string]internal.Factory{},
}
}

// Type gets the type of the Receiver config created by this Factory.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Type gets the type of the Receiver config created by this Factory.
// Type returns the type of the Receiver config created by this Factory.

func (f *Factory) Type() string {
return typeStr
}

// CustomUnmarshaler returns custom unmarshaler for this config.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// CustomUnmarshaler returns custom unmarshaler for this config.
// CustomUnmarshaller returns custom unmarshaller for this factory.

func (f *Factory) CustomUnmarshaler() component.CustomUnmarshaler {
return func(componentViperSection *viper.Viper, intoCfg interface{}) error {

// load the non-dynamic config normally

err := componentViperSection.Unmarshal(intoCfg)
if err != nil {
return err
}

cfg, ok := intoCfg.(*Config)
if !ok {
return fmt.Errorf("config type not hostmetrics.Config")
}

// dynamically load the individual collector configs based on the key name

cfg.Scrapers = map[string]internal.Config{}

scrapersViperSection := componentViperSection.Sub(scrapersKey)
if scrapersViperSection == nil || len(scrapersViperSection.AllKeys()) == 0 {
return fmt.Errorf("must specify at least one scraper when using hostmetrics receiver")
}

for key := range componentViperSection.GetStringMap(scrapersKey) {
factory, ok := f.ScraperFactories[key]
if !ok {
return fmt.Errorf("invalid hostmetrics scraper key: %s", key)
}

collectorCfg := factory.CreateDefaultConfig()
collectorViperSection := scrapersViperSection.Sub(key)
if collectorViperSection != nil {
err := collectorViperSection.UnmarshalExact(collectorCfg)
if err != nil {
return fmt.Errorf("error reading settings for hostmetric scraper type %q: %v", key, err)
}
}

cfg.Scrapers[key] = collectorCfg
}

return nil
}
}

// CreateDefaultConfig creates the default configuration for receiver.
func (f *Factory) CreateDefaultConfig() configmodels.Receiver {
return &Config{
ReceiverSettings: configmodels.ReceiverSettings{
TypeVal: typeStr,
NameVal: typeStr,
},
DefaultCollectionInterval: 10 * time.Second,
}
}

// CreateTraceReceiver creates a trace receiver based on provided config.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this should be
CreateTraceReceiver returns error as trace receiver is not applicable to host metrics receiver.
Other receivers also have similar issue.

func (f *Factory) CreateTraceReceiver(
ctx context.Context,
params component.ReceiverCreateParams,
cfg configmodels.Receiver,
consumer consumer.TraceConsumer,
) (component.TraceReceiver, error) {
// Host Metrics does not support traces
return nil, configerror.ErrDataTypeIsNotSupported
}

// CreateMetricsReceiver creates a metrics receiver based on provided config.
func (f *Factory) CreateMetricsReceiver(
ctx context.Context,
params component.ReceiverCreateParams,
cfg configmodels.Receiver,
consumer consumer.MetricsConsumer,
) (component.MetricsReceiver, error) {

if runtime.GOOS != "windows" {
return nil, errors.New("hostmetrics receiver is currently only supported on windows")
}

config := cfg.(*Config)

hmr, err := NewHostMetricsReceiver(ctx, params.Logger, config, f.ScraperFactories, consumer)
if err != nil {
return nil, err
}

return hmr, nil
}
57 changes: 57 additions & 0 deletions receiver/hostmetricsreceiver/factory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// 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 hostmetricsreceiver

import (
"context"
"runtime"
"testing"

"github.com/stretchr/testify/assert"
"go.uber.org/zap"

"github.com/open-telemetry/opentelemetry-collector/component"
"github.com/open-telemetry/opentelemetry-collector/config/configcheck"
"github.com/open-telemetry/opentelemetry-collector/config/configerror"
)

var creationParams = component.ReceiverCreateParams{Logger: zap.NewNop()}

func TestCreateDefaultConfig(t *testing.T) {
factory := &Factory{}
cfg := factory.CreateDefaultConfig()
assert.NotNil(t, cfg, "failed to create default config")
assert.NoError(t, configcheck.ValidateConfig(cfg))
}

func TestCreateReceiver(t *testing.T) {
factory := &Factory{}
cfg := factory.CreateDefaultConfig()

tReceiver, err := factory.CreateTraceReceiver(context.Background(), creationParams, cfg, nil)

assert.Equal(t, err, configerror.ErrDataTypeIsNotSupported)
assert.Nil(t, tReceiver)

mReceiver, err := factory.CreateMetricsReceiver(context.Background(), creationParams, cfg, nil)

if runtime.GOOS != "windows" {
assert.NotNil(t, err)
assert.Nil(t, tReceiver)
} else {
assert.Nil(t, err)
assert.NotNil(t, mReceiver)
}
}
Loading