correlation

package module
v0.0.0-...-e8da5e4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 28, 2026 License: MIT Imports: 12 Imported by: 0

README

correlation

correlation is the transport-neutral owner of correlation, request, and causation identifiers. It carries those semantics through HTTP, JSON-RPC, queues, scheduled work, webhooks, logs, and OpenTelemetry without creating a global propagator or redefining trace and idempotency concepts.

Semantics

  • CorrelationID groups one logical interaction or workflow.
  • RequestID identifies exactly one transport hop or delivery attempt.
  • CausationID identifies that hop's immediate parent request or message.

These types are deliberately distinct. Trace and span IDs remain owned by OpenTelemetry. Idempotency keys and fingerprints remain owned by idempotency. None of these values is authentication, authorization, tenancy, uniqueness, replay protection, or idempotency evidence.

Quick start

factory, err := correlation.NewFactory(correlation.FactoryOptions{})
if err != nil {
    return err
}

root, err := factory.Start()
if err != nil {
    return err
}
child, err := factory.Next(root)

The default factory uses an explicitly owned, bounded entropy buffer around the cryptographic UUIDv4 generator from identifier. A caller-supplied generator remains instance scoped and must return canonical text accepted by the configured policy.

Inbound metadata is never trusted by extraction alone:

inbound, err := codec.Extract(carrier)
if err != nil {
    return err
}
values, err := factory.Accept(inbound, correlation.InboundPolicy{
    TrustCorrelation: true,
    TrustRequestAsCausation: true,
})

The application must establish that trust from an authenticated immediate transport boundary first. Every accepted hop receives a new request ID.

Adapters

  • http sanitizes inbound headers, applies explicit proxy trust, installs immutable context values, and injects outbound hops.
  • http/requestidbridge explicitly adopts a trusted http-middleware/requestid value without importing its private key.
  • jsonrpc reads and writes a separate metadata object without altering JSON-RPC envelopes.
  • queue preserves workflow identity while generating a distinct request ID for every retry or redelivery.
  • schedule starts independent runs unless metadata is deliberately propagated.
  • webhook gives outbound and inbound webhook hops HTTP semantics.
  • log supplies redacted, keyed-hash, or explicitly raw slog attrs.
  • telemetry attaches attributes to telemetry-owned links and exposes only fixed-cardinality presence flags to metrics.

W3C Trace Context and Baggage remain optional application-owned propagation. They may be linked to these values, but correlation IDs never become trace or span IDs.

Deterministic correlation

NewDeterministic is an explicit opt-in for stable business workflows. It uses HMAC-SHA-256, a versioned domain, length-delimited input, and bounded output. Use a secret key when the input is private or comes from a small input space. Deterministic correlation is linkable and is never the factory default.

Security defaults

Identifiers use the canonical [A-Za-z0-9_-] alphabet and a default maximum of 128 bytes. Carriers reject empty, oversized, malformed, control-bearing, Unicode, and conflicting values. Injection refuses every populated target field. Observability output is redacted unless disclosure is explicitly enabled, and metrics never contain identifier values.

Verification

Run the local release-equivalent gate:

make check-all

It verifies formatting, module tidiness, vet, unit and integration tests, the race detector, 100% production statement coverage in every package, fuzz smoke tests, mutation tests, allocation benchmarks, documentation, API compatibility, linting, Staticcheck, vulnerability analysis, and NilAway.

See the documentation index, security policy, and changelog.

Ecosystem

Use the Golib documentation portal to choose companion packages, supported stacks, recipes, and operations guidance.

Documentation

Overview

Package correlation provides transport-neutral correlation, request, and causation identifiers. Identifiers are diagnostic metadata only; they are never authentication, authorization, tenancy, replay, or idempotency proof.

Index

Examples

Constants

View Source
const (
	// DefaultCorrelationField is the transport-neutral correlation key.
	DefaultCorrelationField = "correlation_id"
	// DefaultRequestField is the transport-neutral request key.
	DefaultRequestField = "request_id"
	// DefaultCausationField is the transport-neutral causation key.
	DefaultCausationField = "causation_id"
)

Variables

View Source
var (
	// ErrInvalidCarrier reports malformed, unbounded, or unsupported metadata.
	ErrInvalidCarrier = errors.New("correlation: invalid carrier")
	// ErrConflictingCarrier reports more than one distinct value for a field.
	ErrConflictingCarrier = errors.New("correlation: conflicting carrier values")
	// ErrCarrierOverwrite reports injection into an already populated field.
	ErrCarrierOverwrite = errors.New("correlation: carrier overwrite")
)
View Source
var (
	// ErrInvalidFactory reports invalid factory configuration.
	ErrInvalidFactory = errors.New("correlation: invalid factory")
	// ErrGeneration reports a generator failure or invalid generated value.
	ErrGeneration = errors.New("correlation: generation failed")
)
View Source
var ErrInvalidDerivation = errors.New("correlation: invalid deterministic derivation")

ErrInvalidDerivation reports unsafe deterministic derivation input or configuration.

View Source
var ErrInvalidDisclosure = errors.New("correlation: invalid disclosure policy")

ErrInvalidDisclosure reports unsafe disclosure configuration.

View Source
var ErrInvalidExternalID = errors.New("correlation: invalid external identifier")

ErrInvalidExternalID reports invalid external identifier metadata.

View Source
var ErrInvalidID = errors.New("correlation: invalid identifier")

ErrInvalidID reports an identifier that violates its validation policy.

View Source
var ErrInvalidPropagator = errors.New("correlation: invalid propagator")

ErrInvalidPropagator reports missing explicit propagation dependencies.

Functions

func Disclose

func Disclose(label, value string, policy DisclosurePolicy) (string, error)

Disclose renders an identifier according to an explicit observability policy. label domain-separates correlation, request, and causation hashes.

func WithValues

func WithValues(ctx context.Context, values Values) context.Context

WithValues returns a derived context carrying a copy of values.

Types

type Carrier

type Carrier interface {
	Values(key string) []string
	Set(key, value string)
}

Carrier is an explicit transport metadata boundary. Values must return a copy or immutable view. Set replaces one field with exactly one value.

type CausationID

type CausationID string

CausationID identifies the immediate parent request, message, or event.

func MustCausationID

func MustCausationID(value string, policy Policy) CausationID

MustCausationID is ParseCausationID for static configuration and tests.

func ParseCausationID

func ParseCausationID(value string, policy Policy) (CausationID, error)

ParseCausationID validates and returns a causation identifier.

func (CausationID) String

func (id CausationID) String() string

type Codec

type Codec struct {
	// contains filtered or unexported fields
}

Codec injects and extracts typed values without assigning trust.

func NewCodec

func NewCodec(options CodecOptions) (*Codec, error)

NewCodec validates and copies carrier configuration.

func (*Codec) Extract

func (codec *Codec) Extract(carrier Carrier) (Values, error)

Extract parses values but deliberately does not decide whether to trust them. Pass the result to Factory.Accept with an explicit InboundPolicy.

func (*Codec) Inject

func (codec *Codec) Inject(carrier Carrier, values Values) error

Inject installs non-empty values and refuses to overwrite any populated field, even when the existing value is malformed.

type CodecOptions

type CodecOptions struct {
	Policy           Policy
	CorrelationField string
	RequestField     string
	CausationField   string
}

CodecOptions configure immutable carrier field names and validation.

type CorrelationID

type CorrelationID string

CorrelationID groups work in one logical interaction or workflow.

func MustCorrelationID

func MustCorrelationID(value string, policy Policy) CorrelationID

MustCorrelationID is ParseCorrelationID for static configuration and tests.

func ParseCorrelationID

func ParseCorrelationID(value string, policy Policy) (CorrelationID, error)

ParseCorrelationID validates and returns a correlation identifier.

func (CorrelationID) String

func (id CorrelationID) String() string

type Deterministic

type Deterministic struct {
	// contains filtered or unexported fields
}

Deterministic derives linkable IDs for an explicitly stable workflow. It is never selected by Factory defaults and should be keyed for private inputs.

func NewDeterministic

func NewDeterministic(options DeterministicOptions) (*Deterministic, error)

NewDeterministic validates and copies deterministic strategy configuration.

func (*Deterministic) Derive

func (strategy *Deterministic) Derive(input []byte) (CorrelationID, error)

Derive hashes input with length-delimited, versioned domain separation.

type DeterministicOptions

type DeterministicOptions struct {
	Domain  string
	Version uint32
	Key     []byte
	Length  int
}

DeterministicOptions configure an explicitly opted-in stable strategy.

type DisclosureMode

type DisclosureMode uint8

DisclosureMode controls identifier disclosure to logs and telemetry.

const (
	// RedactDisclosure is the safe default and emits only a marker.
	RedactDisclosure DisclosureMode = iota
	// HashDisclosure emits a keyed, domain-separated stable token.
	HashDisclosure
	// ExposeDisclosure emits validated raw identifier text.
	ExposeDisclosure
)

type DisclosurePolicy

type DisclosurePolicy struct {
	Mode DisclosureMode
	Key  []byte
}

DisclosurePolicy must explicitly opt into linkable or raw output.

type ExternalID

type ExternalID struct {
	// contains filtered or unexported fields
}

ExternalID is an optional typed external identifier with explicit source and trust metadata. It is not implicitly promoted to any correlation ID.

func NewExternalID

func NewExternalID(options ExternalIDOptions) (ExternalID, error)

NewExternalID validates and copies external metadata.

func (ExternalID) Kind

func (external ExternalID) Kind() string

Kind returns the external identifier's declared semantic kind.

func (ExternalID) Source

func (external ExternalID) Source() string

Source returns the declared transport or system source.

func (ExternalID) Trusted

func (external ExternalID) Trusted() bool

Trusted reports the caller's explicit trust decision.

func (ExternalID) Value

func (external ExternalID) Value() string

Value returns the validated external identifier text.

type ExternalIDOptions

type ExternalIDOptions struct {
	Kind    string
	Value   string
	Source  string
	Trusted bool
	Policy  Policy
}

ExternalIDOptions require the caller to state type, source, and trust.

type Factory

type Factory struct {
	// contains filtered or unexported fields
}

Factory creates fresh hop identifiers without global mutable state.

func NewFactory

func NewFactory(options FactoryOptions) (*Factory, error)

NewFactory constructs a factory. The default generator uses crypto/rand.

func (*Factory) Accept

func (factory *Factory) Accept(inbound Values, policy InboundPolicy) (Values, error)

Accept starts a receiving hop. No inbound value is used unless its exact semantic trust is enabled.

func (*Factory) Next

func (factory *Factory) Next(parent Values) (Values, error)

Next preserves correlation, creates a request ID, and makes the prior request the immediate cause.

Example
generator := &sequenceGenerator{values: []string{"child-request"}}
factory, _ := correlation.NewFactory(correlation.FactoryOptions{Generator: generator})
parent := correlation.Values{
	CorrelationID: correlation.MustCorrelationID("workflow", correlation.Policy{}),
	RequestID:     correlation.MustRequestID("parent-request", correlation.Policy{}),
}
child, _ := factory.Next(parent)
fmt.Println(child.CorrelationID, child.RequestID, child.CausationID)
Output:
workflow child-request parent-request

func (*Factory) Start

func (factory *Factory) Start() (Values, error)

Start creates a new correlation and request identifier.

type FactoryOptions

type FactoryOptions struct {
	Policy    Policy
	Generator Generator
}

FactoryOptions configure an immutable Factory.

type Generator

type Generator interface {
	New() (string, error)
}

Generator supplies canonical random identifier text. It is structurally compatible with identifier.Generator[string] from identifier.

type GeneratorFunc

type GeneratorFunc func() (string, error)

GeneratorFunc adapts a function to Generator.

func (GeneratorFunc) New

func (function GeneratorFunc) New() (string, error)

New calls the wrapped function.

type InboundPolicy

type InboundPolicy struct {
	TrustCorrelation        bool
	TrustRequestAsCausation bool
}

InboundPolicy explicitly identifies which inbound semantics cross a trust boundary. Request IDs are never preserved because each hop gets a new one.

type Policy

type Policy struct {
	MaxLength int
}

Policy bounds and validates an identifier. The zero value accepts the canonical ASCII alphabet [A-Za-z0-9_-] up to 128 bytes.

type Propagator

type Propagator struct {
	// contains filtered or unexported fields
}

Propagator explicitly composes hop generation with a transport codec.

func NewPropagator

func NewPropagator(factory *Factory, codec *Codec) (*Propagator, error)

NewPropagator rejects ambient or incomplete propagation configuration.

func (*Propagator) Receive

func (propagator *Propagator) Receive(carrier Carrier, policy InboundPolicy) (Values, error)

Receive extracts untrusted metadata and applies an explicit trust policy while creating a fresh delivery-attempt request ID.

func (*Propagator) Send

func (propagator *Propagator) Send(carrier Carrier, parent Values) (Values, error)

Send creates the next hop before injecting its values.

type RequestID

type RequestID string

RequestID identifies one transport request or delivery attempt.

func MustRequestID

func MustRequestID(value string, policy Policy) RequestID

MustRequestID is ParseRequestID for static configuration and tests.

func ParseRequestID

func ParseRequestID(value string, policy Policy) (RequestID, error)

ParseRequestID validates and returns a request identifier.

func (RequestID) String

func (id RequestID) String() string

type Values

type Values struct {
	CorrelationID CorrelationID
	RequestID     RequestID
	CausationID   CausationID
}

Values carries the three deliberately distinct identifier semantics.

func FromContext

func FromContext(ctx context.Context) (Values, bool)

FromContext returns values installed by WithValues.

Directories

Path Synopsis
Package httpcorrelation explicitly propagates correlation metadata over HTTP.
Package httpcorrelation explicitly propagates correlation metadata over HTTP.
requestidbridge
Package requestidbridge integrates explicitly with request ID middleware such as http-middleware/requestid without importing hidden context keys.
Package requestidbridge integrates explicitly with request ID middleware such as http-middleware/requestid without importing hidden context keys.
Package jsonrpc propagates correlation through an explicit JSON-RPC metadata object.
Package jsonrpc propagates correlation through an explicit JSON-RPC metadata object.
Package log provides bounded slog attributes compatible with log's standard log/slog composition API.
Package log provides bounded slog attributes compatible with log's standard log/slog composition API.
Package queue propagates correlation metadata through backend-neutral queue metadata maps.
Package queue propagates correlation metadata through backend-neutral queue metadata maps.
Package schedule provides explicit correlation lifecycle helpers for scheduled work.
Package schedule provides explicit correlation lifecycle helpers for scheduled work.
Package telemetry links correlation metadata to OpenTelemetry without treating correlation IDs as trace or span IDs.
Package telemetry links correlation metadata to OpenTelemetry without treating correlation IDs as trace or span IDs.
Package webhook provides an explicit webhook-named HTTP correlation adapter.
Package webhook provides an explicit webhook-named HTTP correlation adapter.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL