Skip to content

Commit

Permalink
Add skeleton for new rabbitmq exporter component (#31800)
Browse files Browse the repository at this point in the history
**Description:**
Sets-up the configuration format and common component boilerplate for
the rabbitmq exporter

Implementation will be in other pull requests

**Link to tracking Issue:**
[28891](#28891)

**Testing:** Standard initial unit tests

**Documentation:** Created README for the component

---------

Co-authored-by: Antoine Toulme <antoine@toulme.name>
  • Loading branch information
swar8080 and atoulme committed Mar 26, 2024
1 parent bc7b449 commit 9adb91e
Show file tree
Hide file tree
Showing 21 changed files with 810 additions and 0 deletions.
27 changes: 27 additions & 0 deletions .chloggen/rabbitmq-exporter-skeleton.yaml
@@ -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: new_component

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

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Add new exporter for sending telemetry to RabbitMQ brokers using the AMQP 0.9.1 protocol

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

# (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: [user]
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Expand Up @@ -72,6 +72,7 @@ exporter/otelarrowexporter/ @open-telemetry/collect
exporter/prometheusexporter/ @open-telemetry/collector-contrib-approvers @Aneurysm9
exporter/prometheusremotewriteexporter/ @open-telemetry/collector-contrib-approvers @Aneurysm9 @rapphil
exporter/pulsarexporter/ @open-telemetry/collector-contrib-approvers @dmitryax @dao-jun
exporter/rabbitmqexporter/ @open-telemetry/collector-contrib-approvers @swar8080
exporter/sapmexporter/ @open-telemetry/collector-contrib-approvers @dmitryax @atoulme
exporter/sentryexporter/ @open-telemetry/collector-contrib-approvers @AbhiPrasad
exporter/signalfxexporter/ @open-telemetry/collector-contrib-approvers @dmitryax @crobert-1
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yaml
Expand Up @@ -72,6 +72,7 @@ body:
- exporter/prometheus
- exporter/prometheusremotewrite
- exporter/pulsar
- exporter/rabbitmq
- exporter/sapm
- exporter/sentry
- exporter/signalfx
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yaml
Expand Up @@ -66,6 +66,7 @@ body:
- exporter/prometheus
- exporter/prometheusremotewrite
- exporter/pulsar
- exporter/rabbitmq
- exporter/sapm
- exporter/sentry
- exporter/signalfx
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/other.yaml
Expand Up @@ -66,6 +66,7 @@ body:
- exporter/prometheus
- exporter/prometheusremotewrite
- exporter/pulsar
- exporter/rabbitmq
- exporter/sapm
- exporter/sentry
- exporter/signalfx
Expand Down
1 change: 1 addition & 0 deletions exporter/rabbitmqexporter/Makefile
@@ -0,0 +1 @@
include ../../Makefile.Common
46 changes: 46 additions & 0 deletions exporter/rabbitmqexporter/README.md
@@ -0,0 +1,46 @@
# RabbitMQ Exporter
<!-- status autogenerated section -->
| Status | |
| ------------- |-----------|
| Stability | [development]: traces, metrics, logs |
| Distributions | [] |
| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aexporter%2Frabbitmq%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aexporter%2Frabbitmq) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aexporter%2Frabbitmq%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aexporter%2Frabbitmq) |
| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@swar8080](https://www.github.com/swar8080) |

[development]: https://github.com/open-telemetry/opentelemetry-collector#development
<!-- end autogenerated section -->

Exports metrics, traces, and logs to [RabbitMQ](https://www.rabbitmq.com/) using the AMQP 0.9.1 protocol

## Getting Started

The following settings can be configured:
- `connection`:
- `endpoint` (required, ex = amqp://localhost:5672): Endpoint to connect to RabbitMQ
- `vhost` (optional): The RabbitMQ [virtual host](https://www.rabbitmq.com/docs/vhosts) to connect to
- `auth`:
- `sasl`: Configuration if using SASL PLAIN authentication
- `username` (required): username for authentication
- `password` (required): password for authentication
- `tls` (optional): TODO, need to add this
- `routing`:
- `routing_key` (default = otlp_spans for traces, otlp_metrics for metrics, otlp_logs for logs): Routing key used to route exported messages to RabbitMQ consumers
- `durable` (default = true): Whether to instruct RabbitMQ to make messages [durable](https://www.rabbitmq.com/docs/queues#durability) by writing to disk
- `message_body_encoding`: (default = "otlp_proto"): The encoding of telemetry sent to RabbitMQ
- `otlp_proto`: payload is Protobuf serialized from `ExportTraceServiceRequest` if set as a traces exporter or `ExportMetricsServiceRequest` for metrics or `ExportLogsServiceRequest` for logs.
- `otlp_json`: ** EXPERIMENTAL ** payload is JSON serialized from `ExportTraceServiceRequest` if set as a traces exporter or `ExportMetricsServiceRequest` for metrics or `ExportLogsServiceRequest` for logs.
- `retry_on_failure`:
- `enabled` (default = false)

Example config:

```yaml
exporters:
rabbitmq:
connection:
endpoint: amqp://localhost:5672
auth:
sasl:
username: user
password: pass
```
43 changes: 43 additions & 0 deletions exporter/rabbitmqexporter/config.go
@@ -0,0 +1,43 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package rabbitmqexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/rabbitmqexporter"

import (
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configretry"
)

type Config struct {
Connection ConnectionConfig `mapstructure:"connection"`
Routing RoutingConfig `mapstructure:"routing"`
MessageBodyEncoding string `mapstructure:"message_body_encoding"`
Durable bool `mapstructure:"durable"`
RetrySettings configretry.BackOffConfig `mapstructure:"retry_on_failure"`
}

type ConnectionConfig struct {
Endpoint string `mapstructure:"endpoint"`
VHost string `mapstructure:"vhost"`
Auth AuthConfig `mapstructure:"auth"`
}

type RoutingConfig struct {
RoutingKey string `mapstructure:"routing_key"`
}

type AuthConfig struct {
SASL SASLConfig `mapstructure:"sasl"`
}

type SASLConfig struct {
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
}

var _ component.Config = (*Config)(nil)

// Validate checks if the exporter configuration is valid
func (cfg *Config) Validate() error {
return nil
}
91 changes: 91 additions & 0 deletions exporter/rabbitmqexporter/config_test.go
@@ -0,0 +1,91 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package rabbitmqexporter

import (
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configretry"
"go.opentelemetry.io/collector/confmap/confmaptest"

"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/rabbitmqexporter/internal/metadata"
)

func TestLoadConfig(t *testing.T) {
t.Parallel()

cm, err := confmaptest.LoadConf(filepath.Join("testdata", "test-config.yaml"))
require.NoError(t, err)

tests := []struct {
id component.ID
expected component.Config
}{
{
id: component.NewIDWithName(metadata.Type, ""),
expected: createDefaultConfig().(*Config),
},
{
id: component.NewIDWithName(metadata.Type, "all_fields"),
expected: &Config{
Connection: ConnectionConfig{
Endpoint: "amqp://localhost:5672",
VHost: "vhost1",
Auth: AuthConfig{
SASL: SASLConfig{
Username: "user",
Password: "pass",
},
},
},
Routing: RoutingConfig{
RoutingKey: "custom_routing_key",
},
MessageBodyEncoding: "otlp_json",
Durable: false,
RetrySettings: configretry.BackOffConfig{
Enabled: true,
},
},
},
{
id: component.NewIDWithName(metadata.Type, "mandatory_fields"),
expected: &Config{
Connection: ConnectionConfig{
Endpoint: "amqp://localhost:5672",
VHost: "",
Auth: AuthConfig{
SASL: SASLConfig{
Username: "user",
Password: "pass",
},
},
},
MessageBodyEncoding: "otlp_proto",
Durable: true,
RetrySettings: configretry.BackOffConfig{
Enabled: false,
},
},
},
}

for _, tt := range tests {
t.Run(tt.id.String(), func(t *testing.T) {
factory := NewFactory()
cfg := factory.CreateDefaultConfig()

sub, err := cm.Sub(tt.id.String())
require.NoError(t, err)
require.NoError(t, component.UnmarshalConfig(sub, cfg))

assert.NoError(t, component.ValidateConfig(cfg))
assert.Equal(t, tt.expected, cfg)
})
}
}
7 changes: 7 additions & 0 deletions exporter/rabbitmqexporter/doc.go
@@ -0,0 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

//go:generate mdatagen metadata.yaml

// Package rabbitmqexporter exports telemetry to RabbitMQ using the AMQP 0.9.1 protocol
package rabbitmqexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/rabbitmqexporter"
101 changes: 101 additions & 0 deletions exporter/rabbitmqexporter/factory.go
@@ -0,0 +1,101 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package rabbitmqexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/rabbitmqexporter"

import (
"context"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configretry"
"go.opentelemetry.io/collector/consumer"
"go.opentelemetry.io/collector/exporter"
"go.opentelemetry.io/collector/exporter/exporterhelper"

"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/rabbitmqexporter/internal/metadata"
)

const (
defaultEncoding = "otlp_proto"
)

func NewFactory() exporter.Factory {
return exporter.NewFactory(
metadata.Type,
createDefaultConfig,
exporter.WithLogs(createLogsExporter, metadata.LogsStability),
exporter.WithMetrics(createMetricsExporter, metadata.TracesStability),
exporter.WithTraces(createTracesExporter, metadata.LogsStability),
)
}

func createDefaultConfig() component.Config {
retrySettings := configretry.BackOffConfig{
Enabled: false,
}
return &Config{
MessageBodyEncoding: defaultEncoding,
Durable: true,
RetrySettings: retrySettings,
}
}

func createTracesExporter(
ctx context.Context,
set exporter.CreateSettings,
cfg component.Config,
) (exporter.Traces, error) {
config := cfg.(*Config)
r := newRabbitmqExporter(config, set.TelemetrySettings)

return exporterhelper.NewTracesExporter(
ctx,
set,
cfg,
r.pushTraces,
exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}),
exporterhelper.WithStart(r.start),
exporterhelper.WithShutdown(r.shutdown),
exporterhelper.WithRetry(config.RetrySettings),
)
}

func createMetricsExporter(
ctx context.Context,
set exporter.CreateSettings,
cfg component.Config,
) (exporter.Metrics, error) {
config := (cfg.(*Config))
r := newRabbitmqExporter(config, set.TelemetrySettings)

return exporterhelper.NewMetricsExporter(
ctx,
set,
cfg,
r.pushMetrics,
exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}),
exporterhelper.WithStart(r.start),
exporterhelper.WithShutdown(r.shutdown),
exporterhelper.WithRetry(config.RetrySettings),
)
}

func createLogsExporter(
ctx context.Context,
set exporter.CreateSettings,
cfg component.Config,
) (exporter.Logs, error) {
config := (cfg.(*Config))
r := newRabbitmqExporter(config, set.TelemetrySettings)

return exporterhelper.NewLogsExporter(
ctx,
set,
cfg,
r.pushLogs,
exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}),
exporterhelper.WithStart(r.start),
exporterhelper.WithShutdown(r.shutdown),
exporterhelper.WithRetry(config.RetrySettings),
)
}

0 comments on commit 9adb91e

Please sign in to comment.