feat(surf): serve startup summary, shutdown report and http request log

- serve prints a startup summary on a terminal (version, environment, URL,
  admin, database host and name, pending migrations, plugins, drivers) and
  logs it as a 'startup summary' record plus 'listening on <addr>'
- on SIGINT/SIGTERM serve drains, prints and logs a shutdown report and
  returns nil (exit 0), or the drain errors (exit 1)
- the request log is on by default under diary component http with
  request_id; the route pattern, never the path, is logged
- lagoon.PendingMigrations, conga.Worker.Stats, diary.HideOnTTY,
  bonfire.IsTerminal and bonfire.Details back the summary and report
This commit is contained in:
Jakub Zych
2026-10-21 12:59:07 +02:00
parent f0ee26f39f
commit c38dc1fe48
23 changed files with 1333 additions and 94 deletions

View File

@@ -73,9 +73,9 @@ func TestServeURL(t *testing.T) {
}
}
// TestServeBanner checks the summary's Admin value and the notes printed
// after the summary for each admin state.
func TestServeBanner(t *testing.T) {
listen := bannerLine{text: "listening on :8123, open http://127.0.0.1:8123/"}
mounted := bannerLine{text: "admin: http://127.0.0.1:8123/backend"}
create := "summer admin:create --email you@example.com --superuser"
for _, tc := range []struct {
name string
@@ -83,25 +83,24 @@ func TestServeBanner(t *testing.T) {
prefix string
mounted bool
admins adminPresence
want []bannerLine
value string
notes []bannerLine
}{
{"present", ":8123", "/backend", true, adminsPresent, []bannerLine{listen, mounted}},
{"none", ":8123", "/backend", true, adminsNone, []bannerLine{listen, mounted,
{"present", ":8123", "/backend", true, adminsPresent, "http://127.0.0.1:8123/backend", nil},
{"none", ":8123", "/backend", true, adminsNone, "http://127.0.0.1:8123/backend", []bannerLine{
{warn: true, text: "no administrators yet; create one with " + create}}},
{"missing table", ":8123", "/backend", true, adminsMissingTable, []bannerLine{listen, mounted,
{"missing table", ":8123", "/backend", true, adminsMissingTable, "http://127.0.0.1:8123/backend", []bannerLine{
{warn: true, text: "the admin tables do not exist yet; run summer migrate, then " + create}}},
{"unknown", ":8123", "/backend", true, adminsUnknown, []bannerLine{listen, mounted,
{"unknown", ":8123", "/backend", true, adminsUnknown, "http://127.0.0.1:8123/backend", []bannerLine{
{text: "sign in with an administrator; " + create + " creates one"}}},
{"off", ":8123", "", false, adminsUnknown, []bannerLine{listen,
{text: "admin: off — no plugin registers an admin controller"},
{text: "to add one, run summer make:admin-controller <vendor.plugin> <Name>, then summer build, summer migrate and " + create + "; the admin needs SUMMER_ADMIN__JWT__SECRET, which summer new writes to .env"}}},
{"unparsable address", "8080", "/backend", true, adminsPresent, []bannerLine{
{text: "listening on 8080"}, {text: "admin: mounted at /backend"}}},
{"off", ":8123", "", false, adminsUnknown, "off — no plugin registers an admin controller", []bannerLine{
{text: "to add an admin, run summer make:admin-controller <vendor.plugin> <Name>, then summer build, summer migrate and " + create + "; the admin needs SUMMER_ADMIN__JWT__SECRET, which summer new writes to .env"}}},
{"unparsable address", "8080", "/backend", true, adminsPresent, "mounted at /backend", nil},
} {
t.Run(tc.name, func(t *testing.T) {
got := serveBanner(tc.addr, tc.prefix, tc.mounted, tc.admins)
if !slices.Equal(got, tc.want) {
t.Fatalf("serveBanner:\n got %#v\nwant %#v", got, tc.want)
value, notes := adminStatus(serveURL(tc.addr), tc.prefix, tc.mounted, tc.admins)
if value != tc.value || !slices.Equal(notes, tc.notes) {
t.Fatalf("adminStatus:\n got %q %#v\nwant %q %#v", value, notes, tc.value, tc.notes)
}
})
}