summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-14 11:37:13 +0300
committerPaul Buetow <paul@buetow.org>2026-04-14 11:37:13 +0300
commit299aa6727025c4f888ec2a38b8945ed39159a99c (patch)
tree8b03f4869f89fb25164f1dcb47213ef7ffeafeb9 /internal
parenta9a8896a7af324c3588984230d51fe2e15aba30c (diff)
docs: add godoc for exports (ask 04)
Document Record, Open, CreateSchema, ResetRecords, ImportFromDir, LoadRecords in storage; Reporter and reporters in goprecords; Fields and Parse in recordline; Config and Run in daemon. Made-with: Cursor
Diffstat (limited to 'internal')
-rw-r--r--internal/daemon/daemon.go2
-rw-r--r--internal/goprecords/report.go10
-rw-r--r--internal/recordline/recordline.go3
-rw-r--r--internal/storage/db.go7
4 files changed, 22 insertions, 0 deletions
diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go
index 876fc81..852051a 100644
--- a/internal/daemon/daemon.go
+++ b/internal/daemon/daemon.go
@@ -24,6 +24,7 @@ const (
defaultIdleTimeout = 2 * time.Minute
)
+// Config holds settings for the HTTP report/upload daemon.
type Config struct {
StatsDir string
Addr string
@@ -107,6 +108,7 @@ func newDaemonHTTPServer(addr string, handler http.Handler, errLog *log.Logger)
}
}
+// Run starts the HTTP server for cfg until ctx is canceled, then shuts down gracefully.
func Run(ctx context.Context, cfg Config) error {
if cfg.StatsDir == "" {
return fmt.Errorf("stats directory is required")
diff --git a/internal/goprecords/report.go b/internal/goprecords/report.go
index a512407..6300163 100644
--- a/internal/goprecords/report.go
+++ b/internal/goprecords/report.go
@@ -106,6 +106,7 @@ func writeReportString(w io.Writer, s string) error {
return err
}
+// Reporter renders aggregate uptime statistics as a string for one category and metric.
type Reporter interface {
Report() string
}
@@ -118,22 +119,29 @@ type reportBuilder struct {
headerIndent uint
}
+// PlaintextReporter formats a report as plain text.
type PlaintextReporter struct {
builder reportBuilder
}
+// MarkdownReporter formats a report as Markdown.
type MarkdownReporter struct {
builder reportBuilder
}
+// GemtextReporter formats a report as Gemtext.
type GemtextReporter struct {
builder reportBuilder
}
+// HTMLReporter formats a report as HTML.
type HTMLReporter struct {
builder reportBuilder
}
+// NewReporter returns a Reporter for category and metric, using outputFormat and
+// limiting to the top limit entities. headerIndent controls heading depth for
+// Markdown, Gemtext, and HTML.
func NewReporter(aggregates *Aggregates, category Category, limit uint, metric Metric, outputFormat OutputFormat, headerIndent uint) Reporter {
builder := reportBuilder{
aggregates: aggregates,
@@ -154,6 +162,8 @@ func NewReporter(aggregates *Aggregates, category Category, limit uint, metric M
}
}
+// NewHostReporter returns a Reporter for the Host category with the given metric
+// and output settings. It is equivalent to NewReporter with CategoryHost.
func NewHostReporter(aggregates *Aggregates, limit uint, metric Metric, outputFormat OutputFormat, headerIndent uint) Reporter {
return NewReporter(aggregates, CategoryHost, limit, metric, outputFormat, headerIndent)
}
diff --git a/internal/recordline/recordline.go b/internal/recordline/recordline.go
index 077fa35..5ff06ab 100644
--- a/internal/recordline/recordline.go
+++ b/internal/recordline/recordline.go
@@ -5,6 +5,7 @@ import (
"strings"
)
+// Fields holds the values parsed from a single uptimed record line.
type Fields struct {
Uptime uint64
BootTime uint64
@@ -13,6 +14,8 @@ type Fields struct {
KernelMajor string
}
+// Parse parses one non-empty line of the form "uptime:boottime:os..." from an
+// uptimed .records file. It returns false if the line is empty or malformed.
func Parse(line string) (Fields, bool) {
line = strings.TrimSpace(line)
if line == "" {
diff --git a/internal/storage/db.go b/internal/storage/db.go
index 03ffd08..edd5a93 100644
--- a/internal/storage/db.go
+++ b/internal/storage/db.go
@@ -28,6 +28,7 @@ CREATE INDEX IF NOT EXISTS idx_record_os_kernel_name ON record(os_kernel_name);
CREATE INDEX IF NOT EXISTS idx_record_os_kernel_major ON record(os_kernel_major);
`
+// Record is one uptimed boot row stored in the record table.
type Record struct {
Host string
Uptime uint64
@@ -37,6 +38,7 @@ type Record struct {
KernelMajor string
}
+// Open opens a SQLite database at path and verifies connectivity.
func Open(ctx context.Context, path string) (*sql.DB, error) {
db, err := sql.Open("sqlite", path)
if err != nil {
@@ -53,16 +55,20 @@ func Open(ctx context.Context, path string) (*sql.DB, error) {
return db, nil
}
+// CreateSchema creates the record table and indexes if they do not exist.
func CreateSchema(ctx context.Context, db *sql.DB) error {
_, err := db.ExecContext(ctx, schemaSQL)
return err
}
+// ResetRecords deletes all rows from the record table.
func ResetRecords(ctx context.Context, db *sql.DB) error {
_, err := db.ExecContext(ctx, "DELETE FROM record")
return err
}
+// ImportFromDir imports non-empty .records files from statsDir into the database,
+// replacing existing rows. It is equivalent to ImportFromFS with os.DirFS(statsDir).
func ImportFromDir(ctx context.Context, db *sql.DB, statsDir string) error {
return ImportFromFS(ctx, db, os.DirFS(statsDir))
}
@@ -97,6 +103,7 @@ func ImportFromFS(ctx context.Context, db *sql.DB, fsys fs.FS) error {
return nil
}
+// LoadRecords returns all rows from the record table ordered by host and boot time.
func LoadRecords(ctx context.Context, db *sql.DB) ([]Record, error) {
var n int
if err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM record").Scan(&n); err != nil {