Documentation
¶
Overview ¶
Package resolog is a resource-aware CloudWatch log tailer.
Most tools answer "how do I tail a log group?" (lucagrulla/cw, aws logs tail, StartLiveTail). resolog answers the question that comes before that: "given a resource, what should I even tail?" — and then interleaves every stream it discovers, docker-compose style.
The design has three orthogonal seams. A consumer can plug in at any of them; nothing forces data through the whole stack.
Resolver resource reference -> log sources (+ a terminal signal) Backend a log source -> a stream of events Sink a stream of events -> output (the default Sink is a TUI renderer)
The primary Resolver is sfn-execution: hand it a Step Functions execution ARN and it resolves the state machine plus every Lambda / Batch / ECS task it ran, and tails them all together.
This package (the module root) is the core: the interface contracts and the Tail orchestrator that wires a Resolution through a Backend into a Sink. Resolvers and Backends live in subpackages and are composed explicitly by the consumer — there is no global registry and no plugin system. See cmd/resolog for the reference wiring, including the scheme dispatch table.
Index ¶
Constants ¶
const DefaultGracePeriod = 5 * time.Second
DefaultGracePeriod is how long Tail keeps streaming after a Resolution reports Done, to catch log lines CloudWatch delivers late. See Resolution.Done.
Variables ¶
This section is empty.
Functions ¶
func Tail ¶
Tail is the core orchestrator. It reads sources out of res as they are discovered, opens a Backend stream for each, merges everything into one interleaved channel, and feeds that to sink. It returns when:
- all sources have ended (historical backends drain naturally), or
- res.Done fires and the grace period elapses (terminal resource), or
- ctx is cancelled (Ctrl-C), or
- sink.Consume returns.
Completion is driven by res.Done (resource status), never by inferring that "the logs stopped" — that inference is wrong often enough to be useless.
Types ¶
type Backend ¶
type Backend interface {
// Stream returns a channel of Events for src. The channel is closed when
// the stream ends (historical exhausted, or ctx cancelled). A live backend
// only ends on ctx cancellation.
Stream(ctx context.Context, src Source) (<-chan Event, error)
}
Backend turns a Source into a stream of Events. Implementations: livetail (StartLiveTail, real-time) and poll (FilterLogEvents, historical).
type Event ¶
type Event struct {
Source Source
Timestamp time.Time // the event time reported by CloudWatch
Message string
Ingestion time.Time // when CloudWatch ingested it (may lag Timestamp)
}
Event is one log line, tagged with the Source it came from.
type FilterSink ¶ added in v0.4.0
FilterSink wraps another Sink and forwards only events Keep accepts. It is the client-side counterpart to a Backend's server-side filter pattern (e.g. --grep vs. --filter in the CLI): every event still flows through the pipeline, but only the ones Keep returns true for reach Inner.
Composition order matters when FilterSink wraps a SortingSink: put FilterSink on the outside (Tail's sink = FilterSink{Inner: sortingSink, ...}) so dropped events never occupy space in the sort buffer, rather than the other way around.
func (FilterSink) Consume ¶ added in v0.4.0
func (f FilterSink) Consume(ctx context.Context, events <-chan Event) error
Consume implements Sink. It mirrors SortingSink.Consume's discipline: relay the kept subset of events to Inner via an intermediate channel that this method owns and closes, then wait for Inner.Consume to return.
On ctx cancellation, Consume still closes out and waits for Inner to unwind (as SortingSink waits for its flush) before returning, but reports ctx.Err() rather than whatever Inner returned — cancellation is the authoritative reason Consume is ending.
type JSONSink ¶ added in v0.4.0
JSONSink is a Sink that writes one compact JSON object per event, one per line (JSON Lines) — the machine-readable counterpart to the Renderer, for piping into jq and friends. It is the canonical "supply your own Sink" example the Sink contract mentions.
The field order and naming are stable and part of the output contract:
{"time":"...","group":"...","stream":"...","label":"...","message":"..."}
time is the event's reported timestamp in RFC3339Nano, falling back to its ingestion time when the former is absent — the same rule the Renderer and SortingSink apply. stream is omitted when the source is group-wide (no single stream).
type Lister ¶
type Lister interface {
// List returns the refs matching filter (a prefix, status, etc. — the exact
// meaning is resolver-defined).
List(ctx context.Context, filter string) ([]ResourceRef, error)
}
Lister is the inverse of a Resolver: where Resolve maps ref -> sources, List maps a kind -> the refs that exist. It is an optional, separate interface so a Resolver can implement it (or not); CLI code type-asserts for it to offer "list -> pick -> tail" in one step.
Cleanly enumerable kinds have an enumerate API (log groups, SFn executions, Batch jobs, Lambdas). EC2 does not ("does this instance even have logs?"), so it is deliberately not a List target.
type MapSink ¶ added in v0.4.0
MapSink wraps another Sink and passes every event through Map before forwarding it to Inner. It is the transformation counterpart to FilterSink: where FilterSink decides whether an event proceeds, MapSink decides what it looks like when it does (the CLI's --fields JSON-field extraction is the motivating consumer). A nil Map forwards events unchanged.
func (MapSink) Consume ¶ added in v0.4.0
Consume implements Sink. It mirrors FilterSink.Consume's discipline: relay the (mapped) events to Inner via an intermediate channel that this method owns and closes, then wait for Inner.Consume to return.
On ctx cancellation, Consume still closes out and waits for Inner to unwind before returning, but reports ctx.Err() rather than whatever Inner returned — cancellation is the authoritative reason Consume is ending.
type Option ¶
type Option func(*options)
Option configures Tail.
func WithErrorHandler ¶
WithErrorHandler registers a callback invoked when a Backend fails to open a stream for a source. Without it such errors are silent — which, with a live backend, looks indistinguishable from "no logs yet", so the CLI sets one.
func WithGracePeriod ¶
WithGracePeriod overrides how long Tail keeps streaming after Done fires.
type Renderer ¶
type Renderer struct {
// Out is where lines are written. Defaults to os.Stdout when nil is passed
// to NewRenderer.
Out io.Writer
// Color enables ANSI color. Callers typically set this from isatty.
Color bool
// ShowTime prepends each line with the event timestamp.
ShowTime bool
// MaxGutter caps the width (in runes) of the label gutter. Labels longer
// than this are middle-ellipsized so a long resource name (e.g. a folded log
// stream id) can't push every message off the right edge. 0 means no cap —
// appropriate when output is piped, so downstream tools see full labels. The
// CLI sets it from the terminal width.
MaxGutter int
// contains filtered or unexported fields
}
Renderer is the default Sink: a docker-compose-style interleaved printer that assigns each Source a stable color and prefixes every line with its label.
It is intentionally simple (one line per event, no progress bar / paging). The richer TUI ("k9s for CloudWatch") is a later, separate Sink — keeping this one minimal preserves the small public surface the design calls for.
func NewRenderer ¶
NewRenderer builds a Renderer writing to out (os.Stdout if nil).
type Resolution ¶
type Resolution struct {
// Sources delivers log sources as they are discovered. It is closed once
// discovery is complete (no more sources will ever appear).
Sources <-chan Source
// Done is closed when the resource reaches a terminal state (job SUCCEEDED,
// execution FAILED…). It drives --follow shutdown. A nil Done means the
// resource is never terminal (e.g. a bare log group), so following runs
// until the caller cancels the context.
//
// Completion MUST be driven by resource status, never by "logs went quiet":
// CloudWatch lags, and the last lines often arrive after the resource ends.
// Tail applies a grace period after Done before stopping. Keeping this as a
// signal (not a return value) prevents Batch/SFn status logic from leaking
// into the tailer.
Done <-chan struct{}
}
Resolution is the live result of resolving a reference. Sources may grow over time (a running Step Functions execution spawns tasks); Done reports that the underlying resource has reached a terminal state.
type Resolver ¶
type Resolver interface {
// Scheme is the reference prefix this Resolver handles, e.g.
// "sfn-execution" or "batch-job". Used by CLI-level scheme dispatch.
Scheme() string
// Resolve turns a reference into a Resolution. ref is the scheme-stripped
// remainder (an ARN, a name, a job id…). Resolve should return quickly;
// ongoing discovery happens on the returned channels.
Resolve(ctx context.Context, ref string) (Resolution, error)
}
Resolver maps a resource reference to the log sources it produces. Resolvers are the primary extension point: log-group, batch-job, sfn-execution, lambda…
A Resolver is just a package that returns a New() value; consumers wire them explicitly. There is deliberately no global registry.
type ResourceRef ¶
type ResourceRef struct {
Scheme string // the Resolver scheme this ref belongs to
Ref string // the scheme-stripped reference, ready to pass to Resolve
Label string
Status string // e.g. "RUNNING", "SUCCEEDED" (resolver-defined)
StartedAt time.Time
}
ResourceRef is one entry from a Lister: a reference that could be tailed, plus enough metadata to show it in a picker.
type Sink ¶
type Sink interface {
// Consume reads events until the channel is closed or ctx is cancelled,
// then returns. The error is propagated out of Tail.
Consume(ctx context.Context, events <-chan Event) error
}
Sink consumes the merged, interleaved event stream. The default Sink is the renderer in this package; a consumer can supply its own (JSON, custom TUI…).
type SortingSink ¶
SortingSink buffers every event and, once the stream ends, emits them to Inner ordered by event time. Tail interleaves sources by arrival, not by timestamp, so reviewing a finished resource (e.g. a completed Step Functions execution tailed with poll + --since) otherwise reads out of order across streams.
It holds all events in memory and prints nothing until the stream closes, so it suits only bounded, historical tailing — not follow mode or the live backend, where the stream never ends. The CLI's --sort flag wires it and requires `--backend poll` without `-f`.
Limit caps how many events it will buffer; past it Consume returns an error rather than growing without bound (OOM). 0 means unlimited. Bound the input with --since/--until instead of relying on a huge limit.
If the context is cancelled (Ctrl-C) mid-fetch, it still flushes the ordered prefix it has buffered rather than discarding everything. Ordering is content-stable (see lessEvent), so the same events always print in the same order — golden-test friendly and free of spurious diff churn.
type Source ¶
type Source struct {
// Key is a stable identifier used for color assignment and de-duplication.
// It must be unique per logical stream within a run.
Key string
// Label is the short human-facing name shown in the output gutter,
// e.g. "lambda/ingest" or "batch[3]".
Label string
// LogGroup is the CloudWatch Logs log group name.
LogGroup string
// LogStream optionally narrows to a single stream within the group.
// Empty means "all streams in the group".
LogStream string
}
Source is a single resolved log stream to tail. A Resolver emits these as it discovers them; a Backend turns each one into a stream of Events.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
backend
|
|
|
livetail
Package livetail is the real-time Backend, built on CloudWatch Logs StartLiveTail.
|
Package livetail is the real-time Backend, built on CloudWatch Logs StartLiveTail. |
|
poll
Package poll is the historical Backend: it pages CloudWatch Logs with FilterLogEvents rather than tailing live.
|
Package poll is the historical Backend: it pages CloudWatch Logs with FilterLogEvents rather than tailing live. |
|
cmd
|
|
|
resolog
command
Command resolog is the reference CLI for the resolog library.
|
Command resolog is the reference CLI for the resolog library. |
|
resolver
|
|
|
batch
Package batch resolves AWS Batch jobs into their CloudWatch log sources.
|
Package batch resolves AWS Batch jobs into their CloudWatch log sources. |
|
batchqueue
Package batchqueue resolves an AWS Batch job queue into the log sources of every job currently active in it — submitted, waiting, or running — tailing them all together and picking up newly submitted jobs as they arrive.
|
Package batchqueue resolves an AWS Batch job queue into the log sources of every job currently active in it — submitted, waiting, or running — tailing them all together and picking up newly submitted jobs as they arrive. |
|
cfnstack
Package cfnstack resolves a CloudFormation stack into the log sources of everything in it that logs — "I just deployed this stack, show me all its logs." One ListStackResources walk maps resource types:
|
Package cfnstack resolves a CloudFormation stack into the log sources of everything in it that logs — "I just deployed this stack, show me all its logs." One ListStackResources walk maps resource types: |
|
codebuild
Package codebuild resolves a CodeBuild build or project into its CloudWatch log source.
|
Package codebuild resolves a CodeBuild build or project into its CloudWatch log source. |
|
ecs
Package ecs resolves an ECS task into its CloudWatch log sources, one per container that uses the awslogs driver.
|
Package ecs resolves an ECS task into its CloudWatch log sources, one per container that uses the awslogs driver. |
|
ecsservice
Package ecsservice resolves an ECS service into the log sources of its tasks, tailing them all together and picking up replacement tasks as rolling deploys cycle them.
|
Package ecsservice resolves an ECS service into the log sources of its tasks, tailing them all together and picking up replacement tasks as rolling deploys cycle them. |
|
lambda
Package lambda resolves a Lambda function to its log group.
|
Package lambda resolves a Lambda function to its log group. |
|
loggroup
Package loggroup is the simplest Resolver: a reference IS a log group name (optionally "group:stream"), so resolution is purely lexical and needs no AWS client.
|
Package loggroup is the simplest Resolver: a reference IS a log group name (optionally "group:stream"), so resolution is purely lexical and needs no AWS client. |
|
sfn
Package sfn is the primary Resolver: hand it a Step Functions execution and it resolves every Lambda / Batch / ECS task that execution ran, streaming new sources as a running execution progresses and signalling Done when it reaches a terminal state.
|
Package sfn is the primary Resolver: hand it a Step Functions execution and it resolves every Lambda / Batch / ECS task that execution ran, streaming new sources as a running execution progresses and signalling Done when it reaches a terminal state. |
|
sfnmachine
Package sfnmachine resolves a Step Functions state machine to the log sources of its most recent execution: the newest RUNNING execution if one is in flight, else the newest execution overall.
|
Package sfnmachine resolves a Step Functions state machine to the log sources of its most recent execution: the newest RUNNING execution if one is in flight, else the newest execution overall. |