node

package
v0.0.0-...-885efd1 Latest Latest
Warning

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

Go to latest
Published: Feb 6, 2026 License: MIT Imports: 36 Imported by: 0

Documentation

Index

Constants

View Source
const (
	OTELExceptionTypeError otelExceptionTypes = "error"
	OTELExceptionTypePanic otelExceptionTypes = "panic"
)

Variables

This section is empty.

Functions

func AddSpanAttributes

func AddSpanAttributes(
	span trace.Span,
	values map[string]any,
)

AddSpanAttributes adds the values to the current span. If the span is nil (such as if otel wasn't initialized or no span has been generated), this call no-ops.

func AddToOTELHTTPLabeler

func AddToOTELHTTPLabeler(labeler otelHTTPLabeler) addAttrOptions

AddToOTELHTTPLabeler adds the values to the otelHTTPLabeler, which will hold the values in reserve until the next span creation. Naturally, the values will not be added to the current span.

func AsTraceMapCarrier

func AsTraceMapCarrier[C TraceMapCarrierBase](
	carrier C,
) propagation.TextMapCarrier

AsTraceMapCarrier converts a traceMapCarrier interface to its propagation package implementation for that structure. ie: map becomes a MapCarrier, headers become HeaderCarriers.

func CloseSpan

func CloseSpan(ctx context.Context)

CloseSpan closes the otel span. If no span is present, no ops.

func DoNotAddToSpan

func DoNotAddToSpan() addAttrOptions

DoNotAddToSpan prevents the values from being added to the current span.

func EmbedInCtx

func EmbedInCtx(ctx context.Context, dn *Node) context.Context

EmbedInCtx adds the node in the context, and returns the updated context.

func GetCaller

func GetCaller(depth int) string

GetCaller retrieves the func name of the caller. Depth is the skip-caller count. Clues funcs that call this one should provide either `1` (if they do not already have a depth value), or `depth+1` otherwise.`

func GetDirAndFile

func GetDirAndFile(
	depth int,
) (dir, fileAndLine, parentAndFileAndLine string)

GetDirAndFile retrieves the file and line number of the caller. Depth is the skip-caller count. Clues funcs that call this one should provide either `1` (if they do not already have a depth value), or `depth+1` otherwise`.

formats: dir `absolute/os/path/to/parent/folder` fileAndLine `<file>:<line>` parentAndFileAndLine `<parent>/<file>:<line>`

func GetSpan

func GetSpan(ctx context.Context) trace.Span

GetSpan retrieves the current otel span from the context. As a sanity measure, ensures the span is not nil. If nil, it returns a noop span.

func InheritAttrs

func InheritAttrs(from, to context.Context, clobber bool) context.Context

InheritAttrs propagates all attributes from one context to another. Clients are not propagated. If attributes exists in the `to` ctx, it is returned unchanged unless clobber=true.

func MapToOTELAttribute

func MapToOTELAttribute(k string, v any) attribute.KeyValue

MapToOTELAttribute converts a single key/value to an otel attribute. Values are type-preserved where possible; everything else stringifies.

func MapToOTELAttributes

func MapToOTELAttributes(m map[string]any) []attribute.KeyValue

MapToOTELAttributes converts a map to otel attributes using shared stringification.

func OTELHTTPLabelerFromCtx

func OTELHTTPLabelerFromCtx(ctx context.Context) (context.Context, otelHTTPLabeler)

OTELHTTPLabelerFromCtx retrieves the current otel http labeler from the context. If no labeler is present, it will create a new one and add it to the context.

func SetSpanError

func SetSpanError(
	ctx context.Context,
	err error,
	msg string,
	exceptionType otelExceptionTypes,
)

SetSpanError sets the span status to error and records the error in the span. If the span is nil, this call no-ops.

Types

type Agent

type Agent struct {
	// the name of the agent
	ID string

	// Data is used here instead of a basic value map so that
	// we can extend the usage of agents in the future by allowing
	// the full set of node behavior.  We'll need a builder for that,
	// but we'll get there eventually.
	Data *Node
}

type Annotation

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

func NewAttribute

func NewAttribute(k string, v any) Annotation

func (Annotation) IsAttribute

func (a Annotation) IsAttribute() bool

func (Annotation) KV

func (a Annotation) KV() otelLog.KeyValue

type Annotationer

type Annotationer interface {
	IsAttribute() bool
	KV() attribute.KeyValue
}

type CluesCtxKey

type CluesCtxKey string

func CtxKey

func CtxKey(namespace string) CluesCtxKey

type Comment

type Comment struct {
	// the func name in which the comment was created.
	Caller string
	// the name of the file owning the caller.
	File string
	// the comment message itself.
	Message string
}

func NewComment

func NewComment(
	depth int,
	template string,
	values ...any,
) Comment

NewComment formats the provided values, and grabs the caller and trace info according to the depth. Depth is a skip-caller count, and any func calling this one should provide either `1` (for itself) or `depth+1` (if it was already given a depth value).

func (Comment) IsEmpty

func (c Comment) IsEmpty() bool

shorthand for checking if an empty comment was generated.

type CommentHistory

type CommentHistory []Comment

CommentHistory allows us to put a stringer on a slice of CommentHistory.

func (CommentHistory) String

func (cs CommentHistory) String() string

String formats the slice of comments as a stack, much like you'd see with an error stacktrace. Comments are listed top-to-bottom from first- to-last.

The format for each comment in the stack is:

<caller> - <file>:<line>
  <message>

type Node

type Node struct {
	Parent *Node

	// OTEL contains the client instance for the in memory OTEL runtime.  It is only
	// present if the end user calls the clues initialization step.
	OTEL *OTELClient

	// ids are optional and are used primarily as tracing markers.
	// if empty, the trace for that node will get skipped when building the
	// full trace along the node's ancestry path in the tree.
	ID string

	// Values are they arbitrary key:value pairs that appear in clues when callers
	// use the Add(ctx, k, v) or err.With(k, v) adders.  Each key-value pair added
	// to the node is used to produce the final set of Values() in the node,
	// with lower nodes in the tree taking priority over higher nodes for any
	// collision resolution.
	Values map[string]any

	// each node can hold a single comment.  The history of comments produced
	// by the ancestry path through the tree will get concatenated from oldest
	// ancestor to the current node to produce the Comment history.
	Comment Comment

	// Agents act as proxy node that can relay specific, intentional data
	// additions.  They're namespaced so that additions to the Agents don't accidentally
	// clobber other values in the node. This also allows Agents to protect
	// variations of data from each other, in case users need to compare differences
	// on the same keys.  That's not the goal for Agents, exactly, but it is capable.
	Agents map[string]*Agent
}

Node contains the data tracked by both clues in contexts and in errors.

These nodes compose a tree, such that nodes can walk their ancestry path from leaf (the current node) to root (the highest ancestor), but not from root to child. This allows clues to establish sets of common ancestor data with unique branches for individual descendants, making the addition of new data inherently theadsafe.

For collisions during aggregation, distance from the root denotes priority, with the root having the lowest priority. IE: if a child overwrites a key declared by an ancestor, the child's entry takes priority.

func FromBytes

func FromBytes(bs []byte) (*Node, error)

FromBytes deserializes the bytes to a new Node. No clients, agents, or hooks are initialized in this process.

func FromCtx

func FromCtx(ctx context.Context) *Node

FromCtx pulls the node within a given namespace out of the context.

func (*Node) AddAgent

func (dn *Node) AddAgent(name string) *Node

AddAgent adds a new named agent to the node.

func (*Node) AddComment

func (dn *Node) AddComment(
	depth int,
	msg string,
	vs ...any,
) *Node

AddComment creates a new nodewith a comment but no other properties.

func (*Node) AddSpan

func (dn *Node) AddSpan(
	ctx context.Context,
	name string,
	kvs map[string]any,
	opts ...trace.SpanStartOption,
) context.Context

AddSpan adds a new otel span in a new node. If the otel client is nil, a new node is still generated with the providede name and kvs, but no otel span is created.

func (*Node) AddToOTELHTTPLabeler

func (dn *Node) AddToOTELHTTPLabeler(
	labeler otelHTTPLabeler,
	m map[string]any,
)

AddToOTELHTTPLabeler adds the values to the current otel http labeler. If the labeler was not initialized, this call no-ops, but will not panic (by guarantees of the otelhttp package).

The labeler will defer the addition of these attrs until the next time that the otelhttp transport runs a request.

func (*Node) AddValues

func (dn *Node) AddValues(
	ctx context.Context,
	m map[string]any,
	opts ...addAttrOptions,
) *Node

AddValues adds all entries in the map to the node's values. automatically propagates values onto the current span.

func (*Node) Bytes

func (dn *Node) Bytes() ([]byte, error)

Bytes serializes the Node to a slice of bytes. Only attributes and comments are maintained. All values are stringified in the process.

Node hierarchy, clients (such as otel), agents, and hooks (such as labelCounter) are all sliced from the result.

func (*Node) Comments

func (dn *Node) Comments() CommentHistory

Comments retrieves the full ancestor comment chain. The return value is ordered from the first added comment (closest to the root) to the most recent one (closest to the leaf).

func (*Node) InitOTEL

func (dn *Node) InitOTEL(
	ctx context.Context,
	name string,
	config OTELConfig,
) error

InitOTEL sets up persistent clients in the clues ecosystem such as otel. Initialization is NOT required. It is an optional step that end users can take if and when they want those clients running in their clues instance.

Multiple initializations will no-op.

func (*Node) InjectTrace

func (dn *Node) InjectTrace(
	ctx context.Context,
	carrier propagation.TextMapCarrier,
)

injectTrace adds the current trace details to the provided carrier. If otel is not initialized, no-ops.

The carrier data is mutated by this call.

func (*Node) Map

func (dn *Node) Map() map[string]any

Map flattens the tree of node.values into a map. Descendant nodes take priority over ancestors in cases of collision.

func (*Node) OTELAttributes

func (dn *Node) OTELAttributes() []attribute.KeyValue

OTELAttributes flattens the node values into attribute.KeyValue entries. Values are stringified using the shared stringify rules to keep consistency across telemetry systems.

func (*Node) OTELLogger

func (dn *Node) OTELLogger() otelLog.Logger

logger gets the otel logger instance from the otel client. Returns nil if otel wasn't initialized.

func (*Node) OTELMeter

func (dn *Node) OTELMeter() metric.Meter

OTELMeter gets the otel logger instance from the otel client. Returns nil if otel wasn't initialized.

func (*Node) ReceiveTrace

func (dn *Node) ReceiveTrace(
	ctx context.Context,
	carrier propagation.TextMapCarrier,
) context.Context

receiveTrace extracts the current trace details from the carrier and adds them to the context. If otel is not initialized, no-ops.

The carrier data is mutated by this call.

func (*Node) RunLineage

func (dn *Node) RunLineage(fn func(id string, vs map[string]any))

RunLineage runs the fn on every valueNode in the ancestry tree, starting at the root and ending at the node.

func (*Node) SetValues

func (dn *Node) SetValues(m map[string]any)

SetValues is generally a helper called by addValues. In certain corner cases (like agents) it may get called directly.

func (*Node) Slice

func (dn *Node) Slice() []any

Slice flattens the tree of node.values into a Slice where all even indices contain the keys, and all odd indices contain values. Descendant nodes take priority over ancestors in cases of collision.

func (*Node) SpawnDescendant

func (dn *Node) SpawnDescendant() *Node

SpawnDescendant generates a new node that is a descendant of the current node. A descendant maintains a pointer to its parent, and carries any genetic necessities (ie, copies of fields) that must be present for continued functionality.

type Noder

type Noder interface {
	Node() *Node
}

type OTELClient

type OTELClient struct {
	ServiceName string

	LoggerProvider *sdkLog.LoggerProvider
	Logger         otelLog.Logger

	MeterProvider *sdkMetric.MeterProvider
	Meter         metric.Meter

	TracerProvider *sdkTrace.TracerProvider
	Tracer         trace.Tracer
	// contains filtered or unexported fields
}

func NewOTELClient

func NewOTELClient(
	ctx context.Context,
	serviceName string,
	config OTELConfig,
) (*OTELClient, error)

NewOTELClient bootstraps the OpenTelemetry pipeline to run against a local server instance. If it does not return an error, make sure to call the client.Close() method for proper cleanup. The service name is used to match traces across backends.

func (*OTELClient) Close

func (cli *OTELClient) Close(ctx context.Context) error

type OTELConfig

type OTELConfig struct {
	// Resource contains information about the thing sourcing logs, metrics, and
	// traces in OTEL. This information will be available in backends on all logs
	// traces, and metrics that are generated from this source.
	//
	// The provided resource should represent the service that's initializing
	// clues. The resource should encapsulate all parts of the metrics that need
	// reporting, not just a subset of them (i.e. it represents the "root" of the
	// information that will be reported to OTEL).
	//
	// If not provided, a minimal Resource containing the service name will be
	// created.
	Resource *resource.Resource

	// specify the endpoint location to use for grpc communication.
	// If empty, no telemetry exporter will be generated.
	// ex: localhost:4317
	// ex: 0.0.0.0:4317
	GRPCEndpoint string

	// Filter contains the filter used when copying baggage to a span, by adding span
	// attributes. If no filter is specified, all baggage is copied over to a span.
	Filter baggagecopy.Filter

	// MeterExporterOpts contains options to apply to the meter provider's exporter.
	MeterExporterOpts []otlpmetricgrpc.Option
}

type TraceMapCarrierBase

type TraceMapCarrierBase interface {
	map[string]string | http.Header
}

TraceMapCarrierBase defines the structures that support otel TraceMapCarrier behavior. A traceMapCarrier is used to pass and receive traces using message delivery headers and other metadata.

Jump to

Keyboard shortcuts

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