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

Add and support receiver creator endpoint properties #25866

Closed
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
27 changes: 27 additions & 0 deletions .chloggen/receivercreatorconfigfromenv.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_creator

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Support `accept_endpoint_environments` for dynamic template evaluation from observer endpoint environments

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

# (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:

# 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: []
80 changes: 80 additions & 0 deletions receiver/receivercreator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,86 @@ receivers:

Similar to the per-endpoint type `resource_attributes` described above but for individual receiver instances. Duplicate attribute entries (including the empty string) in this receiver-specific mapping take precedence. These attribute values also support expansion from endpoint environment content. At this time their values must be strings.

**accept_endpoint_properties**

```yaml
accept_endpoint_properties: true
```

Enabling this feature will allow observer endpoints to embed receiver configuration entries for both modifying existing entries and creating new ones during the evaluation of the containing endpoint. Endpoint properties will not extend to any other observed endpoint or instantiated receiver. The default value is `false`.

Endpoint properties are key-value pairs of the form `<Prefix><Property Key>: <Property Value>`. The prefix is either the RFC 1123 compatible or reverse DNS variant:

`receiver-creator.collector.opentelemetry.io/` or `io.opentelemetry.collector.receiver-creator.`

The property key is of the form `<receiver type>(/<optional receiver name>)(.<optional field type>(.<optional mapping key>))`. For Kubernetes qualified names where only a lone prefix-separating `/` is allowed, `__` can be used to signify `/` for specifying name references. The optional field types are `config`, `resources_attributes`, and `rule`, which can be used in any combination in a full mapping value. The optional mapping key is the first-level mapping field name. The `::` field separator is supported in values, and where compatible with metadata carriers (generally container labels), the `::` field separator can also be used in the `config` field type's optional mapping key.

Currently, endpoint properties are only parsed from `pod`, `port`, `k8s.node` endpoint types' `annotations` maps, as well as `container` endpoint types' `labels` maps.

Examples:

Redis receiver full mapping endpoint property via kubernetes pod annotation:

Collector configuration segment:

```yaml
extensions:
k8s_observer:

receivers:
receiver_creator:
accept_endpoint_properties: true
watch_observers: [k8s_observer]
```

Redis pod manifest:

``` yaml
apiVersion: v1
kind: Pod
metadata:
name: redis
annotations:
receiver-creator.collector.opentelemetry.io/redis: |
rule: type == "port" and port == 6379
config:
collection_interval: 5s
resource_attributes:
some_attribute: attribute_value
spec:
containers:
- name: redis
image: redis
ports:
- containerPort: 6379
```


Simple prometheus receiver `config`, `resource_attributes`, and `rule` endpoint properties via docker container labels:

Collector configuration segment:

```yaml
extensions:
docker_observer:

receivers:
receiver_creator:
accept_endpoint_properties: true
watch_observers: [docker_observer]
```

docker run command:

```bash
docker run \
-l io.opentelemetry.collector.receiver-creator.prometheus_simple/bitnami.config.collection_interval=30s \
-l io.opentelemetry.collector.receiver-creator.prometheus_simple/bitnami.config.labels::a.label=label_value \
-l io.opentelemetry.collector.receiver-creator.prometheus_simple/bitnami.resource_attributes.some_attribute=attribute_value \
-l io.opentelemetry.collector.receiver-creator.prometheus_simple/bitnami.rule='type == "container" and port == 9090' \
bitnami/prometheus
```

## Rule Expressions

Each rule must start with `type == ("pod"|"port"|"hostport"|"container"|"k8s.node") &&` such that the rule matches
Expand Down
24 changes: 24 additions & 0 deletions receiver/receivercreator/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ func newReceiverTemplate(name string, cfg userConfigMap) (receiverTemplate, erro
config: cfg,
endpointID: observer.EndpointID("endpoint.id"),
},
ResourceAttributes: map[string]any{},
}, nil
}

Expand All @@ -78,6 +79,9 @@ type Config struct {
// ResourceAttributes is a map of default resource attributes to add to each resource
// object received by this receiver from dynamically created receivers.
ResourceAttributes resourceAttributes `mapstructure:"resource_attributes"`
// AcceptEndpointProperties determines whether properties specified in observer.EndpointEnv
// should be used in determining receiver runtime configuration for a given endpoint.
AcceptEndpointProperties bool `mapstructure:"accept_endpoint_properties"`
}

func (cfg *Config) Unmarshal(componentParser *confmap.Conf) error {
Expand Down Expand Up @@ -135,3 +139,23 @@ func (cfg *Config) Unmarshal(componentParser *confmap.Conf) error {

return nil
}

func (rt receiverTemplate) copy() receiverTemplate {
Copy link
Contributor

Choose a reason for hiding this comment

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

move it up to around line 70 to keep it close to the struct definition?

cp := receiverTemplate{
receiverConfig: receiverConfig{
id: rt.id, endpointID: rt.endpointID,
config: map[string]any{},
},
Rule: rt.Rule,
ResourceAttributes: map[string]any{},
rule: rt.rule,
}

for k, v := range rt.config {
cp.config[k] = v
}
for k, v := range rt.ResourceAttributes {
cp.ResourceAttributes[k] = v
}
return cp
}
16 changes: 14 additions & 2 deletions receiver/receivercreator/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ func TestLoadConfig(t *testing.T) {
{
id: component.NewIDWithName(metadata.Type, "1"),
expected: &Config{
AcceptEndpointProperties: true,
receiverTemplates: map[string]receiverTemplate{
"examplereceiver/1": {
receiverConfig: receiverConfig{
Expand Down Expand Up @@ -161,8 +162,19 @@ func TestInvalidReceiverResourceAttributeValueType(t *testing.T) {
}

type nopWithEndpointConfig struct {
Endpoint string `mapstructure:"endpoint"`
IntField int `mapstructure:"int_field"`
Endpoint string `mapstructure:"endpoint"`
IntField int `mapstructure:"int_field"`
FloatField float64 `mapstructure:"float_field"`
Nested nested `mapstructure:"nested"`
}

type nested struct {
BoolField bool `mapstructure:"bool_field"`
DoublyNested doublyNested `mapstructure:"doubly_nested"`
}

type doublyNested struct {
MapField map[string]any `mapstructure:"map_field"`
}

type nopWithEndpointFactory struct {
Expand Down
3 changes: 2 additions & 1 deletion receiver/receivercreator/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ func createDefaultConfig() component.Config {
conventions.AttributeK8SNodeUID: "`uid`",
},
},
receiverTemplates: map[string]receiverTemplate{},
receiverTemplates: map[string]receiverTemplate{},
AcceptEndpointProperties: false,
}
}

Expand Down
5 changes: 4 additions & 1 deletion receiver/receivercreator/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/open-telemetry/opentelemetry-collector-contrib/receiver/receiv
go 1.20

require (
github.com/alecthomas/participle/v2 v2.0.0
github.com/antonmedv/expr v1.15.3
github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer v0.86.1-0.20231006161201-d364ad61c4d7
github.com/open-telemetry/opentelemetry-collector-contrib/internal/sharedcomponent v0.86.1-0.20231006161201-d364ad61c4d7
Expand All @@ -19,6 +20,8 @@ require (
go.opentelemetry.io/collector/semconv v0.86.1-0.20231006161201-d364ad61c4d7
go.uber.org/multierr v1.11.0
go.uber.org/zap v1.26.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.27.4
)

require (
Expand Down Expand Up @@ -97,7 +100,7 @@ require (
google.golang.org/grpc v1.58.2 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
)

replace github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer => ../../extension/observer
Expand Down
9 changes: 9 additions & 0 deletions receiver/receivercreator/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading