trace

package
v0.4.2 Latest Latest
Warning

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

Go to latest
Published: Jun 19, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package trace provides the lightweight correlation primitives the gojira crawl uses to emit a reconstructable fan-out tree of log records.

A run is one crawl invocation; it owns a Span tree. Each span carries:

  • [RunID] — the same value across every record of one run.
  • [SpanID] — a fresh opaque short ID per logical unit of work.
  • [ParentSpanID] — the SpanID of whoever enqueued this work.
  • [TicketID] — the Jira issue key when work is issue-scoped.
  • [Phase] — one of the PhaseFetch, PhaseParse, … labels.
  • [Depth] — the issue's crawl depth (root = 0).

Span values are pure values: copy freely, no synchronization. The Span.Logger method returns a *slog.Logger pre-tagged with the span's non-empty correlation attributes, so every record the returned logger emits is auto-correlated without callers having to repeat With(...) at each call site.

IDs are opaque short hex strings drawn from crypto/rand. They are NOT path/hierarchical IDs — a crawl that bleeds across projects or boards is not sequential, so encoding lineage in the ID itself would lie about structure. The parent link reconstructs the tree without misrepresenting it.

This package has no project-internal imports; it depends only on the Go standard library.

Index

Constants

View Source
const (
	PhaseFetch        = "fetch"
	PhaseParse        = "parse"
	PhaseHierarchyJQL = "hierarchy_jql"
	PhaseDevStatus    = "dev_status"
	PhaseRender       = "render"
	PhaseStore        = "store"
	PhaseEnqueue      = "enqueue"
)

Phase labels a unit of work in the crawl pipeline. Producers stamp the current phase onto each span so records can be grouped, counted, and timed per phase without parsing free-text messages.

View Source
const (
	AttrRunID        = "run_id"
	AttrSpanID       = "span_id"
	AttrParentSpanID = "parent_span_id"
	AttrTicketID     = "ticket_id"
	AttrPhase        = "phase"
	AttrDepth        = "depth"
	AttrTraceStream  = "trace_stream"
)

Attribute keys for the canonical slog correlation fields. Centralising them here keeps producers (crawl, client/httplog) and consumers (jq filters, future TUI/MCP frontends) in agreement on names.

View Source
const (
	StreamResponse = "response" // external/data side (HTTP round-tripper)
	StreamStream   = "stream"   // internal/orchestration side (events/fan-out)
)

Trace-stream values. Both streams share run/ticket/span ids so a reader can pivot from "this response" to "the stream activity it caused" without re-correlating manually.

Variables

This section is empty.

Functions

func LoggerFrom

func LoggerFrom(ctx context.Context) *slog.Logger

LoggerFrom returns the logger stored on ctx by WithLogger, or nil if none has been set. A nil return is the caller's signal to fall back to a package-level or default logger.

func NewRunID

func NewRunID() string

NewRunID returns an opaque short identifier for a single crawl invocation: 12 hex characters (6 random bytes) — collision-resistant enough for the scale this tool runs at while staying short enough to scan visually in a terminal.

func NewSpanID

func NewSpanID() string

NewSpanID returns an opaque short identifier for one unit of work: 10 hex characters (5 random bytes). Slightly shorter than RunID because spans are far more numerous within a single run.

func WithLogger

func WithLogger(ctx context.Context, lg *slog.Logger) context.Context

WithLogger returns a derived context carrying lg, so a downstream component (notably the HTTP round-tripper added in phase-c-httptrace-1) can retrieve the active span-bound logger via LoggerFrom and tag its own records with the same correlation attributes.

Types

type Span

type Span struct {
	// RunID is constant across every span and every record of a run.
	RunID string

	// SpanID identifies this unit of work uniquely within the run.
	SpanID string

	// ParentSpanID links to the span that enqueued/spawned this one.
	// Empty for a root span.
	ParentSpanID string

	// TicketID is the Jira issue key (e.g. "PROJ-1417") when the
	// span is issue-scoped. Empty for cross-cutting work (the root
	// span, an end-of-run summary, etc.).
	TicketID string

	// Phase labels what this span is doing; see [PhaseFetch] et al.
	Phase string

	// Depth is the crawl depth at which this span operates; 0 for
	// the root and for seed issues, incremented by [Span.Child] when
	// fan-out enqueues children.
	Depth int
}

Span is a single unit of work in the crawl, carrying the correlation identity that ties its log lines (and the HTTP requests it triggers) into a reconstructable fan-out tree. Span is a value type; copy freely. There is no mutability concern.

func NewRoot

func NewRoot() Span

NewRoot mints a fresh root span — a new [RunID] and a fresh [SpanID] with no parent. The Phase / TicketID / Depth fields remain zero-valued because the root represents the whole invocation, not a specific per-issue task.

func (Span) Child

func (s Span) Child(phase, ticketID string, depth int) Span

Child mints a new span under s: same [RunID], a fresh [SpanID], and ParentSpanID set to s.SpanID. The supplied phase, ticketID, and depth become the child's identity.

This is the only fan-out primitive: every per-issue or per-API-call span in the crawl goes through Child, so the parent_span_id linkage is consistent across the codebase.

func (Span) Logger

func (s Span) Logger(base *slog.Logger) *slog.Logger

Logger returns base annotated with this span's non-empty correlation attributes via slog.Logger.With, so every record the returned logger emits is auto-tagged with run_id / span_id / parent_span_id (when present) / ticket_id / phase / depth.

A nil base is replaced with slog.Default so the method is safe to call from anywhere a logger may not have been threaded through yet. Empty correlation fields (e.g. the root span has no parent) are omitted rather than logged as empty strings, keeping records terse. Depth is always included because 0 is a meaningful value (the root / seed level) and the difference between "depth=0" and "absent" is information that downstream consumers can rely on.

Jump to

Keyboard shortcuts

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