Documentation
¶
Overview ¶
Package errparse turns the raw error output of a failed runner job into a typed compositeerrors.CompositeError.
Parsing is hierarchical: a single failure blob is a stack of nested errors (cloud-provider inside tool inside orchestration), and we want to surface the most specific layer, "Missing IAM permission s3:CreateBucket" rather than "terraform apply failed". Parsers therefore declare a Layer, and the registry tries the deepest (provider) layer first, then tool, then a generic emit-the-body fallback.
The deepest layer holds the most parsers and grows without bound, so gating must be cheap: a parser advertises the Tools it applies to (a free facet index) and the Signals that must be physically present in the text (a single compiled multi-pattern scan). A parser's expensive Parse only runs when its facet gate passes and one of its signals is present, so per-error cost is a function of the text length and the handful of matched candidates, not the total number of registered parsers.
Index ¶
- Constants
- func Parse(ctx *ParseContext) compositeerrors.CompositeError
- func ParseRunnerJobResult(success bool, errorMetadata map[string]string, runnerJob *app.RunnerJob) (*compositeerrors.CompositeErrorData, error)
- func Register(p Parser)
- func RunnerJobErrorText(errorMetadata map[string]string) string
- type Layer
- type Option
- type Owner
- type ParseContext
- type Parser
- type ParserFunc
- type Provider
- type Registry
- type Tool
Constants ¶
const ( ErrorMetadataOutput = "error_output" ErrorMetadataMessage = "message" )
Variables ¶
This section is empty.
Functions ¶
func Parse ¶
func Parse(ctx *ParseContext) compositeerrors.CompositeError
Parse dispatches ctx against the default registry.
func ParseRunnerJobResult ¶ added in v0.19.1058
func ParseRunnerJobResult(success bool, errorMetadata map[string]string, runnerJob *app.RunnerJob) (*compositeerrors.CompositeErrorData, error)
func RunnerJobErrorText ¶ added in v0.19.1058
Types ¶
type Layer ¶
type Layer int
Layer orders parsers from most-specific to generic. Lower layers are tried first, so a provider-level cause wins over the tool-level fallback.
const ( // LayerProvider is the cloud-provider layer (AWS/Azure/GCP error codes). LayerProvider Layer = 0 // LayerToolSpecific is for a specific, recognised cause within a tool (e.g. // terraform's state-lock failure). It is tried before LayerTool so a // specific classifier wins over the tool's catch-all, while a provider // cause still wins over both. LayerToolSpecific Layer = 9 // LayerTool is the execution-tool layer catch-all (terraform/helm/pulumi/ // docker): a recognised-but-unclassified diagnostic for that tool. LayerTool Layer = 10 // LayerGeneric is the always-matches fallback that emits the cleaned error // body when no specific parser recognises the failure. LayerGeneric Layer = 100 )
type Option ¶ added in v0.19.1059
type Option func(*builtParser)
Option customizes a Parser built by NewParser.
func AlwaysCandidate ¶ added in v0.19.1059
func AlwaysCandidate() Option
AlwaysCandidate opts the parser out of signal gating so it is a candidate for every job. It exists for the generic fallback; a normal parser should gate on WithSignals so it is not run against unrelated failures.
func WithProviders ¶ added in v0.19.1059
WithProviders gates the parser on the cloud provider the job targeted. The gate is applied after a signal match (provider resolution is a lazy lookup) and fails open: a job whose provider cannot be resolved still passes, so provider gating is only ever a false-positive guard. Passing no providers or ProviderUnknown is a configuration mistake and panics.
func WithSignals ¶ added in v0.19.1059
WithSignals gates the parser on substrings that must be present in the raw text; the parser's Parse only runs once one is found. At least one signal is required (use AlwaysCandidate for a deliberately signal-less parser).
type Owner ¶
Owner identifies the row a runner job belongs to (polymorphic: table name + id), e.g. ("install_deploys", "<id>").
type ParseContext ¶
type ParseContext struct {
// Raw is the untruncated error output captured from the job.
Raw string
// Tool is the execution tool, or ToolUnknown when it can't be determined.
Tool Tool
// Operation is the job operation (e.g. "apply-plan"), free-form.
Operation string
// Group is the runner job group (e.g. "deploy", "build", "sandbox").
Group string
// Owner is the row the job belongs to.
Owner Owner
// Meta carries the runner-sent error metadata (step, handler, job_type, ...).
Meta map[string]string
// ResolveProvider lazily resolves the cloud provider. It is optional: when
// nil, Provider() reports ProviderUnknown.
ResolveProvider func() Provider
// contains filtered or unexported fields
}
ParseContext carries the facets a parser gates and parses on. The free facets (Raw, Tool, Operation, Group, Owner, Meta) are populated eagerly by the caller from the already-loaded runner job; Provider is resolved lazily and memoized so an unmatched job never pays for the DB lookup.
func (*ParseContext) Provider ¶
func (c *ParseContext) Provider() Provider
Provider returns the cloud provider, resolving it at most once. It fails open to ProviderUnknown so an unresolvable owner never suppresses provider parsing (provider gating is a false-positive guard, never the sole gate).
type Parser ¶
type Parser interface {
// Layer places the parser in the specificity hierarchy.
Layer() Layer
// Tools are the execution tools this parser applies to. An empty slice
// means tool-agnostic (considered for every job). Used to bucket parsers
// for cheap facet-based narrowing.
Tools() []Tool
// Signals are substrings that must be present in the raw text for this
// parser to be a candidate. They are compiled into a single multi-pattern
// matcher per bucket. An empty slice means "always a candidate" (used by
// the generic fallback), which never runs the matcher.
Signals() []string
// Applicable confirms the parser should run after a signal match, using the
// finer facets (notably Provider). It must fail open on unknown facets.
Applicable(ctx *ParseContext) bool
// Parse attempts to produce a typed error, or returns nil to defer to the
// next candidate. It must be selective: a miss returns nil rather than a
// low-confidence match.
Parse(ctx *ParseContext) compositeerrors.CompositeError
}
Parser recognises one class of failure. Implementations must be pure and local: no DB or network access (the one lazy DB facet, Provider, is resolved by the context, not the parser).
func NewParser ¶ added in v0.19.1059
func NewParser(layer Layer, parse ParserFunc, opts ...Option) Parser
NewParser builds a Parser from its layer and parse behaviour plus optional facets. It covers the common case where a parser's gating is static, so a parser package registers a free function instead of a bespoke type with five one-line methods.
The registration models a three-stage candidate pipeline (cheapest first), with layer as the tiebreak once several parsers match:
WithTools structural bucket, considered before any text scan WithSignals / substrings that must be present (one cheap scan), or AlwaysCandidate opt out of signal gating (the generic fallback) WithProviders lazy provider gate applied after a signal match layer precedence when several parsers still match
layer and parse are required: there is no safe zero value for layer (the zero Layer is LayerProvider) and a nil parse panics. Exactly one of WithSignals or AlwaysCandidate must be given, so a parser that simply forgot its signals is rejected rather than silently running against every job.
The Parser interface remains the underlying contract; implement it directly when a parser must hold state or gate on facets these options do not cover (Operation, Group, Owner).
type ParserFunc ¶ added in v0.19.1059
type ParserFunc func(*ParseContext) compositeerrors.CompositeError
ParserFunc is the core recognise-and-classify behaviour of a parser: it attempts to produce a typed error from ctx, or returns nil to defer to the next candidate.
type Provider ¶
type Provider string
Provider is the cloud provider a job targeted. It is resolved lazily because it costs a DB lookup, and only matters once a provider-specific signal has already been found in the text.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry holds the registered parsers and dispatches a ParseContext to them. Parsers are grouped into facet buckets by Tool; within a bucket the signaled parsers share one compiled matcher. The bucket layout is built once, lazily, on the first Parse so that init-time registration order does not matter.
Registration is expected to happen entirely at init time (parser packages blank-imported at the chokepoint). Register panics if called after the first Parse, because a late parser would be silently dropped from the already-built buckets. That bug is far easier to catch as a panic than as a parser that mysteriously never fires.
Parsers are referenced by their index into r.parsers everywhere (buckets, dedup, candidates) rather than by interface value: a Parser may be any implementation, including a non-comparable struct, so it must never be used as a map key.
func (*Registry) Parse ¶
func (r *Registry) Parse(ctx *ParseContext) compositeerrors.CompositeError
Parse runs the applicable parsers against ctx and returns the first confident match in layer order (provider, then tool, then generic), or nil when nothing matches. Within a layer, ties are broken by registration order so dispatch is deterministic regardless of bucket collection order.
type Tool ¶
type Tool string
Tool is the underlying execution tool a runner job used. It is derived from the runner job type and used as a free facet to bucket parsers, so terraform parsers are never even considered for a helm job.
func ToolForRunnerJob ¶ added in v0.19.1058
Directories
¶
| Path | Synopsis |
|---|---|
|
Package all blank-imports every errparse parser package so their init() registrations land in the default registry.
|
Package all blank-imports every errparse parser package so their init() registrations land in the default registry. |
|
Package aws holds the AWS provider-layer CompositeError parsers: cloud error codes surfaced from a runner job's raw output.
|
Package aws holds the AWS provider-layer CompositeError parsers: cloud error codes surfaced from a runner job's raw output. |
|
Package errparsetest provides a shared, table-driven contract runner for errparse parsers.
|
Package errparsetest provides a shared, table-driven contract runner for errparse parsers. |
|
Package generic holds the tool-agnostic, always-matching fallback parser.
|
Package generic holds the tool-agnostic, always-matching fallback parser. |
|
Package helm holds tool-layer CompositeError parsers for helm jobs.
|
Package helm holds tool-layer CompositeError parsers for helm jobs. |
|
Package terraform holds tool-layer CompositeError parsers for terraform jobs.
|
Package terraform holds tool-layer CompositeError parsers for terraform jobs. |