diff --git a/README.md b/README.md
index 383bcbbfc..19de733bc 100644
--- a/README.md
+++ b/README.md
@@ -100,6 +100,7 @@ For more details, see our [quickstart guide](https://docs.odigos.io/intro).
| Google Cloud Monitoring | ✅ | ✅ | |
| Google Cloud Storage | ✅ | | ✅ |
| Grafana Cloud | ✅ | ✅ | ✅ |
+| Groundcover inCloud | ✅ | ✅ | ✅ |
| Honeycomb | ✅ | ✅ | ✅ |
| Last9 | ✅ | ✅ | |
| Lightstep | ✅ | | |
diff --git a/common/config/groundcover.go b/common/config/groundcover.go
new file mode 100644
index 000000000..24941fbca
--- /dev/null
+++ b/common/config/groundcover.go
@@ -0,0 +1,71 @@
+package config
+
+import (
+ "errors"
+
+ "github.com/odigos-io/odigos/common"
+)
+
+const (
+ GroundcoverEndpoint = "GROUNDCOVER_ENDPOINT"
+ GroundcoverApiKey = "GROUNDCOVER_API_KEY"
+)
+
+var (
+ ErrorGroundcoverEndpointMissing = errors.New("Groundcover is missing a required field (\"GROUNDCOVER_ENDPOINT\"), Groundcover will not be configured")
+ ErrorGroundcoverApiKeyMissing = errors.New("Groundcover is missing a required field (\"GROUNDCOVER_API_KEY\"), Groundcover will not be configured")
+)
+
+type Groundcover struct{}
+
+func (j *Groundcover) DestType() common.DestinationType {
+ return common.GroundcoverDestinationType
+}
+
+func (j *Groundcover) ModifyConfig(dest ExporterConfigurer, currentConfig *Config) error {
+ config := dest.GetConfig()
+ uniqueUri := "groundcover-" + dest.GetID()
+
+ url, exists := config[GroundcoverEndpoint]
+ if !exists {
+ return ErrorGroundcoverEndpointMissing
+ }
+
+ endpoint, err := parseOtlpGrpcUrl(url, true)
+ if err != nil {
+ return err
+ }
+
+ exporterName := "otlp/" + uniqueUri
+ exporterConfig := GenericMap{
+ "endpoint": endpoint,
+ "headers": GenericMap{
+ "apikey": "${GROUNDCOVER_API_KEY}",
+ },
+ }
+
+ currentConfig.Exporters[exporterName] = exporterConfig
+
+ if isTracingEnabled(dest) {
+ tracesPipelineName := "traces/" + uniqueUri
+ currentConfig.Service.Pipelines[tracesPipelineName] = Pipeline{
+ Exporters: []string{exporterName},
+ }
+ }
+
+ if isMetricsEnabled(dest) {
+ tracesPipelineName := "metrics/" + uniqueUri
+ currentConfig.Service.Pipelines[tracesPipelineName] = Pipeline{
+ Exporters: []string{exporterName},
+ }
+ }
+
+ if isLoggingEnabled(dest) {
+ tracesPipelineName := "logs/" + uniqueUri
+ currentConfig.Service.Pipelines[tracesPipelineName] = Pipeline{
+ Exporters: []string{exporterName},
+ }
+ }
+
+ return nil
+}
diff --git a/common/config/root.go b/common/config/root.go
index eb5bd9db4..a03518485 100644
--- a/common/config/root.go
+++ b/common/config/root.go
@@ -17,7 +17,7 @@ const (
var availableConfigers = []Configer{
&AppDynamics{}, &Axiom{}, &AWSS3{}, &AzureBlobStorage{}, &Causely{}, &Chronosphere{}, &Clickhouse{}, &Coralogix{},
&Datadog{}, &Debug{}, &Dynatrace{}, &ElasticAPM{}, &Elasticsearch{}, &GenericOTLP{}, &GoogleCloud{},
- &GoogleCloudStorage{}, &GrafanaCloudLoki{}, &GrafanaCloudPrometheus{}, &GrafanaCloudTempo{},
+ &GoogleCloudStorage{}, &GrafanaCloudLoki{}, &GrafanaCloudPrometheus{}, &GrafanaCloudTempo{}, &Groundcover{},
&Honeycomb{}, &Jaeger{}, &Last9{}, &Lightstep{}, &Logzio{}, &Loki{}, &Lumigo{}, &Middleware{}, &Mock{}, &NewRelic{},
&Nop{}, &OpsVerse{}, &OTLPHttp{}, &Prometheus{}, &Qryn{}, &QrynOSS{}, &Quickwit{}, &Sentry{},
&Signoz{}, &Splunk{}, &SumoLogic{}, &Tempo{}, &Uptrace{},
diff --git a/common/dests.go b/common/dests.go
index 1da98cc5a..5f6b4803b 100644
--- a/common/dests.go
+++ b/common/dests.go
@@ -22,6 +22,7 @@ const (
GrafanaCloudLokiDestinationType DestinationType = "grafanacloudloki"
GrafanaCloudPrometheusDestinationType DestinationType = "grafanacloudprometheus"
GrafanaCloudTempoDestinationType DestinationType = "grafanacloudtempo"
+ GroundcoverDestinationType DestinationType = "groundcover"
HoneycombDestinationType DestinationType = "honeycomb"
JaegerDestinationType DestinationType = "jaeger"
Last9DestinationType DestinationType = "last9"
diff --git a/destinations/data/groundcover.yaml b/destinations/data/groundcover.yaml
new file mode 100644
index 000000000..8a0261e1b
--- /dev/null
+++ b/destinations/data/groundcover.yaml
@@ -0,0 +1,30 @@
+apiVersion: internal.odigos.io/v1beta1
+kind: Destination
+metadata:
+ type: groundcover
+ displayName: Groundcover inCloud
+ category: managed
+spec:
+ image: groundcover.svg
+ signals:
+ traces:
+ supported: true
+ metrics:
+ supported: true
+ logs:
+ supported: true
+ fields:
+ - name: GROUNDCOVER_ENDPOINT
+ displayName: Groundcover inCloud Site
+ componentType: input
+ componentProps:
+ type: text
+ required: true
+ tooltip: 'Your inCloud Site is part of the configuration provided to you by groundcover when setting up the managed inCloud backend.'
+ - name: GROUNDCOVER_API_KEY
+ displayName: Groundcover API Key
+ componentType: input
+ secret: true
+ componentProps:
+ type: password
+ required: true
diff --git a/destinations/logos/groundcover.svg b/destinations/logos/groundcover.svg
new file mode 100644
index 000000000..9790b8072
--- /dev/null
+++ b/destinations/logos/groundcover.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/docs/backends-overview.mdx b/docs/backends-overview.mdx
index f13200f5a..24a008b3f 100644
--- a/docs/backends-overview.mdx
+++ b/docs/backends-overview.mdx
@@ -21,6 +21,7 @@ Odigos has destinations for many observability backends.
| Google Cloud Monitoring | Managed | ✅ | ✅ | |
| Google Cloud Storage | Managed | ✅ | | ✅ |
| Grafana Cloud | Managed | ✅ | ✅ | ✅ |
+| Groundcover inCloud | Managed | ✅ | ✅ | ✅ |
| Honeycomb | Managed | ✅ | ✅ | ✅ |
| Jaeger | Self-Hosted | ✅ | | |
| Last9 | Managed | ✅ | ✅ | |
diff --git a/docs/backends/groundcover.mdx b/docs/backends/groundcover.mdx
new file mode 100644
index 000000000..795b83d8c
--- /dev/null
+++ b/docs/backends/groundcover.mdx
@@ -0,0 +1,60 @@
+---
+title: 'Groundcover inCloud'
+---
+
+## Configuring Backend
+
+- **GROUNDCOVER_ENDPOINT** - Endpoint, the format is `host:port`.
+ - `host` is required, also known as your `inCloud_Site`, it is part of the configuration provided to you by Groundcover when setting up the [inCloud Managed](https://docs.groundcover.com/architecture/incloud-managed) backend.
+ - `port` is optional, and defaults to the default OpenTelemetry gRPC port `4317`.
+- **GROUNDCOVER_API_KEY** - API Key provided by Groundcover, refer to [these docs](https://docs.groundcover.com/architecture/incloud-managed/ingestion-endpoints#fetching-the-api-key) for more info.
+
+## Adding a Destination to Odigos
+
+Odigos makes it simple to add and configure destinations, allowing you to select the specific signals [traces/logs/metrics] that you want to send to each destination. There are two primary methods for configuring destinations in Odigos:
+
+1. **Using the UI**
+
+Use the [Odigos CLI](https://docs.odigos.io/cli/odigos_ui) to access the UI:
+
+```bash
+odigos ui
+```
+
+2. **Using kubernetes manifests**
+
+Save the YAML below to a file (e.g., `destination.yaml`) and apply it using `kubectl`:
+
+```bash
+kubectl apply -f destination.yaml
+```
+
+
+```yaml
+apiVersion: odigos.io/v1alpha1
+kind: Destination
+metadata:
+ name: groundcover-example
+ namespace: odigos-system
+spec:
+ data:
+ GROUNDCOVER_ENDPOINT:
+ destinationName: groundcover
+ secretRef:
+ name: groundcover-secret
+ signals:
+ - TRACES
+ - METRICS
+ - LOGS
+ type: groundcover
+
+---
+apiVersion: v1
+data:
+ GROUNDCOVER_API_KEY:
+kind: Secret
+metadata:
+ name: groundcover-secret
+ namespace: odigos-system
+type: Opaque
+```
diff --git a/docs/mint.json b/docs/mint.json
index 425618551..8de7f23a4 100644
--- a/docs/mint.json
+++ b/docs/mint.json
@@ -195,6 +195,7 @@
"backends/grafanacloudloki",
"backends/grafanacloudprometheus",
"backends/grafanacloudtempo",
+ "backends/groundcover",
"backends/honeycomb",
"backends/jaeger",
"backends/last9",
diff --git a/docs/quickstart/next-steps.mdx b/docs/quickstart/next-steps.mdx
index 8c2f5cc17..e863e5d99 100644
--- a/docs/quickstart/next-steps.mdx
+++ b/docs/quickstart/next-steps.mdx
@@ -33,6 +33,7 @@ Select the relevant backend for your use case below to connect it to Odigos.
+