Back to all articlesSystem Integration

The Trace Is Data: Privacy-Preserving Observability for AI Agents

A production blueprint for tracing AI agents without turning prompts, tools, memory, and handoffs into a second data leak.

Mapki

Mapki

Oct 20, 2026•15 min read
Share:
The Trace Is Data: Privacy-Preserving Observability for AI Agents

The Trace Is Data: Privacy-Preserving Observability for AI Agents

An AI agent trace can contain far more sensitive information than the final answer. Prompts may include customer records. Tool arguments may contain account identifiers. Retrieval results can carry internal documents. Inter-agent messages can copy an entire case file from one worker to another. Shared memory and debug logs can preserve those values long after the workflow ends.

That makes observability a security and privacy boundary, not just a debugging feature.

OpenTelemetry’s GenAI conventions make agent behavior easier to inspect: model calls, token counts, durations, tool invocations, and, when explicitly enabled, prompt and completion content. The important detail is that content capture is opt-in because prompts, system instructions, tool schemas, arguments, and results may contain sensitive data. 1

A production design should therefore make this the default:

Capture enough metadata to explain behavior. Capture content only under an explicit, bounded policy. Redact before export whenever possible.

This article presents a practical design for tracing AI agents without creating a second uncontrolled copy of the data they process.

Why ordinary traces become a second data store

Traditional service telemetry usually records a route, status code, duration, and error. Agent telemetry is different because the payload often is the behavior being debugged. Teams want to know what the model saw, which tool it selected, what retrieval returned, and why a retry or handoff happened.

Those are legitimate engineering questions, but recording the raw answer can copy the original sensitive data into a new system with a different access model and retention schedule. A trace backend may be accessible to developers who are not authorized to view the customer record that caused the trace. A support engineer may see a tool argument containing a payment reference. A vendor-hosted observability service may retain a prompt in a region that the application itself is not allowed to use.

OpenTelemetry explicitly places the responsibility on the implementer. It cannot determine which values are sensitive in a particular organization, and it recommends data minimization, consent, protection, and review of instrumentation libraries. 2

Mapki micro-card — telemetry classification

  • Metadata: Model ID, operation, duration, token counts, status, retry count, policy ID.
  • Content: Prompts, completions, system instructions, retrieved passages, tool arguments, tool results.
  • Identifiers: User IDs, tenant IDs, run IDs, trace IDs, account references.
  • Secrets: API keys, session tokens, passwords, private keys, authorization headers.
  • Derived data: Classifications, embeddings metadata, evaluator labels, risk scores, summaries.
  • Default rule: Metadata is observable by default; content needs an explicit purpose and policy.

Audit every channel, not just the final answer

A final-output audit can report that an agent returned a clean appointment confirmation while missing that an internal handoff sent the patient’s full medical history to another worker.

The AgentLeak benchmark studied this exact class of failure across multi-agent systems. In its benchmark of 1,000 scenarios and 4,979 execution traces, inter-agent messages showed a 68.8% leakage rate and shared memory 46.7%, while final-output leakage was 27.2%. The paper reports that output-only audits missed 41.7% of violations. These are benchmark-specific measurements, not universal production rates, but they demonstrate the architectural blind spot. 3

Your telemetry policy should inspect at least these surfaces:

  1. User and model messages: Input prompts, system instructions, completions, and streamed tokens.
  2. Tool boundaries: Tool names, arguments, results, HTTP bodies, SQL parameters, and error payloads.
  3. Retrieval: Query text, document IDs, snippets, metadata, and reranking features.
  4. Coordination: Handoffs, planner messages, worker messages, and supervisor summaries.
  5. Memory: Writes, reads, summaries, embeddings metadata, and expiration events.
  6. Artifacts: Generated files, URLs, patches, screenshots, and exported reports.
  7. Operational logs: Exceptions, retries, serialized request bodies, and debug dumps.

A trace ID connects these events. It must not become permission to read all of them. Access to content-bearing spans should be narrower than access to aggregate metrics.

Start with metadata-only instrumentation

The safest capture policy is to create a useful trace without storing the payload. The following event shape is enough to answer many operational questions:

{
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"operation": "execute_tool",
"tool_name": "customer.lookup",
"tool_operation": "profile.read",
"model": "agent-router-v3",
"duration_ms": 842,
"input_tokens": 912,
"output_tokens": 126,
"status": "ok",
"retry_count": 0,
"tenant_hash": "hmac:v1:8e1c...",
"policy_id": "telemetry-default-v4",
"content_captured": false,
"redaction_policy": "not_applicable"
}
  • Notice what is absent: the customer name, the lookup argument, the returned profile, and the prompt that caused the tool call. The event still supports latency analysis, cost attribution, tool-failure analysis, routing comparisons, and policy audits.

OpenTelemetry’s current GenAI guidance describes attributes for model identity, input and output token usage, finish reasons, and agent span trees. It also shows that enabling content capture adds full messages, system prompts, tool schemas, arguments, and results. 1 Keep that switch behind an environment-specific policy rather than enabling it globally for convenience.

from dataclasses import dataclass


@dataclass(frozen=True)
class TelemetryPolicy:
capture_content: bool = False
capture_tool_arguments: bool = False
capture_retrieval_text: bool = False
max_content_bytes: int = 0


DEFAULT_POLICY = TelemetryPolicy()


def record_agent_step(span, *, operation, model, input_tokens,
output_tokens, duration_ms, status,
policy=DEFAULT_POLICY):
span.set_attribute("gen_ai.operation.name", operation)
span.set_attribute("gen_ai.request.model", model)
span.set_attribute("gen_ai.usage.input_tokens", input_tokens)
span.set_attribute("gen_ai.usage.output_tokens", output_tokens)
span.set_attribute("agent.status", status)
span.set_attribute("telemetry.policy_id", "telemetry-default-v4")
span.set_attribute("telemetry.content_captured", policy.capture_content)
span.set_attribute("telemetry.duration_ms", duration_ms)

# Never attach content merely because the SDK exposes it.
if policy.capture_content and policy.max_content_bytes > 0:
raise RuntimeError(
"Content capture requires a separately approved policy"
)

The last check is intentionally conservative. A production implementation would accept an approved policy object containing purpose, actor, data class, retention, and reviewer information. A boolean environment variable is too easy to enable accidentally.

Redact before serialization when possible

  • There are two places to redact: inside the application before telemetry is serialized, and in the Collector before telemetry leaves the trust boundary. The first is stronger because the sensitive value never enters an export buffer. The second provides centralized defense in depth for libraries and services that emit unexpected attributes.

A practical application pipeline is:

agent event
-> classify field and purpose
-> omit content when metadata is sufficient
-> redact secrets and direct identifiers
-> replace approved identifiers with keyed pseudonyms
-> attach policy ID and redaction outcome
-> serialize OTLP payload
-> export to local Collector

Do not use a single regular expression as the complete solution. Use several controls:

  • Structural omission: Do not create content attributes unless the policy requires them.
  • Key-based blocking: Remove attributes named like authorization, token, api_key, or private_key.
  • Pattern detection: Scan allowed text for emails, card numbers, credentials, and known secret formats.
  • Typed replacement: Replace an email with [REDACTED_EMAIL], not a generic string that destroys debugging context.
  • Keyed correlation: Use HMAC for stable correlation of a tenant or user without exporting the raw identifier.
  • Length limits: Truncate unusually large tool results and retrieval snippets.
  • Drop rules: Drop entire content-bearing spans when classification or redaction fails closed.

The OpenTelemetry Collector redaction processor supports allowlisted keys, blocked key patterns, blocked values, allowed values, URL sanitization, and HMAC-SHA256 or HMAC-SHA512. Its documentation lists traces as beta and logs and metrics as alpha, so pin the Collector distribution and test behavior during upgrades. 4

Use a fail-closed Collector boundary

A local Collector can receive OTLP from the agent runtime, apply policy, and forward only sanitized telemetry to the backend. The allowlist is more important than the regex list: unknown attributes should disappear by default.

receivers:
otlp:
protocols:
grpc:
http:

processors:
memory_limiter:
check_interval: 1s
limit_mib: 512

redaction/agent:
allow_all_keys: false
allowed_keys:
- service.name
- deployment.environment
- gen_ai.operation.name
- gen_ai.request.model
- gen_ai.response.finish_reasons
- gen_ai.usage.input_tokens
- gen_ai.usage.output_tokens
- http.request.method
- http.response.status_code
- agent.tool.name
- agent.tool.operation
- agent.status
- agent.retry_count
- agent.policy_id
- telemetry.content_captured
- telemetry.redaction_policy
- telemetry.tenant_hash
- trace_id
- span_id
blocked_key_patterns:
- ".*authorization.*"
- ".*cookie.*"
- ".*token.*"
- ".*api[_-]?key.*"
- ".*password.*"
- ".*private[_-]?key.*"
blocked_values:
- "(?:sk|pk)-[A-Za-z0-9_-]{20,}"
- "Bearer\\s+[A-Za-z0-9._-]+"
- "[0-9]{13,19}"
redact_all_types: true
hash_function: hmac-sha256
hmac_key: ${env:TELEMETRY_REDACTION_SECRET}
summary: silent

transform/limits:
error_mode: ignore
trace_statements:
- delete_key(attributes, "gen_ai.input.messages")
- delete_key(attributes, "gen_ai.output.messages")
- delete_key(attributes, "gen_ai.system_instructions")
- delete_key(attributes, "gen_ai.tool.call.arguments")
- delete_key(attributes, "gen_ai.tool.call.result")

batch:
timeout: 2s
send_batch_size: 512

exporters:
otlphttp/backend:
endpoint: https://telemetry.example.com/v1/traces
headers:
x-telemetry-policy: "telemetry-default-v4"

service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, redaction/agent, transform/limits, batch]
exporters: [otlphttp/backend]

Treat this as a starting point, not a copy-paste compliance package. The exact attribute paths depend on the SDK and convention version. Validate the generated OTLP payload in CI and run canary tests against the deployed Collector.

The Collector documentation describes filtering, attribute modification, and OTTL transformations as useful controls for quality, governance, cost, and security. 5 Keep the Collector inside the organization’s trust boundary when the backend is external.

Prefer HMAC to ordinary hashes for correlation

Teams often hash an email or user ID so traces can be grouped without revealing the original value. Ordinary hashes are not enough when the input space is small. An attacker can hash a dictionary of common emails or numeric IDs and compare the result. OpenTelemetry warns that hashes may be reversible in practice for predictable values. 2

Use a keyed HMAC with a secret that is not stored alongside telemetry:

import hmac
import hashlib


def pseudonymize(value: str, secret: bytes, version: str = "v1") -> str:
digest = hmac.new(
secret,
value.strip().encode("utf-8"),
hashlib.sha256,
).hexdigest()
return f"hmac:{version}:{digest[:32]}"


# The secret lives in a secret manager or workload identity boundary.
# It must never be sent as a telemetry attribute.

Rotate the HMAC key deliberately. A new key breaks longitudinal correlation, so include a version in the pseudonym and keep old keys only as long as the retention and incident-response policy allows. Never use a user-controlled value as the HMAC secret.

Separate debug capture from production capture

Some incidents require seeing content. The answer is not to enable raw prompts in every production trace. Create a separate, time-bounded debug path:

1. An operator opens an incident and records a purpose and ticket ID.

  1. A policy service grants content capture for a specific tenant, service, environment, or sampled run.

3. The agent emits a policy ID and capture reason into the trace metadata.

  1. Sensitive content is redacted before export unless a second approval explicitly permits a field.
  2. The debug store has shorter retention, narrower access, and stronger audit logging.

6. A scheduled deletion job removes the content when the incident window ends.

7. The policy automatically expires even if the operator forgets to revoke it.

This design keeps the normal backend useful for fleet-wide analysis while reserving raw content for a controlled investigation. It also prevents a developer from changing a deployment flag and silently expanding the retention of every customer prompt.

Mapki micro-card — content-capture contract

  • Purpose: What engineering question requires the content?
  • Scope: Which service, tenant, run, or span is included?
  • Approver: Who authorized the capture?
  • Fields: Which exact content fields are needed?
  • Retention: When is the content deleted?
  • Access: Which roles can view it, and where is access audited?
  • Expiry: What automatic control turns capture off?

Evaluate privacy as a system property

Redaction quality should be measured like latency and task success. A detector that catches emails but misses credentials inside JSON is not a sufficient policy. A final answer that contains no PII does not prove that the planner, worker, memory store, or trace exporter was safe.

Build a privacy test fixture with synthetic canaries:

{
"canaries": {
"email": "[email protected]",
"phone": "+1-202-555-0147",
"account_id": "acct_canary_417",
"api_key": "sk-canary-DO-NOT-USE-417",
"medical_code": "CANARY-DX-417"
},
"allowed_channels": [
"local_test_assertion"
],
"forbidden_sinks": [
"otlp.backend",
"agent.handoff",
"shared.memory",
"debug.log",
"tool.result"
]
}

Run the fixture through a representative workflow and assert that no forbidden sink contains the canary. Test every route separately:

  • Direct model prompt and completion.
  • Planner-to-worker handoff.
  • Worker-to-supervisor summary.
  • Tool arguments and tool results.
  • Retrieval snippets and memory writes.
  • Exception messages and retry payloads.
  • Trace attributes, span events, logs, and artifacts.

The LLM-Redactor research evaluates eight privacy techniques and reports that no single technique dominates. Its practical options include local-only inference, placeholder redaction and restoration, semantic rephrasing, and privacy noise. The authors evaluate combinations across 1,300 samples and explicitly discuss detector and synthetic-workload limitations. 6 The engineering lesson is to choose controls from a threat model rather than expect one scanner to solve every data path.

Connect privacy events to agent semantics

Observability becomes more useful when the trace explains the agent operation without storing the underlying content. OpenLLMetry instruments providers, vector databases, frameworks, and MCP while emitting standard OpenTelemetry data. 7 A newer Agent Telemetry Semantic Conventions draft proposes spans for agent turns, tools, retrieval, memory, handoffs, guardrails, human review, and evaluations. It also makes an important admission: the telemetry generator remains responsible for PII and sensitive-data scrubbing. 8

Record the decision around sensitive content, not the content itself:

type PrivacyEvent = {
traceId: string;
spanId: string;
channel: "prompt" | "tool_args" | "tool_result" | "handoff" | "memory";
classification: "public" | "internal" | "confidential" | "restricted";
action: "omitted" | "redacted" | "pseudonymized" | "captured" | "dropped";
policyId: string;
detectorVersion?: string;
bytesRemoved?: number;
};

function recordPrivacyDecision(event: PrivacyEvent): void {
if (event.action === "captured" && event.classification === "restricted") {
throw new Error("restricted content requires an approved debug policy");
}

// Emit only the decision metadata. Never attach the original value.
telemetry.emit("agent.privacy.decision", event);
}

A trace should let an engineer answer, “Which policy removed this field?” without allowing the same engineer to reconstruct the field from the event.

Retention and deletion are part of tracing

Redaction prevents many leaks, but it does not solve retention. Telemetry systems still need:

  1. Separate retention classes for metrics, metadata traces, and content-bearing debug traces.
  2. Tenant-aware deletion keyed by a controlled pseudonym or legal subject reference.
  3. Encryption in transit and at rest, with access logs for sensitive trace views.
  4. Region and processor controls that match the application’s data-residency requirements.
  5. Backups and indexes included in deletion design, not treated as invisible copies.
  6. A documented policy for embeddings, summaries, evaluator outputs, and derived attributes.

7. A migration test whenever instrumentation or Collector versions change.

A governance-oriented OTel platform such as the Traccia research prototype demonstrates one possible architecture: runtime instrumentation, W3C trace propagation, risk-tier metadata, guardrail spans, and PII redaction before export. 9 The implementation is not a standard, but the separation between runtime evidence and governance policy is useful.

VictoriaMetrics’ Telemetry Talks discussion similarly frames AI-agent observability as a balance between privacy and security while covering prompts, token usage, reasoning chains, and distributed traces.

title="Telemetry Talks ep. 5 - OpenTelemetry in the AI agents era">10

A production rollout sequence

  1. Inventory data paths. List every model call, tool, handoff, memory store, artifact, logger, and telemetry exporter.
  2. Disable raw content by default. Remove prompt and result capture from production instrumentation until a purpose exists.
  3. Define the metadata contract. Standardize model, operation, duration, tokens, status, tool, policy, and correlation fields.
  4. Add in-process redaction. Omit content structurally and sanitize values before serialization.
  5. Deploy a local Collector. Use an allowlist, blocked-key patterns, HMAC pseudonyms, and fail-closed routing.
  6. Split debug storage. Give approved content capture a separate backend, retention class, access policy, and automatic expiry.
  7. Test internal channels. Inject synthetic canaries into handoffs, memory, tool calls, logs, and artifacts.
  8. Measure utility loss. Track task success, debugging time, redaction recall, false positives, latency, and storage cost.
  9. Version everything. Pin semantic-convention, SDK, detector, and redaction-policy versions in deployment metadata.
  10. Drill deletion and revocation. Prove that access expires and content disappears from primary stores, indexes, and backups according to policy.

The goal is not to make agents unobservable. It is to make observability proportional to the question being asked. Metadata can explain that a worker timed out, a router selected a model, or a tool was denied. Raw content should be an exceptional, governed capability—not the default shape of every trace.

When the trace is treated as data, the architecture becomes straightforward: minimize what is collected, sanitize before export, isolate content-bearing investigations, test every communication channel, and preserve only the evidence needed to improve the system.

References & Community Insights

Production checklist

  • Production traces work with content capture disabled.
  • Prompts, completions, tool arguments, tool results, retrieval text, handoffs, and memory are classified separately.
  • In-process redaction runs before telemetry serialization.
  • The Collector uses a fail-closed allowed-key policy.
  • Secrets and authorization material are blocked by key and value patterns.
  • Low-entropy identifiers use keyed HMAC pseudonyms, not ordinary hashes.
  • Debug capture requires an expiring purpose-bound approval.
  • Inter-agent messages and shared memory are included in privacy tests.
  • Detector, SDK, Collector, and semantic-convention versions are recorded.
  • Retention, deletion, access logging, residency, and backup behavior are tested.

Want to implement this in your business?

Mapki designs bespoke AI agents, custom workflow automations, and tool-agnostic integrations tailored specifically to your existing ERP, CRM, and databases.

Tags:AI Agent SecurityObservabilityOpenTelemetryData PrivacyMCP

Continue Reading

View all
Content Creation & Automation

The Floor Cadence: A Sustainable Publishing Rhythm for Small Studios

Set a content floor you can defend for 90 days. Batch, buffer, and protect deep work instead of chasing daily posting.

5 min read
Content Creation & Automation

The Content Brief as a Decision Document: Seven Fields That Stop Rewrite Cycles

Seven concrete fields turn a content brief into a decision document. Fill them in 12 minutes and the first draft arrives closer to done.

7 min read
System Integration

The Credential Broker Is the Boundary: Just-in-Time Identity for AI Agents

A production blueprint for attested workload identity, OAuth token exchange, scoped credentials, and MCP enforcement for tool-using AI agents.

14 min read