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:
@@ -157,6 +157,8 @@ if catalog.Has("blog:import") {
|
||||
| `bonfire.GlobalsOf` | The `bonfire.Globals` of the command an Output belongs to (zero for other Output implementations). |
|
||||
| `bonfire.VerbosityOf` | The `-v` level of the command an Output belongs to. |
|
||||
| `bonfire.IsQuiet` | Whether the command runs with `-q`. |
|
||||
| `bonfire.IsTerminal` | Whether the Output writes to a terminal; long-running commands print a summary block for a person there and log records otherwise. |
|
||||
| `bonfire.Details`, `bonfire.Detail` | Prints a title and aligned label/value lines in the palette (a `Warn` value in the warning color); nothing under `-q`. Used for startup summaries and shutdown reports. |
|
||||
| `bonfire.Interactive` | Whether the Output can ask a person: stdin and stdout are terminals and neither `-n` nor `-q` is set. |
|
||||
| `bonfire.ConfirmProceed` | Asks before a destructive step on an interactive terminal; returns true without asking otherwise. |
|
||||
| `bonfire.ErrAborted` | Returned by a prompt the person cancelled. |
|
||||
|
||||
@@ -3,6 +3,7 @@ package bonfire
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
tea "charm.land/bubbletea/v2"
|
||||
)
|
||||
@@ -13,12 +14,15 @@ import (
|
||||
type consoleState interface {
|
||||
consoleGlobals() Globals
|
||||
consoleInteractive() bool
|
||||
consoleTerminal() bool
|
||||
}
|
||||
|
||||
func (c *console) consoleGlobals() Globals { return c.globals }
|
||||
|
||||
func (c *console) consoleInteractive() bool { return c.canPrompt() }
|
||||
|
||||
func (c *console) consoleTerminal() bool { return c.tty }
|
||||
|
||||
// GlobalsOf returns the global options of the command out belongs to, or
|
||||
// the zero Globals when out is not a bonfire console.
|
||||
func GlobalsOf(out Output) Globals {
|
||||
@@ -48,6 +52,66 @@ func Interactive(out Output) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsTerminal reports whether out writes to a terminal (its stdout is one).
|
||||
// It is false for other Output implementations and inside bonfire.Call.
|
||||
// Long-running commands use it to choose between a styled summary block for
|
||||
// a person and log records for journald.
|
||||
func IsTerminal(out Output) bool {
|
||||
if s, ok := out.(consoleState); ok {
|
||||
return s.consoleTerminal()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Detail is one line of a Details block: a label and its value. Warn
|
||||
// prints the value in the warning color.
|
||||
type Detail struct {
|
||||
Label string
|
||||
Value string
|
||||
Warn bool
|
||||
}
|
||||
|
||||
// Details prints title (when not empty) and rows as aligned label/value
|
||||
// lines in the console palette: muted labels padded to the longest one,
|
||||
// values in the default color or, with Warn, in the warning color. It
|
||||
// prints nothing under -q. serve, queue:work and summer dev use it for
|
||||
// their startup summaries and shutdown reports.
|
||||
func Details(out Output, title string, rows []Detail) {
|
||||
if IsQuiet(out) {
|
||||
return
|
||||
}
|
||||
width := 0
|
||||
for _, r := range rows {
|
||||
width = max(width, len([]rune(r.Label)))
|
||||
}
|
||||
c, styled := out.(*console)
|
||||
var b strings.Builder
|
||||
if title != "" {
|
||||
if styled {
|
||||
b.WriteString(c.palette.Header.Render(title))
|
||||
} else {
|
||||
b.WriteString(title)
|
||||
}
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
for _, r := range rows {
|
||||
label := r.Label + strings.Repeat(" ", width-len([]rune(r.Label)))
|
||||
value := r.Value
|
||||
if styled {
|
||||
label = c.palette.Muted.Render(label)
|
||||
if r.Warn {
|
||||
value = c.palette.Warning.Render(value)
|
||||
}
|
||||
}
|
||||
b.WriteString(" " + label + " " + value + "\n")
|
||||
}
|
||||
if styled {
|
||||
c.emit(c.out, b.String())
|
||||
return
|
||||
}
|
||||
out.Printf("%s", b.String())
|
||||
}
|
||||
|
||||
// ConfirmProceed asks question before a destructive step, defaulting to
|
||||
// no, only when out is Interactive. Off a terminal, with -n or -q and in
|
||||
// bonfire.Call it returns true without asking, so deploys over SSH and
|
||||
|
||||
Reference in New Issue
Block a user