requestlog

package
v0.189.0 Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2026 License: AGPL-3.0 Imports: 8 Imported by: 0

Documentation

Overview

Package requestlog persists a queryable record of every outbound request forge-dashboard makes to GitHub or Forgejo (#482), so a rate-limit or connectivity incident can be debugged from what actually happened on the wire instead of from stdout logs alone. internal/github and internal/forgejo each depend on this package's Recorder — the one interface both clients need identically, so it lives here rather than being duplicated per client, the same way internal/dashboard already holds RateLimiter/RepoRefresher for the equivalent shared-dependency shape.

Index

Constants

View Source
const MaxEntries = 10000

MaxEntries is the row-count retention cap SQLiteRecorder enforces on every write — trimmed on insert rather than swept on a schedule, so storage never grows past this regardless of how bursty traffic gets.

View Source
const OutcomeSuccess = "success"

OutcomeSuccess is Entry.Outcome's value for a request that completed successfully. Any other value is a dashboard.ForgeErrorKind string.

Variables

This section is empty.

Functions

This section is empty.

Types

type Entry

type Entry struct {
	ID        int64
	LoggedAt  time.Time
	Forge     dashboard.Forge
	AccountID string // "" when no per-account credential made this request
	Method    string
	Endpoint  string
	// StatusCode is 0 when the request never got a response at all.
	StatusCode int
	// Outcome is OutcomeSuccess or a dashboard.ForgeErrorKind string.
	Outcome string
	// RateLimitLimit/RateLimitRemaining/RateLimitResetsAt/RateLimitCost
	// are all nil when the response carried no rate-limit fields —
	// not every request reports these.
	RateLimitLimit     *int
	RateLimitRemaining *int
	RateLimitResetsAt  *time.Time
	RateLimitCost      *int
}

Entry is one outbound request's own record.

type Filter

type Filter struct {
	Forge     dashboard.Forge
	AccountID string
}

Filter narrows a listing to entries matching every set field — a zero Filter (both fields empty) matches everything.

type NoopRecorder

type NoopRecorder struct{}

NoopRecorder discards every Entry — what a forge client falls back to when constructed with no Recorder at all, so every existing caller and test keeps compiling and passing unchanged.

func (NoopRecorder) Record

Record implements Recorder by doing nothing.

type Option added in v0.132.5

type Option func(*SQLiteRecorder)

Option configures a SQLiteRecorder.

func WithWriter added in v0.132.5

func WithWriter(w *Writer) Option

WithWriter sends Record's rows through w's bounded queue and single writer instead of writing inline (#902). Record then never waits on the database and never fails; a full queue drops the row and counts it.

type Recorder

type Recorder interface {
	Record(ctx context.Context, e Entry) error
}

Recorder is what internal/github and internal/forgejo depend on to persist an Entry for every outbound request they make. A Record error never changes the outbound request's own result — see NoopRecorder and each client's own call site, which logs it via slog.Warn and otherwise ignores it: logging a request is diagnostic, not part of what the request itself promises to do.

type RowStore added in v0.132.5

type RowStore interface {
	RecordRequest(ctx context.Context, row auth.RequestLogRow, maxEntries int) error
}

RowStore is what the Writer persists rows into. *auth.Store satisfies it.

type SQLiteRecorder

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

SQLiteRecorder is the concrete Recorder every forge client is wired up with — it persists into internal/auth.Store's own request_log table (the same SQLite database auth/session data already lives in, per design.md's "reuse what's already there" decision) rather than standing up a second storage mechanism for one more record type.

It's scoped to one account: SQLiteRecorder is constructed once per signed-in user (wherever that user's forge clients are built — see cmd/forge-dashboard's buildSourcesForUser), and every Entry it records carries that account's own ID regardless of what the caller set on Entry.AccountID — the account whose credential made a request is a property of *which client made it*, not something each individual client call site needs to know or pass through.

func NewSQLiteRecorder

func NewSQLiteRecorder(store *auth.Store, accountID string, opts ...Option) *SQLiteRecorder

NewSQLiteRecorder returns a SQLiteRecorder that persists into store, stamping every recorded Entry with accountID.

func (*SQLiteRecorder) List

func (r *SQLiteRecorder) List(ctx context.Context, filter Filter) ([]Entry, error)

List returns every entry matching filter, newest first — the admin API's own read path (internal/api's request-log handlers), kept on this same type rather than a second one, since it's just RecordRequest's read-side counterpart against the same store.

func (*SQLiteRecorder) Record

func (r *SQLiteRecorder) Record(ctx context.Context, e Entry) error

Record implements Recorder.

type Writer added in v0.132.5

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

Writer is the one place request-log rows are written from (#902). Each outbound forge request used to write its own row inline, so a locked database left one goroutine, and one OS thread, waiting per request for up to the busy timeout. Now callers enqueue and move on; a single goroutine does the writing, and a full queue drops the row and counts it rather than blocking a request.

func NewWriter added in v0.132.5

func NewWriter(store RowStore, size int) *Writer

NewWriter starts a Writer with room for size queued rows.

func (*Writer) Close added in v0.132.5

func (w *Writer) Close()

Close writes what's queued, then stops. A row submitted afterwards is never written, but never blocks or panics either.

func (*Writer) Dropped added in v0.132.5

func (w *Writer) Dropped() int64

Dropped is how many rows a full queue has discarded so far.

Jump to

Keyboard shortcuts

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