Process Logs
Process Logs automatically record every state change on a process instance, capturing the source and destination activity, timestamp, actor identity, and trigger for each transition. The history is stored in the same persistence provider as process instances and is queryable through GetProcessHistoryAsync. Each ProcessHistoryItem entry includes the transition duration, classifier, and executor identity - providing a complete audit trail for compliance without custom logging code. A separate runtime log via IProcessLogProvider captures operational events and exceptions during execution.
Compliance regulations such as HIPAA, SOX, and GDPR require a record of who moved a process from one state to another and when. Without built-in logging, every workflow system needs custom code to capture audit data - and auditors need to trust that the data is complete.
Workflow Engine records every state change on a process instance automatically, creating a permanent audit trail of every transition, timer firing, and command execution. Each entry captures the source and destination activity, the timestamp, the actor identity, and the trigger that caused the change.
With Process Logs, you get a complete, queryable history of every process instance from start to completion - with no custom logging code. For example, after a purchase order is approved, the log shows who approved it, when, from which activity, and whether a timer or user command triggered the transition.
What it is
Every time a process instance changes activity - through a command, a timer firing, setting state directly, or any other mechanism that triggers a transition - the runtime writes a history record to the persistence provider. Think of it as a black box for each process instance: every state change is recorded automatically, and the sequence of entries reconstructs the exact path the instance followed through the scheme.
The history is stored separately from the active instance state. You can query the log for a completed instance, a running instance, or even an instance that has been deleted from the active store - as long as the history table still has the data.
For developers: The ProcessHistoryItem class captures each transition. Query it with GetProcessHistoryAsync(processId, paging) on WorkflowRuntime, which returns a List<ProcessHistoryItem> ordered by timestamp.
// Get the full history for a process instanceList<ProcessHistoryItem> history = await runtime .GetProcessHistoryAsync(processId);foreach (var entry in history){ Console.WriteLine( $"[{entry.TransitionTime:u}] {entry.FromActivityName} " + $"-> {entry.ToActivityName} by {entry.ActorIdentityId}");}What each log entry contains
ProcessHistoryItem captures the following data for every state change:
| Field | Description |
|---|---|
ProcessId | The process instance ID |
FromActivityName | The source activity name before the transition |
FromStateName | The source state name (if set on the activity) |
ToActivityName | The destination activity name after the transition |
ToStateName | The destination state name (if set on the activity) |
TransitionTime | UTC timestamp when the transition executed |
StartTransitionTime | UTC timestamp when the transition started executing |
TransitionDuration | Duration of the transition execution in milliseconds |
TransitionClassifier | Classifier of the transition direction (direct, or other) |
TriggerName | The command or timer name that triggered the transition |
ActorIdentityId | The user ID on whose behalf the command was executed |
ExecutorIdentityId | The user ID who executed the command |
ActorName | The user name on whose behalf the command was executed |
ExecutorName | The user name who executed the command |
IsFinalised | Whether this transition finalized the process |
Separate runtime logging
In addition to the transition history, Workflow Engine has a separate runtime log system via IProcessLogProvider. This captures runtime-level events - messages, errors, exceptions - as ProcessLogEntry objects. The default implementation is MemoryProcessLogger(100, 100), which keeps the last 100 entries per process for up to 100 processes in memory.
// Configure a custom process log providerruntime.WithProcessLogger(new MyDatabaseProcessLogger());The runtime log is distinct from the transition history. Transition history records state changes; the process log records operational events, exceptions, and debugging information during execution.
Paging support
For instances with many transitions, use the Paging parameter with GetProcessHistoryAsync to paginate results:
var firstPage = await runtime.GetProcessHistoryAsync( processId, new Paging(1, 50));var totalCount = await runtime.GetProcessHistoryCountAsync(processId);Why it matters
Process Logs deliver these outcomes:
Audit-ready compliance - Every state change is recorded by default. The
ProcessHistoryItemcontains actor identity, timestamp, and the transition taken - exactly what compliance frameworks require. No custom logging code needed.Faster debugging - When a process takes an unexpected path, the log shows every transition the instance followed, the timestamps, and the actor that triggered each step. This is faster and more reliable than reproducing the sequence by re-running the process.
Complete path reconstruction - The sequence of log entries, from the initial activity through every transition to completion (or current activity), reconstructs the exact path the instance took through the scheme.
Separate operational logging - The runtime log via
IProcessLogProvidercaptures exceptions, errors, and debug messages during execution, separate from the transition history. You can query recent logs, filter by time, or paginate results.
Who it is for
Evaluator (CEO, CTO, PM): Built-in process logs satisfy audit requirements without custom development. The transition history is automatically recorded, queryable, and contains the actor identity and timestamp data that compliance audits require.
Developer: Query ProcessHistoryItem records with GetProcessHistoryAsync on WorkflowRuntime. For runtime operational logging, configure an IProcessLogProvider with WithProcessLogger() and use ProcessLogger.ReadAllAsync, ReadLastAsync, or ReadEarlyAsync to query entries.
Enterprise architect: History records are stored in the same persistence provider as process instances, so they respect the same isolation and backup policies. The Paging parameter on GetProcessHistoryAsync supports large-scale queries without loading the full history into memory.
When to use it
Process logs are valuable in any workflow that needs an audit trail or debugging capability:
Compliance-required audit trails - Regulated workflows (healthcare approvals, financial transactions, document sign-offs) need a permanent record of every state change. The
ProcessHistoryItemcaptures exactly the data auditors look for.Debugging unexpected workflow paths - When a process takes an unexpected route, the log shows every transition, the conditions that led to it, and the actor that triggered each step. No need to reproduce the scenario.
User action tracking - The
ActorIdentityIdandExecutorIdentityIdfields capture who performed each action and on whose behalf, making it possible to trace user activity across the workflow.Performance analysis - The
StartTransitionTimeandTransitionDurationfields capture how long each transition took to execute, helping identify slow activities or bottlenecks.
How it compares
The following table compares Workflow Engine's automatic process logging with the alternative of custom audit logging.
| Approach | What it requires | Result |
|---|---|---|
| Custom audit logging | Write logging code in every action, maintain a separate audit table, ensure it captures all transitions | Fragile, easy to miss transitions, hard to keep in sync with the scheme |
| Workflow Engine Process Logs | Transition history is recorded automatically for every state change; query with GetProcessHistoryAsync | Complete, consistent audit trail - no custom code, no missed transitions |
The ProcessHistoryItem captures every state change by default, including the transition direction classifier, trigger name (command or timer), and execution duration - data a custom logging implementation would need to reconstruct manually.
Frequently asked questions
Does Workflow Engine capture process logs automatically?
Yes. Every transition - whether triggered by a command, timer, direct state change, or subprocess completion - writes a ProcessHistoryItem to the persistence provider. No configuration is needed to enable it.
What data does each process log entry capture?
Each ProcessHistoryItem records the source and destination activity names, the source and destination state names, the UTC transition time, the start transition time and duration, the transition classifier, the trigger name (command or timer), the actor identity, the executor identity, and whether the transition finalized the process.
Is the process log stored with the same persistence provider?
Yes. The transition history is stored in the same persistence provider (MSSQL, PostgreSQL, MySQL, etc.) as the process instances. It is a separate table indexed by process instance ID.
Is there a separate runtime log for debugging?
Yes. The runtime has an IProcessLogProvider interface (implemented by MemoryProcessLogger by default) that captures operational messages, exceptions, and debugging events during execution. This is separate from the ProcessHistoryItem transition history.
Can I customize what data gets logged during a state change?
The ProcessHistoryItem fields are fixed and automatically populated. For custom operational data, use the IProcessLogProvider runtime log, which accepts ProcessLogEntry objects with a free-form Properties field (JObject) and Message string.