Documentation
¶
Overview ¶
Package store persists governed telemetry records (what optic.yaml allowed through) and answers the dashboard's query/analytics needs.
Contract: everything stored here is ALREADY restricted/redacted by the engine. The store is deliberately downstream of governance so no driver can ever see raw sensitive payloads.
Index ¶
- Constants
- func AnalysisLimit(limit int) int
- type AppLog
- type AppLogFilter
- type AppLogStore
- type AppLogSummary
- type AsyncOption
- type AsyncWriter
- type ClickHouseStore
- func (s *ClickHouseStore) AppLogStats(ctx context.Context, since time.Time) (*ext.AppLogSummary, error)
- func (s *ClickHouseStore) Close() error
- func (s *ClickHouseStore) Count(ctx context.Context) (int64, error)
- func (s *ClickHouseStore) CountAppLogs(ctx context.Context) (int64, error)
- func (s *ClickHouseStore) CountSpans(ctx context.Context) (int64, error)
- func (s *ClickHouseStore) Get(ctx context.Context, id int64) (*Record, error)
- func (s *ClickHouseStore) Prune(ctx context.Context, maxRows int64) (int64, error)
- func (s *ClickHouseStore) PruneAppLogsBefore(ctx context.Context, cutoff time.Time) (int64, error)
- func (s *ClickHouseStore) PruneBefore(ctx context.Context, cutoff time.Time) (int64, error)
- func (s *ClickHouseStore) PruneSpansBefore(ctx context.Context, cutoff time.Time) (int64, error)
- func (s *ClickHouseStore) Purge(ctx context.Context, label, value string, before time.Time) (int64, error)
- func (s *ClickHouseStore) Query(ctx context.Context, f Filter) ([]Record, int64, error)
- func (s *ClickHouseStore) QueryAppLogs(ctx context.Context, f ext.AppLogFilter) ([]ext.AppLog, int64, error)
- func (s *ClickHouseStore) QuerySpans(ctx context.Context, f ext.SpanFilter) ([]ext.Span, int64, error)
- func (s *ClickHouseStore) Recent(ctx context.Context, since time.Time, limit int) ([]Record, error)
- func (s *ClickHouseStore) RecentFunc(ctx context.Context, since time.Time, limit int, fn func(*Record) error) error
- func (s *ClickHouseStore) RouteStats(ctx context.Context, since time.Time) ([]RouteDetail, error)
- func (s *ClickHouseStore) RuleMatchCounts(ctx context.Context, since time.Time, ruleNames []string) ([]RuleMatch, error)
- func (s *ClickHouseStore) Save(ctx context.Context, r *Record) error
- func (s *ClickHouseStore) SaveAppLogs(ctx context.Context, lines []ext.AppLog) error
- func (s *ClickHouseStore) SaveSpans(ctx context.Context, list []ext.Span) error
- func (s *ClickHouseStore) ServiceStats(ctx context.Context, since time.Time) ([]ServiceStat, error)
- func (s *ClickHouseStore) SpanBreakdown(ctx context.Context, since time.Time, route string, limit int) ([]ext.SpanBreakdown, error)
- func (s *ClickHouseStore) SpanStats(ctx context.Context, since time.Time) (*ext.SpanSummary, error)
- func (s *ClickHouseStore) Stats(ctx context.Context, since time.Time, bucket time.Duration) (*Stats, error)
- func (s *ClickHouseStore) Traces(ctx context.Context, f ext.TraceFilter) ([]ext.TraceSummary, int64, error)
- func (s *ClickHouseStore) UsageByLabel(ctx context.Context, since time.Time, label string) ([]Usage, error)
- type Filter
- type LogStore
- type PostgresStore
- func (s *PostgresStore) AppLogStats(ctx context.Context, since time.Time) (*ext.AppLogSummary, error)
- func (s *PostgresStore) Close() error
- func (s *PostgresStore) Count(ctx context.Context) (int64, error)
- func (s *PostgresStore) CountAppLogs(ctx context.Context) (int64, error)
- func (s *PostgresStore) CountSpans(ctx context.Context) (int64, error)
- func (s *PostgresStore) Get(ctx context.Context, id int64) (*Record, error)
- func (s *PostgresStore) Prune(ctx context.Context, maxRows int64) (int64, error)
- func (s *PostgresStore) PruneAppLogsBefore(ctx context.Context, cutoff time.Time) (int64, error)
- func (s *PostgresStore) PruneBefore(ctx context.Context, cutoff time.Time) (int64, error)
- func (s *PostgresStore) PruneSpansBefore(ctx context.Context, cutoff time.Time) (int64, error)
- func (s *PostgresStore) Purge(ctx context.Context, label, value string, before time.Time) (int64, error)
- func (s *PostgresStore) Query(ctx context.Context, f Filter) ([]Record, int64, error)
- func (s *PostgresStore) QueryAppLogs(ctx context.Context, f ext.AppLogFilter) ([]ext.AppLog, int64, error)
- func (s *PostgresStore) QuerySpans(ctx context.Context, f ext.SpanFilter) ([]ext.Span, int64, error)
- func (s *PostgresStore) Recent(ctx context.Context, since time.Time, limit int) ([]Record, error)
- func (s *PostgresStore) RecentFunc(ctx context.Context, since time.Time, limit int, fn func(*Record) error) error
- func (s *PostgresStore) RouteStats(ctx context.Context, since time.Time) ([]RouteDetail, error)
- func (s *PostgresStore) RuleMatchCounts(ctx context.Context, since time.Time, ruleNames []string) ([]RuleMatch, error)
- func (s *PostgresStore) Save(ctx context.Context, r *Record) error
- func (s *PostgresStore) SaveAppLogs(ctx context.Context, lines []ext.AppLog) error
- func (s *PostgresStore) SaveSpans(ctx context.Context, list []ext.Span) error
- func (s *PostgresStore) ServiceStats(ctx context.Context, since time.Time) ([]ServiceStat, error)
- func (s *PostgresStore) SpanBreakdown(ctx context.Context, since time.Time, route string, limit int) ([]ext.SpanBreakdown, error)
- func (s *PostgresStore) SpanStats(ctx context.Context, since time.Time) (*ext.SpanSummary, error)
- func (s *PostgresStore) Stats(ctx context.Context, since time.Time, bucket time.Duration) (*Stats, error)
- func (s *PostgresStore) Traces(ctx context.Context, f ext.TraceFilter) ([]ext.TraceSummary, int64, error)
- func (s *PostgresStore) UsageByLabel(ctx context.Context, since time.Time, label string) ([]Usage, error)
- type Record
- type RouteDetail
- type RouteStat
- type RuleMatch
- type SQLiteStore
- func (s *SQLiteStore) AppLogStats(ctx context.Context, since time.Time) (*ext.AppLogSummary, error)
- func (s *SQLiteStore) Close() error
- func (s *SQLiteStore) Count(ctx context.Context) (int64, error)
- func (s *SQLiteStore) CountAppLogs(ctx context.Context) (int64, error)
- func (s *SQLiteStore) CountSpans(ctx context.Context) (int64, error)
- func (s *SQLiteStore) Get(ctx context.Context, id int64) (*Record, error)
- func (s *SQLiteStore) Prune(ctx context.Context, maxRows int64) (int64, error)
- func (s *SQLiteStore) PruneAppLogsBefore(ctx context.Context, cutoff time.Time) (int64, error)
- func (s *SQLiteStore) PruneBefore(ctx context.Context, cutoff time.Time) (int64, error)
- func (s *SQLiteStore) PruneSpansBefore(ctx context.Context, cutoff time.Time) (int64, error)
- func (s *SQLiteStore) Purge(ctx context.Context, label, value string, before time.Time) (int64, error)
- func (s *SQLiteStore) Query(ctx context.Context, f Filter) ([]Record, int64, error)
- func (s *SQLiteStore) QueryAppLogs(ctx context.Context, f ext.AppLogFilter) ([]ext.AppLog, int64, error)
- func (s *SQLiteStore) QuerySpans(ctx context.Context, f ext.SpanFilter) ([]ext.Span, int64, error)
- func (s *SQLiteStore) Recent(ctx context.Context, since time.Time, limit int) ([]Record, error)
- func (s *SQLiteStore) RecentFunc(ctx context.Context, since time.Time, limit int, fn func(*Record) error) error
- func (s *SQLiteStore) RouteStats(ctx context.Context, since time.Time) ([]RouteDetail, error)
- func (s *SQLiteStore) RuleMatchCounts(ctx context.Context, since time.Time, ruleNames []string) ([]RuleMatch, error)
- func (s *SQLiteStore) Save(ctx context.Context, r *Record) error
- func (s *SQLiteStore) SaveAppLogs(ctx context.Context, lines []ext.AppLog) error
- func (s *SQLiteStore) SaveSpans(ctx context.Context, list []ext.Span) error
- func (s *SQLiteStore) ServiceStats(ctx context.Context, since time.Time) ([]ServiceStat, error)
- func (s *SQLiteStore) SpanBreakdown(ctx context.Context, since time.Time, route string, limit int) ([]ext.SpanBreakdown, error)
- func (s *SQLiteStore) SpanStats(ctx context.Context, since time.Time) (*ext.SpanSummary, error)
- func (s *SQLiteStore) Stats(ctx context.Context, since time.Time, bucket time.Duration) (*Stats, error)
- func (s *SQLiteStore) Traces(ctx context.Context, f ext.TraceFilter) ([]ext.TraceSummary, int64, error)
- func (s *SQLiteStore) UsageByLabel(ctx context.Context, since time.Time, label string) ([]Usage, error)
- type ServiceStat
- type Span
- type SpanBreakdown
- type SpanFilter
- type SpanStore
- type SpanSummary
- type Stats
- type TimeBucket
- type TraceFilter
- type TraceStore
- type TraceSummary
- type Usage
Constants ¶
const ( DefaultAnalysisMaxRows = ext.DefaultAnalysisMaxRows MaxAnalysisMaxRows = ext.MaxAnalysisMaxRows )
Variables ¶
This section is empty.
Functions ¶
func AnalysisLimit ¶ added in v0.8.0
AnalysisLimit resolves a requested limit against the defaults.
Types ¶
type AppLog ¶ added in v0.9.0
AppLog is one application log line correlated to a span. AppLogStore is OPTIONAL — a driver is complete without it; detect support with a type assertion rather than assuming.
type AppLogFilter ¶ added in v0.9.0
type AppLogFilter = ext.AppLogFilter
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type AppLogStore ¶ added in v0.9.0
type AppLogStore = ext.AppLogStore
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type AppLogSummary ¶ added in v0.9.0
type AppLogSummary = ext.AppLogSummary
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type AsyncOption ¶
type AsyncOption func(*AsyncWriter)
func WithAppLogMaxAge ¶ added in v0.9.0
func WithAppLogMaxAge(d time.Duration) AsyncOption
WithAppLogMaxAge sets the retention horizon for application log lines. It is a no-op unless the store implements ext.AppLogStore.
func WithDropCallback ¶
func WithDropCallback(fn func()) AsyncOption
WithDropCallback wires drop accounting into the metrics collector.
func WithMaxAge ¶
func WithMaxAge(d time.Duration) AsyncOption
WithMaxAge deletes records older than d on the same schedule. Row-count and age limits compose: whichever removes a record first wins.
func WithRetention ¶
func WithRetention(maxRows int64) AsyncOption
WithRetention prunes the store down to maxRows periodically.
func WithSpanMaxAge ¶ added in v0.15.0
func WithSpanMaxAge(d time.Duration) AsyncOption
WithSpanMaxAge sets the retention horizon for inner spans. It is a no-op unless the store implements ext.SpanStore.
type AsyncWriter ¶
type AsyncWriter struct {
// contains filtered or unexported fields
}
AsyncWriter decouples the request hot path from persistence: Enqueue is a non-blocking channel send, and a single background worker drains into the LogStore. Under backpressure records are DROPPED (and counted) — an observability tool must never become the bottleneck it measures.
func NewAsyncWriter ¶
func NewAsyncWriter(s LogStore, queueSize int, logger *slog.Logger, opts ...AsyncOption) *AsyncWriter
func (*AsyncWriter) Close ¶
func (w *AsyncWriter) Close() error
Close drains outstanding records, then closes the underlying store.
func (*AsyncWriter) Enqueue ¶
func (w *AsyncWriter) Enqueue(rec *Record)
Enqueue hands off a record without ever blocking the caller.
type ClickHouseStore ¶ added in v0.8.0
type ClickHouseStore struct {
// contains filtered or unexported fields
}
ClickHouseStore is the column-oriented LogStore driver.
Why a third driver: every dashboard query here is a time-bucketed aggregation over a table that only grows — Stats, RouteStats, ServiceStats, UsageByLabel. SQLite and Postgres are row stores answering those with sorts and scans; ClickHouse answers them with column reads, and is a common choice for teams already keeping API traffic at volume.
Two things work differently here than in the row stores, and both are visible in this file rather than hidden:
- There is no autoincrement. IDs are generated client-side (see nextID) rather than by the database.
- DELETE is a mutation, applied asynchronously by default. Every delete path runs with mutations_sync=2 so Purge and the retention functions behave synchronously, as the shared conformance suite requires and as an erasure request demands.
func NewClickHouse ¶ added in v0.8.0
func NewClickHouse(dsn string) (*ClickHouseStore, error)
NewClickHouse opens (and migrates) a ClickHouse-backed store. dsn is a clickhouse-go URL: clickhouse://user:pass@host:9000/database
func (*ClickHouseStore) AppLogStats ¶ added in v0.11.0
func (s *ClickHouseStore) AppLogStats(ctx context.Context, since time.Time) (*ext.AppLogSummary, error)
AppLogStats aggregates in the database rather than by counting rows in the caller — a summary of the first page is wrong at exactly the volumes where a summary starts to matter.
func (*ClickHouseStore) Close ¶ added in v0.8.0
func (s *ClickHouseStore) Close() error
func (*ClickHouseStore) Count ¶ added in v0.8.0
func (s *ClickHouseStore) Count(ctx context.Context) (int64, error)
func (*ClickHouseStore) CountAppLogs ¶ added in v0.11.0
func (s *ClickHouseStore) CountAppLogs(ctx context.Context) (int64, error)
func (*ClickHouseStore) CountSpans ¶ added in v0.15.0
func (s *ClickHouseStore) CountSpans(ctx context.Context) (int64, error)
func (*ClickHouseStore) PruneAppLogsBefore ¶ added in v0.11.0
PruneAppLogsBefore enforces the app-log retention horizon.
mutations_sync=2 for the same reason the record path uses it: an unsynchronised ALTER ... DELETE returns before the data is gone, so retention would report success while the rows were still readable.
func (*ClickHouseStore) PruneBefore ¶ added in v0.8.0
func (*ClickHouseStore) PruneSpansBefore ¶ added in v0.15.0
func (*ClickHouseStore) Purge ¶ added in v0.8.0
func (s *ClickHouseStore) Purge(ctx context.Context, label, value string, before time.Time) (int64, error)
Purge implements erasure requests. The label match is on the exact `"label":"value"` pair extracted from the JSON document, not a substring or a LIKE pattern — deleting a neighbouring tenant's data is the one mistake an erasure tool must never make, and a LIKE with unescaped metacharacters is exactly how the SQLite driver once made it.
func (*ClickHouseStore) QueryAppLogs ¶ added in v0.11.0
func (s *ClickHouseStore) QueryAppLogs(ctx context.Context, f ext.AppLogFilter) ([]ext.AppLog, int64, error)
QueryAppLogs returns matching lines oldest-first.
func (*ClickHouseStore) QuerySpans ¶ added in v0.15.0
func (s *ClickHouseStore) QuerySpans(ctx context.Context, f ext.SpanFilter) ([]ext.Span, int64, error)
func (*ClickHouseStore) RecentFunc ¶ added in v0.8.0
func (*ClickHouseStore) RouteStats ¶ added in v0.8.0
func (s *ClickHouseStore) RouteStats(ctx context.Context, since time.Time) ([]RouteDetail, error)
func (*ClickHouseStore) RuleMatchCounts ¶ added in v0.8.0
func (s *ClickHouseStore) RuleMatchCounts(ctx context.Context, since time.Time, ruleNames []string) ([]RuleMatch, error)
RuleMatchCounts counts rule firings in a single pass. matched_rules is a JSON array of strings; arrayJoin over JSONExtract expands it so the counting happens in the database rather than in N round trips.
func (*ClickHouseStore) Save ¶ added in v0.8.0
func (s *ClickHouseStore) Save(ctx context.Context, r *Record) error
func (*ClickHouseStore) SaveAppLogs ¶ added in v0.11.0
SaveAppLogs writes a batch.
ClickHouse has no autoincrement, so ids come from the same timestamp+sequence generator the record path uses — monotonic enough to order lines written in the same millisecond, which is exactly when a request logs several times.
func (*ClickHouseStore) ServiceStats ¶ added in v0.8.0
func (s *ClickHouseStore) ServiceStats(ctx context.Context, since time.Time) ([]ServiceStat, error)
func (*ClickHouseStore) SpanBreakdown ¶ added in v0.15.0
func (s *ClickHouseStore) SpanBreakdown(ctx context.Context, since time.Time, route string, limit int) ([]ext.SpanBreakdown, error)
func (*ClickHouseStore) SpanStats ¶ added in v0.15.0
func (s *ClickHouseStore) SpanStats(ctx context.Context, since time.Time) (*ext.SpanSummary, error)
func (*ClickHouseStore) Traces ¶ added in v0.14.0
func (s *ClickHouseStore) Traces(ctx context.Context, f ext.TraceFilter) ([]ext.TraceSummary, int64, error)
Traces rolls the recorded hops up into one row per trace.
ClickHouse has no DISTINCT ON and correlated subqueries are a trap here, so the root hop is picked with argMin over a sort key that expresses both cases at once: `(parent_span != ”, ts)` puts a parentless hop first and falls back to the earliest hop when the entry service was never instrumented.
func (*ClickHouseStore) UsageByLabel ¶ added in v0.8.0
func (s *ClickHouseStore) UsageByLabel(ctx context.Context, since time.Time, label string) ([]Usage, error)
UsageByLabel aggregates in Go for the same reason the other drivers do: labels and meters are stored as JSON documents whose keys are not known in advance, so grouping in SQL would need a per-key query.
type Filter ¶
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type LogStore ¶
LogStore is the persistence contract. Implementations must be safe for concurrent use. Save is called from the async writer, never from the request hot path.
type PostgresStore ¶
type PostgresStore struct {
// contains filtered or unexported fields
}
PostgresStore is the multi-node LogStore. SQLite is perfect for a sidecar with one writer; the moment several agents (or several replicas of one agent) need to share history, they need a server they can all reach.
Notes on the schema choice:
- JSONB rather than TEXT for headers/labels/meters, so usage aggregation and label filtering happen in the database instead of in Go.
- Timestamps stay as bigint milliseconds, matching the SQLite driver, so records are portable between the two without conversion surprises.
func NewPostgres ¶
func NewPostgres(dsn string) (*PostgresStore, error)
NewPostgres opens (and migrates) a Postgres-backed store. dsn is a standard libpq/pgx URL: postgres://user:pass@host:5432/db?sslmode=disable
func (*PostgresStore) AppLogStats ¶ added in v0.11.0
func (s *PostgresStore) AppLogStats(ctx context.Context, since time.Time) (*ext.AppLogSummary, error)
AppLogStats aggregates in the database rather than by counting rows in the caller: a dashboard that summarises the first page and calls it a total is quietly lying at exactly the volumes where the summary starts to matter.
func (*PostgresStore) Close ¶
func (s *PostgresStore) Close() error
func (*PostgresStore) CountAppLogs ¶ added in v0.11.0
func (s *PostgresStore) CountAppLogs(ctx context.Context) (int64, error)
func (*PostgresStore) CountSpans ¶ added in v0.15.0
func (s *PostgresStore) CountSpans(ctx context.Context) (int64, error)
func (*PostgresStore) PruneAppLogsBefore ¶ added in v0.11.0
PruneAppLogsBefore enforces the app-log retention horizon, which is separate from the record horizon because the volumes differ by orders of magnitude.
func (*PostgresStore) PruneBefore ¶
func (*PostgresStore) PruneSpansBefore ¶ added in v0.15.0
func (*PostgresStore) QueryAppLogs ¶ added in v0.11.0
func (s *PostgresStore) QueryAppLogs(ctx context.Context, f ext.AppLogFilter) ([]ext.AppLog, int64, error)
QueryAppLogs returns matching lines oldest-first: reading what a request did means reading it in the order it happened.
func (*PostgresStore) QuerySpans ¶ added in v0.15.0
func (s *PostgresStore) QuerySpans(ctx context.Context, f ext.SpanFilter) ([]ext.Span, int64, error)
func (*PostgresStore) RecentFunc ¶ added in v0.8.0
func (s *PostgresStore) RecentFunc(ctx context.Context, since time.Time, limit int, fn func(*Record) error) error
RecentFunc streams records one at a time so an analysis pass costs one record of memory rather than the whole window. Recent() materialises the same rows; prefer this wherever the caller only folds over them.
func (*PostgresStore) RouteStats ¶
func (s *PostgresStore) RouteStats(ctx context.Context, since time.Time) ([]RouteDetail, error)
func (*PostgresStore) RuleMatchCounts ¶
func (*PostgresStore) SaveAppLogs ¶ added in v0.11.0
SaveAppLogs writes a batch in one round trip.
Batching is the point: application logs arrive at many lines per request, and a statement per line makes the store the slowest part of the system.
func (*PostgresStore) ServiceStats ¶
func (s *PostgresStore) ServiceStats(ctx context.Context, since time.Time) ([]ServiceStat, error)
func (*PostgresStore) SpanBreakdown ¶ added in v0.15.0
func (s *PostgresStore) SpanBreakdown(ctx context.Context, since time.Time, route string, limit int) ([]ext.SpanBreakdown, error)
SpanBreakdown uses percentile_cont, so the p95 comes from the same pass rather than one ordered subquery per operation name.
func (*PostgresStore) SpanStats ¶ added in v0.15.0
func (s *PostgresStore) SpanStats(ctx context.Context, since time.Time) (*ext.SpanSummary, error)
func (*PostgresStore) Traces ¶ added in v0.14.0
func (s *PostgresStore) Traces(ctx context.Context, f ext.TraceFilter) ([]ext.TraceSummary, int64, error)
Traces rolls the recorded hops up into one row per trace. See the SQLite implementation for the shape; the difference here is DISTINCT ON, which picks the root hop without a correlated subquery per trace.
func (*PostgresStore) UsageByLabel ¶
type Record ¶
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type RouteDetail ¶
type RouteDetail = ext.RouteDetail
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type RouteStat ¶
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type RuleMatch ¶
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type SQLiteStore ¶
type SQLiteStore struct {
// contains filtered or unexported fields
}
SQLiteStore is the default embedded LogStore. WAL mode keeps concurrent dashboard reads from blocking the single async writer.
func NewSQLite ¶
func NewSQLite(dsn string) (*SQLiteStore, error)
func (*SQLiteStore) AppLogStats ¶ added in v0.9.0
func (s *SQLiteStore) AppLogStats(ctx context.Context, since time.Time) (*ext.AppLogSummary, error)
AppLogStats aggregates stored lines. Three cheap grouped counts rather than one walk: the point of asking the database is not having to carry the rows.
func (*SQLiteStore) Close ¶
func (s *SQLiteStore) Close() error
func (*SQLiteStore) CountAppLogs ¶ added in v0.9.0
func (s *SQLiteStore) CountAppLogs(ctx context.Context) (int64, error)
func (*SQLiteStore) CountSpans ¶ added in v0.15.0
func (s *SQLiteStore) CountSpans(ctx context.Context) (int64, error)
func (*SQLiteStore) PruneAppLogsBefore ¶ added in v0.9.0
PruneAppLogsBefore enforces the app-log retention horizon, which is separate from the record horizon because the volumes differ by orders of magnitude.
func (*SQLiteStore) PruneBefore ¶
func (*SQLiteStore) PruneSpansBefore ¶ added in v0.15.0
func (*SQLiteStore) Purge ¶
func (s *SQLiteStore) Purge(ctx context.Context, label, value string, before time.Time) (int64, error)
Purge implements erasure requests. Labels are stored as a JSON object, so the match is on the exact `"label":"value"` pair — substring matching on the value alone would delete another tenant's data, which is the one mistake an erasure tool must never make.
func (*SQLiteStore) QueryAppLogs ¶ added in v0.9.0
func (s *SQLiteStore) QueryAppLogs(ctx context.Context, f ext.AppLogFilter) ([]ext.AppLog, int64, error)
QueryAppLogs returns matching lines oldest-first: reading what a request did means reading it in the order it happened.
func (*SQLiteStore) QuerySpans ¶ added in v0.15.0
func (s *SQLiteStore) QuerySpans(ctx context.Context, f ext.SpanFilter) ([]ext.Span, int64, error)
QuerySpans returns matching spans OLDEST-FIRST: reading a request's work means reading it in the order it happened.
func (*SQLiteStore) RecentFunc ¶ added in v0.8.0
func (s *SQLiteStore) RecentFunc(ctx context.Context, since time.Time, limit int, fn func(*Record) error) error
RecentFunc streams records one at a time so an analysis pass costs one record of memory rather than the whole window. Recent() materialises the same rows; prefer this wherever the caller only folds over them.
func (*SQLiteStore) RouteStats ¶
func (s *SQLiteStore) RouteStats(ctx context.Context, since time.Time) ([]RouteDetail, error)
func (*SQLiteStore) RuleMatchCounts ¶
func (s *SQLiteStore) RuleMatchCounts(ctx context.Context, since time.Time, ruleNames []string) ([]RuleMatch, error)
RuleMatchCounts counts how often each named rule fired.
This used to run one `matched_rules LIKE '%"name"%'` per rule — N full table scans per dashboard load, since a LIKE pattern with a leading wildcard can never use an index. It is now a single pass: json_each expands the JSON array into rows, the ts index bounds the window, and GROUP BY does the counting in SQLite instead of N round trips.
func (*SQLiteStore) SaveAppLogs ¶ added in v0.9.0
SaveAppLogs writes a batch in one transaction. Batching is the point — application logs arrive at many lines per request, and a transaction per line makes the store the slowest part of the system.
func (*SQLiteStore) SaveSpans ¶ added in v0.15.0
SaveSpans persists a batch in one transaction. Called from the async writer, never from a request path.
func (*SQLiteStore) ServiceStats ¶
func (s *SQLiteStore) ServiceStats(ctx context.Context, since time.Time) ([]ServiceStat, error)
func (*SQLiteStore) SpanBreakdown ¶ added in v0.15.0
func (s *SQLiteStore) SpanBreakdown(ctx context.Context, since time.Time, route string, limit int) ([]ext.SpanBreakdown, error)
SpanBreakdown answers "where did the time go" for a window.
Requests is counted alongside Count on purpose: Count/Requests is the per-request multiplier, and a multiplier of 40 on a query named once in the source is the shape an N+1 makes. A total alone hides it — 4,000 calls looks like busy traffic until you know it was 100 requests.
func (*SQLiteStore) SpanStats ¶ added in v0.15.0
func (s *SQLiteStore) SpanStats(ctx context.Context, since time.Time) (*ext.SpanSummary, error)
func (*SQLiteStore) Traces ¶ added in v0.14.0
func (s *SQLiteStore) Traces(ctx context.Context, f ext.TraceFilter) ([]ext.TraceSummary, int64, error)
func (*SQLiteStore) UsageByLabel ¶
func (s *SQLiteStore) UsageByLabel(ctx context.Context, since time.Time, label string) ([]Usage, error)
UsageByLabel aggregates in Go rather than SQL: labels/meters are stored as JSON text, and the window is bounded by retention (~100k rows), so a single narrow scan is simpler and fast enough.
type ServiceStat ¶
type ServiceStat = ext.ServiceStat
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type Span ¶ added in v0.15.0
Span is one operation inside a request. SpanStore is OPTIONAL for the same reason the two above are.
type SpanBreakdown ¶ added in v0.15.0
type SpanBreakdown = ext.SpanBreakdown
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type SpanFilter ¶ added in v0.15.0
type SpanFilter = ext.SpanFilter
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type SpanStore ¶ added in v0.15.0
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type SpanSummary ¶ added in v0.15.0
type SpanSummary = ext.SpanSummary
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type Stats ¶
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type TimeBucket ¶
type TimeBucket = ext.TimeBucket
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type TraceFilter ¶ added in v0.14.0
type TraceFilter = ext.TraceFilter
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type TraceStore ¶ added in v0.14.0
type TraceStore = ext.TraceStore
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.
type TraceSummary ¶ added in v0.14.0
type TraceSummary = ext.TraceSummary
TraceSummary rolls every hop of one request into a row. TraceStore is OPTIONAL for the same reason AppLogStore is: Store is implemented outside this module, so it cannot grow methods.
type Usage ¶
The record types and the store contract live in ext, the public extension surface, so an out-of-tree driver can name them. These aliases are not conversions — Record and ext.Record are the same type — so nothing in the rest of the codebase changes, and there is exactly one Record in the program.