Observability Guide
Workflows are much easier to trust when you can see how they behave in production.
In Orchestrix, observability is mainly built around:
- structured execution results
- lifecycle hooks
- optional built-in logging
- plugin-based extensions
Start with the result object
Every execution returns a FlowResult, and every step produces a StepResult.
That already gives you a lot of useful information:
- final flow status
- total duration
- which step failed
- how many attempts were made
- per-step durations
This is the first observability layer of the library: execution is visible by design.
Built-in logging
Orchestrix can enable a built-in logger through flow configuration:
const flow = create("observable-flow", {
logging: true
});You can also configure logging options when needed through the flow config.
Hooks for operational telemetry
Hooks are the main way to connect Orchestrix to your logging, metrics, and monitoring stack.
const flow = create("my-flow", {
hooks: {
onFlowStart: ({ flowName }) => {
logger.info({ flowName }, "flow started");
},
onStepComplete: ({ flowName, stepName, result }) => {
logger.info({ flowName, stepName, result }, "step completed");
},
onFlowFail: ({ flowName, result }) => {
logger.error({ flowName, result }, "flow failed");
}
}
});Metrics example
Hooks are a good fit for emitting counters and histograms:
const flow = create("metrics-flow", {
hooks: {
onFlowComplete: ({ flowName, result }) => {
flowCounter.inc({ flow_name: flowName, status: result.status });
flowDuration.observe({ flow_name: flowName }, result.durationMs / 1000);
},
onStepFail: ({ flowName, stepName }) => {
stepFailureCounter.inc({ flow_name: flowName, step_name: stepName });
}
}
});Tracing pattern
You can also use hooks to integrate with tracing systems by storing spans or correlation values in context.
const flow = create("traced-flow", {
hooks: {
onFlowStart: ({ flowName, context }) => {
const span = tracer.startSpan(flowName);
context.set("root-span", span);
},
onStepStart: ({ stepName, context }) => {
const rootSpan = context.get("root-span");
const stepSpan = tracer.startSpan(stepName, { parent: rootSpan });
context.set(`span:${stepName}`, stepSpan);
},
onStepComplete: ({ stepName, context }) => {
const stepSpan = context.get<{ end: () => void }>(`span:${stepName}`);
stepSpan?.end();
}
}
});Correlation
One of the most useful observability practices is to include a correlation ID in the flow input or context and propagate it through logs and service calls.
That makes it much easier to trace one business operation across multiple systems.
Best Practices
- Use structured logs.
- Emit metrics from hooks, not from step internals when possible.
- Log or store the final
FlowResultfor important workflows. - Add correlation identifiers early in execution.
- Treat compensation events as important operational signals worth monitoring.