# Process Logs 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` ordered by timestamp. ```csharp // Get the full history for a process instance List 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: Table: Process history item fields | 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. ```csharp // Configure a custom process log provider runtime.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: ```csharp 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 `ProcessHistoryItem` contains 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 `IProcessLogProvider` captures 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 **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 `ProcessHistoryItem` captures 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 `ActorIdentityId` and `ExecutorIdentityId` fields capture who performed each action and on whose behalf, making it possible to trace user activity across the workflow. - **Performance analysis** - The `StartTransitionTime` and `TransitionDuration` fields 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. Table: Comparison of process logging approaches | 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. ## See also - [Process Instance](https://docs.workflowengine.io/get-started/concepts/process-instance/): The entity whose state changes produce history entries. - Process Logs Reference: The ProcessHistoryItem schema, query API, and IProcessLogProvider interface. - Persistence Providers: How process history is stored alongside scheme and instance data. - [Timers and Scheduling](https://docs.workflowengine.io/evaluate/workflow-engine-features/timers-scheduling/): How timer-triggered transitions are recorded in the process log.