- a reaper started at Mount checks every local session against the store every min(idle_ttl/2, 1m) and closes each copy whose record is gone, logging the expired step (A-CR-01, A-IN-06) - the GET stream re-check ends the stream when the record is gone (A-IN-01) - tool calls served without a session on the stateful path log the session as ephemeral (A-IN-06) - TestPierReaperSmoke and the ReapNow, LocalSessions, StopReaper seams
79 lines
2.3 KiB
Go
79 lines
2.3 KiB
Go
package pier
|
|
|
|
import (
|
|
"log/slog"
|
|
"time"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/diary"
|
|
)
|
|
|
|
// LogComponent is the diary component pier logs under.
|
|
const LogComponent = "pier"
|
|
|
|
// sessionPrefixLen is how much of a session id the audit lines show.
|
|
const sessionPrefixLen = 8
|
|
|
|
// stateless is the session value of a call served on the stateless path.
|
|
const stateless = "stateless"
|
|
|
|
// logger is the module's logger (component pier).
|
|
func logger() *slog.Logger {
|
|
return diary.For(LogComponent)
|
|
}
|
|
|
|
// sessionPrefix shortens a session id for logging; a stateless call logs
|
|
// "stateless" and a call served without a session on the stateful path
|
|
// "ephemeral".
|
|
func sessionPrefix(id string) string {
|
|
if id == "" {
|
|
return stateless
|
|
}
|
|
if id == ephemeralSession {
|
|
return ephemeralSession
|
|
}
|
|
if len(id) > sessionPrefixLen {
|
|
return id[:sessionPrefixLen]
|
|
}
|
|
return id
|
|
}
|
|
|
|
// logToolCall writes the one audit line per tool call (D-23): the tool,
|
|
// its guard, the frontend user id (0 when none), the backend admin id (0
|
|
// when none), the OAuth client id, the token kind, the session prefix, the
|
|
// route's status and the duration. Never the arguments, the body or a token.
|
|
func logToolCall(log *slog.Logger, id Identity, t *tool, session string, status int, took time.Duration) {
|
|
var userID, adminID uint
|
|
var clientID string
|
|
if id.Frontend != nil {
|
|
userID = id.Frontend.UserID
|
|
clientID = id.Frontend.ClientID
|
|
}
|
|
if id.Backend != nil {
|
|
adminID = id.Backend.UserID
|
|
if clientID == "" {
|
|
clientID = id.Backend.ClientID
|
|
}
|
|
}
|
|
log.Info("pier: tool call",
|
|
"tool", t.name,
|
|
"guard", t.guardName,
|
|
"user_id", userID,
|
|
"admin_id", adminID,
|
|
"client_id", clientID,
|
|
"token_kind", id.TokenKind,
|
|
"session", sessionPrefix(session),
|
|
"status", status,
|
|
"duration_ms", took.Milliseconds(),
|
|
)
|
|
}
|
|
|
|
// logSession writes one line per session lifecycle step with the session
|
|
// prefix and the binding, never the token. The steps: open (serveNew),
|
|
// rehydrate (lookup), end (DELETE), binding_refused (another binding
|
|
// presented the id), revoked (a revocation or deletion event),
|
|
// stream_closed (a GET stream whose bearer or record is gone) and expired
|
|
// (the reaper closed a local copy whose record expired).
|
|
func logSession(log *slog.Logger, step, session, binding string) {
|
|
log.Info("pier: session", "step", step, "session", sessionPrefix(session), "binding", binding)
|
|
}
|