Skip to content

Commit

Permalink
Allow count connector to count by attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
djaglowski committed Mar 9, 2023
1 parent 581a879 commit 120e2cf
Show file tree
Hide file tree
Showing 36 changed files with 8,308 additions and 836 deletions.
16 changes: 16 additions & 0 deletions .chloggen/count-by-attributes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# 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: countconnector

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Add ability to count by attributes

# One or more tracking issues related to the change
issues: [19432]

# (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:
60 changes: 56 additions & 4 deletions connector/countconnector/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,15 @@ Optionally, emit custom counts by defining metrics under one or more of the foll
- `datapoints`
- `logs`

Under each custom metric name, specify one or more conditions using [OTTL Syntax].
Data that matches any one of the conditions will be counted. i.e. Conditions are ORed together.

Optionally, specify a description for the metric.

Note: If any custom metrics are defined for a data type, the default metric will not be emitted.

#### Conditions

Conditions may be specified for custom metrics. If specified, data that matches any one
of the conditions will be counted. i.e. Conditions are ORed together.

```yaml
receivers:
foo:
Expand All @@ -82,7 +86,29 @@ connectors:
- 'name == "prodevent"'
```

Note: If any custom metrics are defined for a data type, the default metric will not be emitted.
#### Attributes

`spans`, `spanevents`, `datapoints`, and `logs` may be counted according to attributes.

If attributes are specified for custom metrics, a separate count will be generated for each unique
set of attribute values. Each count will be emitted as a data point on the same metric.

Optionally, include a `default_value` for an attribute, to count data that does not contain the attribute.

```yaml
receivers:
foo:
exporters:
bar:
connectors:
count:
logs:
my.log.count:
description: The number of logs from each environment.
attributes:
- key: env
default_value: unspecified_environment
```

### Example Usage

Expand Down Expand Up @@ -177,6 +203,32 @@ service:
exporters: [bar]
```
Count logs with a severity of ERROR or higher. Maintain a separate count for each environment.
```yaml
receivers:
foo:
exporters:
bar:
connectors:
count:
logs:
my.error.log.count:
description: Error+ logs.
conditions:
- `severity_number >= SEVERITY_NUMBER_ERROR`
attributes:
- key: env
service:
pipelines:
logs:
receivers: [foo]
exporters: [count]
metrics:
receivers: [count]
exporters: [bar]
```
Count all spans and span events (default behavior). Count metrics and data points based on the `env` attribute.

```yaml
Expand Down
74 changes: 57 additions & 17 deletions connector/countconnector/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,17 @@ const (

// Config for the connector
type Config struct {
Spans map[string]MetricInfo `mapstructure:"spans"`
SpanEvents map[string]MetricInfo `mapstructure:"spanevents"`
Metrics map[string]MetricInfo `mapstructure:"metrics"`
DataPoints map[string]MetricInfo `mapstructure:"datapoints"`
Logs map[string]MetricInfo `mapstructure:"logs"`
Spans map[string]MetricInfoWithAttributes `mapstructure:"spans"`
SpanEvents map[string]MetricInfoWithAttributes `mapstructure:"spanevents"`
Metrics map[string]MetricInfo `mapstructure:"metrics"`
DataPoints map[string]MetricInfoWithAttributes `mapstructure:"datapoints"`
Logs map[string]MetricInfoWithAttributes `mapstructure:"logs"`
}

// MetricInfoWithAttributes for a data type
type MetricInfoWithAttributes struct {
MetricInfo `mapstructure:",squash"`
Attributes []AttributeConfig `mapstructure:"attributes"`
}

// MetricInfo for a data type
Expand All @@ -52,6 +58,11 @@ type MetricInfo struct {
Conditions []string `mapstructure:"conditions"`
}

type AttributeConfig struct {
Key string `mapstructure:"key"`
DefaultValue string `mapstructure:"default_value"`
}

func (c *Config) Validate() error {
for name, info := range c.Spans {
if name == "" {
Expand All @@ -64,6 +75,9 @@ func (c *Config) Validate() error {
if _, err = parseConditions(parser, info.Conditions); err != nil {
return fmt.Errorf("spans condition: metric %q: %w", name, err)
}
if err := info.validateAttributes(); err != nil {
return fmt.Errorf("spans attributes: metric %q: %w", name, err)
}
}
for name, info := range c.SpanEvents {
if name == "" {
Expand All @@ -76,6 +90,9 @@ func (c *Config) Validate() error {
if _, err = parseConditions(parser, info.Conditions); err != nil {
return fmt.Errorf("spanevents condition: metric %q: %w", name, err)
}
if err := info.validateAttributes(); err != nil {
return fmt.Errorf("spans attributes: metric %q: %w", name, err)
}
}
for name, info := range c.Metrics {
if name == "" {
Expand All @@ -101,6 +118,9 @@ func (c *Config) Validate() error {
if _, err = parseConditions(parser, info.Conditions); err != nil {
return fmt.Errorf("datapoints condition: metric %q: %w", name, err)
}
if err := info.validateAttributes(); err != nil {
return fmt.Errorf("spans attributes: metric %q: %w", name, err)
}
}
for name, info := range c.Logs {
if name == "" {
Expand All @@ -113,6 +133,18 @@ func (c *Config) Validate() error {
if _, err = parseConditions(parser, info.Conditions); err != nil {
return fmt.Errorf("logs condition: metric %q: %w", name, err)
}
if err := info.validateAttributes(); err != nil {
return fmt.Errorf("spans attributes: metric %q: %w", name, err)
}
}
return nil
}

func (i *MetricInfoWithAttributes) validateAttributes() error {
for _, attr := range i.Attributes {
if attr.Key == "" {
return fmt.Errorf("attribute key missing")
}
}
return nil
}
Expand Down Expand Up @@ -148,18 +180,22 @@ func (c *Config) Unmarshal(componentParser *confmap.Conf) error {
return nil
}

func defaultSpansConfig() map[string]MetricInfo {
return map[string]MetricInfo{
func defaultSpansConfig() map[string]MetricInfoWithAttributes {
return map[string]MetricInfoWithAttributes{
defaultMetricNameSpans: {
Description: defaultMetricDescSpans,
MetricInfo: MetricInfo{
Description: defaultMetricDescSpans,
},
},
}
}

func defaultSpanEventsConfig() map[string]MetricInfo {
return map[string]MetricInfo{
func defaultSpanEventsConfig() map[string]MetricInfoWithAttributes {
return map[string]MetricInfoWithAttributes{
defaultMetricNameSpanEvents: {
Description: defaultMetricDescSpanEvents,
MetricInfo: MetricInfo{
Description: defaultMetricDescSpanEvents,
},
},
}
}
Expand All @@ -172,18 +208,22 @@ func defaultMetricsConfig() map[string]MetricInfo {
}
}

func defaultDataPointsConfig() map[string]MetricInfo {
return map[string]MetricInfo{
func defaultDataPointsConfig() map[string]MetricInfoWithAttributes {
return map[string]MetricInfoWithAttributes{
defaultMetricNameDataPoints: {
Description: defaultMetricDescDataPoints,
MetricInfo: MetricInfo{
Description: defaultMetricDescDataPoints,
},
},
}
}

func defaultLogsConfig() map[string]MetricInfo {
return map[string]MetricInfo{
func defaultLogsConfig() map[string]MetricInfoWithAttributes {
return map[string]MetricInfoWithAttributes{
defaultMetricNameLogs: {
Description: defaultMetricDescLogs,
MetricInfo: MetricInfo{
Description: defaultMetricDescLogs,
},
},
}
}
Loading

0 comments on commit 120e2cf

Please sign in to comment.