Chronicle

Retention

Policy-based event archival and purge.

Chronicle's retention system automatically archives and purges audit events according to configurable policies. The retention.Enforcer runs periodically (or on demand) and applies each policy to its matching events.

Policy

A retention.Policy defines how long events of a given category are kept:

FieldTypeDescription
IDid.IDTypeID with retpol_ prefix
CategorystringCategory to apply to. Use "*" for all categories.
Durationtime.DurationRetain events for this duration. Events older than this are candidates.
ArchiveboolIf true, write to the archive sink before purging.
AppIDstringApplication scope.

Create a policy

Via the HTTP API

POST /v1/retention

Request body:

{
  "category": "auth",
  "duration": "2160h",
  "archive": true
}

Via the store directly

import (
    "time"
    "github.com/xraph/chronicle/retention"
    "github.com/xraph/chronicle/id"
)

policy := &retention.Policy{
    ID:       id.NewPolicyID(),
    Category: "auth",
    Duration: 90 * 24 * time.Hour, // 90 days
    Archive:  true,
    AppID:    "myapp",
}
err := store.SavePolicy(ctx, policy)

Enforcer

retention.NewEnforcer(store, archiveSink, logger) creates the enforcer. archiveSink may be nil if no archival is needed.

import "github.com/xraph/chronicle/retention"

enforcer := retention.NewEnforcer(myStore, s3Sink, logger)

result, err := enforcer.Enforce(ctx)
fmt.Printf("archived=%d purged=%d retained=%d\n",
    result.Archived, result.Purged, result.Retained)

Enforce iterates all policies, finds events older than Duration, optionally writes them to the archive sink, then deletes them from the store.

EnforceResult

FieldTypeDescription
Archivedint64Events written to the archive sink
Purgedint64Events removed from the store
Retainedint64Events still within retention window

Archive sink

When Policy.Archive = true, the enforcer writes the events to the configured sink.Sink before purging. The archive sink receives the batch via sink.Write(ctx, events).

Configure the archive sink via the extension:

ext := extension.New(
    extension.WithStore(s),
    extension.WithArchiveSink(s3Sink),
)

Automated scheduling

The extension.WithRetentionInterval(d) option starts a background goroutine that calls Enforce every d:

ext := extension.New(
    extension.WithStore(s),
    extension.WithRetentionInterval(24 * time.Hour),
    extension.WithArchiveSink(s3Sink),
)

Set to 0 to disable automatic enforcement.

HTTP endpoints

MethodPathDescription
GET/v1/retentionList retention policies
POST/v1/retentionCreate or update a policy
DELETE/v1/retention/:idDelete a policy
POST/v1/retention/enforceTrigger immediate enforcement
GET/v1/retention/archivesList archive records

On this page