history

package
v2.8.4 Latest Latest
Warning

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

Go to latest
Published: Jul 13, 2026 License: MIT Imports: 28 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrChannelFull = errors.New("channel is full")
View Source
var ErrNoTable = errors.New("no trace table configured")

Functions

func CreateTable

func CreateTable(ctx ql.TxContext, name string) error

CreateTable creates the history table with the given name together with the indexes used by Records and Cleanup, unless they already exist.

func InitializeGlobal added in v2.7.4

func InitializeGlobal(ctx context.Context, opts Options) error

InitializeGlobal sets up the global history Service used by Track. It creates the history table (if it does not exist yet) and starts the background task that sends records tracked outside of a transaction.

func RenderOverview added in v2.7.6

func RenderOverview(w io.Writer, title string, headers []string, rows []OverviewRow) error

RenderOverview writes a standalone clickable table; each row links to Link.

func RenderPage added in v2.7.6

func RenderPage[T ~string](ctx context.Context, w io.Writer, groupId T, title string) error

RenderPage uses the global history singleton to render the history page for groupId. You need to initialize it using InitializeGlobal first.

func RenderPageAt added in v2.7.13

func RenderPageAt[T ~string](ctx context.Context, w io.Writer, groupId T, title string, createdTime time.Time) error

RenderPageAt is RenderPage with the Athena fallback: createdTime decides whether records are read from the local table or from Athena.

func RenderPageSummary added in v2.7.6

func RenderPageSummary[T ~string](ctx context.Context, w io.Writer, groupId T, title string, summary []SummaryItem) error

RenderPageSummary is RenderPage with a current-state summary above the ledger.

func RenderPageSummaryAt added in v2.7.13

func RenderPageSummaryAt[T ~string](ctx context.Context, w io.Writer, groupId T, title string, summary []SummaryItem, createdTime time.Time) error

RenderPageSummaryAt is RenderPageSummary with the Athena fallback (see RenderPageAt).

func Track added in v2.7.4

func Track[T ~string](ctx context.Context, groupId T, item Item)

Track uses the global history singleton. You need to initialize it using InitializeGlobal first.

Types

type AthenaConfig added in v2.7.13

type AthenaConfig struct {
	// required Athena configuration
	Database       string
	Table          string
	WorkGroup      string
	OutputLocation string

	// optional AWS region
	Region string

	// LookupThreshold selects Athena over the local table once the tracked
	// object is older than this. Defaults to 24h when zero.
	LookupThreshold time.Duration

	// LookbackMargin is subtracted from the object creation time to form the
	// Athena query's MinTimestamp, bounding the scanned partitions. Defaults
	// to 30m when zero.
	LookbackMargin time.Duration
}

AthenaConfig enables the Athena read fallback on a Service (see WithAthena).

type AthenaQuery

type AthenaQuery struct {
	GroupId GroupId

	// required athena configuration
	Database       string
	Table          string
	WorkGroup      string
	OutputLocation *url.URL

	// Optional region
	Region string

	// optional values to reduce the amount of data that
	// the query needs to scan. Either value can be left empty to
	MinTimestamp *time.Time
	MaxTimestamp *time.Time
}

func (AthenaQuery) Records

func (q AthenaQuery) Records(ctx context.Context) ([]Record, error)

type Cleanup

type Cleanup struct {
	Interval time.Duration
	Jitter   time.Duration
	MaxAge   time.Duration
}

func (Cleanup) Run

func (c Cleanup) Run(ctx context.Context, service *Service)

Run executes cleanup on the given service in a loop waiting for Cleanup.Interval + rand(Cleanup.Jitter) before each Service.Cleanup. It will delete all items that are older than Cleanup.MaxAge.

type EventCreator

type EventCreator func(serviceId, serviceVersion string, rec RecordToSend) events.Event

EventCreator builds the event that is sent out for a tracked record. It receives the ServiceId and ServiceVersion from the EventSending config.

type EventSender

type EventSender = events.EventSender

EventSender is re-exported from the events package for convenience.

type EventSending

type EventSending struct {
	// EventSender sends the events created by EventCreator.
	EventSender EventSender
	// EventCreator builds the event that is sent for a tracked record.
	EventCreator EventCreator

	// ServiceId and ServiceVersion identify the sender of the events. If left
	// empty, they are loaded from the SERVICE_ID and SERVICE_VERSION environment
	// variables in New.
	ServiceId      string
	ServiceVersion string

	// Write events to the kafka outbox first. If false, events are sent async.
	WriteToOutbox bool
}

EventSending groups options required for sending events to an EventSender.

type GroupId

type GroupId string

GroupId groups multiple history.Record instances into one history trace.

func (GroupId) LogValue

func (g GroupId) LogValue() slog.Value

func (GroupId) String

func (g GroupId) String() string

type Item

type Item interface {
	// HistoryString returns a human-readable description of this trace.Item.
	HistoryString() string
}

Item must be implemented by every event that is to be traced. Every Item should be json serializable.

type Option added in v2.7.13

type Option func(*Service)

Option customizes a Service created with New.

func WithAthena added in v2.7.13

func WithAthena(cfg AthenaConfig) Option

WithAthena enables the Athena fallback for reads: RecordsAt loads records from Athena instead of the local table when the tracked object is older than AthenaConfig.LookupThreshold. See RecordsAt.

type Options added in v2.7.4

type Options struct {
	// DB starts the transactions used to create the table and to write records.
	DB ql.TxStarter

	// ServiceId identifies this service as the sender of the emitted events.
	ServiceId string
	// HistoryTable is the name of the table that history records are written to.
	HistoryTable string
	// EventCreator builds the event that is sent out for every tracked record.
	EventCreator EventCreator
	// Athena, when set, enables the Athena read fallback for old records
	// (see WithAthena and Service.RecordsAt).
	Athena *AthenaConfig
}

Options configures the global history Service set up by InitializeGlobal.

type OverviewModel added in v2.7.6

type OverviewModel struct {
	Title   string
	Headers []string
	Rows    []OverviewRow
}

OverviewModel is the template model for a clickable list page linking to per-item detail pages.

type OverviewRow added in v2.7.6

type OverviewRow struct {
	Link  string
	Cells []string
}

OverviewRow is one list entry; Cells aligns with OverviewModel.Headers and Link is the detail-page URL the row navigates to.

type PageModel added in v2.7.6

type PageModel struct {
	Title        string
	GroupId      string
	ErrorMessage string
	Summary      []SummaryItem
	Records      []RecordView
}

PageModel is the template model for the generic history page.

type Record

type Record struct {
	Timestamp      time.Time       `db:"timestamp"`
	RequestTraceId RequestTraceId  `db:"request_trace_id"`
	Step           string          `db:"step"`
	Description    string          `db:"description"`
	Payload        json.RawMessage `db:"payload"`

	// Optional field that might indicate the sender of an event. This is useful if the
	// event comes from an external source, e.g. athena.
	// For local data, it is set to either the serviceId or to `local`, if no serviceId
	// is specified.
	EventSender        string `db:"-"`
	EventSenderVersion string `db:"-"`
}

Record describes one tracing record.

func RecordsAt added in v2.7.13

func RecordsAt[T ~string](ctx ql.TxContext, groupId T, createdTime time.Time) ([]Record, error)

RecordsAt uses the global history singleton to load records for groupId with the Athena fallback (see Service.RecordsAt).

type RecordToSend

type RecordToSend struct {
	GroupId        GroupId
	Timestamp      time.Time
	Step           string
	Description    string
	Payload        json.RawMessage
	RequestTraceId RequestTraceId
}

RecordToSend is a single tracked record, ready to be written to the history table and/or converted into an event.

type RecordView added in v2.7.6

type RecordView struct {
	Record
	// JSON is the indented payload.
	JSON string
	// ShowSeparator is true when this record starts a new RequestTraceId group.
	ShowSeparator bool
}

RecordView wraps a Record with its pretty-printed JSON payload for rendering.

type RequestTraceId

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

func (RequestTraceId) IsValid

func (h RequestTraceId) IsValid() bool

func (*RequestTraceId) Scan

func (h *RequestTraceId) Scan(src any) error

func (RequestTraceId) String

func (h RequestTraceId) String() string

func (RequestTraceId) Value

func (h RequestTraceId) Value() (driver.Value, error)

type Service

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

Service traces events by writing them to a history table and/or sending them out as events. Create an instance with New.

func New

func New(txStarter ql.TxStarter, table pgx.Identifier, eventSending *EventSending, opts ...Option) *Service

New creates a new history.Service instance to trace events. By default the service writes records to the history table given by table.

If you specify the optional eventSending parameter, every tracked record is also turned into an event. With EventSending.WriteToOutbox the event is written to the kafka outbox as part of the same transaction (via EventSender.SendInTx); otherwise it is sent asynchronously once the transaction commits (via EventSender.SendAsync).

If Service.SendAsync was called prior, trace events that are not tracked within a transaction are put into a channel (without blocking) and are sent later.

You can specify parameter table as nil to not write to the history table. If you specify an EventSending config, history entries are then only sent out as events.

func (*Service) Cleanup

func (h *Service) Cleanup(ctx context.Context, txStarter ql.TxStarter, before time.Time) error

Cleanup deletes all events that happened before the given timestamp.

func (*Service) Records

func (h *Service) Records(ctx ql.TxContext, groupId GroupId) ([]Record, error)

Records returns all local events for the given groupId. This method does not guarantee any ordering between the records returned.

func (*Service) RecordsAt added in v2.7.13

func (h *Service) RecordsAt(ctx ql.TxContext, groupId GroupId, createdTime time.Time) ([]Record, error)

RecordsAt returns the records for groupId. With Athena configured (WithAthena) it bridges the local table and long-term Athena storage, because a cleanup job deletes local rows after a retention window while Athena keeps them forever:

  • createdTime older than AthenaConfig.LookupThreshold: read from Athena, falling back to the local table if Athena fails.
  • createdTime within the threshold: read the local table only.
  • createdTime zero (age unknown): read the local table first and, only when it returns nothing, fall back to Athena — so records aged out of the local table are still found.

Any Athena failure is logged and never fails the read.

func (*Service) RenderPage added in v2.7.6

func (h *Service) RenderPage(ctx context.Context, w io.Writer, groupId GroupId, title string) error

RenderPage writes a standalone HTML history page for groupId to w. Records are loaded in a new read transaction, sorted by Timestamp (Service.Records is unordered), and an <hr> separates consecutive RequestTraceId groups.

ponytail: payload is rendered as pretty JSON only; add a key/value table when an item needs structured display.

func (*Service) RenderPageAt added in v2.7.13

func (h *Service) RenderPageAt(ctx context.Context, w io.Writer, groupId GroupId, title string, createdTime time.Time) error

RenderPageAt is RenderPage with an Athena fallback: records are loaded via RecordsAt using createdTime to decide between the local table and Athena.

func (*Service) RenderPageSummary added in v2.7.6

func (h *Service) RenderPageSummary(ctx context.Context, w io.Writer, groupId GroupId, title string, summary []SummaryItem) error

RenderPageSummary is RenderPage with an extra current-state summary rendered above the ledger.

func (*Service) RenderPageSummaryAt added in v2.7.13

func (h *Service) RenderPageSummaryAt(ctx context.Context, w io.Writer, groupId GroupId, title string, summary []SummaryItem, createdTime time.Time) error

RenderPageSummaryAt is RenderPageSummary with the Athena fallback (see RenderPageAt).

func (*Service) SendAsync

func (h *Service) SendAsync(ctx context.Context)

SendAsync starts the async process. This will start a background task to send out records that are not traced within a transaction. You can stop the background task by canceling the Context ctx.

func (*Service) Track

func (h *Service) Track(ctx context.Context, groupId GroupId, item Item)

Track records the given item under groupId. Depending on the Service configuration the record is written to the history table and/or sent out as an event. Tracking never returns an error: any failure is only logged.

If the context carries a transaction, the record is written within it. Otherwise a new transaction is opened, unless async sending was enabled via Service.SendAsync, in which case the record is queued without blocking.

type SummaryItem added in v2.7.6

type SummaryItem struct {
	Label string
	Value string
}

SummaryItem is one label/value row shown above the ledger, describing the current state of the tracked object. Ordered slice (not a map) so the page renders stably.

Jump to

Keyboard shortcuts

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