---
title: Dispatch audit message
summary: Capture audit metadata, apply the caller's payload, and write the audit record through the active sink.
status: draft
owner: SAIF Documentation
last_reviewed: 2026-07-30
library: SAIF.Framework.Logging
reference_type: package
operation_id: LOG-OP-001
trigger: Caller invokes clsLogAudit.AuditMessage(...) or AuditCustomMessage(...)
---

# Dispatch audit message

This operation records a single audit event, but only once a hosting application has explicitly turned audit logging on. It gathers ambient context (who, where, and in what environment), merges in the caller's message or custom payload, and writes the resulting record to whichever sink is currently active — a local CSV file if one was opened, or the remote `wsLogging` SOAP service otherwise.

| Field | Value |
| --- | --- |
| **Operation ID** | LOG-OP-001 |
| **Trigger** | Caller invokes `clsLogAudit.AuditMessage(...)` or `clsLogAudit.AuditCustomMessage(...)`. |
| **Inputs** | Message text, optional state objects, and for the custom overload `performedTo`, optional `performedBy`, optional `performedAt`, optional `overrideApplicationName`. |
| **Outputs** | CSV append or `wsLogging.WriteAudit(...)` side effect; no return value. |
| **Primary components** | `clsLogAudit.AuditMessage`, `clsLogAudit.AuditCustomMessage`, `clsLogAudit.GetBasicAuditInfo`, `clsLogAudit.WriteMessage` |
| **Entry point** | `SAIF.Framework.Logging/clsLogAudit.vb` |

## Steps

1. Check `clsLogAudit.IsEnabled` first; while it is `False`, the operation returns immediately and performs no context capture or sink work ([BR-001](../business-rules.md#br-001-audit-logging-is-opt-in-and-disabled-by-default)).
2. Assemble a baseline `AuditInfoStruct` in `GetBasicAuditInfo()`.
   - Stamp `AuditDate = Now` and clear `DataText`.
   - For web hosts (`clsLogCommon.IsWeb` is `True`), read machine, application, page, and environment values from `HttpContext.Server` and `HttpContext.Request`, then construct `New clsSecurityPrincipal(clsSecurityPrincipal.Platform.Web)`.
   - For non-web hosts, read the executable and environment data from `Process.MainModule`, set `PageName = "WINFORMS"`, use `Environment.MachineName`, and construct `New clsSecurityPrincipal(clsSecurityPrincipal.Platform.Windows)`.
   - Copy `Secprinc.UserName` into `UserName` when the principal resolves one; otherwise leave it empty.
   - On failure: the helper swallows the exception and returns whatever fields it managed to populate ([BR-005](../business-rules.md#br-005-logging-failures-must-never-raise-exceptions-to-the-caller)).

   > **Origin**: The identity-capture in step 2 delegates to `clsSecurityPrincipal` and follows the same pattern documented in [Principal identity initialization](../../saif-framework-security/operations/principal-identity-initialization.md) (`SAIF.Framework.Security`).
3. Merge the caller's payload into the struct.
   - `AuditMessage(...)` copies `inMsg` into `MessageText` and serializes `inStateInfo` through `clsLogCommon.GetStateInfo(...)`, which writes primitive values directly and reflects object properties into name/type/value lines.
   - `AuditCustomMessage(...)` copies `performedTo` into `DataText`, then overrides the audit date, user name, or application name only where the caller supplied an explicit, non-default value.
   - `AuditCustomMessage(...)` then replaces the environment text with `AppGlobal.EnvironmentService.ToDevelopmentEnvironment(AppGlobal.EnvironmentService.GetApplicationEnvironment()).ToString()`.

   > **Origin**: The environment lookup in step 3.3 depends on `IEnvironmentService.GetApplicationEnvironment()` from `SAIF.Framework.Security.EnvironmentApi`, summarized in [Retrieve a configuration setting](../../saif-framework-security-environmentapi/operations/retrieve-configuration-setting.md) (`SAIF.Framework.Security.EnvironmentApi`).
4. Select the output sink in `WriteMessage(...)`.
   - If `m_OutFile Is Nothing`, continue to the SOAP branch below.
   - Otherwise append `AuditInfoStruct.ToCSVString()` to the open file writer and flush it.
5. In the SOAP branch, resolve `loggingServiceUrl`, construct `wsLogging.clsWSLogging`, copy the local struct into a `wsLogging.AuditInfoStruct`, call `WriteAudit(...)`, and dispose the proxy.
   - On failure: the SOAP branch catches and discards the exception, so the caller always regains control ([BR-005](../business-rules.md#br-005-logging-failures-must-never-raise-exceptions-to-the-caller)).

   > **Origin**: The `loggingServiceUrl` lookup in step 5 delegates to Environment API configuration retrieval, summarized in [Retrieve a configuration setting](../../saif-framework-security-environmentapi/operations/retrieve-configuration-setting.md) (`SAIF.Framework.Security.EnvironmentApi`).

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Audit request]) --> Enabled{IsEnabled?}
	Enabled -->|No| EndSkip([Return without logging])
	Enabled -->|Yes| Context[Build AuditInfoStruct]
	Context --> Payload[Apply message and state/custom overrides]
	Payload --> Sink{File sink active?}
	Sink -->|Yes| FileWrite[Append CSV row and flush]
	Sink -->|No| Resolve[Resolve loggingServiceUrl]
	Resolve --> SoapWrite[Call wsLogging.WriteAudit]
	FileWrite --> EndOk([Return to caller])
	SoapWrite --> EndOk
```

## Failure and edge-case behavior

- While `IsEnabled` is `False`, the operation exits before touching context or any sink, so disabled audit logging carries no performance cost beyond the flag check ([BR-001](../business-rules.md#br-001-audit-logging-is-opt-in-and-disabled-by-default)).
- Context capture and the SOAP dispatch both suppress exceptions, so a partially populated or entirely unsent audit record can be dropped silently rather than surfacing a failure to the caller ([BR-005](../business-rules.md#br-005-logging-failures-must-never-raise-exceptions-to-the-caller)).
- Once a file sink has been opened through `ToFile(...)`, this operation never falls back to the SOAP path for that call.

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

## Sources
- `SAIF.Framework.Logging/clsLogAudit.vb`
- `SAIF.Framework.Logging/clsLogCommon.vb`
- `SAIF.Framework.Logging/AuditInfoStruct.vb`
- `SAIF.Framework.Security/clsSecurityPrincipal.vb`
- `SAIF.Framework.Security/EnvironmentServices/EnvironmentExtensions.vb`
- `SAIF.Framework.Security.EnvironmentApi/Services.Common/EnvironmentServiceBase.cs`
- `SAIF.Framework.Security.EnvironmentApi/Services.Common/EnvironmentConfigKeys.cs`
