In this guide, you will learn how to contribute a new destination to Odigos. We will create a new dummy destination called mydest. Creating a new destination involves these steps:
  1. Extending the UI for the new destination
  2. Adding the collector configuration for the new destination
  3. Generating the documentation for the new destination

User Interface

For our new destination to be visible in the UI, we need to define the destination metadata and fields in YAML format:
1

Add Logo

Go to destinations/logos/ directory and add your logo.
  • Must be in SVG format
  • Example: mydest.svg
mydest.svg
<svg fill="#F5F5F5" width="16" height="12" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
  <title>My Destination</title>
  <g>
    <path d="M5.17215 9.01884L2.18377 7.69813C1.48159 7.38732 1.0448 6.73677 1.0448 5.99948C1.0448 5.2622 1.48056 4.61165 2.18377 4.30083L6.36172 2.45349L6.45156 2.41425V0H1.66127C1.0417 0 0.538818 0.4781 0.538818 1.06772V10.9312C0.538818 11.5209 1.0417 11.999 1.66127 11.999H5.83303H6.45259V9.5682L5.17319 9.01781H5.17215V9.01884Z"/>
    <path d="M14.3397 0H9.5484V2.4411L10.8041 2.98115L10.801 2.9698L13.8162 4.3029C14.5184 4.61372 14.9552 5.26426 14.9552 6.00155C14.9552 6.73883 14.5194 7.38938 13.8162 7.7002L10.1649 9.31417L9.54736 9.57646V12H14.3387C14.9583 12 15.4611 11.5219 15.4611 10.9323V1.06772C15.4611 0.4781 14.9583 0 14.3387 0H14.3397Z"/>
    <path d="M8.00048 8.47972C9.36972 8.47972 10.4808 7.36966 10.4808 5.99938C10.4808 4.6291 9.37076 3.51904 8.00048 3.51904C6.6302 3.51904 5.52014 4.6291 5.52014 5.99938C5.52014 7.36966 6.6302 8.47972 8.00048 8.47972Z"/>
  </g>
</svg>
2

Add Destination Metadata

Go to destinations/data/ directory and create a new YAML file.
  • Example: mydest.yaml
mydest.yaml
apiVersion: internal.odigos.io/v1beta1
kind: Destination
metadata:
  type: mydest
  displayName: My Destination
  category: managed
spec:
  image: mydest.svg
  signals:
    traces:
      supported: true
    metrics:
      supported: true
    logs:
      supported: false
  fields:
    - name: MYDEST_URL
      displayName: URL
      componentType: input
      componentProps:
        required: true
    - name: MYDEST_REGION
      displayName: Region
      componentType: input
      componentProps:
        required: true
    - name: MYDEST_API_KEY
      displayName: API Key
      componentType: input
      componentProps:
        type: password
        required: true
      secret: true

Collector Configuration

Now that our new vendor can be persisted/loaded in the Kubernetes data store, we need to implement the collector configuration.
1

Add Destination Type

Go to common/dests.go and add your new destination to the DestinationType enum.
  • Make sure the value is the same as the type property in mydest.yaml
2

Add Collector Config

Go to common/config directory and create a new GO file.
  • Example: mydest.go
mydest.go
package config

import (
  "fmt"

  "github.com/odigos-io/odigos/common"
)

const (
  regionKey = "MYDEST_REGION"
  urlKey    = "MYDEST_URL"
  apiKeyKey = "MYDEST_API_KEY"
)

type MyDest struct{}

func (m *MyDest) DestType() common.DestinationType {
  // DestinationType defined in common/dests.go
  return common.MyDestDestinationType
}

func (m *MyDest) ModifyConfig(dest ExporterConfigurer, currentConfig *Config) ([]string, error) {
  config := dest.GetConfig()
  // To make sure that the exporter and pipeline names are unique, we'll need to define a unique ID
  uniqueUri := "mydest-" + dest.GetID()

  region, exists := config[regionKey]
  if !exists {
    region = "us"
    return errorMissingKey(regionKey)
  }

  endpoint, exists := config[urlKey]
  if !exists {
    endpoint = fmt.Sprintf("https://%s.mydest.com:4317", region)
  }

  // Modify the exporter here
  exporterName := "otlp/" + uniqueUri
  exporterConfig := GenericMap{
    "endpoint": endpoint,
    "headers": GenericMap{
      // The API Key is a secret, so we can't expose it in the config
      "x-mydest-header-apikey": "${MYDEST_API_KEY}",
    },
  }

  currentConfig.Exporters[exporterName] = exporterConfig

  // Modify the pipelines here
  var pipelineNames []string

  if isTracingEnabled(dest) {
    pipeName := "traces/" + uniqueUri
    currentConfig.Service.Pipelines[pipeName] = Pipeline{
      Exporters: []string{exporterName},
    }
    pipelineNames = append(pipelineNames, pipeName)
  }

  if isMetricsEnabled(dest) {
    pipeName := "metrics/" + uniqueUri
    currentConfig.Service.Pipelines[pipeName] = Pipeline{
      Exporters: []string{exporterName},
    }
    pipelineNames = append(pipelineNames, pipeName)
  }

  if isLoggingEnabled(dest) {
    pipeName := "logs/" + uniqueUri
    currentConfig.Service.Pipelines[pipeName] = Pipeline{
      Exporters: []string{exporterName},
    }
    pipelineNames = append(pipelineNames, pipeName)
  }

  return pipelineNames, nil
}
3

Add Available Config

Go to common/config/root.go and add the new destination to the availableConfigers list.
  • Example: &MyDest{}
common/config/root.go
var availableConfigers = []Configer{
  &MyDest{},
  /* List of existing destinations...  */
}

Kubernetes-Specific Collector Configuration

If your destination configures Kubernetes settings, for example you have a config field that accepts a value that should be mounted in the Collector Pod, create a K8sConfiger object in destinations.k8sconfig. This interface provides an additional function, ModifyGatewayCollectorDeployment, which accepts a Destination and Collector Deployment. Your implementation can use this function to modify the Deployment as necessary based on the Destination config. Note: It is the responsibility of your implementation to check for the validity of this config, such as checking for conflicts or values that already exist. The K8sConfiger interface also requires a DestType() function, similar to common Destinations. This function returns the type of common Destination that this Kubernetes implementation relies on. This is used by the Autoscaler to conditionally apply the K8sConfiger only for the matching Destination. When it is implemented, add your K8sConfiger implementation to the availableConfigers list in destinations/k8sconfig/root.go

Generating Documentation

1

Install Python

Make sure you have Python installed on your system.
2

Generate Documentation

Go to docs directory, and run:
python sync-dest-doc.py
# OR
python3 sync-dest-doc.py
3

Edit Documentation

The documentation has been generated in the docs/backends directory. Feel free to add any additional content to the generated file.
  • Edit only between the !! START CUSTOM EDIT !! and !! END CUSTOM EDIT !! comments
  • Example: mydest.mdx
mydest.mdx
{/*
    !! Do not remove this comment, this acts as a key indicator in `docs/sync-dest-doc.py` !!
    !! START CUSTOM EDIT !!
*/}

**Creating Account**<br />
Go to the **[🔗 website](https://odigos.io) > Account** and click **Sign Up**

**Obtaining Access Token**<br />
Go to **⚙️ > Access Tokens** and click **Create New**

{/*
    !! Do not remove this comment, this acts as a key indicator in `docs/sync-dest-doc.py` !!
    !! END CUSTOM EDIT !!
*/}
4

Update README.md

Go to README.md and add your new destination to the list of destinations.

That’s it! Now you can use your new destination in the UI and send data to it.

Please submit a PR to the odigos git repository.