---
title: Compose the trace and log message
summary: Build the newline-joined trace/log payload, redacting password-like content when debug logging is on.
status: draft
owner: andmil
last_reviewed: 2026-09-15
library: SAIF.Web.API
reference_type: package
operation_id: OP-05
trigger: OP-01 (Post-process an API response), steps 13, 14, 15.
---

# Compose the trace and log message

`ApiResponseHandler.BuildTraceMessage` (`private`) builds the newline-joined trace/log payload used by the trace call (emitted only when `ILogService` is resolved) and the error-logging calls.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-05 |
| **Trigger** | [Post-process an API response](op-01-post-process-an-api-response.md), steps 13, 14, 15. |
| **Inputs** | request/response context, `debugMode` flag |
| **Outputs** | newline-joined `string` |
| **Primary components** | `ApiResponseHandler.BuildTraceMessage` |
| **Entry point** | `src/SAIF.Web.API/ApiResponseHandler.cs` |

## Steps

1. Build the base message array: method + timestamp, request URI, `MessageID`, Splunk URL, elapsed ms, exception message, authenticated user ID (or literal `anonymous` when empty), client IP (or `anonymous`), response status ([BR-WEBAPI-009](../business-rules.md#br-webapi-009-trace-every-request-with-debug-gated-verbosity)).
2. Add the client-identity headers `Client-Name`, `Client-Is-Web`, `Client-User`, `Application-ID` via `TryGetFirstHeader` ([BR-WEBAPI-019](../business-rules.md#br-webapi-019-header-reads-never-throw)).
   - Missing headers render as empty strings, never throw.
   - This step delegates to a locally-implemented operation.

   > **Origin**: Step 2 is implemented in [Read the first value of a request header](op-10-read-the-first-value-of-a-request-header.md) (`SAIF.Web.API`) and executed on behalf of this operation.
3. If `debugMode` is false, join and return ([BR-WEBAPI-009](../business-rules.md#br-webapi-009-trace-every-request-with-debug-gated-verbosity)).
4. If `debugMode` is true: obtain the `HttpContextBase`, `Seek(0, Begin)` on `context.Request.InputStream`, copy it to a `MemoryStream`, and UTF-8 decode it ([BR-WEBAPI-009](../business-rules.md#br-webapi-009-trace-every-request-with-debug-gated-verbosity)).
   - **Risk:** `GetHttpContext(request)` is dereferenced without a null check here — a self-hosted or context-less request would raise `NullReferenceException`.*
5. Redact the decoded body with `Regex.Replace(inputStream, @"password[^,\n]*", @"""Password"": ""********""", IgnoreCase)` ([BR-WEBAPI-007](../business-rules.md#br-webapi-007-redact-password-material-from-debug-traces)).
   - Only the *input stream* copy is redacted — `Request Content` and `Response Content` (step 6) are **not** run through the redaction regex.
6. Append request content, redacted input stream, request headers, request content headers, response content, response headers, response content headers ([BR-WEBAPI-009](../business-rules.md#br-webapi-009-trace-every-request-with-debug-gated-verbosity)).
   - All null-conditional with `?? ""` fallbacks.
   - `SAIF.Common.Extensions.ToStringAll` is implemented in `SAIF.Framework.Core`; its internal steps could not be embedded — the package is not indexed for this run.**

## Process flow

```mermaid
flowchart TD
	Start(["Called from OP-01 steps<br>13-15"]) --> Base["Build base message<br>fields"]
	Base --> Headers["Add client-identity<br>headers via<br>TryGetFirstHeader"]
	Headers --> Debug{debugMode?}
	Debug -->|No| Join[Join and return]
	Debug -->|Yes| InputStream["Read and copy request<br>InputStream"]
	InputStream --> Redact["Redact password-like<br>content"]
	Redact --> Append["Append bodies, headers,<br>content headers"]
	Append --> Join
	Join --> End([Return trace message])
```

## Failure and edge-case behavior
- Debug-mode tracing on a context-less request (no ambient `HttpContextBase`) can raise `NullReferenceException` at step 4.*
- Request/response headers and bodies (including any `Authorization` header) are written to the trace un-redacted when debug logging is on — only the input-stream copy is redacted.

> **Note:** Statements marked with * were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with ** could not be confirmed; treat as unknown until verified.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

## Sources
- `src/SAIF.Web.API/ApiResponseHandler.cs`
