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

# Examples

> End-to-end walkthroughs of common sampling rules in Odigos Enterprise, with UI steps and equivalent YAML.

End-to-end walkthroughs of common sampling rules. Each example shows the rule in the **UI** and as a **YAML** `Sampling` resource (the same CRD applied via `kubectl apply` or GitOps). Use these as starting points and adjust scope, operations, and percentages to match your environment.

<Note>
  YAML examples are accurate against the current `Sampling` CRD schema. The screenshots for each scenario reflect the live UI; minor styling may shift between releases.
</Note>

For the field reference behind each example—every Source scope option, every Operation option, every Keep Percentage choice—see [Configuration](./configuration). For the rules engine itself, see [Rules](./rules/overview).

<Info>
  **YAML examples on this page** conform to the `Sampling` CRD (`odigos.io/v1alpha1`). For every field, type, validation rule, and default—including options not covered by the examples below—see the [`Sampling` API reference](../../../api-reference/odigos.io.v1alpha1#odigos-io-v1alpha1-Sampling).
</Info>

<Tip>
  **Scope rules to only the workloads they need to evaluate.** Cluster-wide rules are checked against every trace; tightly scoped rules (Specific Source, Namespace, or Language) are skipped entirely for unrelated workloads, which avoids wasted matching work in the gateway. Several examples below illustrate this pattern.
</Tip>

## 1. Drop a noisy custom endpoint

**Goal:** Drop traces for a high-volume polling endpoint (`/api/v1/poll`) that produces many traces but is not useful for debugging or SLOs. This is a typical **Noisy** rule for traffic that's neither a Kubernetes probe nor a metrics scrape, but is still pure noise.

<Tabs>
  <Tab title="UI">
    Create a Noisy rule with:

    * **Name:** `Drop polling endpoint`
    * **Notes:** `High-volume poll endpoint with no SLO/debug value.`
    * **Source scope:** Specific Source = `odimall / Deployment / notification-service`
    * **Operation:** HTTP Server, route prefix `/api/v1/poll`, method **GET**
    * **Drop Percentage:** Drop All

    <div style={{ maxWidth: '900px', marginLeft: 'auto', marginRight: 'auto' }}>
      <Frame caption="Noisy rule dropping GET traces for /api/v1/poll on the notification-service Deployment.">
        <img src="https://mintcdn.com/odigos/Ni37DdWA1VTwcWpK/images/sampling/drop-poll-endpoint-example.png?fit=max&auto=format&n=Ni37DdWA1VTwcWpK&q=85&s=102aa70d7ece6368d65564256293c7f0" alt="UI screenshot of a Noisy rule that drops GET traces for /api/v1/poll, scoped to the notification-service Deployment in the odimall namespace." width="1413" height="990" data-path="images/sampling/drop-poll-endpoint-example.png" />
      </Frame>
    </div>
  </Tab>

  <Tab title="YAML">
    ```yaml drop-poll-endpoint.yaml theme={null}
    apiVersion: odigos.io/v1alpha1
    kind: Sampling
    metadata:
      name: drop-poll-endpoint
      namespace: odigos-system
    spec:
      name: Drop /api/v1/poll
      noisyOperations:
        - name: Drop polling endpoint
          notes: High-volume poll endpoint with no SLO/debug value.
          percentageAtMost: 0
          sourceScopes:
            - workloadNamespace: odimall
              workloadKind: Deployment
              workloadName: notification-service
          operation:
            httpServer:
              routePrefix: /api/v1/poll
              method: GET
    ```
  </Tab>
</Tabs>

## 2. Keep slow requests at 100%

**Goal:** Always retain traces for `GET /api/products` whenever they take longer than 500 ms. This is a **Highly Relevant** duration rule—a complement to the built-in [Keep All Error Traces](./rules/highly-relevant#built-in-rule-keep-all-error-traces) rule, focused on latency rather than errors.

<Tabs>
  <Tab title="UI">
    Create a Highly Relevant rule with:

    * **Name:** `Slow GET /api/products`
    * **Notes:** `SLO-relevant path; retain anything over 500ms for investigation.`
    * **Rule Type:** Duration
    * **Source scope:** Specific Source = `odimall / Deployment / frontend`
    * **Operation:** HTTP Server, route `/api/products`, method **GET**
    * **Keep Percentage:** Keep All
    * **Duration:** 500ms

    <div style={{ maxWidth: '900px', marginLeft: 'auto', marginRight: 'auto' }}>
      <Frame caption="Highly Relevant rule keeping all GET /api/products traces longer than 500 ms on the frontend Deployment.">
        <img src="https://mintcdn.com/odigos/Ni37DdWA1VTwcWpK/images/sampling/keep-slow-products-example.png?fit=max&auto=format&n=Ni37DdWA1VTwcWpK&q=85&s=a20b0f51a16027c4a32791d855a3ff0e" alt="UI screenshot of a Highly Relevant rule that keeps 100% of slow GET /api/products traces, scoped to the frontend Deployment in the odimall namespace." width="1413" height="990" data-path="images/sampling/keep-slow-products-example.png" />
      </Frame>
    </div>
  </Tab>

  <Tab title="YAML">
    ```yaml keep-slow-products.yaml theme={null}
    apiVersion: odigos.io/v1alpha1
    kind: Sampling
    metadata:
      name: keep-slow-products
      namespace: odigos-system
    spec:
      name: Keep slow product reads
      highlyRelevantOperations:
        - name: Slow GET /api/products
          notes: SLO-relevant path; retain anything over 500ms for investigation.
          durationAtLeastMs: 500
          percentageAtLeast: 100
          sourceScopes:
            - workloadNamespace: odimall
              workloadKind: Deployment
              workloadName: frontend
          operation:
            httpServer:
              route: /api/products
              method: GET
    ```
  </Tab>
</Tabs>

## 3. Apply a cluster-wide 5% baseline

**Goal:** Keep 5% of all cluster traffic as a statistical baseline, regardless of source or operation. This is the same shape as the built-in [Drop Traces Cluster-Wide](./rules/cost-reduction#built-in-rule-drop-traces-cluster-wide) rule and is the simplest way to cut volume after Noisy and Highly Relevant rules have run.

<Tabs>
  <Tab title="UI">
    Create a Cost Reduction rule with:

    * **Name:** `5% baseline`
    * **Notes:** `Statistical baseline for non-noisy, non-important traffic.`
    * **Source scope:** Entire cluster
    * **Operation:** All Operations
    * **Drop Percentage:** 5

    <div style={{ maxWidth: '900px', marginLeft: 'auto', marginRight: 'auto' }}>
      <Frame caption="Cost Reduction rule keeping at most 5% of all cluster traffic.">
        <img src="https://mintcdn.com/odigos/Ni37DdWA1VTwcWpK/images/sampling/baseline-cluster-sample-example.png?fit=max&auto=format&n=Ni37DdWA1VTwcWpK&q=85&s=50cc53df3883927c0a1702c856c02fe8" alt="UI screenshot of a Cost Reduction rule that caps cluster-wide retention at 5%." width="1413" height="990" data-path="images/sampling/baseline-cluster-sample-example.png" />
      </Frame>
    </div>
  </Tab>

  <Tab title="YAML">
    ```yaml baseline-cluster-sample.yaml theme={null}
    apiVersion: odigos.io/v1alpha1
    kind: Sampling
    metadata:
      name: baseline-cluster-sample
      namespace: odigos-system
    spec:
      name: Cluster baseline 5%
      costReductionRules:
        - name: 5% baseline
          notes: Statistical baseline for non-noisy, non-important traffic.
          percentageAtMost: 5
    ```
  </Tab>
</Tabs>

<Tip>
  Cost Reduction rules with **no** Operation block apply to every operation in the scope. Combine with Highly Relevant rules to make sure error and latency traces survive the cap—Highly Relevant always wins over Cost Reduction.
</Tip>

## 4. Scope a rule to namespace and language

**Goal:** Drop scrape traffic to `/internal/metrics` for **Java** workloads in the `prod` namespace only—leave other namespaces and other languages untouched. This example demonstrates the **AND** semantics across scope types: a single source scope item with both `workloadNamespace` and `workloadLanguage` set.

<Tabs>
  <Tab title="UI">
    Create a Noisy rule with:

    * **Name:** `Java metrics scrape in prod`
    * **Notes:** `Internal Prometheus scrape endpoint; the scrape itself isn't useful for tracing.`
    * **Source scope:** Specific Namespace = `prod` **and** Specific Programming Language = **Java**
    * **Operation:** HTTP Server, route `/internal/metrics`, method **GET**
    * **Drop Percentage:** Drop All

    <div style={{ maxWidth: '900px', marginLeft: 'auto', marginRight: 'auto' }}>
      <Frame caption="Noisy rule scoped to Java workloads in the prod namespace.">
        <img src="https://mintcdn.com/odigos/Ni37DdWA1VTwcWpK/images/sampling/drop-metrics-java-prod-example.png?fit=max&auto=format&n=Ni37DdWA1VTwcWpK&q=85&s=275e5a1e330c052c4c75d27895afbe88" alt="UI screenshot of a Noisy rule scoped with namespace prod AND language Java." width="1413" height="990" data-path="images/sampling/drop-metrics-java-prod-example.png" />
      </Frame>
    </div>
  </Tab>

  <Tab title="YAML">
    ```yaml drop-metrics-java-prod.yaml theme={null}
    apiVersion: odigos.io/v1alpha1
    kind: Sampling
    metadata:
      name: drop-metrics-java-prod
      namespace: odigos-system
    spec:
      name: Drop /internal/metrics (Java in prod)
      noisyOperations:
        - name: Java metrics scrape in prod
          notes: Internal Prometheus scrape endpoint; the scrape itself isn't useful for tracing.
          percentageAtMost: 0
          sourceScopes:
            - workloadNamespace: prod
              workloadLanguage: java
          operation:
            httpServer:
              route: /internal/metrics
              method: GET
    ```
  </Tab>
</Tabs>

<Note>
  Source scope combines in two layers:

  * **Different categories must all match.** This rule sets Specific Namespace = `prod` together with Specific Programming Language = `java`, so a workload has to be in `prod` **and** be a Java workload. In YAML that maps to a single `sourceScopes` item with both fields set on it.
  * **Multiple values inside one category are alternatives.** Setting the namespace category to `prod` and `staging` would match a Java workload in either one. In YAML that maps to multiple `sourceScopes` items, each carrying just the namespace field.
</Note>

## 5. Combine Highly Relevant and Cost Reduction

**Goal:** A `payment-service` where **every error trace** must be kept (Highly Relevant) and **all other traffic** is capped at 1% (Cost Reduction). This is the canonical "keep what matters, sample the rest" pattern, expressed in a single `Sampling` object that bundles both categories together.

<Tabs>
  <Tab title="UI">
    Create two rules:

    **1. Highly Relevant**

    * **Name:** `Keep payment-service errors`
    * **Notes:** `Errors from payment-service are always investigated; never sample them away.`
    * **Rule Type:** Error
    * **Source scope:** Specific Source = `odimall / Deployment / payment-service`
    * **Operation:** All Operations
    * **Keep Percentage:** Keep All

    <div style={{ maxWidth: '900px', marginLeft: 'auto', marginRight: 'auto' }}>
      <Frame caption="Highly Relevant rule keeping 100% of error traces from payment-service.">
        <img src="https://mintcdn.com/odigos/Ni37DdWA1VTwcWpK/images/sampling/payment-service-policy-relevant-example.png?fit=max&auto=format&n=Ni37DdWA1VTwcWpK&q=85&s=f4352d98a24c24594c9249eb60ceb281" alt="UI screenshot of a Highly Relevant rule with Rule Type Error scoped to payment-service, Keep at least 100%." width="1413" height="990" data-path="images/sampling/payment-service-policy-relevant-example.png" />
      </Frame>
    </div>

    **2. Cost Reduction**

    * **Name:** `payment-service 1% cap`
    * **Notes:** `Cap healthy payment-service traffic to keep cost in check; HR errors above always win.`
    * **Source scope:** Specific Source = `odimall / Deployment / payment-service`
    * **Operation:** All Operations
    * **Drop Percentage:** 1%

    <div style={{ maxWidth: '900px', marginLeft: 'auto', marginRight: 'auto' }}>
      <Frame caption="Cost Reduction rule capping payment-service traffic at 1%.">
        <img src="https://mintcdn.com/odigos/Ni37DdWA1VTwcWpK/images/sampling/payment-service-policy-cost-example.png?fit=max&auto=format&n=Ni37DdWA1VTwcWpK&q=85&s=4948667e517c18b33fe0bf68c0522ad5" alt="UI screenshot of a Cost Reduction rule on payment-service with Keep at most 1%." width="1413" height="990" data-path="images/sampling/payment-service-policy-cost-example.png" />
      </Frame>
    </div>
  </Tab>

  <Tab title="YAML">
    ```yaml payment-service-policy.yaml theme={null}
    apiVersion: odigos.io/v1alpha1
    kind: Sampling
    metadata:
      name: payment-service-policy
      namespace: odigos-system
    spec:
      name: payment-service policy
      notes: Always keep errors; cap healthy traffic at 1%.
      highlyRelevantOperations:
        - name: Keep payment-service errors
          notes: Errors from payment-service are always investigated; never sample them away.
          error: true
          percentageAtLeast: 100
          sourceScopes:
            - workloadNamespace: odimall
              workloadKind: Deployment
              workloadName: payment-service
      costReductionRules:
        - name: payment-service 1% cap
          notes: Cap healthy payment-service traffic to keep cost in check; HR errors above always win.
          percentageAtMost: 1
          sourceScopes:
            - workloadNamespace: odimall
              workloadKind: Deployment
              workloadName: payment-service
    ```
  </Tab>
</Tabs>

<Note>
  A trace from `payment-service` that contains any error span is kept at 100% by the Highly Relevant rule. A trace with no errors falls through to the Cost Reduction cap of 1%. Both rules are evaluated for every matching trace; Highly Relevant's keep percentage wins when both apply. See [Evaluation between Highly Relevant and Cost Reduction](./rules/overview#evaluation-between-highly-relevant-and-cost-reduction-categories).
</Note>

## YAML reference notes

A few details that aren't obvious from YAML alone but matter when authoring rules. The full schema—every field, type, and validation rule—is in the [`Sampling` API reference](../../../api-reference/odigos.io.v1alpha1#odigos-io-v1alpha1-Sampling).

<AccordionGroup>
  <Accordion title="Source scope: language enum and workloadKind casing">
    The YAML enum for `workloadLanguage` uses lowercase identifiers: `java`, `python`, `go`, `dotnet`, `javascript`, `php`, `ruby`. The UI displays the friendly names (Java, Python, Go, .Net, NodeJS, PHP, Ruby).

    `workloadKind` must match the Kubernetes resource kind exactly (case-sensitive PascalCase): `Deployment`, `StatefulSet`, `DaemonSet`, `Job`, `CronJob`. Lowercase or pluralized values will silently fail to match.
  </Accordion>

  <Accordion title="Defaults when fields are omitted">
    Empty or missing fields don't mean "match nothing"—each one has a default that often biases toward broader matching:

    * **`sourceScopes` empty or absent** — the rule matches **every** source.
    * **`operation` omitted** — the rule matches **every** operation in the scope.
    * **Noisy `percentageAtMost` omitted** — defaults to **0%** (drops everything).
    * **Highly Relevant `percentageAtLeast` omitted** — defaults to **100%** (keeps everything).
    * **Cost Reduction `percentageAtMost`** — **required**. There is no default; the resource will fail validation if the field is absent.
  </Accordion>

  <Accordion title="HTTP matchers: route, method, and templated paths">
    * On HTTP Server matchers, set **either** `route` (exact match) **or** `routePrefix` (prefix match)—not both. Both match the framework's **templated path** (e.g., `/users/{id}`, `/users/:id`, `/users/*`), not the resolved URL.
    * `method` is a free-form string in YAML. The UI restricts it to GET, POST, PATCH, DELETE, and PUT, but YAML accepts any method (e.g., HEAD, OPTIONS). Leave it empty to match any method.
    * HTTP Client matchers (Noisy only) use `templatedPath` / `templatedPathPrefix`—the framework's parameterized path (e.g., `/users/{id}`), **not** the resolved URL (e.g., `/users/42`). Match against the route as your HTTP library reports it.
  </Accordion>

  <Accordion title="Kafka matchers: empty topic matches all topics">
    Leaving `kafkaTopic` empty on a `kafkaConsumer` or `kafkaProducer` matcher matches **every** topic for that direction. Set the topic explicitly to scope a Kafka rule to a specific stream.
  </Accordion>

  <Accordion title="Highly Relevant: combining `error` and `durationAtLeastMs`">
    Setting both `error: true` and `durationAtLeastMs` on a single `highlyRelevantOperations` item is an **AND**—the span must be an error **and** longer than the threshold to match. For "errors **or** slow," use two separate items in the `highlyRelevantOperations` array.
  </Accordion>

  <Accordion title="`name` and `disabled` surface in observability data">
    The rule `name` is written as a **metric attribute** and stored as a **span attribute** on participating spans, so use a value that's safe for dashboards and queries—avoid PII or characters your backend doesn't index well.

    `disabled: true` (per rule, or `spec.disabled` for the entire `Sampling` object) removes the rule from sampling decisions but **still emits metrics** for it. That's useful for tuning a rule and observing its would-be impact before re-enabling it, rather than deleting it outright.
  </Accordion>
</AccordionGroup>

## Applying YAML rules

You can apply any of the YAML examples above with `kubectl`, or commit them to your GitOps repository alongside the rest of your Odigos configuration:

```bash theme={null}
kubectl apply -f drop-poll-endpoint.yaml
```

Each `Sampling` resource is a self-contained group of rules. You can split rules across multiple `Sampling` objects—by team, environment, or use case—and they will be **joined together** to form the global sampling policy.

```bash theme={null}
kubectl get samplings.odigos.io -n odigos-system
```

### Disabling a rule

To take a rule out of sampling decisions without deleting it, you can either flip the toggle in the UI or set `disabled: true` in YAML. Disabled rules **still emit sampling metrics**, so you can observe what the rule would have done before re-enabling it—useful as a "soft delete" while tuning, rather than removing the rule outright. See [Enabled](./configuration#enabled) for when to reach for this versus deleting the rule.

<Tabs>
  <Tab title="UI">
    Each rule's detail view has a toggle in the top-right corner that flips its label between **Rule Enabled** and **Rule Disabled**. Slide it off to take the rule out of sampling decisions immediately; slide it back on to re-enable. The toggle is **per rule**—other rules in the same `Sampling` object continue to apply.

    <div style={{ display: 'flex', flexWrap: 'wrap', gap: '1.5rem', alignItems: 'flex-start', marginTop: '1rem' }}>
      <div style={{ flex: '1 1 320px', maxWidth: '440px' }}>
        <Frame caption="Rule Enabled — toggle on, the rule is included in sampling decisions.">
          <img src="https://mintcdn.com/odigos/Ni37DdWA1VTwcWpK/images/sampling/ui-enable-rule.png?fit=max&auto=format&n=Ni37DdWA1VTwcWpK&q=85&s=4e5f6ce5034b996a1d932fd2183ded88" alt="UI screenshot of the Rule Enabled toggle in the on (green) position." width="920" height="216" data-path="images/sampling/ui-enable-rule.png" />
        </Frame>
      </div>

      <div style={{ flex: '1 1 320px', maxWidth: '440px' }}>
        <Frame caption="Rule Disabled — toggle off, the rule is excluded but still emits metrics.">
          <img src="https://mintcdn.com/odigos/Ni37DdWA1VTwcWpK/images/sampling/ui-disable-rule.png?fit=max&auto=format&n=Ni37DdWA1VTwcWpK&q=85&s=8e0623bb7fee782f80f0473c69046805" alt="UI screenshot of the Rule Disabled toggle in the off (red) position." width="920" height="216" data-path="images/sampling/ui-disable-rule.png" />
        </Frame>
      </div>
    </div>
  </Tab>

  <Tab title="YAML">
    The `disabled` flag exists at two levels:

    * **Per rule** — set `disabled: true` on an individual entry in `noisyOperations`, `highlyRelevantOperations`, or `costReductionRules`. The other rules in the same `Sampling` object continue to apply. This is what the UI toggle writes.
    * **Per `Sampling` object** — set `spec.disabled: true` on the resource. Every rule in that object is taken out of decisions in one step, leaving rules in other `Sampling` objects untouched.

    ```yaml disable-a-rule.yaml theme={null}
    apiVersion: odigos.io/v1alpha1
    kind: Sampling
    metadata:
      name: payment-service-policy
      namespace: odigos-system
    spec:
      name: payment-service policy
      costReductionRules:
        - name: payment-service 1% cap
          notes: Cap healthy payment-service traffic to keep cost in check; HR errors above always win.
          disabled: true
          percentageAtMost: 1
          sourceScopes:
            - workloadNamespace: odimall
              workloadKind: Deployment
              workloadName: payment-service
    ```
  </Tab>
</Tabs>

<Tip>
  The examples on this page cover the most common shapes; the [`Sampling` API reference](../../../api-reference/odigos.io.v1alpha1#odigos-io-v1alpha1-Sampling) is the source of truth for every field, type, validation rule, and default on the CRD. Use it when you're extending an example or building a rule that doesn't fit one of the patterns above.
</Tip>
