Claude
Skills
Sign in
Back

service-remapping

Included with Lifetime
$97 forever

Create and manage APM service remapping rules — rewrite service names at ingestion time to collapse noisy inferred entities, clean up auto-generated names, handle org renames, or normalize naming conventions. Use for any request involving service renaming, service mapping, inferred service cleanup, peer.service normalization, or collapsing fragmented service names.

General

What this skill does


# APM Service Remapping

> **Before acting:** Surface an impact preview (monitors/dashboards referencing the old service name) before presenting the planned rule. For inferred-entity remaps, also confirm `peer.service` is set on outbound spans. Variables from `## Context to resolve before acting` can be gathered alongside that preview rather than blocking it.

---

## How Service Remapping Works — Domain Knowledge

Read this before building any rule. It gives you the mental model to construct the right filter and catch edge cases.

**What remapping does:** A rule intercepts telemetry at ingestion time and rewrites the service name before indexing. A rule says: "for any entity matching this filter, replace its service name with this new value."

**Two entity types — pick the right one:**

| Entity type | `rule_type` integer | What it targets |
|---|---|---|
| **SERVICE** | `0` | Instrumented services — have spans with an explicit `service` tag set by a tracer |
| **INFERRED_ENTITY** | `1` | Auto-detected from outbound calls — named from `peer.service`. **Requires `peer.service` to be set on outbound spans** (see prerequisite below). |

**Prerequisite for inferred entity remapping — `peer.service` must be set:**

Inferred entity remapping only works when the tracer sets `peer.service` on outbound spans. Without it, entities are keyed by `peer.hostname` and remapping rules will not apply.

To enable this, set the following env var on the **instrumented service** (not the downstream dependency):

```bash
DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=true
```

This makes the ddtrace tracer automatically propagate `peer.service` from `peer.hostname` on outbound HTTP, gRPC, and database calls. Without this, `pup traces search` will show spans with `peer.hostname` but no `peer.service`, and no service remapping rule will match.

To verify `peer.service` is being set before building a rule:

```bash
pup traces search --query "@peer.service:<ENTITY_NAME>" --from 15m --limit 5
```

If zero results — the tracer is not setting `peer.service`. Ask the user to add `DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=true` to their service's environment and redeploy before continuing.

**Filter syntax** — a standard Datadog event-grammar query string:

| Goal | Filter |
|---|---|
| Exact service match | `service:payments` |
| All services with a prefix | `service:deploy-test*` |
| All services with a suffix | `service:*.tropos` |
| All services containing a string | `service:*payments*` |
| All inferred services under a domain | `peer.service:*.shopify.com` |
| Service in one environment only | `service:payments AND env:prod` |
| Multiple possible values | `service:(payments OR billing)` |

> **Supported operations only:** The above forms — exact match, wildcards, `AND`/`OR` — are the only accepted operations. More advanced query syntax (CIDR ranges, numeric comparisons, fuzzy matching, etc.) is not supported and will be rejected by the API with a filter syntax error.

**New name syntax** — the `value` field in `rewrite_tag_rules`:

| Form | Example | Use for |
|---|---|---|
| Static string | `my-service` | Every matched entity gets exactly this name |
| Tag interpolation | `{{service}}` | Substitute the full value of a tag |
| Tag + regex capture | `{{service\|^(.+?)\..*$}}` | Extract part of a tag value (non-greedy capture) |

**Regex constraints for `{{tag\|regex}}`:**
- Maximum **1 capture group** per expression
- **No greedy quantifiers inside capture groups** — use non-greedy variants: `(.+?)` not `(.+)`, `(.*?)` not `(.*)`
- Quantifiers on capture groups themselves (e.g. `(foo)+`) are not allowed
- **No capture group** → the entire match is used as the replacement value
- **Capture group spanning the entire match** (e.g. `^(.*)$`) is currently rejected by the UI and will soon be rejected by the API — if you want the full tag value, use tag interpolation (`{{service}}`) instead of a regex

**Five remapping patterns:**

| Pattern | User says… | Filter example | New name example |
|---|---|---|---|
| **N:1 group** | "These N services are all the same thing" | `peer.service:*.shopify.com` | `shopify` |
| **Strip suffix/prefix** | "The name has junk at the end/start" | `service:*.tropos` | `{{service\|^(.+?)\..*$}}` |
| **1:1 rename** | "We renamed this service and Datadog needs to match" | `service:old-auth-service` | `auth-service` |
| **Env split** | "I want separate services per env but they all have the same name" | `service:my-service AND env:prod` | `my-service-prod` |
| **Prefix normalization** | "All services should start with an env or team name" | `service:payments*` | `{{env}}-{{service}}` |

---

## Triggers

Invoke this skill when the user wants to:
- Rename a service in Datadog without re-instrumenting
- Collapse multiple inferred service names into one (e.g. many `api.shopify.com/*` variants → `shopify`)
- Strip environment suffixes, version tags, or deployment metadata baked into service names
- Normalize `peer.service` names to something meaningful
- Rename a service after an org change, product rebrand, or migration
- Split a single service into per-env variants (`my-service` + `env:prod` → `my-service-prod`)
- List, review, or delete existing service remapping rules

Do NOT invoke this skill if:
- The user wants to rename the service in their application code — that requires a tracer config change (`DD_SERVICE`), not a remapping rule
- The user wants to correlate telemetry across infrastructure tags — that is the "Correlate telemetry" action type in the UI, not remapping

---

## Prerequisites

### pup-cli: check, install, and authenticate

### Claude runs

```bash
pup --version
```

If not found:

### Claude runs

```bash
brew tap datadog-labs/pack
brew install pup
```

Check auth:
```bash
pup auth status
```

If not authenticated:

### Claude runs

```bash
pup auth login
```

> This opens a browser tab for OAuth. Complete the login there — Claude will continue once the command exits.

### Credentials for write operations

`pup apm service-remapping list` and `get` work with OAuth. Create, update, and delete require API keys (`DD_API_KEY`, `DD_APP_KEY`, `DD_SITE`) until `apm_service_renaming_write` is added to pup's OAuth scopes.

### Claude runs

```bash
echo "DD_API_KEY set: $([ -n "${DD_API_KEY:-}" ] && echo yes || echo no)"
echo "DD_APP_KEY set: $([ -n "${DD_APP_KEY:-}" ] && echo yes || echo no)"
echo "DD_SITE: ${DD_SITE:-not set (defaulting to datadoghq.com)}"
```

If any are missing and you need to create/update/delete rules:

### What you need to do in a terminal

```bash
export DD_API_KEY=<your-api-key>
export DD_APP_KEY=<your-app-key>
export DD_SITE=datadoghq.com   # adjust for your site
```

> Common sites: `datadoghq.com` (US1), `datadoghq.eu` (EU1), `us3.datadoghq.com`, `us5.datadoghq.com`, `ap1.datadoghq.com`

Wait for the user to set credentials, then re-run the check above before continuing.

---

## Context to resolve before acting

| Variable | How to resolve |
|---|---|
| `ENV` | Required before creating the rule (Step 4). Ask the user — do NOT assume `prod`. Read-only verification and impact preview do not need `ENV` and should run first. |
| `ORIGINAL_SERVICE` | Current service name(s) to remap — discover with `pup apm services list` or ask the user |
| `ENTITY_TYPE` | Instrumented service (`rule_type: 0`) or inferred entity (`rule_type: 1`)? Ask if unclear — see Domain Knowledge |
| `TARGET_NAME` | The desired new service name — ask the user |
| `PATTERN` | Which pattern applies — identify from the user's description (see Domain Knowledge above) |

---

## Step 0: Discover Current Service Names

If the user hasn't specified exact names to remap, discover what exists first:

### Claude runs

```bash
pup apm services list --from 1h          # use --env <ENV> to target a single environment
pup traces search --query "service:<PARTIAL_NAME>" --from 1h --limit 20
```

Use the output to help the user identify exact service names. Ask the user to 

Related in General