exitrecord

package
v0.16.1 Latest Latest
Warning

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

Go to latest
Published: Sep 24, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package exitrecord persists why systemd last stopped a miren daemon, so the next run can tell the user about it.

The information only exists for an instant. systemd exposes the reason a unit stopped as the unit's Result property, and resets it to "success" as soon as the replacement instance activates — so a process that looks at its own unit during startup always sees a healthy unit, however violently its predecessor died. The one place the reason is readable is an ExecStopPost hook, which runs after the main process is gone and has SERVICE_RESULT in its environment.

So the hook writes a record here, and the next boot reads it. Without this, a server killed for exceeding its memory limit comes back up with no idea that it ever went down, and neither does the operator.

Index

Constants

View Source
const (
	// FileName holds an exit that has not yet been reported.
	FileName = "last-exit.json"

	// ReportedFileName holds one that has. Renaming rather than deleting keeps
	// the detail available for later diagnosis while making sure the warning is
	// logged once per occurrence instead of on every boot.
	ReportedFileName = "last-exit.reported.json"

	// ResultSuccess is systemd's SERVICE_RESULT for a clean stop.
	ResultSuccess = "success"

	// ResultOOMKill is systemd's SERVICE_RESULT when the kernel's out-of-memory
	// killer took a process in the unit's cgroup.
	ResultOOMKill = "oom-kill"
)

Variables

This section is empty.

Functions

func Clear

func Clear(dir string) error

Clear removes any stored record. Called after a clean stop, so the file's presence always means the previous run ended badly.

func MarkReported

func MarkReported(dir string) error

MarkReported moves the record aside once it has been surfaced to the user.

func Write

func Write(dir string, r Record) error

Write stores a record in dir, replacing any previous one. The write is atomic so a crash mid-write can't leave a half-written record for the next boot to choke on.

Types

type Record

type Record struct {
	At   time.Time `json:"at"`
	Unit string    `json:"unit"`

	// Result is systemd's SERVICE_RESULT, e.g. "oom-kill", "signal",
	// "exit-code", "timeout".
	Result string `json:"result"`

	// ExitCode is systemd's EXIT_CODE: "exited", "killed" or "dumped".
	ExitCode string `json:"exit_code,omitempty"`

	// ExitStatus is the numeric status or signal that goes with ExitCode.
	ExitStatus string `json:"exit_status,omitempty"`

	// MemoryPeak is the highest memory the unit's cgroup reached, and MemoryMax
	// the limit it was held to. Both are 0 when systemd didn't report them —
	// MemoryPeak needs systemd 254 or newer, and MemoryMax reads as "infinity"
	// when no limit is set.
	MemoryPeak int64 `json:"memory_peak,omitempty"`
	MemoryMax  int64 `json:"memory_max,omitempty"`

	// Restarts is the unit's NRestarts counter at the time of the exit.
	Restarts int `json:"restarts,omitempty"`
}

Record is one abnormal exit of a miren daemon.

func Read

func Read(dir string) (Record, bool, error)

Read returns the unreported record in dir. The boolean is false when there isn't one, which is the ordinary case: nothing went wrong last time.

func (Record) LogTo

func (r Record) LogTo(log *slog.Logger)

LogTo writes the record as a single warning.

Warn rather than Error: the platform did its job. The control process was contained and restarted instead of taking the host down with it, and an Error here would page someone about a system that worked as designed.

Individual fields are named rather than logging the struct, per the log-level guidance in CLAUDE.md — "%+v" on a record renders its whole field tree inline.

func (Record) OOMKilled

func (r Record) OOMKilled() bool

OOMKilled reports whether this exit was the kernel reclaiming memory.

Jump to

Keyboard shortcuts

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