Files
scadalink-design/Component-AuditLogging.md
2026-03-16 07:39:26 -04:00

7.4 KiB

Component: Audit Logging

Purpose

The Audit Logging component records all configuration and administrative changes in the system with the resulting state after each change, providing a queryable trail of who changed what and when.

Location

Central cluster. All auditable actions occur through central (sites receive configurations but do not originate changes).

Responsibilities

  • Provide a service interface (IAuditService) for components to log changes after successful operations.
  • Serialize entity state as JSON and store audit entries in the configuration MS SQL database.
  • Write audit entries synchronously within the same database transaction as the change (via the unit-of-work).
  • Provide query capabilities for the Central UI audit log viewer.

Integration Pattern

Audit logging uses a direct service call pattern. Components call IAuditService after a successful operation:

IAuditService.LogAsync(user, action, entityType, entityId, entityName, afterState)
  • user: The authenticated AD user who performed the action (provided by Security & Auth).
  • action: The type of operation (create, update, delete, deploy, disable, enable).
  • entityType: What was changed (template, instance, alarm, shared script, etc.).
  • entityId: Unique identifier of the specific entity.
  • entityName: Human-readable name of the entity.
  • afterState: The entity's state after the change, serialized as JSON. Null for deletes.

The IAuditService interface is defined in Commons (alongside the other shared interfaces). The implementation is provided by the Audit Logging component and registered in the DI container.

Transactional Guarantee

Audit entries are written synchronously within the same database transaction as the change. Since all central components use the unit-of-work pattern (EF Core's DbContext), the audit entry is added to the same DbContext and committed in the same SaveChangesAsync() call. This guarantees:

  • If the change succeeds, the audit entry is always recorded.
  • If the change fails and rolls back, the audit entry is also rolled back.
  • No audit entries are lost due to process crashes between the change and the audit write.

Integration Example

Template Engine: Update Template
    │
    ├── repository.UpdateTemplate(template)
    ├── auditService.LogAsync(user, "update", "Template", template.Id, 
    │       template.Name, serialize(template))
    └── repository.SaveChangesAsync()  ← both the change and audit entry commit together

Audited Actions

Category Actions
Templates Create, edit, delete templates
Scripts Create, edit, delete template scripts and shared scripts
Alarms Create, edit, delete alarm definitions
Instances Create, override values, bind connections, area assignment, disable, enable, delete
Deployments Deploy to instance (who, what, which instance, success/failure)
System-Wide Artifact Deployments Deploy shared scripts / external system definitions / DB connections / notification lists to sites (who, what, result)
External Systems Create, edit, delete definitions
Database Connections Create, edit, delete definitions
Notification Lists Create, edit, delete lists and recipients
Inbound API API key create, enable/disable, delete. API method create, edit, delete
Areas Create, edit, delete area definitions
Sites & Data Connections Create, edit, delete sites. Define and assign data connections to sites
Security/Admin Role mapping changes, site permission changes

Audit Entry Schema

Each audit log entry contains:

Field Type Description
Id Long / GUID Unique identifier for the audit entry.
Timestamp DateTimeOffset When the action occurred (UTC).
User String Authenticated AD username who performed the action.
Action String (enum) The type of operation: Create, Update, Delete, Deploy, Disable, Enable.
EntityType String What was changed: Template, Instance, SharedScript, Alarm, ExternalSystem, DatabaseConnection, NotificationList, ApiKey, ApiMethod, Area, Site, DataConnection, LdapGroupMapping.
EntityId String Unique identifier of the specific entity.
EntityName String Human-readable name of the entity (for display without needing to deserialize state).
State JSON (nvarchar(max)) The entity's state after the change, serialized as JSON. Null for deletes.

State Serialization

  • Entity state is serialized as JSON using the standard .NET JSON serializer.
  • JSON is stored in an nvarchar(max) column in SQL Server.
  • The UI can render the JSON state for inspection. SQL Server's built-in JSON functions (JSON_VALUE, OPENJSON) can be used for ad-hoc queries against the state if needed.
  • For delete operations, the state is null (the entity no longer exists). The previous state can be found by querying the most recent prior audit entry for the same entity.

Granularity

  • One audit entry per save operation. When a user edits a template and changes multiple attributes in a single save, one audit entry is created containing the full template state after the save.
  • This captures the complete picture of what the entity looked like after each change without requiring per-field tracking.

Reconstructing Change History

Since only the "after" state is stored, a full change history for an entity can be reconstructed by querying all audit entries for that entity ordered by timestamp. Comparing consecutive entries (entry N-1's state vs. entry N's state) reveals what changed at each step. This is a query-time concern handled by the Central UI, not a write-time concern.


Storage

  • Stored in the configuration MS SQL database in a dedicated audit table, accessed via the IAuditLoggingRepository.
  • Entries are append-only — audit records are never modified or deleted.
  • No retention policy — audit logs are retained indefinitely.
  • Indexes on: Timestamp, User, EntityType, EntityId, Action for efficient filtering.

Query Capabilities

The Central UI audit log viewer can filter by:

  • User: Who made the change.
  • Entity type: What kind of entity was changed.
  • Action type: What kind of operation was performed.
  • Time range: When the change occurred.
  • Specific entity ID/name: Changes to a particular entity.

Results are returned in reverse chronological order (most recent first) with pagination support.


Dependencies

  • Configuration Database: Storage for audit entries via IAuditLoggingRepository. Audit entries participate in the same unit-of-work transaction as the changes they record.
  • Security & Auth: Provides the authenticated user identity for each entry.
  • Commons: Defines the IAuditService interface and AuditLogEntry entity class.

Interactions

  • All central components that modify state: Call IAuditService.LogAsync() after successful operations. This includes Template Engine, Deployment Manager, Security & Auth, Inbound API, External System Gateway, and Notification Service.
  • Central UI: Provides the audit log viewer for querying and displaying entries.
  • Configuration Database: Audit entries are committed in the same transaction as the changes they record.