1. Start with operational questions, not fields
Observability for an AI application means being able to reconstruct its behavior from related signals: which request arrived, which stages ran, what failed, and how long each part took. For an application that already calls a model through an API, instrumentation does not mean copying every input and response into a log. It means collecting enough context to answer operational questions consistently, within a clearly defined scope and data policy.
Before choosing a library or building a dashboard, write down the questions the team needs to answer during an incident. For example: Which application and prompt versions handled this request? Was the model called once, or were there retries? Which tool ran, and how long did it take? Was the delay in the application, network, model, or a tool? What usage did the API report? These questions shape the design; fields that do not help answer them should not be added out of habit.
It is useful to distinguish observability from content evaluation. This article focuses on a request’s technical and operational path: failures, latency, retries, and reported usage. It does not propose a method for determining whether an answer is true, choosing a provider, or designing a conversational flow. Keeping that boundary clear helps keep logs small and prevents a technical signal from being presented as proof of quality.
Diagnostic questions and minimum signals
Use this table to justify each field or dashboard. If a signal does not support a specific decision or investigation, consider leaving it out.
| Question | Useful signals | Possible decision |
|---|---|---|
| What happened to a specific request? | Request ID, final status, stages, and timestamps | Investigate a specific request |
| Where is latency concentrated? | Total duration and duration by stage | Investigate the slow stage |
| Was there a retry? | Attempt number, reason, and outcome for each attempt | Fix retry limits, retry policy, or a dependency |
| What did the API report about usage? | Usage fields available in the response, preserved as reported data | Compare observed usage without confusing it with billing |
| Was sensitive information exposed? | Redaction or classification result, without retaining the sensitive value | Adjust filters and access controls |
2. Map the request lifecycle and define correlation
A request that looks like a single call from the interface may involve several operations: input validation, prompt construction, a model call, response processing, and possibly a tool call. If retries occur, each attempt should remain visible as a distinct operation. Logs should let you link these events without relying on identifiers that the external API does not guarantee.
Generate your own identifier for the request when it enters your application, then propagate it through the components you control. Add child identifiers or stage numbers to distinguish model and tool calls. If the provider returns a request identifier, store it as an additional field for later queries or support, but do not use it as the only link: it may not be available for every error or execution path.
Also define the timing boundary for each measurement. Total duration starts when the application accepts the request and ends when it delivers a response or records the final failure. A model call’s duration starts when that call begins and ends when a response or error is received. A tool call has its own start and end times. Recording milliseconds without defining these boundaries produces figures that cannot be compared reliably.
Minimum request flow
Apply this outline to a simple request and expand it only when the application actually has additional stages.
- 01Create a request_id at the application’s entry point and record the start time.
- 02Validate and prepare the request; associate a prompt version without automatically storing its contents.
- 03Record each model call as a stage with its attempt number, requested model, relevant configuration, and timings.
- 04If a tool is called, record its name, schema version if available, duration, status, and normalized result.
- 05Record the final response or terminal error, the closing time, and total duration.
3. Define a minimum schema and record what the API actually returns
A minimum schema should separate data generated by your application from fields received from the provider. Application-owned fields commonly include the request identifier, stage, attempt number, status, timestamps, and code and prompt versions. The requested model, configuration, and any identifier returned by the provider can help reconstruct an execution, but their origins should be labelled.
Usage reported by an API is not universal. It can vary by endpoint, model, modality, version, or response type; it may also be absent from errors or partial responses. The documentation available for this guide does not specify a particular provider, so it cannot establish a universal list of fields. Instead, implement an adapter for each API and consult its current primary documentation to check field names, units, and conditions. Store the result as “API-reported usage,” including which fields were present, and do not silently fill missing values with zeros.
Also keep application-measured time separate from any duration reported by the provider. The former measures the path through your system; the latter, if available, follows the provider’s definition. Make units explicit—for example, milliseconds for durations—and define whether timestamps are stored in UTC. Consistent conventions make it possible to compare requests and detect changes without mixing clocks or different intervals.
Initial per-request and per-stage schema
Provider usage fields vary. Keep only those offered in the documented API response for the configuration in use.
| Group | Recommended fields | Source |
|---|---|---|
| Correlation | Your own request_id; stage_id or stage number | Application |
| Versions | Application version; prompt version; requested model | Application and configuration |
| Timing | Start, end, and total duration; duration by stage; unit | Application |
| Status | Normalized final outcome; error category; attempt | Application |
| Provider | Request ID returned, if available; resolved model, if documented | API response |
| Usage | Usage fields documented by the API for that operation; indicator of missing fields | API response |
| Tools | Name, relevant version, status, and duration | Application |
4. Instrument structured events end to end
Structured logs are easier to filter and group than prose messages. Define stable names for events, statuses, and fields; avoid having every component use a different label for the same concept. You do not need a specific observability vendor to get started: you can emit JSON events from the application and send them to the platform the team already uses.
One useful pattern is to emit a start and end event for each stage, or a single end event containing start time, end time, and outcome when the stage is short and does not need real-time updates. For longer operations, the end event should retain its link to the original request. If you use distributed traces, propagate context across services and queues you control; verify that the identifier survives the transition from synchronous to asynchronous work.
The example below is schematic pseudocode, not a working integration with an API: response and error field names depend on the SDK and provider. In a real implementation, adapt usage and error extraction to current documentation, and make sure the exception handler does not automatically log bodies that may contain sensitive data.
Instrumentation sequence
Add telemetry where the application has the full context, and normalize each external response before emitting it to the logging system.
- 01Create the application-generated request identifier and associate the environment and application version.
- 02Open an event or span for each important operation; include the request ID and stage ID.
- 03Measure start, end, and duration using the same unit and a monotonic clock for intervals.
- 04Normalize statuses and error categories; keep the external code separate if it is available and permitted.
- 05Extract only usage fields documented for the specific operation; mark missing fields explicitly.
- 06Apply redaction before exporting events, then validate the result using synthetic data.
5. Minimize sensitive data before storing or exporting it
Observability does not require keeping full prompts, complete responses, or tool arguments for every request. This content may contain personal data, secrets, commercial information, or material that is unnecessary for operational questions. Start with metadata and derived signals: opaque identifiers, versions, lengths, error categories, statuses, and timings.
Decide for each field whether to exclude, redact, transform, or store it with restricted access and limited retention. To correlate with a business entity, a pseudonymous key or internal reference that only an authorized system can resolve may be sufficient. A hash does not guarantee anonymity if the original value is predictable or can be checked against a list; do not automatically treat it as a privacy solution.
Test redaction before enabling logging in production. Use synthetic examples covering typical cases and variations, such as an email address in an input, a token in a header, or confidential data in a tool response. Inspect both the event leaving the application and the event reaching the store: a rule applied only in the dashboard or after export leaves the data exposed in transit.
Minimization decisions by data type
Classification depends on the organization’s legal, contractual, and security context; this table is a design guide, not a legal determination.
| Data | Initial handling | Reason |
|---|---|---|
| Application-generated request identifier | Keep with controlled operational access | Needed to correlate events |
| Prompt or application version | Keep as a stable label | Enables comparison between executions |
| Full input or output text | Exclude by default; if essential, restrict access and retention | May contain sensitive information |
| Credentials and access tokens | Do not log; block or redact at the boundary | Exposure may enable unauthorized access |
| Customer identifier | Use a pseudonymous reference if it is sufficient for diagnosis | Reduces direct exposure |
| Normalized error code and status | Keep without the raw response body | Supports diagnosis with lower risk |
Test redaction before production
Add automated tests to the code that constructs or exports events.
- 01Prepare synthetic inputs and responses containing fictitious sensitive data.
- 02Run the instrumentation and capture the event immediately before export.
- 03Verify that prohibited fields are absent or redacted and do not appear in error messages.
- 04Repeat the test with exceptions, retries, and tool calls—not only with the final response.
- 05Review who can query the logs and set a retention period appropriate to the operational use.
6. Build dashboards and alerts for investigation, not for accumulating charts
A useful dashboard answers a question and makes clear what action might follow. Start with three views: request health, latency distribution, and reported usage. For health, show completed, failed, and unresolved requests by error category. For latency, show total duration and duration by stage, with percentiles as well as averages, because an average can conceal a long tail of slow requests. For usage, show only available fields and break them down by model, version, or request type when that helps reveal changes.
Alerts should represent a condition someone can investigate or fix. An error rate that exceeds the usual pattern over a defined interval may warrant an alert; an isolated failure can remain in the log without waking a team. Thresholds depend on volume and service expectations, so there is no need to set a universal value without data. Include the observation window, owner, and a link to the relevant query or response procedure.
Do not present a cost estimate based on reported usage as a billed amount. For an internal estimate, multiply the available units by the prices and rules that apply to the specific account and configuration, and label the result as an estimate. Actual amounts may depend on conditions that cannot be inferred from the response event alone; verify any reconciliation against the provider’s current official billing information and documentation.
Initial diagnostic dashboard
Add dimensions only when they help locate a cause without unnecessarily exposing personal information.
| View | Measures | Diagnostic use |
|---|---|---|
| Health | Total, completed, failed, and unresolved requests; error category | Detect changes in failure rate |
| Latency | Total and per-stage duration; median and percentiles | Locate slow stages and long tails |
| Retries | Attempts per request, reason, and outcome | Detect hidden failures or excess calls |
| Reported usage | Values present by API, model, and version | Observe changes in reported consumption |
| Telemetry quality | Events without IDs, events without closure, expected fields missing | Detect incomplete instrumentation |
7. Investigate a failed request reproducibly
When a report arrives, first pin down the request ID and confirm that it matches the right environment and time period. Gather the events in order by time and stage. Before interpreting the result, verify that the trace is complete: is there a start and end event? Are tool spans missing? Does the log record a terminal error or just a failed attempt? An incomplete execution can look like a model failure when the evidence simply was not captured.
Next, reconstruct the versions and sequence: application code, prompt version, requested model and any observable resolved model, number of attempts, tools, and statuses. Compare total duration with the sum of the stages, accounting for local work, queues, and time that was not instrumented. If the sum does not match, record that as a telemetry gap, not as proof of a cause.
Finally, separate facts from hypotheses. A provider timeout may be recorded as the outcome of an attempt; on its own, it does not explain why the timeout happened. A slow tool may account for part of the measured time, but not necessarily the final behavior. Record what is known, what is missing, and what check could distinguish between hypotheses. This discipline helps prevent claims about causes that the log does not establish.
Investigation procedure
Follow the same order for each incident to maintain a verifiable account.
- 01Find the application-generated request_id and confirm the environment, date, and application version.
- 02Order events by start time and stage; check for gaps or missing end events.
- 03Reconstruct the prompt, model, configuration, attempts, and tools from recorded versions and identifiers.
- 04Compare total duration with stage durations and locate any unexplained time.
- 05Review statuses, error categories, and available usage fields, distinguishing a missing value from zero.
- 06Separate observed facts from hypotheses; perform an additional check before declaring a cause.
- 07Document any missing field or event and add a test to confirm that instrumentation covers that case.
8. Verify the instrumentation and expand in stages
Instrumentation also needs testing: an application may work while dropping IDs, omitting end events, or logging data that should have been redacted. Run controlled tests for success, error, timeout, retry, and tool calls. For each case, verify the complete sequence from the incoming event to the final outcome, along with permissions and redaction before export.
Start with a limited production path and check that queries answer real questions. Review how much volume the logs generate and whether the team can find a request without manually searching several systems. Adjust event selection and retention before expanding. The goal is not to maximize telemetry, but to maintain enough searchable evidence to operate the system.
Telemetry conventions and API usage fields can change. Version your internal schema and validate the adapters when the SDK, API, or configuration changes. If the provider changes a response, the normalization layer should be adaptable without making every dashboard and query depend on external field names. General observability practices can guide the organization of signals and traces; they do not replace primary technical documentation for a specific provider’s fields or billing.
Acceptance checklist
Do not consider instrumentation complete until you have checked events and privacy using controlled test cases.
| Case | Check | Expected result |
|---|---|---|
| Success | Request and stages are correlated | The request’s path can be reconstructed using one application-generated ID |
| API error | Status, category, and closure are present | A failure is not confused with a missing event |
| Retry | Each attempt is separate and ordered | The failed attempt remains visible after a later success |
| Tool | Name, duration, and status are recorded | The stage can be distinguished from the model call |
| Usage absent | A field is not returned by the API | It is marked as not reported, not as zero |
| Synthetic sensitive data | Event is inspected before export | The value does not appear in the exported log |
Open questions
- No specific provider or API is identified, so it is not possible to state which usage or error fields it returns, or when they may be missing.
- The general guide does not establish prices, account conditions, or final charges. Any estimate requires checking current official documentation and billing information for the applicable provider and period.
- Retention periods, access controls, and data handling must be determined in the context of each organization’s legal, contractual, and security requirements.
Keep exploring
Sources consulted
Corrections and transparency
If you spot incorrect or outdated information, send us a correction with the page and source we should review.
Submit a correction