---
title: SAIF.Framework.Logging architecture
summary: Architectural responsibilities, boundaries, and interaction patterns.
status: draft
owner: <owner>
last_reviewed: 2026-07-23
library: SAIF.Framework.Logging
reference_type: package
---

# SAIF.Framework.Logging architecture

SAIF.Framework.Logging is a cross-cutting, application-agnostic logging utility library that provides audit, error, and (deprecated) trace logging concerns, each dispatching to either a local CSV file or a remote SOAP web service (`wsLogging`) depending on the hosting application type.

## Responsibilities
- Provide audit logging (`clsLogAudit`) for application/business-event messages, opt-in via `IsEnabled` (defaults `False`).
- Provide error logging (`clsLogError`), including exception detail capture, ViewState-noise suppression, and optional email notification of errors.
- Provide trace logging (`clsLogTrace`) for method-level tracing — functionally disabled (see [Design constraints](#design-constraints)).
- Provide a legacy login-event logger (`clsLoginLog.LogItem`) that writes monthly CSV files.
- Provide an MSMQ queue path-name helper (`clsLoggingQueues`) that formats a queue path string from configuration.
- Retain a deprecated, independently designed rolling-file logger (`LogList`/`LogList.LogItem`) for backward compatibility only.

## Component boundaries
- `clsLogAudit`, `clsLogError`, `clsLogTrace`: primary logging entry points, each following the same internal shape — a `GetBasic*Info()` context-gathering method, a value-type info struct (`AuditInfoStruct`/`ErrorInfoStruct`/`TraceInfoStruct`), and a `WriteMessage` dispatcher.
- `clsLogCommon`: `Public` shared helper class. Its web/non-web context detection (`IsWeb`), environment/application-name derivation, calling-method reflection, and related helper methods/properties are `Friend`-scoped (assembly-internal) and not part of the external public surface; its format-string constants (e.g. `STATEFMTSIMPLE`, `TOFILEFORMAT`) are `Public Const` and are part of the external public surface.
- `wsLogging.clsWSLogging` (generated SOAP client proxy, `Web References/wsLogging/Reference.vb`): remote sink boundary — marshals `AuditInfoStruct`/`ErrorInfoStruct`/`TraceInfoStruct` data to a legacy ASMX web service via `WriteAudit`/`WriteError`/`WriteTrace` operations.
- `clsLoginLog`: independent boundary — writes directly to a monthly CSV file; does not use the `wsLogging` sink or the `clsLogCommon` info-struct pattern.
- `clsLoggingQueues`: independent boundary — resolves an MSMQ path-name string from `ConfigurationManager.AppSettings`; does not open or write to a queue itself*.
- `LogList`/`LogList.LogItem`: independent, obsolete boundary — a separate rolling-file logger unrelated to the `clsLogXxx` dual-sink pattern.

## Interaction model
- Callers (hosting applications) invoke one of the public logging entry points (`clsLogAudit.AuditMessage`/`AuditCustomMessage`, `clsLogError.CreateError`/`CreateErrorWithEmail`, `clsLogTrace.MethodBegin`/`MethodEnd`/`MethodMessage`).
- Each entry point gathers ambient context (machine name, application name, page name, environment, username) via a `GetBasic*Info()` method, which constructs a `clsSecurityPrincipal` instance (from `SAIF.Framework.Security`) purely to read the current user's identity for inclusion in the log record.
- `clsLogCommon.IsWeb` determines whether context is sourced from `HttpContext.Server`/`Request` (web) or `Process`/`Environment` (non-web), governing which sink is permitted (see [Design constraints](#design-constraints)).
- The populated info struct is passed to `WriteMessage`, which dispatches to either:
  - a local file sink (`m_OutFile.WriteLine`, CSV format), if `ToFile()` was previously called; or
  - the remote SOAP sink (`wsLogging.clsWSLogging.WriteAudit`/`WriteError`/`WriteTrace`), by default — with the endpoint URL resolved via `AppGlobal.EnvironmentService.GetConfigSetting(EnvironmentConfigKeys.LoggingServiceUrl)`.
- `clsLogError.CreateErrorWithEmail` additionally constructs a `clsSAIFMessage` (from `SAIF.Framework.Mail`) and calls `SendMail(...)` to notify a recipient by email, in parallel with the file/SOAP write.
- All logging entry-point bodies (or their private write helpers) wrap execution in `Try...Catch` with empty/`'gobble gobble` catch blocks, so logging failures are silently swallowed and never propagate to the caller.

The following diagram shows high-level component interactions.

```mermaid
flowchart TD
	Caller[Hosting application] --> LogAudit[clsLogAudit]
	Caller --> LogError[clsLogError]
	Caller --> LogTrace["clsLogTrace<br>(obsolete, no-op sink)"]
	Caller --> LoginLog[clsLoginLog]
	Caller --> LoggingQueues[clsLoggingQueues]
	Caller --> LogListLegacy["LogList<br>(obsolete)"]

	LogAudit --> LogCommon[clsLogCommon]
	LogError --> LogCommon
	LogTrace --> LogCommon

	LogAudit --> SecurityPrincipal["clsSecurityPrincipal<br>(SAIF.Framework.Security)"]
	LogError --> SecurityPrincipal
	LogTrace --> SecurityPrincipal

	LogAudit --> EnvService["AppGlobal.EnvironmentService<br>(SAIF.Framework.Security.EnvironmentApi)"]
	LogError --> EnvService
	LogTrace --> EnvService

	LogAudit -->|IsWeb=False, ToFile called| FileSinkA["Local CSV file"]
	LogAudit -->|default| WsLogging["wsLogging.clsWSLogging<br>(SOAP/ASMX web service)"]
	LogError -->|IsWeb=False, ToFile called| FileSinkE["Local CSV file"]
	LogError -->|default| WsLogging
	LogTrace -.->|no-op, never writes| WsLogging

	LogError --> SaifMail["clsSAIFMessage<br>(SAIF.Framework.Mail)"]

	LoginLog --> FileSinkL["Monthly login CSV file"]
	LoggingQueues --> QueuePath["MSMQ path string<br>(no queue I/O in this library)"]
```

## Sequence diagram
The following diagram shows the primary error-logging request/response sequence, including the file/web-service sink branch.

```mermaid
sequenceDiagram
	participant Caller
	participant clsLogError
	participant clsSecurityPrincipal
	participant wsLogging as wsLogging.clsWSLogging
	Caller->>clsLogError: CreateError(exception, stateInfo)
	clsLogError->>clsSecurityPrincipal: read current user identity
	clsSecurityPrincipal-->>clsLogError: UserName / IsAuthenticated
	clsLogError->>clsLogError: SuppressLogging() check (ViewState noise)
	alt not suppressed and ToFile() previously called
		clsLogError->>clsLogError: WriteMessageToFile (local CSV)
	else default (web-service sink)
		clsLogError->>wsLogging: WriteError(ErrorInfoStruct)
		wsLogging-->>clsLogError: (fire-and-forget / swallowed failure)
	end
	clsLogError-->>Caller: (no exception propagated on failure)
```

## Design constraints
- **Dual-sink design**: every main logging class writes to exactly one of two sinks — a local CSV file (opened via `ToFile()`) or the remote `wsLogging` SOAP web service (default) — selected per-instance, not concurrently.
- **File logging is prohibited for web applications**: `clsLogCommon.IsWeb` (`Not System.Web.HttpContext.Current Is Nothing`) gates `ToFile()`; if `IsWeb` is `True`, `ToFile()` throws `ApplicationException("Logging to files not valid for web applications.")`. Web applications must use the `wsLogging` web-service sink. See [BR-003](business-rules.md#br-003-file-based-logging-is-prohibited-in-web-applications).
- **`clsLogTrace` is fully disabled and obsolete**: all public trace methods (`MethodBegin`, `MethodEnd`, `MethodMessage`) are decorated `<Obsolete("Log Trace No Longer Supported, Please remove")>`, and the private `WriteMessage` sink is a no-op (`'Removed Logic as tracing should not be used.`). The class still exposes `IsEnabled`/`UserTraceEnabled` gating logic and a private `WSWriteMessage` path, but no trace data ever reaches the file or web-service sinks regardless of flag state. See [BR-002](business-rules.md#br-002-trace-logging-is-opt-in-via-flag-or-command-line-switch-but-functionally-inert).
- **Best-effort logging**: all logging entry points swallow failures silently via empty/`'gobble gobble` `Try...Catch` blocks, so a failure to log (e.g., web service unreachable) never causes the calling application to fail. See [BR-005](business-rules.md#br-005-logging-failures-must-never-raise-exceptions-to-the-caller).
- **Tight coupling to sibling framework libraries**: logging classes directly construct `clsSecurityPrincipal` and reference `AppGlobal.EnvironmentService` rather than depending on abstractions, coupling this library to `SAIF.Framework.Security` and `SAIF.Framework.Security.EnvironmentApi` — architectural observation, inferred*.
- **Environment/application-name detection is convention-based**: `GetAppEnvironment`/`GetWebAppName` parse the physical file/module path (splitting on `:` and `\`) rather than reading explicit configuration, an inferred convention rather than a documented contract*.
- **`LogList` and `clsLoginLog` bypass the dual-sink pattern**: `LogList` is an independently designed rolling-file logger, and `clsLoginLog` writes directly to a monthly CSV file; neither uses the `clsLogCommon`/`wsLogging` pattern used by `clsLogAudit`/`clsLogError`/`clsLogTrace`.

> **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
- [Index](index.md)
- [Overview](overview.md)
- [Dependencies](dependencies.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [Configuration](configuration.md)
- [API reference](api/index.md)

## Sources
- `SAIF.Framework.Logging/clsLogAudit.vb`
- `SAIF.Framework.Logging/clsLogCommon.vb`
- `SAIF.Framework.Logging/clsLogError.vb`
- `SAIF.Framework.Logging/clsLoggingQueues.vb`
- `SAIF.Framework.Logging/clsLoginLog.vb`
- `SAIF.Framework.Logging/clsLogTrace.vb`
- `SAIF.Framework.Logging/LogList.vb`
- `SAIF.Framework.Logging/Web References/wsLogging/Reference.vb`
- `SAIF.Framework.Logging/SAIF.BOF.Framework.Logging.vbproj`
- `SAIF.Framework.Logging/app.config`
