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,Actionfor 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
IAuditServiceinterface andAuditLogEntryentity 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.