> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mezmo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Metrics Data Optimization Pipeline

> Build a Mezmo pipeline that enriches, state-routes, aggregates, and limits cardinality on OpenTelemetry metrics to reduce volume.

***

## Step 1: Create a new Pipeline to handle and route OpenTelemetry Metrics

Create a new Mezmo Pipeline by clicking [New Pipeline](https://app.mezmo.com/pipelines/pipeline/new) in the platform.  Give this a name like `Metric Handler`, select Create Blank Pipeline, then select Continue at the bottom.

## Step 2: Add OpenTelemetry Metric Source

Click `Add Source` and select your OpenTelemetry Metric source from the `Shared Sources` list similar to before.

## Step 3: Insert State Enrichment

As we did with the previous pipeline, we will prepare the data to take advantage of [Responsive Pipelines](/telemetry-pipelines/configure-responsive-pipelines) in the future by enriching each metric with the current pipelines operational state.   Click the `three dots` on your Otel Metric Source and select `Add Node->Add Processor->Script Execution`.

<Frame caption="Metric State Enrichment">
  <img src="https://mintcdn.com/mezmo-9a59581a/5cIdgEAM73o6sWZ8/images/OptTutorial/76pknbpszl4xfabgzustgpnrf5hyvccmflxji3yow646vsg2cn206x8q0f4g0mwu.png?fit=max&auto=format&n=5cIdgEAM73o6sWZ8&q=85&s=09cdd336540c4e089ae2064261e45f8f" alt="Image" width="2124" height="1982" data-path="images/OptTutorial/76pknbpszl4xfabgzustgpnrf5hyvccmflxji3yow646vsg2cn206x8q0f4g0mwu.png" />
</Frame>

Paste in the following JavaScript and click `Save`.  Note that the script does a bit more than add the `operational_state` state variable by tagging this data in-flight.

```javascript theme={null}
function processEvent(message, metadata, timestamp, annotations) {
  const state = getPipelineStateVariable("operational_state")
  message.op_state = state
  
  message.name = message.name.toString()
  message.tags.op_state = state

  metadata.resource.attributes["pipeline.path"] = "with_mezmo"

  if( message == null ){ return null }
  
  return message
}

```

## Step 4: Route Based on State

After the initial Enrichment processor, let's route the data flow based on that `operational_state`.  Connect a Route processor to the Enrichment Script with the following configuration:

* Title: `State Router`
* Route 1:
* Title: `Normal`
* Criteria: `message.op_state` `contains` `normal`
* Route 2:
* Title: `Incident`
* Criteria: `message.op_state` `contains` `incident`
* Route 3:
* Title: `Deploy`
* Criteria: `message.op_state` `contains` `deploy`

You will end up with a pipeline that looks like the following

<Frame caption="Metric State Router">
  <img src="https://mintcdn.com/mezmo-9a59581a/5cIdgEAM73o6sWZ8/images/OptTutorial/1tepkafcbeyoi8jecv1pomsmeb9l9o76docnznro1tst7b7jry3m7wc5rh88nb60.png?fit=max&auto=format&n=5cIdgEAM73o6sWZ8&q=85&s=f353f28555560156cd87ac111c525596" alt="Image" width="1070" height="1980" data-path="images/OptTutorial/1tepkafcbeyoi8jecv1pomsmeb9l9o76docnznro1tst7b7jry3m7wc5rh88nb60.png" />
</Frame>

## Step 5: Normalize and Aggregate in Normal State

A common approach to reduce Metric data volumes is to aggregate those metrics and reduce their cardinality. Mezmo makes this incredibly easy with intuitive processors.  We will implement a 5 min aggregation on all incoming metrics and trim off the tags being used.  Connected to your `Normal` and `Unmatched` outputs from the `State Router`, add a `Script Execution` processor with the following script:

```javascript theme={null}
function processEvent(message, metadata, timestamp, annotations) {

  let service_name = message.tags.service_name
  let host_id = message.tags.host_id
  
  if( service_name == null ){
    service_name = metadata.resource.attributes['service.name']
  }
  if( service_name == null ){ service_name = 'NA' }
  if( host_id == null ){
    host_id = metadata.resource.attributes['host.id']
  }
  if( host_id == null ){ host_id = 'NA' }

  message.tags = {
    'service_name': service_name,
    'host_id': host_id
  }
  
  return message
}

```

Next, we will limit the cardinality of that `host_id` tag to 10 by connecting a `Tag Cardinality Limit` processor with the following configuration:

* Tags: `message.tags.host_id`
* Action: `drop_tag`
* Value Limit: `10`
* Mode: `Probablistic`

Finally, let's aggregate on a 5 min window by adding an `Aggregate` processor.  Leave the default configuration, only changing the following:

* Interval (seconds): `300`

<Frame caption="Metric Aggregator">
  <img src="https://mintcdn.com/mezmo-9a59581a/5cIdgEAM73o6sWZ8/images/OptTutorial/ufxns1xbvjyar2lg56uif0uwvnbawg0hxyqyhmulcs55vieqlu5z022p7oky7jvz.png?fit=max&auto=format&n=5cIdgEAM73o6sWZ8&q=85&s=7851c9df9a2131ec4a3bd9cac2ec838f" alt="Image" width="1074" height="1982" data-path="images/OptTutorial/ufxns1xbvjyar2lg56uif0uwvnbawg0hxyqyhmulcs55vieqlu5z022p7oky7jvz.png" />
</Frame>

## Step 6: Sending Data Downstream Systems

Now, connect all outputs to a Blackhole destination.  This is simply a placeholder for any Observability system you'd like.  Explore our destinations in-app or in our [docs](/telemetry-pipelines/supported-telemetry-data-destinations) to easily send telemetry data downstream into tools, data lakes and more.

You should have a pipeline that looks like the following.

<Frame caption="Metric Blackhole Connected">
  <img src="https://mintcdn.com/mezmo-9a59581a/5cIdgEAM73o6sWZ8/images/OptTutorial/k31cpo7io0io53p1rxttjfpio8ppg5lvqrna3iodlemohlk1v66qt5tot4c7inn2.png?fit=max&auto=format&n=5cIdgEAM73o6sWZ8&q=85&s=d8017cdd90d81ad3592c188a82507c7d" alt="Image" width="3342" height="622" data-path="images/OptTutorial/k31cpo7io0io53p1rxttjfpio8ppg5lvqrna3iodlemohlk1v66qt5tot4c7inn2.png" />
</Frame>

## Step 7: Deploy

Finally, you must deploy your pipeline in order to start taking advantage of your metric optimizations.

## Step 8: Initiate State and Grab State ID

Same as with the Logs, let's initiate the State and save the `State ID` of this pipeline for later.

First, flip the State in the UX from Normal to Incident and back to Normal to initialize.

Then, in your terminal  window,  run the following command with the metric `pipeline's ID` and grab that `State ID`.

```bash theme={null}
curl --request GET \
 --url 'https://api.mezmo.com/v3/pipeline/state-variable?pipeline_id=PIPELINE_ID' \
 --header 'Authorization: Token PIPELINE_API_KEY'

```
