Skip to content

Commit

Permalink
[receiver/statsd] Make full config structure public (#38186)
Browse files Browse the repository at this point in the history
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue.
Ex. Adding a feature - Explain what this achieves.-->
#### Description

Currently some parts of the config struct are in an internal package,
which makes using the exported types from the receiver's module
insufficient for programmatically generating a config for the receiver.

Since the config types are shared with the parsing code, I had to move
the types into a non-top-level package. I chose to rename the
`internal/protocol` subpackage to `internal/parser` since most code in
there appears to be related to parsing, and make a public `protocol`
package that contains types related to configuring things related to the
StatsD protocol. I don't have a strong opinions on the names for any of
the packages and am open to suggestions.

---------

Co-authored-by: Antoine Toulme <atoulme@splunk.com>
  • Loading branch information
evan-bradley and atoulme authored Feb 26, 2025
1 parent 1b86776 commit e8a0def
Show file tree
Hide file tree
Showing 12 changed files with 124 additions and 85 deletions.
27 changes: 27 additions & 0 deletions .chloggen/statsd-public-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: receiver/statsd

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Make all types within the config struct public

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [38186]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext: This allows programmatically generating the receiver's config using the module's public types.

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: [api]
2 changes: 1 addition & 1 deletion receiver/statsdreceiver/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"go.opentelemetry.io/collector/config/confignet"
"go.uber.org/multierr"

"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/internal/protocol"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/protocol"
)

// Config defines configuration for StatsD receiver.
Expand Down
2 changes: 1 addition & 1 deletion receiver/statsdreceiver/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"go.opentelemetry.io/collector/confmap/xconfmap"

"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/internal/metadata"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/internal/protocol"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/protocol"
)

func TestLoadConfig(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion receiver/statsdreceiver/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"go.opentelemetry.io/collector/receiver"

"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/internal/metadata"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/internal/protocol"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/protocol"
)

const (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package protocol // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/internal/protocol"
package parser // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/internal/parser"

import (
"sort"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package protocol
package parser

import (
"testing"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package protocol
package parser

import (
"testing"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package protocol // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/internal/protocol"
package parser // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/internal/parser"

import (
"net"

"go.opentelemetry.io/collector/client"
"go.opentelemetry.io/collector/pdata/pmetric"

"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/protocol"
)

// Parser is something that can map input StatsD strings to OTLP Metric representations.
type Parser interface {
Initialize(enableMetricType bool, enableSimpleTags bool, isMonotonicCounter bool, enableIPOnlyAggregation bool, sendTimerHistogram []TimerHistogramMapping) error
Initialize(enableMetricType bool, enableSimpleTags bool, isMonotonicCounter bool, enableIPOnlyAggregation bool, sendTimerHistogram []protocol.TimerHistogramMapping) error
GetMetrics() []BatchMetrics
Aggregate(line string, addr net.Addr) error
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package protocol // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/internal/protocol"
package parser // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/internal/parser"

import (
"errors"
Expand All @@ -18,18 +18,16 @@ import (
"go.opentelemetry.io/collector/pdata/pmetric"
semconv "go.opentelemetry.io/collector/semconv/v1.22.0"
"go.opentelemetry.io/otel/attribute"

"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver/protocol"
)

var (
errEmptyMetricName = errors.New("empty metric name")
errEmptyMetricValue = errors.New("empty metric value")
)

type (
MetricType string // From the statsd line e.g., "c", "g", "h"
TypeName string // How humans describe the MetricTypes ("counter", "gauge")
ObserverType string // How the server will aggregate histogram and timings ("gauge", "summary")
)
type MetricType string // From the statsd line e.g., "c", "g", "h"

const (
tagMetricType = "metric_type"
Expand All @@ -40,46 +38,17 @@ const (
TimingType MetricType = "ms"
DistributionType MetricType = "d"

CounterTypeName TypeName = "counter"
GaugeTypeName TypeName = "gauge"
HistogramTypeName TypeName = "histogram"
TimingTypeName TypeName = "timing"
TimingAltTypeName TypeName = "timer"
DistributionTypeName TypeName = "distribution"

GaugeObserver ObserverType = "gauge"
SummaryObserver ObserverType = "summary"
HistogramObserver ObserverType = "histogram"
DisableObserver ObserverType = "disabled"

DefaultObserverType = DisableObserver

receiverName = "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver"
)

type TimerHistogramMapping struct {
StatsdType TypeName `mapstructure:"statsd_type"`
ObserverType ObserverType `mapstructure:"observer_type"`
Histogram HistogramConfig `mapstructure:"histogram"`
Summary SummaryConfig `mapstructure:"summary"`
}

type HistogramConfig struct {
MaxSize int32 `mapstructure:"max_size"`
}

type SummaryConfig struct {
Percentiles []float64 `mapstructure:"percentiles"`
}

type ObserverCategory struct {
method ObserverType
method protocol.ObserverType
histogramConfig structure.Config
summaryPercentiles []float64
}

var defaultObserverCategory = ObserverCategory{
method: DefaultObserverType,
method: protocol.DefaultObserverType,
}

// StatsDParser supports the Parse method for parsing StatsD messages with Tags.
Expand Down Expand Up @@ -146,28 +115,28 @@ type statsDMetricDescription struct {
attrs attribute.Set
}

func (t MetricType) FullName() TypeName {
func (t MetricType) FullName() protocol.TypeName {
switch t {
case GaugeType:
return GaugeTypeName
return protocol.GaugeTypeName
case CounterType:
return CounterTypeName
return protocol.CounterTypeName
case TimingType:
return TimingTypeName
return protocol.TimingTypeName
case HistogramType:
return HistogramTypeName
return protocol.HistogramTypeName
case DistributionType:
return DistributionTypeName
return protocol.DistributionTypeName
}
return TypeName(fmt.Sprintf("unknown(%s)", t))
return protocol.TypeName(fmt.Sprintf("unknown(%s)", t))
}

func (p *StatsDParser) resetState(when time.Time) {
p.lastIntervalTime = when
p.instrumentsByAddress = make(map[netAddr]*instruments)
}

func (p *StatsDParser) Initialize(enableMetricType bool, enableSimpleTags bool, isMonotonicCounter bool, enableIPOnlyAggregation bool, sendTimerHistogram []TimerHistogramMapping) error {
func (p *StatsDParser) Initialize(enableMetricType bool, enableSimpleTags bool, isMonotonicCounter bool, enableIPOnlyAggregation bool, sendTimerHistogram []protocol.TimerHistogramMapping) error {
p.resetState(timeNowFunc())

p.histogramEvents = defaultObserverCategory
Expand All @@ -180,21 +149,21 @@ func (p *StatsDParser) Initialize(enableMetricType bool, enableSimpleTags bool,
// Note: validation occurs in ("../".Config).validate()
for _, eachMap := range sendTimerHistogram {
switch eachMap.StatsdType {
case HistogramTypeName, DistributionTypeName:
case protocol.HistogramTypeName, protocol.DistributionTypeName:
p.histogramEvents.method = eachMap.ObserverType
p.histogramEvents.histogramConfig = expoHistogramConfig(eachMap.Histogram)
p.histogramEvents.summaryPercentiles = eachMap.Summary.Percentiles
case TimingTypeName, TimingAltTypeName:
case protocol.TimingTypeName, protocol.TimingAltTypeName:
p.timerEvents.method = eachMap.ObserverType
p.timerEvents.histogramConfig = expoHistogramConfig(eachMap.Histogram)
p.timerEvents.summaryPercentiles = eachMap.Summary.Percentiles
case CounterTypeName, GaugeTypeName:
case protocol.CounterTypeName, protocol.GaugeTypeName:
}
}
return nil
}

func expoHistogramConfig(opts HistogramConfig) structure.Config {
func expoHistogramConfig(opts protocol.HistogramConfig) structure.Config {
var r []structure.Option
if opts.MaxSize >= structure.MinSize {
r = append(r, structure.WithMaxSize(opts.MaxSize))
Expand Down Expand Up @@ -331,9 +300,9 @@ func (p *StatsDParser) Aggregate(line string, addr net.Addr) error {
case TimingType, HistogramType, DistributionType:
category := p.observerCategoryFor(parsedMetric.description.metricType)
switch category.method {
case GaugeObserver:
case protocol.GaugeObserver:
instrument.timersAndDistributions = append(instrument.timersAndDistributions, buildGaugeMetric(parsedMetric, timeNowFunc()))
case SummaryObserver:
case protocol.SummaryObserver:
raw := parsedMetric.sampleValue()
if existing, ok := instrument.summaries[parsedMetric.description]; !ok {
instrument.summaries[parsedMetric.description] = summaryMetric{
Expand All @@ -348,7 +317,7 @@ func (p *StatsDParser) Aggregate(line string, addr net.Addr) error {
percentiles: category.summaryPercentiles,
}
}
case HistogramObserver:
case protocol.HistogramObserver:
raw := parsedMetric.sampleValue()
var agg *histogramStructure
if existing, ok := instrument.histograms[parsedMetric.description]; ok {
Expand All @@ -366,7 +335,7 @@ func (p *StatsDParser) Aggregate(line string, addr net.Addr) error {
uint64(raw.count), // Note! Rounding float64 to uint64 here.
)

case DisableObserver:
case protocol.DisableObserver:
// No action.
}
}
Expand Down
Loading

0 comments on commit e8a0def

Please sign in to comment.