Documentation
¶
Overview ¶
Package auditlog provides an audit logging library for Azure/go-workflow.
It records every step execution event — attempts, retries, durations, errors, dependencies, and final statuses — with timestamped events and export to JSON and NDJSON.
Quick start ¶
audit, _ := auditlog.New(auditlog.Config{WorkflowID: "checkout"})
w := &flow.Workflow{}
w.Add(
flow.Step(fetch),
flow.Step(save).DependsOn(fetch),
)
audit.Attach(w) // inject callbacks BEFORE Do
err := w.Do(ctx) // run the workflow
audit.Snapshot(w) // capture final DAG state AFTER Do
report := audit.Report() // machine-readable snapshot
_ = audit.ExportJSON("audit.json")
Example (BasicUsage) ¶
Example_basicUsage shows the minimal workflow audit setup.
package main
import (
"context"
"fmt"
flow "github.com/Azure/go-workflow"
auditlog "github.com/larsartmann/go-workflow-auditlog"
)
// exampleStep is used by the Example functions.
type exampleStep struct {
name string
}
func (s *exampleStep) Do(_ context.Context) error { return nil }
func (s *exampleStep) String() string { return s.name }
func main() {
audit, _ := auditlog.New(auditlog.Config{
Enabled: true,
WorkflowID: "demo",
})
step := &exampleStep{name: "fetch"}
w := &flow.Workflow{}
w.Add(flow.Step(step))
audit.Attach(w)
_ = w.Do(context.Background())
audit.Snapshot(w)
report := audit.Report()
fmt.Printf("Steps: %d, Succeeded: %d\n", report.StepCount, report.SucceededCount)
}
Output: Steps: 1, Succeeded: 1
Example (ExportToFile) ¶
Example_exportToFile shows how to export the audit report to JSON.
package main
import (
"context"
"fmt"
"os"
flow "github.com/Azure/go-workflow"
auditlog "github.com/larsartmann/go-workflow-auditlog"
)
// exampleStep is used by the Example functions.
type exampleStep struct {
name string
}
func (s *exampleStep) Do(_ context.Context) error { return nil }
func (s *exampleStep) String() string { return s.name }
func main() {
audit, _ := auditlog.New(auditlog.Config{Enabled: true})
w := &flow.Workflow{}
w.Add(flow.Step(&exampleStep{name: "step"}))
audit.Attach(w)
_ = w.Do(context.Background())
audit.Snapshot(w)
_ = audit.ExportJSON(os.TempDir() + "/audit-example.json")
fmt.Println("exported")
}
Output: exported
Example (Filtering) ¶
Example_filtering shows how to filter a report.
package main
import (
"context"
"errors"
"fmt"
flow "github.com/Azure/go-workflow"
auditlog "github.com/larsartmann/go-workflow-auditlog"
)
// exampleStep is used by the Example functions.
type exampleStep struct {
name string
}
func (s *exampleStep) Do(_ context.Context) error { return nil }
func (s *exampleStep) String() string { return s.name }
func main() {
audit, _ := auditlog.New(auditlog.Config{Enabled: true})
w := &flow.Workflow{}
w.Add(
flow.Step(&exampleStep{name: "ok"}),
flow.Step(flow.Func("bad", func(_ context.Context) error { return errors.New("fail") })),
)
audit.Attach(w)
_ = w.Do(context.Background())
audit.Snapshot(w)
filtered := audit.ReportFiltered(auditlog.WithStepsByStatus(auditlog.StepStatusSucceeded))
fmt.Printf("Filtered steps: %d\n", filtered.StepCount)
}
Output: Filtered steps: 1
Example (MermaidDiagram) ¶
Example_mermaidDiagram shows how to generate a Mermaid DAG visualization. The diagram is written to any io.Writer — here we use io.Discard since the output is non-deterministic across runs.
package main
import (
"context"
"io"
flow "github.com/Azure/go-workflow"
auditlog "github.com/larsartmann/go-workflow-auditlog"
)
// exampleStep is used by the Example functions.
type exampleStep struct {
name string
}
func (s *exampleStep) Do(_ context.Context) error { return nil }
func (s *exampleStep) String() string { return s.name }
func main() {
audit, _ := auditlog.New(auditlog.Config{Enabled: true})
a := &exampleStep{name: "fetch"}
b := &exampleStep{name: "save"}
w := &flow.Workflow{}
w.Add(
flow.Step(a),
flow.Step(b).DependsOn(a),
)
audit.Attach(w)
_ = w.Do(context.Background())
audit.Snapshot(w)
report := audit.Report()
_ = report.WriteMermaid(io.Discard)
}
Output:
Index ¶
- Constants
- Variables
- func CheckNoClobber(path string) error
- func ErrorClassifications() map[error]errorfamily.Family
- func HasPointerAddress(name string) bool
- func RegisterClassifications(reg *errorfamily.Registry)
- type Auditor
- func (a *Auditor) Attach(w *flow.Workflow) *flow.Workflow
- func (a *Auditor) DroppedEventCount() int64
- func (a *Auditor) Events() []Event
- func (a *Auditor) EventsCount() int
- func (a *Auditor) ExportD2(path string) error
- func (a *Auditor) ExportGraphviz(path string) error
- func (a *Auditor) ExportHTML(path string) error
- func (a *Auditor) ExportHTMLTree(path string) error
- func (a *Auditor) ExportJSON(path string) error
- func (a *Auditor) ExportMermaid(path string) error
- func (a *Auditor) ExportNDJSON(path string) error
- func (a *Auditor) ExportPlantUML(path string) error
- func (a *Auditor) ExportTable(path string, format output.Format, opts output.RenderOptions) error
- func (a *Auditor) ExportTree(path string) error
- func (a *Auditor) Report() WorkflowReport
- func (a *Auditor) ReportFiltered(opts ...ReportOption) WorkflowReport
- func (a *Auditor) RunID() RunID
- func (a *Auditor) Snapshot(w *flow.Workflow)
- func (a *Auditor) WriteD2(writer io.Writer) error
- func (a *Auditor) WriteD2String() (string, error)
- func (a *Auditor) WriteGraphviz(writer io.Writer) error
- func (a *Auditor) WriteGraphvizString() (string, error)
- func (a *Auditor) WriteHTML(writer io.Writer) error
- func (a *Auditor) WriteHTMLString() (string, error)
- func (a *Auditor) WriteHTMLTree(writer io.Writer) error
- func (a *Auditor) WriteHTMLTreeString() (string, error)
- func (a *Auditor) WriteJSON(writer io.Writer) error
- func (a *Auditor) WriteMermaid(writer io.Writer) error
- func (a *Auditor) WriteMermaidString() (string, error)
- func (a *Auditor) WriteNDJSON(writer io.Writer) error
- func (a *Auditor) WritePlantUML(writer io.Writer) error
- func (a *Auditor) WritePlantUMLString() (string, error)
- func (a *Auditor) WriteTable(writer io.Writer, format output.Format, opts output.RenderOptions) error
- func (a *Auditor) WriteTableString(format output.Format, opts output.RenderOptions) (string, error)
- func (a *Auditor) WriteTree(writer io.Writer) error
- func (a *Auditor) WriteTreeString() (string, error)
- type Config
- type DiffResult
- type Event
- type EventMeta
- type EventType
- type Phase
- type Recorder
- type ReportIndex
- type ReportOption
- type RunID
- type StatusMeta
- type StepDiff
- type StepInfo
- type StepRef
- type StepStatus
- type TypeMetadata
- type WorkflowReport
- func (r WorkflowReport) Diff(other WorkflowReport) DiffResult
- func (r WorkflowReport) Duration() time.Duration
- func (r WorkflowReport) EventsByStep(stepName string) []Event
- func (r WorkflowReport) EventsByType(t EventType) []Event
- func (r WorkflowReport) ExportD2(path string) error
- func (r WorkflowReport) ExportGraphviz(path string) error
- func (r WorkflowReport) ExportHTML(path string) error
- func (r WorkflowReport) ExportHTMLTree(path string) error
- func (r WorkflowReport) ExportJSON(path string) error
- func (r WorkflowReport) ExportMermaid(path string) error
- func (r WorkflowReport) ExportNDJSON(path string) error
- func (r WorkflowReport) ExportPlantUML(path string) error
- func (r WorkflowReport) ExportTable(path string, format output.Format, opts output.RenderOptions) error
- func (r WorkflowReport) ExportTree(path string) error
- func (r WorkflowReport) FailedSteps() []StepInfo
- func (r WorkflowReport) Filtered(opts ...ReportOption) WorkflowReport
- func (r WorkflowReport) NameCollisions() []string
- func (r WorkflowReport) RetriedSteps() []StepInfo
- func (r WorkflowReport) SkippedSteps() []StepInfo
- func (r WorkflowReport) StepByName(name string) *StepInfo
- func (r WorkflowReport) SucceededSteps() []StepInfo
- func (r WorkflowReport) Summary() string
- func (r WorkflowReport) Validate() error
- func (r WorkflowReport) WriteD2(writer io.Writer) error
- func (r WorkflowReport) WriteD2String() (string, error)
- func (r WorkflowReport) WriteGraphviz(writer io.Writer) error
- func (r WorkflowReport) WriteGraphvizString() (string, error)
- func (r WorkflowReport) WriteHTML(writer io.Writer) error
- func (r WorkflowReport) WriteHTMLString() (string, error)
- func (r WorkflowReport) WriteHTMLTree(writer io.Writer) error
- func (r WorkflowReport) WriteHTMLTreeString() (string, error)
- func (r WorkflowReport) WriteJSON(writer io.Writer) error
- func (r WorkflowReport) WriteMermaid(writer io.Writer) error
- func (r WorkflowReport) WriteMermaidString() (string, error)
- func (r WorkflowReport) WriteNDJSON(writer io.Writer) error
- func (r WorkflowReport) WritePlantUML(writer io.Writer) error
- func (r WorkflowReport) WritePlantUMLString() (string, error)
- func (r WorkflowReport) WriteTable(writer io.Writer, format output.Format, opts output.RenderOptions) error
- func (r WorkflowReport) WriteTableString(format output.Format, opts output.RenderOptions) (string, error)
- func (r WorkflowReport) WriteTree(writer io.Writer) error
- func (r WorkflowReport) WriteTreeString() (string, error)
Examples ¶
Constants ¶
const EnvKeyEnabled = "WORKFLOW_AUDITLOG_ENABLED"
EnvKeyEnabled is the environment variable that controls audit logging. Set to "true", "1", or "yes" to enable. Any other value (or unset) disables it.
const SchemaVersion = "0.1.0"
SchemaVersion is the current report schema version.
Variables ¶
var ( ErrEmpty = errors.New("ndjson input is empty") ErrNoEvents = errors.New("ndjson input contains no events") ErrOversizedLine = errors.New("ndjson line exceeds maximum size") )
Sentinel errors for NDJSON reading.
var ( // ErrEventCountMismatch indicates the report's EventCount field does not // match the length of its Events slice. ErrEventCountMismatch = errors.New("event_count does not match len(events)") // ErrStepCountMismatch indicates the report's StepCount field does not // match the length of its Steps slice. ErrStepCountMismatch = errors.New("step_count does not match len(steps)") // ErrStatusDrift indicates a step's stored Status disagrees with the // status implied by its Error pointer (see [StepInfo.DeriveStatus]). ErrStatusDrift = errors.New("step status does not match derived status") // ErrCountMismatch indicates a denormalized status-count field // (SucceededCount, FailedCount, etc.) disagrees with the actual count // derived from the Steps slice. ErrCountMismatch = errors.New("status count does not match steps") // ErrRenderFailed wraps errors encountered while rendering or marshaling a // report for output (JSON encoding, diagram rendering, HTML generation, // table/tree rendering). Classified as Infrastructure — these failures are // not retryable (programming error or resource exhaustion). // Consumers can match on it with [errors.Is]. ErrRenderFailed = errors.New("render failed") )
Sentinel errors returned by WorkflowReport.Validate. Consumers can match on these with errors.Is to distinguish validation failure modes without parsing error text.
var ErrExportWriteFailed = errors.New("export write failed")
ErrExportWriteFailed wraps errors encountered while writing exported output to a file or io.Writer (file creation, buffer flush, atomic rename, direct writes). Classified as Infrastructure — these are system-level failures not retryable by the caller. Consumers can match on it with errors.Is.
var ErrFileExists = fmt.Errorf("%w: file already exists", ErrExportWriteFailed)
ErrFileExists is returned when a file already exists at the target path and the caller requested no-clobber behavior. Classified as Rejection — the caller asked for an impossible operation (writing to an existing file without overwrite). Consumers can match on it with errors.Is.
var ErrReplayNoEvents = errors.New("no events to replay")
ErrReplayNoEvents is returned when ReplayEvents receives zero events.
var ErrReportLoadFailed = errors.New("report load failed")
ErrReportLoadFailed wraps errors encountered while loading or decoding a report from a file, reader, or byte slice. Classified as Transient — the caller may retry (e.g. the file might be temporarily locked or mid-write). Consumers can match on it with errors.Is.
var ErrWorkflowIDPathSep = errors.New("config.WorkflowID must not contain path separators")
ErrWorkflowIDPathSep is returned by Config.Validate (and thus New) when Config.WorkflowID contains a path separator, which would break file-based export paths. Consumers can match on it with errors.Is.
Functions ¶
func CheckNoClobber ¶ added in v0.5.1
CheckNoClobber returns ErrFileExists if a file already exists at path. Call this before Export* methods to prevent accidental overwrites:
if err := auditlog.CheckNoClobber(path); err != nil { return err }
report.ExportJSON(path)
func ErrorClassifications ¶ added in v0.5.0
func ErrorClassifications() map[error]errorfamily.Family
ErrorClassifications returns the canonical mapping of auditlog sentinel errors to their behavioral errorfamily.Family.
The mapping encodes domain knowledge that only auditlog owns: whether a given error is the caller's fault (errorfamily.Rejection — bad input), a data-integrity violation (errorfamily.Corruption — structurally invalid report), a transient failure (errorfamily.Transient — retryable), or a system-level failure (errorfamily.Infrastructure — not retryable).
func HasPointerAddress ¶ added in v0.5.1
HasPointerAddress reports whether name looks like an unoverridden Go String() default (e.g., "*TestStep(0xc0000a4000)"). Consumers can use this to detect steps that haven't implemented String() and provide a human-readable fallback before attaching the auditor:
if auditlog.HasPointerAddress(flow.String(step)) {
flow.Name("fetch")(flow.Step(step))
}
func RegisterClassifications ¶ added in v0.5.0
func RegisterClassifications(reg *errorfamily.Registry)
RegisterClassifications registers all auditlog sentinel errors into the provided registry with their behavioral errorfamily.Family classification.
Consumers using a custom errorfamily.Registry (rather than the package-level errorfamily.DefaultRegistry) must call this to receive classification metadata. For the common case, auditlog's [init] already registers into errorfamily.DefaultRegistry, so most consumers never need to call this.
Types ¶
type Auditor ¶
type Auditor struct {
// contains filtered or unexported fields
}
Auditor wraps a flow.Workflow with audit logging.
func New ¶
New creates an audit log Auditor.
When Config.Enabled is false (the zero value), New checks the WORKFLOW_AUDITLOG_ENABLED environment variable. Set it to "true", "1", or "yes" to enable audit logging without changing code.
If WorkflowID is empty it defaults to "default".
Returns an error if Config.Validate() fails.
func (*Auditor) Attach ¶
Attach injects audit BeforeStep/AfterStep callbacks into every step in the workflow. Call this BEFORE w.Do(ctx).
The callbacks are merged into each step's existing config via State.MergeConfig, so user-defined callbacks (Input, Output, BeforeStep, AfterStep) are preserved. Audit callbacks are appended last so they observe the final error.
When the Auditor is disabled, Attach is a no-op.
func (*Auditor) DroppedEventCount ¶
DroppedEventCount returns the number of events dropped due to Config.MaxEvents.
func (*Auditor) EventsCount ¶
EventsCount returns the number of captured events without copying the slice.
func (*Auditor) ExportGraphviz ¶
ExportGraphviz writes the step DAG as Graphviz DOT to path.
func (*Auditor) ExportHTML ¶ added in v0.3.0
ExportHTML writes the HTML dashboard to path.
func (*Auditor) ExportHTMLTree ¶ added in v0.2.0
ExportHTMLTree writes the step DAG as an HTML tree to path.
func (*Auditor) ExportJSON ¶ added in v0.2.0
ExportJSON writes the full WorkflowReport as indented JSON to path.
func (*Auditor) ExportMermaid ¶
ExportMermaid writes the step DAG as Mermaid to path.
func (*Auditor) ExportNDJSON ¶ added in v0.2.0
ExportNDJSON writes every event as NDJSON to path.
func (*Auditor) ExportPlantUML ¶
ExportPlantUML writes the step DAG as PlantUML to path.
func (*Auditor) ExportTable ¶ added in v0.2.0
ExportTable writes the step summary table to path in the specified format.
func (*Auditor) ExportTree ¶ added in v0.2.0
ExportTree writes the step DAG as an ASCII tree to path.
func (*Auditor) Report ¶
func (a *Auditor) Report() WorkflowReport
Report returns a consolidated snapshot of everything observed so far.
func (*Auditor) ReportFiltered ¶
func (a *Auditor) ReportFiltered(opts ...ReportOption) WorkflowReport
ReportFiltered returns a filtered report. Convenience method on Auditor.
func (*Auditor) RunID ¶
RunID returns the run identifier stamped on every captured event. Useful for correlating the audit log with external systems (traces, logs) before a full report is built.
func (*Auditor) Snapshot ¶
Snapshot reads the workflow's final state after Do() to capture the full DAG structure, final statuses, and any steps that were skipped or canceled (which bypass Before/After callbacks entirely).
Call this AFTER w.Do(ctx) returns.
When the Auditor is disabled, Snapshot is a no-op.
func (*Auditor) WriteD2 ¶ added in v0.2.0
WriteD2 writes the step DAG as a D2 diagram to the writer.
func (*Auditor) WriteD2String ¶ added in v0.2.0
WriteD2String returns the D2 diagram as a string.
func (*Auditor) WriteGraphviz ¶
WriteGraphviz writes the step DAG as a Graphviz DOT diagram to the writer.
func (*Auditor) WriteGraphvizString ¶ added in v0.2.0
WriteGraphvizString returns the Graphviz DOT diagram as a string.
func (*Auditor) WriteHTML ¶ added in v0.3.0
WriteHTML writes a self-contained interactive HTML dashboard to writer.
func (*Auditor) WriteHTMLString ¶ added in v0.3.0
WriteHTMLString returns the HTML dashboard as a string.
func (*Auditor) WriteHTMLTree ¶ added in v0.2.0
WriteHTMLTree writes the step DAG as an HTML nested list tree to the writer.
func (*Auditor) WriteHTMLTreeString ¶ added in v0.2.0
WriteHTMLTreeString returns the HTML tree as a string.
func (*Auditor) WriteJSON ¶ added in v0.2.0
WriteJSON writes the full WorkflowReport as indented JSON to writer.
func (*Auditor) WriteMermaid ¶
WriteMermaid writes the step DAG as a Mermaid diagram to the writer.
func (*Auditor) WriteMermaidString ¶ added in v0.2.0
WriteMermaidString returns the Mermaid diagram as a string.
func (*Auditor) WriteNDJSON ¶ added in v0.2.0
WriteNDJSON writes every captured event as line-delimited JSON to writer.
func (*Auditor) WritePlantUML ¶
WritePlantUML writes the step DAG as a PlantUML diagram to the writer.
func (*Auditor) WritePlantUMLString ¶ added in v0.2.0
WritePlantUMLString returns the PlantUML diagram as a string.
func (*Auditor) WriteTable ¶ added in v0.2.0
func (a *Auditor) WriteTable(writer io.Writer, format output.Format, opts output.RenderOptions) error
WriteTable writes the step summary as a table in the specified format.
func (*Auditor) WriteTableString ¶ added in v0.2.0
WriteTableString returns the step summary table as a string in the given format.
func (*Auditor) WriteTree ¶ added in v0.2.0
WriteTree writes the step DAG as an ASCII tree to the writer.
func (*Auditor) WriteTreeString ¶ added in v0.2.0
WriteTreeString returns the ASCII tree as a string.
type Config ¶
type Config struct {
// Enabled turns audit logging on or off. When false the Auditor is a no-op.
// If left as zero-value (false), New() checks the WORKFLOW_AUDITLOG_ENABLED env var.
Enabled bool
// WorkflowID is an optional human-readable identifier for the workflow.
WorkflowID string
// RunID is an optional identifier for a single execution ("run") of the
// workflow. It is stamped on every Event and on the WorkflowReport so that
// all observations from one execution can be correlated across systems
// (e.g. matched to a distributed trace). If empty, New() generates a random
// 128-bit hex ID.
RunID RunID
// OnEvent is called after each event is captured, outside the recorder
// lock so it cannot deadlock the recorder. Must not block.
// Note: concurrent steps invoke this concurrently — the callback must be
// goroutine-safe (e.g. guard shared state with a mutex). Nil disables it.
OnEvent func(Event)
// MaxEvents caps the number of events stored in memory. When 0 (default),
// events grow without bound. When > 0, the recorder stops appending new
// events after reaching the cap and increments DroppedEventCount.
MaxEvents int
// InitialEventCapacity pre-allocates the events slice to avoid runtime
// reallocations. When 0, defaults to 256.
InitialEventCapacity int
}
Config controls the audit log behaviour.
type DiffResult ¶
type DiffResult struct {
AddedSteps []StepDiff `json:"added_steps,omitempty"`
RemovedSteps []StepDiff `json:"removed_steps,omitempty"`
StatusChanged []StepDiff `json:"status_changed,omitempty"`
DurationDelta float64 `json:"duration_delta_ms"`
}
DiffResult describes the differences between two workflow reports.
func (DiffResult) HasChanges ¶
func (d DiffResult) HasChanges() bool
HasChanges returns true if the diff found any differences.
type Event ¶
type Event struct {
StepRef
RunID RunID `json:"run_id,omitempty"`
Sequence int `json:"sequence"`
Timestamp time.Time `json:"timestamp"`
EventType EventType `json:"event_type"`
Phase Phase `json:"phase"`
Attempt int `json:"attempt,omitempty"`
DurationMs *float64 `json:"duration_ms,omitempty"`
Error *string `json:"error,omitempty"`
Status StepStatus `json:"status,omitempty"`
}
Event is a single, timestamped observation from a workflow step execution.
func ReadEvents ¶
ReadEvents reads line-delimited JSON events from reader. Each line must be a single JSON-encoded Event object. Blank lines are skipped. Returns the parsed events in order.
Returns ErrEmpty if the input contains no bytes, ErrNoEvents if all lines were blank, or ErrOversizedLine if any line exceeds 1 MB.
func (Event) IsAttemptEnd ¶
IsAttemptEnd returns true if the event is an attempt-end event.
func (Event) IsAttemptStart ¶
IsAttemptStart returns true if the event is an attempt-start event.
type EventType ¶
type EventType string
EventType categorizes audit log events.
Every event is one of two types, mirroring the two go-workflow callbacks: AttemptStart (from BeforeStep) and AttemptEnd (from AfterStep). EventType is intentionally redundant with Phase — an AttemptStart always carries PhaseBefore, an AttemptEnd always carries PhaseAfter. Both fields are kept so consumers can filter by either axis (event kind or lifecycle position) without cross-referencing.
func (EventType) Color ¶
Color returns the CSS color token for this event type, used in HTML visualizations.
type Phase ¶
type Phase string
Phase indicates whether an event is the start or end of an operation.
It is deliberately redundant with EventType: AttemptStart ↔ PhaseBefore and AttemptEnd ↔ PhaseAfter. The duplication is retained in the JSON output so that consumers can filter on lifecycle position ("before"/"after") without knowing the event-type vocabulary, and vice versa.
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
Recorder captures workflow execution events in-memory with minimal overhead.
Locking Protocol ¶
All mutable state is protected by a single sync.RWMutex (mu):
Write path: mu.Lock() — recordBeforeStep, recordAfterStep, snapshot Read path: mu.RLock() — BuildReport, Events, EventsCount
The onEvent callback is always called outside the lock to prevent user code from blocking or deadlocking the recorder.
func NewRecorder ¶
NewRecorder creates a new event recorder.
workflowID identifies the workflow (stable across runs); runID identifies a single execution and is stamped on every captured Event so all observations from one run can be correlated. Pass a non-empty runID (e.g. a trace ID) to integrate with external observability systems.
func (*Recorder) BuildReport ¶
func (r *Recorder) BuildReport() WorkflowReport
BuildReport assembles a machine-readable WorkflowReport from all captured events and step records.
func (*Recorder) DroppedEventCount ¶
DroppedEventCount returns the number of events dropped due to MaxEvents cap.
func (*Recorder) EventsCount ¶
EventsCount returns the number of captured events without copying the slice.
type ReportIndex ¶
type ReportIndex struct {
// contains filtered or unexported fields
}
ReportIndex precomputes lookup maps over a WorkflowReport for repeated O(1) queries. Build it once from a final report, then query cheaply — useful when a consumer inspects the same report many times (e.g. in a UI or analysis loop).
The index shares the report's backing slices; it is read-only and must not outlive mutations to the underlying report. Rebuild the index (call NewReportIndex) if the report changes.
func NewReportIndex ¶
func NewReportIndex(r WorkflowReport) *ReportIndex
NewReportIndex builds an O(1) lookup index over the given report. The report is not retained beyond its slices; callers may discard the WorkflowReport value but must not mutate its Steps or Events in place afterward.
func (*ReportIndex) EventsByStep ¶
func (idx *ReportIndex) EventsByStep(name string) []Event
EventsByStep returns all events for the given step name (nil if none). O(1).
func (*ReportIndex) EventsByType ¶
func (idx *ReportIndex) EventsByType(t EventType) []Event
EventsByType returns all events matching the given type (nil if none). O(1).
func (*ReportIndex) StepByID ¶
func (idx *ReportIndex) StepByID(id int) *StepInfo
StepByID returns a pointer to the step with the given StepInfo.StepID, or nil. O(1).
func (*ReportIndex) StepByName ¶
func (idx *ReportIndex) StepByName(name string) *StepInfo
StepByName returns a pointer to the first step with the given name, or nil. O(1).
type ReportOption ¶
type ReportOption func(*reportFilter)
ReportOption configures a filter for WorkflowReport.Filtered.
func WithEventsByType ¶
func WithEventsByType(eventType EventType) ReportOption
WithEventsByType filters to only events matching the given type.
func WithStepsByName ¶
func WithStepsByName(names ...string) ReportOption
WithStepsByName filters to only steps matching any of the given names.
func WithStepsByStatus ¶
func WithStepsByStatus(statuses ...StepStatus) ReportOption
WithStepsByStatus filters to only steps matching any of the given statuses.
func WithTimeRange ¶
func WithTimeRange(from, to time.Time) ReportOption
WithTimeRange filters events to those within the given time range (inclusive).
type RunID ¶ added in v0.2.0
type RunID string
RunID identifies a single execution ("run") of a workflow. It is stamped on every Event and on the WorkflowReport so all observations from one execution can be correlated across systems (e.g. matched to a distributed trace).
RunID is a branded string type: it serializes to/from JSON as a plain string but the type system prevents accidentally passing a WorkflowID (also a string) where a RunID is expected. Convert with RunID("value") or string(id).
type StatusMeta ¶ added in v0.3.0
StatusMeta holds display info for a StepStatus.
type StepDiff ¶
type StepDiff struct {
Name string `json:"name"`
Status StepStatus `json:"status"`
OldStatus StepStatus `json:"old_status,omitempty"`
Duration float64 `json:"duration_ms,omitempty"`
}
StepDiff captures a single step's state in a diff context. For status changes, Status holds the new value and OldStatus the previous one (OldStatus is empty for added steps).
type StepInfo ¶
type StepInfo struct {
StepRef
// StepID is a 1-based, unique identifier assigned when the step is first
// observed. It disambiguates steps that share the same Name (which can
// happen when two step types produce identical String() output). Stable
// within a single report/run; not guaranteed stable across runs.
StepID int `json:"step_id,omitempty"`
Status StepStatus `json:"status"`
AttemptCount int `json:"attempt_count"`
MaxAttempts int `json:"max_attempts,omitempty"`
StartedAt *time.Time `json:"started_at,omitempty"`
FinishedAt *time.Time `json:"finished_at,omitempty"`
DurationMs *float64 `json:"duration_ms,omitempty"`
Dependencies []StepRef `json:"dependencies,omitempty"`
Dependents []StepRef `json:"dependents,omitempty"`
Error *string `json:"error,omitempty"`
HasRetry bool `json:"has_retry"`
HasTimeout bool `json:"has_timeout"`
}
StepInfo aggregates all observed data for a single workflow step.
func (StepInfo) DeriveStatus ¶
func (s StepInfo) DeriveStatus() StepStatus
DeriveStatus computes the step status from the step's own error pointer. This is the canonical derivation — the stored Status field should always match this method so it can never drift from the underlying data.
If Snapshot() has not been called yet, the status may be pending/running. After Snapshot(), the status reflects the workflow's final state.
func (StepInfo) Type ¶ added in v0.5.1
Type returns the step's Go type name (e.g., "FetchStep"). This is the programmatic identifier of the step implementation. Provides method-style access for API consistency with StepStatus.Label, StepStatus.Icon, and StepStatus.Color.
type StepRef ¶
StepRef identifies a step within a workflow. Embedded in Event and StepInfo for JSON flattening.
type StepStatus ¶
type StepStatus string
StepStatus mirrors flow.StepStatus as a stable string enum for JSON export.
const ( StepStatusPending StepStatus = "pending" StepStatusRunning StepStatus = "running" StepStatusSucceeded StepStatus = "succeeded" StepStatusFailed StepStatus = "failed" StepStatusCanceled StepStatus = "canceled" StepStatusSkipped StepStatus = "skipped" )
func (StepStatus) Color ¶ added in v0.2.0
func (s StepStatus) Color() (string, string)
Color returns the fill and font colors for this step status, used by all diagram renderers (Mermaid, Graphviz, PlantUML, D2). Terminal statuses get colors; non-terminal statuses (pending/running) return empty strings (the renderer uses its default appearance).
func (StepStatus) Icon ¶
func (s StepStatus) Icon() string
Icon returns a display emoji for this step status.
func (StepStatus) IsError ¶
func (s StepStatus) IsError() bool
IsError returns true if the step failed or was canceled.
func (StepStatus) IsKnown ¶ added in v0.2.1
func (s StepStatus) IsKnown() bool
IsKnown returns true if the status is a recognized value.
func (StepStatus) IsTerminal ¶
func (s StepStatus) IsTerminal() bool
IsTerminal returns true if the step has reached a terminal state (succeeded, failed, canceled, or skipped).
func (StepStatus) Label ¶
func (s StepStatus) Label() string
Label returns the human-readable display label for this step status.
type TypeMetadata ¶ added in v0.3.0
type TypeMetadata struct {
Statuses map[string]StatusMeta `json:"statuses"`
Events map[string]EventMeta `json:"events"`
}
TypeMetadata provides display metadata (icons, labels, colors) for all enum types used in the HTML visualization. It is injected into the template as JSON so that JavaScript reads from a single Go-authoritative source instead of maintaining parallel hardcoded constants.
func BuildTypeMetadata ¶ added in v0.3.0
func BuildTypeMetadata() TypeMetadata
BuildTypeMetadata constructs display metadata from the Go enum constants. This is the single source of truth — the HTML template's JavaScript reads from the injected JSON rather than maintaining parallel constant definitions.
type WorkflowReport ¶
type WorkflowReport struct {
Version string `json:"version"`
WorkflowID string `json:"workflow_id"`
RunID RunID `json:"run_id,omitempty"`
ExportedAt time.Time `json:"exported_at"`
EventCount int `json:"event_count"`
StepCount int `json:"step_count"`
SucceededCount int `json:"succeeded_count"`
FailedCount int `json:"failed_count"`
SkippedCount int `json:"skipped_count"`
CanceledCount int `json:"canceled_count"`
PendingCount int `json:"pending_count"`
RunningCount int `json:"running_count"`
TotalDurationMs float64 `json:"total_duration_ms"`
WallClockDurationMs float64 `json:"wall_clock_duration_ms"`
WorkflowSucceeded bool `json:"workflow_succeeded"`
DroppedEventCount int64 `json:"dropped_event_count"`
PeakConcurrency int `json:"peak_concurrency,omitempty"`
CriticalPathDurationMs float64 `json:"critical_path_duration_ms,omitempty"`
FailureReason string `json:"failure_reason,omitempty"`
// Reconstructed is true when the report was built by ReplayEvents from a
// flat event stream rather than from live workflow hooks.
Reconstructed bool `json:"reconstructed,omitempty"`
Events []Event `json:"events,omitempty"`
Steps []StepInfo `json:"steps"`
}
WorkflowReport is a consolidated, machine-readable snapshot of the audit log.
func LoadReport ¶
func LoadReport(path string) (WorkflowReport, error)
LoadReport reads a JSON WorkflowReport from a file path. This is the inverse of ExportJSON.
func LoadReportFromBytes ¶
func LoadReportFromBytes(data []byte) (WorkflowReport, error)
LoadReportFromBytes parses a JSON WorkflowReport from a byte slice.
func LoadReportFromReader ¶
func LoadReportFromReader(reader io.Reader) (WorkflowReport, error)
LoadReportFromReader reads a JSON WorkflowReport from any io.Reader.
func ReplayEvents ¶
func ReplayEvents(events []Event) (WorkflowReport, error)
ReplayEvents reconstructs a WorkflowReport from a flat event stream.
This is the inverse of ExportNDJSON: write events to NDJSON, then later read them back and reconstruct the report for offline analysis.
Limitations:
- Dependencies/dependents are not inferred (events carry no DAG edges). Use Snapshot-captured reports for full DAG info.
- MaxAttempts/HasRetry/HasTimeout are not available from events alone.
- The report has Reconstructed=true.
func (WorkflowReport) Diff ¶
func (r WorkflowReport) Diff(other WorkflowReport) DiffResult
Diff compares this report against another and returns the differences. Useful for detecting regressions between workflow runs.
Output slices are sorted by step name for deterministic results across runs.
func (WorkflowReport) Duration ¶
func (r WorkflowReport) Duration() time.Duration
Duration returns the total wall-clock duration spanned by all events, from the earliest to the latest timestamp. This is different from TotalDurationMs (which sums individual step durations and may overcount when steps run in parallel). The same value is available as the WallClockDurationMs JSON field.
Example ¶
ExampleWorkflowReport_Duration demonstrates how to get the wall-clock duration of a workflow run. This is the "how long did I wait" number, not the sum of individual step durations (which overcounts for parallel steps).
package main
import (
"fmt"
auditlog "github.com/larsartmann/go-workflow-auditlog"
)
func main() {
report := auditlog.WorkflowReport{
WallClockDurationMs: 48800,
}
fmt.Printf("%.1fs\n", report.WallClockDurationMs/1000)
}
Output: 48.8s
func (WorkflowReport) EventsByStep ¶
func (r WorkflowReport) EventsByStep(stepName string) []Event
EventsByStep returns all events for the given step name.
func (WorkflowReport) EventsByType ¶
func (r WorkflowReport) EventsByType(t EventType) []Event
EventsByType returns all events matching the given event type.
func (WorkflowReport) ExportD2 ¶ added in v0.2.0
func (r WorkflowReport) ExportD2(path string) error
ExportD2 writes the step DAG as a D2 diagram to path.
func (WorkflowReport) ExportGraphviz ¶ added in v0.2.0
func (r WorkflowReport) ExportGraphviz(path string) error
ExportGraphviz writes the step DAG as a Graphviz DOT diagram to path.
func (WorkflowReport) ExportHTML ¶ added in v0.3.0
func (r WorkflowReport) ExportHTML(path string) error
ExportHTML writes the HTML dashboard to path (atomic write via temp+rename).
func (WorkflowReport) ExportHTMLTree ¶ added in v0.2.0
func (r WorkflowReport) ExportHTMLTree(path string) error
ExportHTMLTree writes the step DAG as an HTML nested-list tree to path.
func (WorkflowReport) ExportJSON ¶ added in v0.2.0
func (r WorkflowReport) ExportJSON(path string) error
ExportJSON writes the report as indented JSON to path.
func (WorkflowReport) ExportMermaid ¶ added in v0.2.0
func (r WorkflowReport) ExportMermaid(path string) error
ExportMermaid writes the step DAG as a Mermaid diagram to path.
func (WorkflowReport) ExportNDJSON ¶ added in v0.2.0
func (r WorkflowReport) ExportNDJSON(path string) error
ExportNDJSON writes the report's events as NDJSON to path.
func (WorkflowReport) ExportPlantUML ¶ added in v0.2.0
func (r WorkflowReport) ExportPlantUML(path string) error
ExportPlantUML writes the step DAG as a PlantUML diagram to path.
func (WorkflowReport) ExportTable ¶ added in v0.2.0
func (r WorkflowReport) ExportTable(path string, format output.Format, opts output.RenderOptions) error
ExportTable writes the step summary table to path in the given format.
func (WorkflowReport) ExportTree ¶ added in v0.2.0
func (r WorkflowReport) ExportTree(path string) error
ExportTree writes the step DAG as an ASCII tree to path.
func (WorkflowReport) FailedSteps ¶
func (r WorkflowReport) FailedSteps() []StepInfo
FailedSteps returns all steps with an error status (failed or canceled).
func (WorkflowReport) Filtered ¶
func (r WorkflowReport) Filtered(opts ...ReportOption) WorkflowReport
Filtered returns a new report containing only the steps and events that match all of the given filter options. Aggregate counts are recomputed.
With no options, returns a copy of the report.
Example ¶
ExampleWorkflowReport_Filtered demonstrates how to filter a report to show only failed steps for quick debugging.
package main
import (
"fmt"
auditlog "github.com/larsartmann/go-workflow-auditlog"
)
func main() {
report := auditlog.WorkflowReport{
Steps: []auditlog.StepInfo{
{StepRef: auditlog.StepRef{Name: "fetch"}, Status: auditlog.StepStatusSucceeded},
{StepRef: auditlog.StepRef{Name: "validate"}, Status: auditlog.StepStatusFailed},
{StepRef: auditlog.StepRef{Name: "transform"}, Status: auditlog.StepStatusSkipped},
},
}
failedOnly := report.Filtered(auditlog.WithStepsByStatus(auditlog.StepStatusFailed))
for _, s := range failedOnly.Steps {
fmt.Println(s.Name)
}
}
Output: validate
func (WorkflowReport) NameCollisions ¶ added in v0.5.1
func (r WorkflowReport) NameCollisions() []string
NameCollisions returns step names that appear more than once in the report. When two steps share the same Name (which happens when step types produce identical String() output), diagram and table exports silently merge them. This method surfaces those collisions so consumers can add disambiguating names via flow.Name().
func (WorkflowReport) RetriedSteps ¶
func (r WorkflowReport) RetriedSteps() []StepInfo
RetriedSteps returns all steps that had more than one attempt.
func (WorkflowReport) SkippedSteps ¶
func (r WorkflowReport) SkippedSteps() []StepInfo
SkippedSteps returns all steps that were skipped.
func (WorkflowReport) StepByName ¶
func (r WorkflowReport) StepByName(name string) *StepInfo
StepByName returns the first StepInfo matching the given exact name. Returns nil if no step matches.
func (WorkflowReport) SucceededSteps ¶
func (r WorkflowReport) SucceededSteps() []StepInfo
SucceededSteps returns all steps that succeeded.
func (WorkflowReport) Summary ¶
func (r WorkflowReport) Summary() string
Summary returns a human-readable one-line summary of the report. Uses wall-clock duration (actual elapsed time) rather than the summed per-step duration, and includes the failure reason when the workflow did not succeed.
func (WorkflowReport) Validate ¶
func (r WorkflowReport) Validate() error
Validate checks internal consistency of the report: denormalized count fields must match the actual slice lengths, and every step's Status must match its DeriveStatus. Returns nil if consistent.
The status drift check catches the case where a step's stored Status field disagrees with what its Error pointer implies — e.g., Status=Pending with a non-nil Error (which DeriveStatus would map to Failed).
func (WorkflowReport) WriteD2 ¶ added in v0.2.0
func (r WorkflowReport) WriteD2(writer io.Writer) error
WriteD2 writes the step dependency DAG as a D2 diagram. Nodes are colored by status (green=succeeded, red=failed, gray=skipped, orange=canceled) via inline style attributes.
The diagram title is derived from the report's WorkflowID so each rendered diagram is self-labeling. When WorkflowID is empty the title falls back to "Workflow DAG".
func (WorkflowReport) WriteD2String ¶ added in v0.2.0
func (r WorkflowReport) WriteD2String() (string, error)
WriteD2String returns the D2 diagram as a string. Returns a non-nil error only if diagram generation fails.
func (WorkflowReport) WriteGraphviz ¶
func (r WorkflowReport) WriteGraphviz(writer io.Writer) error
WriteGraphviz writes the step dependency DAG as a Graphviz DOT digraph. Nodes are colored by status (green=succeeded, red=failed, gray=skipped, orange=canceled) via fillcolor attributes. The output is valid DOT, consumable by `dot -Tsvg` or any Graphviz renderer.
func (WorkflowReport) WriteGraphvizString ¶
func (r WorkflowReport) WriteGraphvizString() (string, error)
WriteGraphvizString returns the Graphviz DOT diagram as a string. Returns a non-nil error only if diagram generation fails.
func (WorkflowReport) WriteHTML ¶ added in v0.3.0
func (r WorkflowReport) WriteHTML(writer io.Writer) error
WriteHTML writes a self-contained interactive HTML dashboard to writer. The output is a single HTML file with embedded CSS and JavaScript — no external dependencies, no network requests. It can be opened directly in any modern browser or attached to an email/report.
func (WorkflowReport) WriteHTMLString ¶ added in v0.3.0
func (r WorkflowReport) WriteHTMLString() (string, error)
WriteHTMLString returns the HTML dashboard as a string. Convenience wrapper around WriteHTML for in-memory use.
func (WorkflowReport) WriteHTMLTree ¶ added in v0.2.0
func (r WorkflowReport) WriteHTMLTree(writer io.Writer) error
WriteHTMLTree writes the step dependency DAG as an HTML nested list tree. Nodes are labeled with step name, status, and retry count.
func (WorkflowReport) WriteHTMLTreeString ¶ added in v0.2.0
func (r WorkflowReport) WriteHTMLTreeString() (string, error)
WriteHTMLTreeString returns the HTML tree as a string. Returns a non-nil error only if tree generation fails.
func (WorkflowReport) WriteJSON ¶
func (r WorkflowReport) WriteJSON(writer io.Writer) error
WriteJSON writes the report as indented JSON to the writer.
func (WorkflowReport) WriteMermaid ¶
func (r WorkflowReport) WriteMermaid(writer io.Writer) error
WriteMermaid writes the step dependency DAG as a Mermaid flowchart diagram. Nodes are colored by status (green=succeeded, red=failed, gray=skipped, orange=canceled) via per-node style directives.
The output is raw flowchart syntax (no ```mermaid code fence) so it can be written to .mmd files or embedded directly.
func (WorkflowReport) WriteMermaidString ¶
func (r WorkflowReport) WriteMermaidString() (string, error)
WriteMermaidString returns the Mermaid diagram as a string. Returns a non-nil error only if diagram generation fails.
func (WorkflowReport) WriteNDJSON ¶
func (r WorkflowReport) WriteNDJSON(writer io.Writer) error
WriteNDJSON writes the report's events as newline-delimited JSON. Each line is a single Event object. This is the inverse of ReadEvents.
func (WorkflowReport) WritePlantUML ¶
func (r WorkflowReport) WritePlantUML(writer io.Writer) error
WritePlantUML writes the step dependency DAG as a PlantUML component diagram. Nodes are colored by status via inline color specifications.
func (WorkflowReport) WritePlantUMLString ¶
func (r WorkflowReport) WritePlantUMLString() (string, error)
WritePlantUMLString returns the PlantUML diagram as a string. Returns a non-nil error only if diagram generation fails.
func (WorkflowReport) WriteTable ¶ added in v0.2.0
func (r WorkflowReport) WriteTable(writer io.Writer, format output.Format, opts output.RenderOptions) error
WriteTable writes the step summary as a table in the specified format. Supported formats (when respective sub-modules are imported): table, json, csv, tsv, markdown, xml, d2, yaml, html, tree, mermaid, dot, jsonl, asciidoc, toml, plantuml.
The opts parameter controls color mode, title, and output destination. Pass output.RenderOptions{} for defaults.
func (WorkflowReport) WriteTableString ¶ added in v0.2.0
func (r WorkflowReport) WriteTableString(format output.Format, opts output.RenderOptions) (string, error)
WriteTableString returns the step summary table as a string in the specified format. See WriteTable for supported formats.
func (WorkflowReport) WriteTree ¶ added in v0.2.0
func (r WorkflowReport) WriteTree(writer io.Writer) error
WriteTree writes the step dependency DAG as an ASCII tree. Nodes are labeled with step name, status, and retry count.
func (WorkflowReport) WriteTreeString ¶ added in v0.2.0
func (r WorkflowReport) WriteTreeString() (string, error)
WriteTreeString returns the ASCII tree as a string. Returns a non-nil error only if tree generation fails.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Command workflow-auditlog-demo demonstrates the go-workflow-auditlog library with a data pipeline: fetch → validate → transform → save, with retry, fan-out, error handling, and audit export.
|
Command workflow-auditlog-demo demonstrates the go-workflow-auditlog library with a data pipeline: fetch → validate → transform → save, with retry, fan-out, error handling, and audit export. |