Context + Stream + Collector + EnvironmentC++ Coro Runtime values and outputs
Core C++ Coro values passed into makers, operators, and endpoint handlers. These are the stable application-facing handles to the generated runtime.
When to use
Use this page while implementing a generated business function or endpoint handler.
Behavior
- Contexts carry cancellation and correlation across graph boundaries.
- Collectors and stream contexts are the supported way to emit values; calling downstream functions directly bypasses graph semantics and observability.
- The service environment is supplied during construction so business implementations can create scoped metrics, obtain loggers, and resolve configured dependencies.
Typed tracing attributes
servicelib::tracing::Attribute owns a typed string, int64, double, or bool value. Use String, Int64, Float64, and Bool factories; no untyped dictionary or stream object is passed to the tracer.
AttributeView is a borrowed, read-only range accepted by span, tracer, and tracing-helper methods. Immediate calls with {Attribute::String(...), ...} still work. A cached array or vector can be passed as std::span<const Attribute> without copying its attributes.
Attribute lifetime and sampling
The view does not own its backing values. Keep a cached array or vector alive and unchanged for every synchronous tracer call that reads it. A backend retaining attributes after the call must copy the values into its own storage.
A braced attribute list is valid for an immediate call, not for a stored view. Do not store or return a view of a temporary list or local array that has already expired.
Generated callers cache their fixed attributes when tracing is configured. They check the tracer and the current message sampling flag before invoking span helpers. Task-pool names and fixed call semantics are cached too, not read again for every message.
When adding custom spans, keep business execution outside the tracing condition. Build reusable metadata during initialization and avoid evaluating request attributes when tracing is disabled. The OpenTelemetry SDK may still allocate for recording or exporting an enabled span; cached framework attributes are not a claim of allocation-free tracing.
// cachedAttributes is stable, caller-owned storage prepared at initialization.
servicelib::tracing::ActiveSpan span;
if (tracer && servicelib::tracing::SamplingEnabled(context)) {
span = servicelib::tracing::StartSpanInPlace(
context, tracer.get(), "business.quote",
std::span<const servicelib::tracing::Attribute>{cachedAttributes});
}
// Run the business operation regardless of whether tracing is enabled.Custom Span and Tracer implementations
Custom C++ implementations must change overridden attribute parameters from std::initializer_list<Attribute> to AttributeView. This applies to setAttributes, addEvent, start, startChildOf, and startDetachedChildOf. Rebuild the implementation against the updated runtime; this is an override-signature change, not an ABI-compatibility guarantee.
Preserve explicit parent contexts, detached-span behavior, and span completion. Iterate the range directly for synchronous export, or copy attrs.begin() through attrs.end() into owned storage when retaining the data. Do not retain a borrowed view to call-local attributes.
// Declarations in the corresponding custom Tracer and Span subclasses:
std::shared_ptr<servicelib::tracing::Span> start(
std::string_view spanName,
servicelib::tracing::AttributeView attrs) const override;
void setAttributes(servicelib::tracing::AttributeView attrs) override;Pipeline and component metadata
Every generated stream remains a concrete runtime node. getPipeline() and getComponent() expose its static grouping metadata; a stream outside a component has an empty component name.
Existing link counters and call spans use the receiving stream's pipeline and component. Node and link identities remain intact. No component_instance label, component invocation counter, or component execution wrapper is introduced.
Core runtime types
Types normally visible in preserved implementation signatures.
servicelib::MessageContextPer-message contextCarries correlation, cancellation and deadline state. Forward it with every output.
servicelib::ContextLifecycle contextPassed to makers and lifecycle operations.
servicelib::StreamBaseStream metadataIdentifies the invoking stream; it is not a constructor dependency of a shared business function.
Output / ErrorOutputAwaitable outputsUse co_await out.out(context, value) or the generated equivalent.
servicelib::Payload<T>Shared payloadRetains typed data for asynchronous consumers; do not replace ownership with a reference to a temporary.
SourceStreamContext / SinkStreamContextGraph boundariesAwait collect and collectError when emitting decoded values, responses or failures.
servicelib::IServiceEnvironmentMaker dependencyProvides configuration and observability without binding the function to one stream or endpoint configuration.
cppIoBackend / CPP_CORO_IO_BACKENDGeneration / build optionSelect epoll (default) or uring. This is independent of static/dynamic graph typing and does not change the business API.
Generated extension pattern
co_await stream.collect(context, value);
co_await stream.collectError(context, failure);