SAService Architect Open designer
SAService ArchitectDocumentation
Framework reference Context + Stream + Collector + Environment

C++ userver Runtime values and outputs

Core C++ userver 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.

Type or methodRoleDescription
servicelib::MessageContextPer-message context

Carries stream ID and runtime propagation state. Pass or move it into every output so downstream work remains correlated.

servicelib::ContextLifecycle context

Used by maker and service lifecycle code; it is distinct from the per-message MessageContext.

servicelib::StreamBaseStream metadata

Reference to the generated stream currently invoking the callable.

Output / ErrorOutputCallable outputs

Framework-supplied adapters. out(context, value) or .out(context, value) emits normal or error values according to the generated callable signature.

servicelib::Payload<T>Shared payload

Owns or shares a typed value across asynchronous graph calls without forcing unnecessary copies.

servicelib::SourceStreamContext<T, R, E>Source endpoint context

collect and collectError emit decoded values and typed failures.

servicelib::SinkStreamContext<T, R, E>Sink endpoint context

collect emits transport results and collectError emits typed failures.

servicelib::BeginResult<State>Endpoint begin result

Returns the message context and request-local handler state together.

servicelib::IServiceEnvironmentMaker dependency

Exposes runtime configuration, logger, metrics, tracing, and registered service dependencies.

Generated extension pattern

stream.collect(std::move(context), std::move(value));
stream.collectError(std::move(context), error);