Skip to content
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

[processor/geoip] Add GeoIP providers configuration and maxmind factory #33268

Merged
Merged
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
dd89cf6
feat: add geoipprovider internal package
rogercoll May 28, 2024
18c1d24
add providers to configuration
rogercoll May 28, 2024
ca50fa1
feat: add unmarshal implementation for geoip providers
rogercoll May 29, 2024
49c277b
add provider's mock and configuration load test case
rogercoll May 29, 2024
4450aa8
feat: add list of providers to the geoip processor
rogercoll May 29, 2024
a7381ae
chore: add changelog entry
rogercoll May 30, 2024
1d8dad2
fix format and linter
rogercoll May 30, 2024
48f3d8d
Merge branch 'main' into geoipprocessor_provider
rogercoll May 30, 2024
686b9e7
fix .chloggen/geoipprocessor_provider.yaml
rogercoll May 31, 2024
cb2b2dc
Merge branch 'main' into geoipprocessor_provider
rogercoll Jun 27, 2024
9bbfd46
chore: replace CreateSettings for Settings
rogercoll Jun 27, 2024
81137cc
feat: validate all providers configuration
rogercoll Jun 27, 2024
87b0161
feat: add maxmind provider factory
rogercoll Jun 28, 2024
31ba472
add configuration unmarshal test cases
rogercoll Jun 28, 2024
0cec847
chore: tidy mod files
rogercoll Jun 28, 2024
be9e2df
chore: update changelog to reflect maxmind
rogercoll Jun 28, 2024
74bde08
chore: fix imports order
rogercoll Jun 28, 2024
05d0be9
docs: add configuration section
rogercoll Jun 28, 2024
f20bfc4
chore: add comments to factory methods
rogercoll Jun 28, 2024
f7f9902
docs: reference added attributes
rogercoll Jun 28, 2024
21e80e8
Merge branch 'main' into geoipprocessor_provider
rogercoll Jun 28, 2024
f8c2991
chore: remove additional require mod section
rogercoll Jun 28, 2024
bda01e5
rename providers config key variable
rogercoll Jun 28, 2024
cd5293d
Update processor/geoipprocessor/README.md
rogercoll Jul 2, 2024
e196b02
Merge branch 'main' into geoipprocessor_provider
rogercoll Jul 2, 2024
bb6ba71
chore: remove deprecated test helpers
rogercoll Jul 2, 2024
0bec9c9
Merge branch 'main' into geoipprocessor_provider
rogercoll Jul 2, 2024
e392379
chore: tidy indirect deps
rogercoll Jul 2, 2024
e5fb50a
Merge branch 'main' into geoipprocessor_provider
rogercoll Jul 2, 2024
eec083e
Merge branch 'main' into geoipprocessor_provider
rogercoll Jul 4, 2024
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
Prev Previous commit
Next Next commit
feat: add list of providers to the geoip processor
rogercoll committed May 29, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 4450aa85e6247183afa523d54a78eec54bee2db1
48 changes: 45 additions & 3 deletions processor/geoipprocessor/factory.go
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ package geoipprocessor // import "github.com/open-telemetry/opentelemetry-collec

import (
"context"
"fmt"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/consumer"
@@ -38,14 +39,55 @@ func createDefaultConfig() component.Config {
return &Config{}
}

func createGeoIPProviders(
ctx context.Context,
set processor.CreateSettings,
config *Config,
factories map[string]provider.GeoIPProviderFactory,
) ([]provider.GeoIPProvider, error) {
providers := make([]provider.GeoIPProvider, 0, len(config.Providers))

for key, cfg := range config.Providers {
factory := factories[key]
if factory == nil {
return nil, fmt.Errorf("geoIP provider factory not found for key: %q", key)
}

provider, err := factory.CreateGeoIPProvider(ctx, set, cfg)
if err != nil {
return nil, fmt.Errorf("failed to create provider for key %q: %w", key, err)
}

providers = append(providers, provider)

}

return providers, nil
}

func createMetricsProcessor(ctx context.Context, set processor.CreateSettings, cfg component.Config, nextConsumer consumer.Metrics) (processor.Metrics, error) {
return processorhelper.NewMetricsProcessor(ctx, set, cfg, nextConsumer, newGeoIPProcessor().processMetrics, processorhelper.WithCapabilities(processorCapabilities))
geoCfg := cfg.(*Config)
providers, err := createGeoIPProviders(ctx, set, geoCfg, providerFactories)
if err != nil {
return nil, err
}
return processorhelper.NewMetricsProcessor(ctx, set, cfg, nextConsumer, newGeoIPProcessor(providers).processMetrics, processorhelper.WithCapabilities(processorCapabilities))
}

func createTracesProcessor(ctx context.Context, set processor.CreateSettings, cfg component.Config, nextConsumer consumer.Traces) (processor.Traces, error) {
return processorhelper.NewTracesProcessor(ctx, set, cfg, nextConsumer, newGeoIPProcessor().processTraces, processorhelper.WithCapabilities(processorCapabilities))
geoCfg := cfg.(*Config)
providers, err := createGeoIPProviders(ctx, set, geoCfg, providerFactories)
if err != nil {
return nil, err
}
return processorhelper.NewTracesProcessor(ctx, set, cfg, nextConsumer, newGeoIPProcessor(providers).processTraces, processorhelper.WithCapabilities(processorCapabilities))
}

func createLogsProcessor(ctx context.Context, set processor.CreateSettings, cfg component.Config, nextConsumer consumer.Logs) (processor.Logs, error) {
return processorhelper.NewLogsProcessor(ctx, set, cfg, nextConsumer, newGeoIPProcessor().processLogs, processorhelper.WithCapabilities(processorCapabilities))
geoCfg := cfg.(*Config)
providers, err := createGeoIPProviders(ctx, set, geoCfg, providerFactories)
if err != nil {
return nil, err
}
return processorhelper.NewLogsProcessor(ctx, set, cfg, nextConsumer, newGeoIPProcessor(providers).processLogs, processorhelper.WithCapabilities(processorCapabilities))
}
14 changes: 11 additions & 3 deletions processor/geoipprocessor/geoip_processor.go
Original file line number Diff line number Diff line change
@@ -6,15 +6,23 @@ package geoipprocessor // import "github.com/open-telemetry/opentelemetry-collec
import (
"context"

"github.com/open-telemetry/opentelemetry-collector-contrib/processor/geoipprocessor/internal/provider"
"go.opentelemetry.io/collector/pdata/plog"
"go.opentelemetry.io/collector/pdata/pmetric"
"go.opentelemetry.io/collector/pdata/ptrace"
)

type geoIPProcessor struct{}
// GeoProviders will be used by the Processor retrieve geographical metadata given an IP address.
type GeoProviders = []provider.GeoIPProvider

func newGeoIPProcessor() *geoIPProcessor {
return &geoIPProcessor{}
type geoIPProcessor struct {
providers GeoProviders
}

func newGeoIPProcessor(providers GeoProviders) *geoIPProcessor {
return &geoIPProcessor{
providers,
}
}

func (g *geoIPProcessor) processMetrics(_ context.Context, ms pmetric.Metrics) (pmetric.Metrics, error) {
72 changes: 56 additions & 16 deletions processor/geoipprocessor/provider_test.go
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ import (
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/otelcol/otelcoltest"
"go.opentelemetry.io/collector/processor"
"go.opentelemetry.io/collector/processor/processortest"
"go.opentelemetry.io/otel/attribute"
)

@@ -41,30 +42,69 @@ func (fm *ProviderFactoryMock) CreateGeoIPProvider(ctx context.Context, settings
return fm.CreateGeoIPProviderF(ctx, settings, cfg)
}

var baseMockProvider = ProviderMock{
LocationF: func(context.Context, net.IP) (attribute.Set, error) {
return attribute.Set{}, nil
},
}

var baseMockFactory = ProviderFactoryMock{
CreateDefaultConfigF: func() provider.Config {
type emptyConfig struct{}
return &emptyConfig{}
},
CreateGeoIPProviderF: func(ctx context.Context, settings processor.CreateSettings, cfg provider.Config) (provider.GeoIPProvider, error) {
return &baseMockProvider, nil
},
}

func TestLoadConfig_MockProvider(t *testing.T) {
mockProvider := ProviderMock{
LocationF: func(context.Context, net.IP) (attribute.Set, error) {
return attribute.Set{}, nil
},
}
mockFactory := ProviderFactoryMock{
CreateDefaultConfigF: func() provider.Config {
type SampleConfig struct {
Database string `mapstructure:"database"`
}
return &SampleConfig{}
},
CreateGeoIPProviderF: func(ctx context.Context, settings processor.CreateSettings, cfg provider.Config) (provider.GeoIPProvider, error) {
return &mockProvider, nil
},
baseMockFactory.CreateDefaultConfigF = func() provider.Config {
type SampleConfig struct {
Database string `mapstructure:"database"`
}
return &SampleConfig{}
}

factories, err := otelcoltest.NopFactories()
require.NoError(t, err)

providerFactories["mock"] = &mockFactory
providerFactories["mock"] = &baseMockFactory
factory := NewFactory()
factories.Processors[metadata.Type] = factory
_, err = otelcoltest.LoadConfigAndValidate(filepath.Join("testdata", "config-mockProvider.yaml"), factories)
assert.NoError(t, err)
}

func TestGeoProviderLocation(t *testing.T) {
exampleIP := net.IPv4(240, 0, 0, 0)
baseMockProvider.LocationF = func(ctx context.Context, ip net.IP) (attribute.Set, error) {
// dummy provider that only returns data if the IP is 240.0.0.0
if ip.Equal(exampleIP) {
return attribute.NewSet(
attribute.String("geo.city_name", "Barcelona"),
attribute.String("geo.country_name", "Spain"),
), nil
}
return attribute.NewSet(), nil
}
factory := NewFactory()
config := factory.CreateDefaultConfig()
geoCfg := config.(*Config)
geoCfg.Providers = make(map[string]provider.Config, 1)
geoCfg.Providers["mock"] = &baseMockFactory

providers, err := createGeoIPProviders(context.Background(), processortest.NewNopCreateSettings(), geoCfg, providerFactories)
if err != nil {
t.Fatal(err)
}

processor := newGeoIPProcessor(providers)
assert.Equal(t, 1, len(processor.providers))

attributes, err := processor.providers[0].Location(context.Background(), exampleIP)
assert.NoError(t, err)
value, has := attributes.Value("geo.city_name")
require.True(t, has)
require.Equal(t, "Barcelona", value.AsString())
}