From d95cb0f9dae0fd88736f394cea36a81436fdcbaf Mon Sep 17 00:00:00 2001 From: tkosushi Date: Mon, 8 Jun 2026 18:42:50 +0900 Subject: [PATCH 1/7] Add Observability (telemetry export) guide Document the telemetryrouter feature for users: forwarding a workspace's OpenTelemetry traces and logs to external backends via the Tailor Terraform provider. - New guide at docs/guides/observability.md covering telemetry export setup, authentication, endpoint format/validation rules, the Datadog-via-OTel-Collector pattern, and resource attributes config. - Note that metrics are not yet supported. - Add "observability" to the Guides nav order. Co-Authored-By: Claude Opus 4.8 (1M context) --- .vitepress/config/constants.ts | 1 + docs/guides/observability.md | 221 +++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 docs/guides/observability.md diff --git a/.vitepress/config/constants.ts b/.vitepress/config/constants.ts index 7e88929..b58bcf9 100644 --- a/.vitepress/config/constants.ts +++ b/.vitepress/config/constants.ts @@ -9,6 +9,7 @@ export const navItemOrder: Record = { "auth", "application", "events", + "observability", ], tutorials: [ "app-endpoint", diff --git a/docs/guides/observability.md b/docs/guides/observability.md new file mode 100644 index 0000000..e26344c --- /dev/null +++ b/docs/guides/observability.md @@ -0,0 +1,221 @@ +--- +doc_type: guide +--- + +# Observability + +Tailor Platform forwards the OpenTelemetry signals generated by your workspace to the observability backend of your choice. +By configuring a telemetry export, you can integrate platform-generated **traces** and **logs** with tools such as Datadog, Grafana, or Honeycomb, without changing any application code. + +Common use cases include: + +- Sending request traces from your platform services to an existing distributed tracing backend +- Centralizing platform logs alongside your application logs +- Enriching all outgoing signals with a consistent service name and deployment environment + +Telemetry export is configured through the Tailor Terraform provider. There are two resources: + +- `tailor_telemetryrouter_telemetry_export` — defines an export destination +- `tailor_telemetryrouter_resource_attributes_config` — defines workspace-level resource attributes that are attached to every signal + +## How it works + +Telemetry routing is scoped to a workspace. Each export destination you define receives the workspace's signals over OTLP (the OpenTelemetry Protocol), and you choose which signals each destination receives. + +- Signals are routed per workspace to every enabled export destination. +- Traces and logs can be enabled independently per export. +- Authentication credentials are never stored inline — they are referenced from [Secret Manager](secretmanager.md) and resolved at send time. + +**Metrics are not supported yet.** The `enable_metrics` field exists for forward compatibility, but the platform does not currently emit or forward metric signals. Enabling it has no effect today, so configure your destinations for traces and logs only. + +## Configuring a telemetry export + +A telemetry export defines a single destination. A workspace may have multiple exports, each identified by a unique `name`. + +The following example forwards traces and logs to a generic OTLP backend over HTTP, authenticating with a bearer token stored in Secret Manager: + +```hcl {{ title: 'telemetry_export.tf' }} +resource "tailor_telemetryrouter_telemetry_export" "backend" { + workspace_id = tailor_workspace.example.id + + name = "otlp-backend" + endpoint = "https://otlp.example.com" + protocol = "http" + + auth = { + bearer_token = { + secret_value = { + vault_name = tailor_secretmanager_vault.example.name + secret_name = "otlp-backend-token" + } + } + } + + enable_traces = true + enable_logs = true +} +``` + +To send telemetry to Datadog, route it through your own OpenTelemetry Collector. See [Exporting to Datadog](#exporting-to-datadog) below. + +### Arguments + +| Argument | Type | Required | Description | +| --- | --- | --- | --- | +| `workspace_id` | String | Yes | The ID of the workspace this export belongs to. | +| `name` | String | Yes | Unique name of the destination within the workspace. Must match the pattern `^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$` (3–63 characters, lowercase alphanumerics and hyphens, no leading or trailing hyphen). | +| `endpoint` | String | Yes | The OTLP endpoint to forward signals to. See [Endpoint format](#endpoint-format) for the rules. | +| `protocol` | String | Yes | The OTLP transport protocol. One of `grpc` or `http`. | +| `enabled` | Boolean | No | Whether this destination is active. Defaults to `true`. | +| `enable_traces` | Boolean | No | Whether to forward trace signals. Defaults to `false`. | +| `enable_logs` | Boolean | No | Whether to forward log signals. Defaults to `false`. | +| `enable_metrics` | Boolean | No | Reserved for future use. **Metrics are not supported yet** — see [How it works](#how-it-works). Defaults to `false`. | +| `headers` | Map of String | No | Additional headers attached to each outgoing request. | +| `auth` | Block | No | Authentication for the endpoint. Exactly one of `api_key` or `bearer_token` may be set. | + +### Authentication + +The optional `auth` block configures how Tailor authenticates to the destination. Set **exactly one** of the following. + +**API key** — the secret value is sent in the header you name: + +```hcl {{ title: 'auth_api_key.tf' }} +auth = { + api_key = { + header_name = "x-api-key" + secret_value = { + vault_name = tailor_secretmanager_vault.example.name + secret_name = "backend-api-key" + } + } +} +``` + +**Bearer token** — the secret value is sent as an `Authorization: Bearer ` header: + +```hcl {{ title: 'auth_bearer.tf' }} +auth = { + bearer_token = { + secret_value = { + vault_name = tailor_secretmanager_vault.example.name + secret_name = "backend-token" + } + } +} +``` + +In both cases `secret_value` references a secret in [Secret Manager](secretmanager.md): + +- `vault_name` — the name of the vault that stores the secret +- `secret_name` — the key of the secret within the vault + +## Endpoint format + +The connection to the destination must use TLS; plain `http://` is not supported. The required `endpoint` format depends on the `protocol`: + +- **`http`** — an HTTPS base URL, for example `https://otlp.example.com`. Do **not** include the OTLP signal path (`/v1/traces`, `/v1/metrics`, `/v1/logs`); it is appended automatically for each enabled signal. Query strings and fragments are not allowed. +- **`grpc`** — either a bare `host:port` (the port is **required**, for example `otlp.example.com:4317`) or an `https://host[:port]` URL (the port defaults to `443` when omitted). A path, query string, or fragment is not allowed. + +Endpoints that resolve to a private or internal host (for example RFC 1918 ranges or loopback addresses) are rejected by default. + +| Protocol | Valid | Invalid | +| --- | --- | --- | +| `http` | `https://otlp.example.com` | `https://otlp.example.com/v1/traces` (signal path), `http://otlp.example.com` (not TLS) | +| `grpc` | `otlp.example.com:4317`, `https://otlp.example.com` | `otlp.example.com` (no port), `https://otlp.example.com/path` (has path) | + +## Exporting to Datadog + +Datadog cannot currently be used as a direct telemetry export target. Instead, run your own OpenTelemetry Collector with the [Datadog exporter](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/datadogexporter) configured, point your Tailor telemetry export at that collector, and let the collector forward signals to Datadog. + +```mermaid +flowchart LR + A[Tailor Platform
telemetry export] -->|OTLP| B[Your OpenTelemetry
Collector] + B -->|datadog exporter| C[Datadog] +``` + +### 1. Configure your OpenTelemetry Collector + +Run an OpenTelemetry Collector that receives OTLP from Tailor and exports to Datadog. A minimal configuration: + +```yaml {{ title: 'otel-collector.yaml' }} +receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + +processors: + batch: {} + +exporters: + datadog: + api: + key: ${env:DD_API_KEY} + site: datadoghq.com + +service: + pipelines: + traces: + receivers: [otlp] + processors: [batch] + exporters: [datadog] + logs: + receivers: [otlp] + processors: [batch] + exporters: [datadog] +``` + +This collector must be reachable from Tailor over TLS at a publicly resolvable address. Terminate TLS in front of the collector (for example with a load balancer) and expose its OTLP gRPC endpoint. + +### 2. Point the telemetry export at your collector + +Configure the export `endpoint` to your collector's OTLP endpoint rather than Datadog directly: + +```hcl {{ title: 'datadog_export.tf' }} +resource "tailor_telemetryrouter_telemetry_export" "datadog" { + workspace_id = tailor_workspace.example.id + + name = "datadog-collector" + endpoint = "otel-collector.example.com:4317" + protocol = "grpc" + + enable_traces = true + enable_logs = true +} +``` + +If your collector requires authentication, add an `auth` block or `headers` as described in [Authentication](#authentication). Because the endpoint points at your own collector, make sure it is not a private or internal host — see [Endpoint format](#endpoint-format). + +## Configuring resource attributes + +The `tailor_telemetryrouter_resource_attributes_config` resource defines workspace-level resource attributes that are attached to every outgoing signal. It is a singleton: a workspace has at most one resource attributes configuration. + +```hcl {{ title: 'resource_attributes.tf' }} +resource "tailor_telemetryrouter_resource_attributes_config" "this" { + workspace_id = tailor_workspace.example.id + + service_name_prefix = "acme" + deployment_environment_name = "production" +} +``` + +### Arguments + +| Argument | Type | Required | Description | +| --- | --- | --- | --- | +| `workspace_id` | String | Yes | The ID of the workspace this configuration belongs to. | +| `service_name_prefix` | String | Yes | Prefix prepended to each microservice's own `service.name` to form the final `service.name` attribute on outgoing signals (`-`). Must match the pattern `^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$`. | +| `deployment_environment_name` | String | No | Customer-side deployment environment (for example `production` or `staging`), following the OpenTelemetry semantic convention `deployment.environment.name`. Maximum 256 characters. When omitted, the attribute is left untouched. | + +## Security considerations + +- Authentication credentials are referenced from [Secret Manager](secretmanager.md), never stored inline in the export configuration. +- Secret values are write-only when managed through Terraform and are never exposed in state files or logs. +- The destination connection must use TLS; plaintext `http://` endpoints are rejected. + +## Best practices + +1. **Separate environments**: Use distinct exports (and Secret Manager vaults) per environment, and set `deployment_environment_name` accordingly. +2. **Enable only the signals you need**: Leave `enable_traces` / `enable_logs` off for destinations that should not receive a given signal. +3. **Use a consistent service name prefix**: Set `service_name_prefix` so platform signals are easy to identify in your backend. +4. **Rotate credentials**: Update the referenced secret values when rotating API keys or tokens. From 6faf8ee288e55dd16022c7b5b12b54ee16eb77fa Mon Sep 17 00:00:00 2001 From: tkosushi Date: Mon, 8 Jun 2026 18:54:46 +0900 Subject: [PATCH 2/7] Use consistent service name TelemetryRouter Replace the "Telemetry routing" wording in the How it works section with the proper service name TelemetryRouter to remove inconsistent terminology. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/guides/observability.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/observability.md b/docs/guides/observability.md index e26344c..17a6ff0 100644 --- a/docs/guides/observability.md +++ b/docs/guides/observability.md @@ -20,7 +20,7 @@ Telemetry export is configured through the Tailor Terraform provider. There are ## How it works -Telemetry routing is scoped to a workspace. Each export destination you define receives the workspace's signals over OTLP (the OpenTelemetry Protocol), and you choose which signals each destination receives. +TelemetryRouter routes signals per workspace. Each export destination you define receives the workspace's signals over OTLP (the OpenTelemetry Protocol), and you choose which signals each destination receives. - Signals are routed per workspace to every enabled export destination. - Traces and logs can be enabled independently per export. From 1a96702daf8cb1d9f07f2af84333e73b776fd468 Mon Sep 17 00:00:00 2001 From: tkosushi Date: Thu, 11 Jun 2026 11:22:11 +0900 Subject: [PATCH 3/7] Reframe observability guide around OpenTelemetry export Rename observability.md to opentelemetry.md and rewrite for the platform user's mental model: the user-facing resource is the telemetry export, while TelemetryRouter is the internal component (and resource-name prefix). - Retitle to "Observability / OpenTelemetry" and distinguish from in-console log viewing - Add a concept diagram (signals -> TelemetryRouter -> your telemetry exports) - Lead with direct OTLP backends (New Relic, Honeycomb); present the collector path (Datadog) as one option, noting Datadog's direct OTLP intake has constraints (traces in preview) - Point argument details to the Terraform Registry instead of duplicating tables - Correct credential guidance: prefer the auth block (Secret Manager); headers are sensitive but persist in Terraform state, so not for secrets - Soften endpoint TLS wording to match implementation (only private/internal hosts are rejected; no config-time http:// rejection) - Add the guide to guides/index.md; allowlist docs.datadoghq.com in schema.yml Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/guides/index.md | 1 + docs/guides/observability.md | 221 ------------------------------ docs/guides/opentelemetry.md | 255 +++++++++++++++++++++++++++++++++++ schema.yml | 1 + 4 files changed, 257 insertions(+), 221 deletions(-) delete mode 100644 docs/guides/observability.md create mode 100644 docs/guides/opentelemetry.md diff --git a/docs/guides/index.md b/docs/guides/index.md index 3cf3aa8..1af860b 100644 --- a/docs/guides/index.md +++ b/docs/guides/index.md @@ -12,6 +12,7 @@ Comprehensive guides for building applications on Tailor Platform. - [Resolver](resolver.md) - Build custom GraphQL resolvers with business logic and data transformations - [Events](events.md) - Event types and payloads for building dynamic workflows and automations - [Secret Manager](secretmanager.md) - Securely manage API keys, tokens, and credentials with versioning +- [Observability / OpenTelemetry](opentelemetry.md) - Forward platform-generated traces and logs to external backends like New Relic, Honeycomb, or Datadog - [Static Website Hosting](static-website-hosting.md) - Deploy single-page applications with CDN caching and access control ## Service-Specific Guides diff --git a/docs/guides/observability.md b/docs/guides/observability.md deleted file mode 100644 index 17a6ff0..0000000 --- a/docs/guides/observability.md +++ /dev/null @@ -1,221 +0,0 @@ ---- -doc_type: guide ---- - -# Observability - -Tailor Platform forwards the OpenTelemetry signals generated by your workspace to the observability backend of your choice. -By configuring a telemetry export, you can integrate platform-generated **traces** and **logs** with tools such as Datadog, Grafana, or Honeycomb, without changing any application code. - -Common use cases include: - -- Sending request traces from your platform services to an existing distributed tracing backend -- Centralizing platform logs alongside your application logs -- Enriching all outgoing signals with a consistent service name and deployment environment - -Telemetry export is configured through the Tailor Terraform provider. There are two resources: - -- `tailor_telemetryrouter_telemetry_export` — defines an export destination -- `tailor_telemetryrouter_resource_attributes_config` — defines workspace-level resource attributes that are attached to every signal - -## How it works - -TelemetryRouter routes signals per workspace. Each export destination you define receives the workspace's signals over OTLP (the OpenTelemetry Protocol), and you choose which signals each destination receives. - -- Signals are routed per workspace to every enabled export destination. -- Traces and logs can be enabled independently per export. -- Authentication credentials are never stored inline — they are referenced from [Secret Manager](secretmanager.md) and resolved at send time. - -**Metrics are not supported yet.** The `enable_metrics` field exists for forward compatibility, but the platform does not currently emit or forward metric signals. Enabling it has no effect today, so configure your destinations for traces and logs only. - -## Configuring a telemetry export - -A telemetry export defines a single destination. A workspace may have multiple exports, each identified by a unique `name`. - -The following example forwards traces and logs to a generic OTLP backend over HTTP, authenticating with a bearer token stored in Secret Manager: - -```hcl {{ title: 'telemetry_export.tf' }} -resource "tailor_telemetryrouter_telemetry_export" "backend" { - workspace_id = tailor_workspace.example.id - - name = "otlp-backend" - endpoint = "https://otlp.example.com" - protocol = "http" - - auth = { - bearer_token = { - secret_value = { - vault_name = tailor_secretmanager_vault.example.name - secret_name = "otlp-backend-token" - } - } - } - - enable_traces = true - enable_logs = true -} -``` - -To send telemetry to Datadog, route it through your own OpenTelemetry Collector. See [Exporting to Datadog](#exporting-to-datadog) below. - -### Arguments - -| Argument | Type | Required | Description | -| --- | --- | --- | --- | -| `workspace_id` | String | Yes | The ID of the workspace this export belongs to. | -| `name` | String | Yes | Unique name of the destination within the workspace. Must match the pattern `^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$` (3–63 characters, lowercase alphanumerics and hyphens, no leading or trailing hyphen). | -| `endpoint` | String | Yes | The OTLP endpoint to forward signals to. See [Endpoint format](#endpoint-format) for the rules. | -| `protocol` | String | Yes | The OTLP transport protocol. One of `grpc` or `http`. | -| `enabled` | Boolean | No | Whether this destination is active. Defaults to `true`. | -| `enable_traces` | Boolean | No | Whether to forward trace signals. Defaults to `false`. | -| `enable_logs` | Boolean | No | Whether to forward log signals. Defaults to `false`. | -| `enable_metrics` | Boolean | No | Reserved for future use. **Metrics are not supported yet** — see [How it works](#how-it-works). Defaults to `false`. | -| `headers` | Map of String | No | Additional headers attached to each outgoing request. | -| `auth` | Block | No | Authentication for the endpoint. Exactly one of `api_key` or `bearer_token` may be set. | - -### Authentication - -The optional `auth` block configures how Tailor authenticates to the destination. Set **exactly one** of the following. - -**API key** — the secret value is sent in the header you name: - -```hcl {{ title: 'auth_api_key.tf' }} -auth = { - api_key = { - header_name = "x-api-key" - secret_value = { - vault_name = tailor_secretmanager_vault.example.name - secret_name = "backend-api-key" - } - } -} -``` - -**Bearer token** — the secret value is sent as an `Authorization: Bearer ` header: - -```hcl {{ title: 'auth_bearer.tf' }} -auth = { - bearer_token = { - secret_value = { - vault_name = tailor_secretmanager_vault.example.name - secret_name = "backend-token" - } - } -} -``` - -In both cases `secret_value` references a secret in [Secret Manager](secretmanager.md): - -- `vault_name` — the name of the vault that stores the secret -- `secret_name` — the key of the secret within the vault - -## Endpoint format - -The connection to the destination must use TLS; plain `http://` is not supported. The required `endpoint` format depends on the `protocol`: - -- **`http`** — an HTTPS base URL, for example `https://otlp.example.com`. Do **not** include the OTLP signal path (`/v1/traces`, `/v1/metrics`, `/v1/logs`); it is appended automatically for each enabled signal. Query strings and fragments are not allowed. -- **`grpc`** — either a bare `host:port` (the port is **required**, for example `otlp.example.com:4317`) or an `https://host[:port]` URL (the port defaults to `443` when omitted). A path, query string, or fragment is not allowed. - -Endpoints that resolve to a private or internal host (for example RFC 1918 ranges or loopback addresses) are rejected by default. - -| Protocol | Valid | Invalid | -| --- | --- | --- | -| `http` | `https://otlp.example.com` | `https://otlp.example.com/v1/traces` (signal path), `http://otlp.example.com` (not TLS) | -| `grpc` | `otlp.example.com:4317`, `https://otlp.example.com` | `otlp.example.com` (no port), `https://otlp.example.com/path` (has path) | - -## Exporting to Datadog - -Datadog cannot currently be used as a direct telemetry export target. Instead, run your own OpenTelemetry Collector with the [Datadog exporter](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/datadogexporter) configured, point your Tailor telemetry export at that collector, and let the collector forward signals to Datadog. - -```mermaid -flowchart LR - A[Tailor Platform
telemetry export] -->|OTLP| B[Your OpenTelemetry
Collector] - B -->|datadog exporter| C[Datadog] -``` - -### 1. Configure your OpenTelemetry Collector - -Run an OpenTelemetry Collector that receives OTLP from Tailor and exports to Datadog. A minimal configuration: - -```yaml {{ title: 'otel-collector.yaml' }} -receivers: - otlp: - protocols: - grpc: - endpoint: 0.0.0.0:4317 - -processors: - batch: {} - -exporters: - datadog: - api: - key: ${env:DD_API_KEY} - site: datadoghq.com - -service: - pipelines: - traces: - receivers: [otlp] - processors: [batch] - exporters: [datadog] - logs: - receivers: [otlp] - processors: [batch] - exporters: [datadog] -``` - -This collector must be reachable from Tailor over TLS at a publicly resolvable address. Terminate TLS in front of the collector (for example with a load balancer) and expose its OTLP gRPC endpoint. - -### 2. Point the telemetry export at your collector - -Configure the export `endpoint` to your collector's OTLP endpoint rather than Datadog directly: - -```hcl {{ title: 'datadog_export.tf' }} -resource "tailor_telemetryrouter_telemetry_export" "datadog" { - workspace_id = tailor_workspace.example.id - - name = "datadog-collector" - endpoint = "otel-collector.example.com:4317" - protocol = "grpc" - - enable_traces = true - enable_logs = true -} -``` - -If your collector requires authentication, add an `auth` block or `headers` as described in [Authentication](#authentication). Because the endpoint points at your own collector, make sure it is not a private or internal host — see [Endpoint format](#endpoint-format). - -## Configuring resource attributes - -The `tailor_telemetryrouter_resource_attributes_config` resource defines workspace-level resource attributes that are attached to every outgoing signal. It is a singleton: a workspace has at most one resource attributes configuration. - -```hcl {{ title: 'resource_attributes.tf' }} -resource "tailor_telemetryrouter_resource_attributes_config" "this" { - workspace_id = tailor_workspace.example.id - - service_name_prefix = "acme" - deployment_environment_name = "production" -} -``` - -### Arguments - -| Argument | Type | Required | Description | -| --- | --- | --- | --- | -| `workspace_id` | String | Yes | The ID of the workspace this configuration belongs to. | -| `service_name_prefix` | String | Yes | Prefix prepended to each microservice's own `service.name` to form the final `service.name` attribute on outgoing signals (`-`). Must match the pattern `^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$`. | -| `deployment_environment_name` | String | No | Customer-side deployment environment (for example `production` or `staging`), following the OpenTelemetry semantic convention `deployment.environment.name`. Maximum 256 characters. When omitted, the attribute is left untouched. | - -## Security considerations - -- Authentication credentials are referenced from [Secret Manager](secretmanager.md), never stored inline in the export configuration. -- Secret values are write-only when managed through Terraform and are never exposed in state files or logs. -- The destination connection must use TLS; plaintext `http://` endpoints are rejected. - -## Best practices - -1. **Separate environments**: Use distinct exports (and Secret Manager vaults) per environment, and set `deployment_environment_name` accordingly. -2. **Enable only the signals you need**: Leave `enable_traces` / `enable_logs` off for destinations that should not receive a given signal. -3. **Use a consistent service name prefix**: Set `service_name_prefix` so platform signals are easy to identify in your backend. -4. **Rotate credentials**: Update the referenced secret values when rotating API keys or tokens. diff --git a/docs/guides/opentelemetry.md b/docs/guides/opentelemetry.md new file mode 100644 index 0000000..c9c0ea8 --- /dev/null +++ b/docs/guides/opentelemetry.md @@ -0,0 +1,255 @@ +--- +doc_type: guide +title: Observability / OpenTelemetry +--- + +# Observability / OpenTelemetry + +Tailor Platform automatically generates [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-specification) signals — **traces** and **logs** — for the services in your workspace. By configuring a **telemetry export**, you can forward those signals to the observability backend of your choice, such as New Relic, Honeycomb, Grafana, or Datadog, without changing any application code. + +This is different from inspecting logs in the Tailor console: the [console](/getting-started/console/overview) lets you view pipeline execution logs inside the platform, while this guide is about **forwarding signals to an external backend** that you operate. + +Common use cases include: + +- Sending request traces from your platform services to an existing distributed tracing backend +- Centralizing platform logs alongside your application logs +- Enriching all outgoing signals with a consistent service name and deployment environment + +## How telemetry export works + +The platform collects the OpenTelemetry signals your services emit and forwards them, over OTLP (the OpenTelemetry Protocol), to each **telemetry export** you have configured. A telemetry export is the resource *you* define — it points at one backend and decides which signals that backend receives. The internal platform component that performs this routing is **TelemetryRouter**; you don't configure it directly, but it is the source of the `tailor_telemetryrouter_` prefix on the resources below. + +```mermaid +flowchart TD + A[Your workspace services
emit OpenTelemetry signals] -->|traces / logs| B[TelemetryRouter
routes your workspace's signals] + B -->|OTLP| C[telemetry export
New Relic] + B -->|OTLP| D[telemetry export
Honeycomb] + B -->|OTLP| E[telemetry export
...] +``` + +You configure telemetry export through the Tailor Terraform provider. There are two resources: + +- `tailor_telemetryrouter_telemetry_export` — defines an export destination. A workspace may have many; each is given a `name` that is unique within that workspace. +- `tailor_telemetryrouter_resource_attributes_config` — defines workspace-level resource attributes attached to every outgoing signal. A workspace has at most one. + +A few things to keep in mind: + +- **Traces and logs can be enabled independently** per export, so each destination receives only the signals you choose. +- **Authentication credentials are never stored inline** — they are referenced from [Secret Manager](secretmanager.md) and resolved at send time. + +::: warning Metrics +Metric signals are not part of telemetry export today. While the `enable_metrics` field exists, the platform does not currently emit metric signals, so enabling it has no practical effect. Configure your destinations for traces and logs. +::: + +## Configuring a telemetry export + +A telemetry export defines a single destination. Most OTLP-compatible backends can be targeted **directly**, with no additional infrastructure on your side. + +The following example forwards traces and logs to [New Relic](https://github.com/newrelic), authenticating with a license key stored in Secret Manager: + +```hcl {{ title: 'telemetry_export.tf' }} +resource "tailor_telemetryrouter_telemetry_export" "newrelic" { + workspace_id = tailor_workspace.example.id + + name = "newrelic" + endpoint = "https://otlp.nr-data.net" + protocol = "http" + + auth = { + api_key = { + header_name = "api-key" + secret_value = { + vault_name = tailor_secretmanager_vault.example.name + secret_name = "newrelic-license-key" + } + } + } + + enable_traces = true + enable_logs = true +} +``` + +For more backends — including ones that cannot ingest OTLP directly, such as Datadog — see [Backend examples](#backend-examples). + +For the full list of arguments and their constraints, refer to the [Tailor Platform Provider documentation](https://registry.terraform.io/providers/tailor-platform/tailor/latest/docs/resources/telemetryrouter_telemetry_export). + +### Authentication + +The optional `auth` block configures how Tailor authenticates to the destination. Set **exactly one** of the following. + +**API key** — the secret value is sent in the header you name: + +```hcl {{ title: 'auth_api_key.tf' }} +auth = { + api_key = { + header_name = "x-api-key" + secret_value = { + vault_name = tailor_secretmanager_vault.example.name + secret_name = "backend-api-key" + } + } +} +``` + +**Bearer token** — the secret value is sent as an `Authorization: Bearer ` header: + +```hcl {{ title: 'auth_bearer.tf' }} +auth = { + bearer_token = { + secret_value = { + vault_name = tailor_secretmanager_vault.example.name + secret_name = "backend-token" + } + } +} +``` + +In both cases `secret_value` references a secret in [Secret Manager](secretmanager.md): + +- `vault_name` — the name of the vault that stores the secret +- `secret_name` — the key of the secret within the vault + +## Endpoint format + +Use a TLS-enabled endpoint (HTTPS) so credentials and signals are encrypted in transit; plaintext endpoints are not recommended, and a plaintext gRPC target fails to connect. The required `endpoint` format depends on the `protocol`: + +- **`http`** — an HTTPS base URL, for example `https://otlp.example.com`. Do **not** include the OTLP signal path (`/v1/traces`, `/v1/logs`); it is appended automatically for each enabled signal. Avoid query strings and fragments. +- **`grpc`** — either a bare `host:port` (include the port, for example `otlp.example.com:4317`) or an `https://host[:port]` URL (the port defaults to `443` when omitted). Do not include a path, query string, or fragment. + +Endpoints that resolve to a private or internal host (for example RFC 1918 ranges or loopback addresses) are rejected by default. + +| Protocol | Recommended | Avoid | +| --- | --- | --- | +| `http` | `https://otlp.example.com` | `https://otlp.example.com/v1/traces` (signal path), `http://otlp.example.com` (not TLS) | +| `grpc` | `otlp.example.com:4317`, `https://otlp.example.com` | `otlp.example.com` (no port), `https://otlp.example.com/path` (has path) | + +## Backend examples + +### New Relic + +New Relic ingests OTLP directly. Point the export at its OTLP endpoint and authenticate with a license key sent in the `api-key` header — see the [example above](#configuring-a-telemetry-export). Use the OTLP endpoint for your account's region (for example `https://otlp.nr-data.net` for US or `https://otlp.eu01.nr-data.net` for EU). + +### Honeycomb + +[Honeycomb](https://github.com/honeycombio) also ingests OTLP directly. Authenticate with an API key sent in the `x-honeycomb-team` header: + +```hcl {{ title: 'honeycomb_export.tf' }} +resource "tailor_telemetryrouter_telemetry_export" "honeycomb" { + workspace_id = tailor_workspace.example.id + + name = "honeycomb" + endpoint = "https://api.honeycomb.io" + protocol = "http" + + auth = { + api_key = { + header_name = "x-honeycomb-team" + secret_value = { + vault_name = tailor_secretmanager_vault.example.name + secret_name = "honeycomb-api-key" + } + } + } + + enable_traces = true + enable_logs = true +} +``` + +Use the endpoint for your account's region (for example `https://api.honeycomb.io` for US or `https://api.eu1.honeycomb.io` for EU). + +### Routing through an OpenTelemetry Collector (Datadog) + +Datadog provides a [direct OTLP intake endpoint](https://docs.datadoghq.com/opentelemetry/setup/otlp_ingest/), but it comes with constraints — trace intake is in preview and requires requesting access, and some behavior differs from the Agent/Collector path. For a full-featured setup, a common approach is to run your own [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) with the Datadog exporter: point your Tailor telemetry export at the collector and let it forward signals to Datadog. + +This collector pattern applies to any backend you'd rather reach through a collector — for processing, fan-out, or vendor-specific exporters — not just Datadog. + +```mermaid +flowchart LR + A[Tailor Platform
telemetry export] -->|OTLP| B[Your OpenTelemetry
Collector] + B -->|datadog exporter| C[Datadog] +``` + +#### 1. Configure your OpenTelemetry Collector + +Run an OpenTelemetry Collector that receives OTLP from Tailor and exports to Datadog. A minimal configuration: + +```yaml {{ title: 'otel-collector.yaml' }} +receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + +processors: + batch: {} + +exporters: + datadog: + api: + key: ${env:DD_API_KEY} + site: datadoghq.com + +service: + pipelines: + traces: + receivers: [otlp] + processors: [batch] + exporters: [datadog] + logs: + receivers: [otlp] + processors: [batch] + exporters: [datadog] +``` + +This collector must be reachable from Tailor over TLS at a publicly resolvable address. Terminate TLS in front of the collector (for example with a load balancer) and expose its OTLP gRPC endpoint. + +#### 2. Point the telemetry export at your collector + +Configure the export `endpoint` to your collector's OTLP endpoint rather than Datadog directly: + +```hcl {{ title: 'datadog_export.tf' }} +resource "tailor_telemetryrouter_telemetry_export" "datadog" { + workspace_id = tailor_workspace.example.id + + name = "datadog-collector" + endpoint = "otel-collector.example.com:4317" + protocol = "grpc" + + enable_traces = true + enable_logs = true +} +``` + +If your collector requires authentication, add an `auth` block as described in [Authentication](#authentication) so the credentials stay in Secret Manager. (The `headers` map can carry static, non-secret headers, but its values are persisted in Terraform state, so don't put credentials there.) Because the endpoint points at your own collector, make sure it is not a private or internal host — see [Endpoint format](#endpoint-format). + +## Configuring resource attributes + +The `tailor_telemetryrouter_resource_attributes_config` resource defines workspace-level resource attributes that are attached to every outgoing signal. It is a singleton: a workspace has at most one resource attributes configuration. + +```hcl {{ title: 'resource_attributes.tf' }} +resource "tailor_telemetryrouter_resource_attributes_config" "this" { + workspace_id = tailor_workspace.example.id + + service_name_prefix = "acme" + deployment_environment_name = "production" +} +``` + +`service_name_prefix` is prepended to each microservice's own `service.name` to form the final `service.name` attribute on outgoing signals (`-`), making platform signals easy to identify in your backend. `deployment_environment_name` follows the OpenTelemetry semantic convention `deployment.environment.name`. + +For the full list of arguments and their constraints, refer to the [Tailor Platform Provider documentation](https://registry.terraform.io/providers/tailor-platform/tailor/latest/docs/resources/telemetryrouter_resource_attributes_config). + +## Security considerations + +- Prefer the `auth` block for credentials: it references secrets in [Secret Manager](secretmanager.md), so the secret values themselves are never stored in the export configuration or in Terraform state. +- The `headers` map is marked sensitive (redacted from Terraform plan and diff output), but its values are still persisted in Terraform state. Use it only for non-secret, static headers — put credentials in the `auth` block instead. +- Use TLS-enabled (HTTPS) endpoints so credentials and signals are encrypted in transit. Endpoints that resolve to a private or internal host are rejected. + +## Best practices + +1. **Separate environments**: Use distinct exports (and Secret Manager vaults) per environment, and set `deployment_environment_name` accordingly. +2. **Enable only the signals you need**: Leave `enable_traces` / `enable_logs` off for destinations that should not receive a given signal. +3. **Use a consistent service name prefix**: Set `service_name_prefix` so platform signals are easy to identify in your backend. +4. **Rotate credentials**: Update the referenced secret values when rotating API keys or tokens. diff --git a/schema.yml b/schema.yml index dd37df7..a00faa3 100644 --- a/schema.yml +++ b/schema.yml @@ -16,6 +16,7 @@ links: - registry.terraform.io - en.wikipedia.org - vitest.dev + - docs.datadoghq.com - unicode.org - ibm.com - iana.org From c13e0f3389998e303ea39d3b8660a6c98e43a89f Mon Sep 17 00:00:00 2001 From: tkosushi Date: Thu, 11 Jun 2026 11:24:54 +0900 Subject: [PATCH 4/7] Fix guides nav order entry after observability->opentelemetry rename Co-Authored-By: Claude Opus 4.8 (1M context) --- .vitepress/config/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vitepress/config/constants.ts b/.vitepress/config/constants.ts index b58bcf9..e2dbd29 100644 --- a/.vitepress/config/constants.ts +++ b/.vitepress/config/constants.ts @@ -9,7 +9,7 @@ export const navItemOrder: Record = { "auth", "application", "events", - "observability", + "opentelemetry", ], tutorials: [ "app-endpoint", From 79d03af389df42f24cad4704b7f405646610a1ec Mon Sep 17 00:00:00 2001 From: tkosushi Date: Thu, 11 Jun 2026 12:11:59 +0900 Subject: [PATCH 5/7] Make backend region examples region-neutral Honeycomb and New Relic only offer US/EU data centers (no JP region), and the endpoint region reflects the backend account's region, not Tailor's. Drop the EU example and point to vendor docs for region-specific endpoints. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/guides/opentelemetry.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/opentelemetry.md b/docs/guides/opentelemetry.md index c9c0ea8..5be345c 100644 --- a/docs/guides/opentelemetry.md +++ b/docs/guides/opentelemetry.md @@ -128,7 +128,7 @@ Endpoints that resolve to a private or internal host (for example RFC 1918 range ### New Relic -New Relic ingests OTLP directly. Point the export at its OTLP endpoint and authenticate with a license key sent in the `api-key` header — see the [example above](#configuring-a-telemetry-export). Use the OTLP endpoint for your account's region (for example `https://otlp.nr-data.net` for US or `https://otlp.eu01.nr-data.net` for EU). +New Relic ingests OTLP directly. Point the export at its OTLP endpoint and authenticate with a license key sent in the `api-key` header — see the [example above](#configuring-a-telemetry-export). Use the OTLP endpoint that matches your New Relic account's region (for example `https://otlp.nr-data.net` for a US account); see New Relic's documentation for the endpoint of your region. ### Honeycomb @@ -157,7 +157,7 @@ resource "tailor_telemetryrouter_telemetry_export" "honeycomb" { } ``` -Use the endpoint for your account's region (for example `https://api.honeycomb.io` for US or `https://api.eu1.honeycomb.io` for EU). +Use the endpoint that matches your Honeycomb account's region (for example `https://api.honeycomb.io` for a US account); see Honeycomb's documentation for the endpoint of your region. ### Routing through an OpenTelemetry Collector (Datadog) From 032669c4e7ed51c04e355a25c5ee307f312c8bc9 Mon Sep 17 00:00:00 2001 From: tkosushi Date: Thu, 11 Jun 2026 12:16:31 +0900 Subject: [PATCH 6/7] Drop console-vs-export distinction sentence from intro Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/guides/opentelemetry.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/guides/opentelemetry.md b/docs/guides/opentelemetry.md index 5be345c..d7f352d 100644 --- a/docs/guides/opentelemetry.md +++ b/docs/guides/opentelemetry.md @@ -7,8 +7,6 @@ title: Observability / OpenTelemetry Tailor Platform automatically generates [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-specification) signals — **traces** and **logs** — for the services in your workspace. By configuring a **telemetry export**, you can forward those signals to the observability backend of your choice, such as New Relic, Honeycomb, Grafana, or Datadog, without changing any application code. -This is different from inspecting logs in the Tailor console: the [console](/getting-started/console/overview) lets you view pipeline execution logs inside the platform, while this guide is about **forwarding signals to an external backend** that you operate. - Common use cases include: - Sending request traces from your platform services to an existing distributed tracing backend From ff00ca592e1b4ffc0d7c14359cf8b5eee2234316 Mon Sep 17 00:00:00 2001 From: Anukiran Date: Thu, 11 Jun 2026 14:19:29 -0500 Subject: [PATCH 7/7] order guides sidebar items --- .vitepress/config/constants.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.vitepress/config/constants.ts b/.vitepress/config/constants.ts index e2dbd29..4299d4e 100644 --- a/.vitepress/config/constants.ts +++ b/.vitepress/config/constants.ts @@ -87,6 +87,18 @@ export const defaultSidebarOrder: string[] = ["overview", "quickstart"]; // Section-specific overrides (only if you need different ordering for a specific section) export const sidebarItemOrder: Record = { + guides: [ + "application", + "events", + "resolver", + "secretmanager", + "static-website-hosting", + "opentelemetry", + "tailordb", + "executor", + "function", + "auth", + ], "setup-auth": [ "overview", "setup-identity-provider",