Skip to content

Commit

Permalink
Add helper component to reduce boilerplate (#1334)
Browse files Browse the repository at this point in the history
Signed-off-by: Bogdan Drutu <[email protected]>
  • Loading branch information
bogdandrutu authored Jul 14, 2020
1 parent 68c4e05 commit 2195bbc
Show file tree
Hide file tree
Showing 15 changed files with 476 additions and 309 deletions.
145 changes: 64 additions & 81 deletions receiver/hostmetricsreceiver/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config"
"go.opentelemetry.io/collector/config/configerror"
"go.opentelemetry.io/collector/config/configmodels"
"go.opentelemetry.io/collector/consumer"
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal"
Expand All @@ -36,6 +35,7 @@ import (
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/processesscraper"
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/processscraper"
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/swapscraper"
"go.opentelemetry.io/collector/receiver/receiverhelper"
)

// This file implements Factory for HostMetrics receiver.
Expand All @@ -46,99 +46,93 @@ const (
scrapersKey = "scrapers"
)

// Factory is the Factory for receiver.
type Factory struct {
scraperFactories map[string]internal.ScraperFactory
resourceScraperFactories map[string]internal.ResourceScraperFactory
}
var (
scraperFactories = map[string]internal.ScraperFactory{
cpuscraper.TypeStr: &cpuscraper.Factory{},
diskscraper.TypeStr: &diskscraper.Factory{},
loadscraper.TypeStr: &loadscraper.Factory{},
filesystemscraper.TypeStr: &filesystemscraper.Factory{},
memoryscraper.TypeStr: &memoryscraper.Factory{},
networkscraper.TypeStr: &networkscraper.Factory{},
processesscraper.TypeStr: &processesscraper.Factory{},
swapscraper.TypeStr: &swapscraper.Factory{},
}

// NewFactory creates a new factory for host metrics receiver.
func NewFactory() *Factory {
return &Factory{
scraperFactories: map[string]internal.ScraperFactory{
cpuscraper.TypeStr: &cpuscraper.Factory{},
diskscraper.TypeStr: &diskscraper.Factory{},
loadscraper.TypeStr: &loadscraper.Factory{},
filesystemscraper.TypeStr: &filesystemscraper.Factory{},
memoryscraper.TypeStr: &memoryscraper.Factory{},
networkscraper.TypeStr: &networkscraper.Factory{},
processesscraper.TypeStr: &processesscraper.Factory{},
swapscraper.TypeStr: &swapscraper.Factory{},
},
resourceScraperFactories: map[string]internal.ResourceScraperFactory{
processscraper.TypeStr: &processscraper.Factory{},
},
resourceScraperFactories = map[string]internal.ResourceScraperFactory{
processscraper.TypeStr: &processscraper.Factory{},
}
}
)

// Type returns the type of the Receiver config created by this Factory.
func (f *Factory) Type() configmodels.Type {
return typeStr
// NewFactory creates a new factory for host metrics receiver.
func NewFactory() component.ReceiverFactory {
return receiverhelper.NewFactory(
typeStr,
createDefaultConfig,
receiverhelper.WithMetricsReceiver(createMetricsReceiver),
receiverhelper.WithCustomUnmarshaler(customUnmarshaler))
}

// CustomUnmarshaler returns custom unmarshaler for this config.
func (f *Factory) CustomUnmarshaler() component.CustomUnmarshaler {
return func(componentViperSection *viper.Viper, intoCfg interface{}) error {
// customUnmarshaler returns custom unmarshaler for this config.
func customUnmarshaler(componentViperSection *viper.Viper, intoCfg interface{}) error {

// load the non-dynamic config normally
// 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")
}
err := componentViperSection.Unmarshal(intoCfg)
if err != nil {
return err
}

if cfg.CollectionInterval <= 0 {
return fmt.Errorf("collection_interval must be a positive duration")
}
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
if cfg.CollectionInterval <= 0 {
return fmt.Errorf("collection_interval must be a positive duration")
}

cfg.Scrapers = map[string]internal.Config{}
// dynamically load the individual collector configs based on the key name

scrapersViperSection := config.ViperSub(componentViperSection, scrapersKey)
if scrapersViperSection == nil || len(scrapersViperSection.AllKeys()) == 0 {
return fmt.Errorf("must specify at least one scraper when using hostmetrics receiver")
}
cfg.Scrapers = map[string]internal.Config{}

for key := range componentViperSection.GetStringMap(scrapersKey) {
factory, ok := f.getScraperFactory(key)
if !ok {
return fmt.Errorf("invalid scraper key: %s", key)
}
scrapersViperSection := config.ViperSub(componentViperSection, scrapersKey)
if scrapersViperSection == nil || len(scrapersViperSection.AllKeys()) == 0 {
return fmt.Errorf("must specify at least one scraper when using hostmetrics receiver")
}

collectorCfg := factory.CreateDefaultConfig()
collectorViperSection := config.ViperSub(scrapersViperSection, key)
err := collectorViperSection.UnmarshalExact(collectorCfg)
if err != nil {
return fmt.Errorf("error reading settings for scraper type %q: %v", key, err)
}
for key := range componentViperSection.GetStringMap(scrapersKey) {
factory, ok := getScraperFactory(key)
if !ok {
return fmt.Errorf("invalid scraper key: %s", key)
}

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

return nil
cfg.Scrapers[key] = collectorCfg
}

return nil
}

func (f *Factory) getScraperFactory(key string) (internal.BaseFactory, bool) {
if factory, ok := f.scraperFactories[key]; ok {
func getScraperFactory(key string) (internal.BaseFactory, bool) {
if factory, ok := scraperFactories[key]; ok {
return factory, true
}

if factory, ok := f.resourceScraperFactories[key]; ok {
if factory, ok := resourceScraperFactories[key]; ok {
return factory, true
}

return nil, false
}

// CreateDefaultConfig creates the default configuration for receiver.
func (f *Factory) CreateDefaultConfig() configmodels.Receiver {
// createDefaultConfig creates the default configuration for receiver.
func createDefaultConfig() configmodels.Receiver {
return &Config{
ReceiverSettings: configmodels.ReceiverSettings{
TypeVal: typeStr,
Expand All @@ -148,27 +142,16 @@ func (f *Factory) CreateDefaultConfig() configmodels.Receiver {
}
}

// CreateTraceReceiver returns error as trace receiver is not applicable to host metrics receiver.
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(
// createMetricsReceiver creates a metrics receiver based on provided config.
func createMetricsReceiver(
ctx context.Context,
params component.ReceiverCreateParams,
cfg configmodels.Receiver,
consumer consumer.MetricsConsumer,
) (component.MetricsReceiver, error) {
config := cfg.(*Config)
oCfg := cfg.(*Config)

hmr, err := newHostMetricsReceiver(ctx, params.Logger, config, f.scraperFactories, f.resourceScraperFactories, consumer)
hmr, err := newHostMetricsReceiver(ctx, params.Logger, oCfg, scraperFactories, resourceScraperFactories, consumer)
if err != nil {
return nil, err
}
Expand Down
6 changes: 3 additions & 3 deletions receiver/hostmetricsreceiver/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ import (
var creationParams = component.ReceiverCreateParams{Logger: zap.NewNop()}

func TestCreateDefaultConfig(t *testing.T) {
factory := &Factory{}
factory := NewFactory()
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{}
factory := NewFactory()
cfg := factory.CreateDefaultConfig()

tReceiver, err := factory.CreateTraceReceiver(context.Background(), creationParams, cfg, nil)
Expand All @@ -55,7 +55,7 @@ func TestCreateReceiver(t *testing.T) {
func TestCreateReceiver_ScraperKeyConfigError(t *testing.T) {
const errorKey string = "error"

factory := &Factory{}
factory := NewFactory()
cfg := &Config{Scrapers: map[string]internal.Config{errorKey: &mockConfig{}}}

_, err := factory.CreateMetricsReceiver(context.Background(), creationParams, cfg, nil)
Expand Down
4 changes: 2 additions & 2 deletions receiver/jaegerreceiver/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestLoadConfig(t *testing.T) {
factories, err := config.ExampleComponents()
assert.NoError(t, err)

factory := &Factory{}
factory := NewFactory()
factories.Receivers[typeStr] = factory
cfg, err := config.LoadConfigFile(t, path.Join(".", "testdata", "config.yaml"), factories)

Expand Down Expand Up @@ -154,7 +154,7 @@ func TestFailedLoadConfig(t *testing.T) {
factories, err := config.ExampleComponents()
assert.NoError(t, err)

factory := &Factory{}
factory := NewFactory()
factories.Receivers[typeStr] = factory
_, err = config.LoadConfigFile(t, path.Join(".", "testdata", "bad_typo_default_proto_config.yaml"), factories)
assert.EqualError(t, err, "error reading settings for receiver type \"jaeger\": unknown protocols in the Jaeger receiver")
Expand Down
Loading

0 comments on commit 2195bbc

Please sign in to comment.