Troubleshooting & FAQ
Common Issues
Schema does not compile after upgrading to v10.0.1
Cause: The property Schema on HttpRequestLogTemplate was misspelled and has been renamed to Scheme (the correct HTTP term) in v10.0.1.
Fix: Rename all references from Schema to Scheme:
// ❌ v10.0.0
var requestLog = new HttpRequestLogTemplate
{
Schema = context.Request.Scheme,
};
// ✅ v10.0.1
var requestLog = new HttpRequestLogTemplate
{
Scheme = context.Request.Scheme,
};
Duration expects a formatted string, not a number
Cause: HttpResponseLogTemplate.Duration is a string?. An earlier 10.0.1 preview exposed it as double?, but that change was reverted before the 10.0.1 packages were published — the shipped property has always been string?. Code that assigns a double (e.g., duration.TotalMilliseconds) will not compile.
Fix: Assign a pre-formatted string. The built-in consumers format it as "{milliseconds} ms":
// ❌ Does not compile — Duration is string?
var responseLog = new HttpResponseLogTemplate
{
Duration = duration.TotalMilliseconds,
};
// ✅
var responseLog = new HttpResponseLogTemplate
{
Duration = $"{duration.TotalMilliseconds} ms",
};
RequestId / TraceIdentifier do not exist after upgrading to v10.0.2
Cause: These properties were removed from BaseHttpLogTemplate in v10.0.2. The built-in consumers (LoggingMiddleware in RA.Utilities.Api, RequestResponseLoggingHandler in RA.Utilities.Integrations) no longer populate them — request correlation is now carried by the logging scope instead of being duplicated on every template.
Fix: Remove references to the removed properties. For correlation, rely on scopes/enrichers: LoggingMiddleware enriches every entry it writes with an x-request-id scope value, and RA.Utilities.Logging.Core provides a RequestIdEnricher for Serilog. Custom consumers can wrap the call in their own scope:
using (_logger.BeginScope(new Dictionary<string, object> { [LoggingConstants.XRequestId] = requestId }))
{
// log templates written in this scope carry the correlation id
}
The constant LoggingConstants.XRequestId (value "x-request-id") remains available from RA.Utilities.Logging.Shared.Constants for consistent header name references.
Request and response logs show different RequestedOn timestamps
Cause: In v10.0.0, RequestedOn was a computed property (=> DateTime.UtcNow) that evaluated at serialization time, so request and response logs got different timestamps.
Fix: Upgrade to v10.0.1 where RequestedOn is a settable property that defaults to DateTime.UtcNow at construction time. If you need the exact request time, set it explicitly when creating the log template.
LoggingConstants type or namespace not found
Cause: The LoggingConstants class (in namespace RA.Utilities.Logging.Shared.Constants) was added in v10.0.1 and provides the canonical header name XRequestId. If your project isn't referencing it, you may get a compile error.
Fix: Add the using directive:
using RA.Utilities.Logging.Shared.Constants;
Known Limitations
- Multi-valued HTTP headers are flattened:
RequestHeadersandResponseHeadersuseIDictionary<string, string>, which collapses multi-valued headers (e.g.,Set-Cookie) into a singlestringvia.ToString(). The original array of values is not preserved. RequestBody/ResponseBodyisobject?: The body type is untyped, and the content type (e.g.,application/json,text/plain) is not captured on the log template. If you need the content type in your logs, capture it separately.ToString()may fail on cyclic object graphs:BaseHttpLogTemplate.ToString()callsJsonSerializer.Serialize(this)with default options. If a request or response body contains a cyclic reference, serialization will throw. Consider logging via Serilog's{@LogTemplate}destructuring instead, which handles cycles gracefully.- No built-in body truncation: Large request or response bodies are logged in their entirety. The built-in consumers buffer the full body into memory via
EnableBuffering()/ReadBodyAsync(). For high-throughput APIs with large payloads, consider implementing body size limits or sampling in your own middleware.
Performance Tips
- Use
ILogger.IsEnabled()guards: The built-inLoggingMiddlewarechecks_logger.IsEnabled(LogLevel.Information)before constructing log templates. Follow this pattern in custom consumers to avoid allocating log objects when the log level is disabled. - Prefer
{@LogTemplate}destructuring over.ToString(): Serilog's structured logging with{@RequestLog}captures the object graph natively without the intermediate JSON string allocation. LoggingConstants.XRequestIdis aconst: It is inlined at compile time with zero runtime cost. Use it instead of the magic string"x-request-id".