Documentation
¶
Overview ¶
Package logstream shares one live log stream per app part between everyone watching it on a replica (O-51).
The console's Logs tab used to ask the runtime for the last 500 lines every five seconds, from every tab that had an app open. Each ask is a container log read (Docker) or a pod log request (Kubernetes), so the runtime's load grew with the number of people looking rather than with the number of apps. A Hub holds one following runtime.Logs stream per (runtime, app, part) while at least one viewer watches it, keeps the most recent lines in a bounded ring for whoever joins next, and fans each new line out to every viewer. The runtime stream closes a short grace period after the last viewer leaves, so a page reload does not reopen it.
Only what the runtime printed is shared here. Whether a viewer may read it is decided by the caller when the viewer connects, and decided again on an interval while the viewer stays connected (Serve, R-048, design 06 §4.2): a shared stream never carries an authorization decision.
Design notes: docs/design/notes-shared-log-streams-o51.md.
Index ¶
Constants ¶
const ( // Backfill is how many recent lines a stream holds for a viewer who joins // after it opened, and how many it asks the runtime for when it opens. DefaultBackfill = 1000 // DefaultTail is what a one-shot read returns when no tail is given, and // MaxTail is the most it returns whatever is asked for. A larger tail is // cut to MaxTail rather than refused: a person asking for "everything" is // better served by the most Pando will send than by an error. DefaultTail = 200 MaxTail = 5000 // DefaultGrace is how long a stream with no viewers stays open, so a page // reload or a switch between parts and back does not reopen it. DefaultGrace = 30 * time.Second // DefaultBuffer is how many events one viewer may fall behind by before // it is disconnected. Large enough to take a full backfill arriving in one // burst when a stream opens. DefaultBuffer = 2048 // MaxLineBytes is the longest line passed on; the rest of a longer line is // dropped and the line ends with an ellipsis. One unbroken megabyte of // output would otherwise be one megabyte per viewer per buffer slot. MaxLineBytes = 16 << 10 // Reconnect backoff after the runtime's stream ends. DefaultRetryMin = time.Second DefaultRetryMax = 30 * time.Second )
Defaults. Each is a [P] default recorded in the design note.
const DefaultReauthEvery = assertion.Lifetime
DefaultReauthEvery is how often a connected viewer's access is checked again. It is assertion.Lifetime itself rather than a copy of its value, as the proxy's long-lived connections are: design 06 §3.1 sets one revocation window, and every long-lived path re-checks on exactly that interval.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Authorize ¶
Authorize decides again whether the viewer may still read the log. A nil error allows; any error ends the stream, an unknown answer included.
type Hub ¶
type Hub struct {
// contains filtered or unexported fields
}
Hub is one replica's set of shared log streams. Use New.
func (*Hub) Serve ¶
Serve writes sub's backfill and then its events to v until the viewer goes (ctx ends, or a write fails), the viewer falls too far behind, or authorize stops allowing. It closes sub. It returns nil when the viewer went, and an *Ended when Pando ended the stream.
authorize runs every DefaultReauthEvery: the check that let the viewer in fires once, and without this a log stream would outlive the access that opened it (R-048, design 06 §3.1, §4.2).
func (*Hub) Subscribe ¶
func (h *Hub) Subscribe(ctx context.Context, rt api.RuntimeAdapter, key Key) (*Subscription, error)
Subscribe joins the shared stream for key, opening it on rt if this replica has none. The caller has already authorized the viewer. The open's error — nothing running under that name, the runtime unreachable — is returned here, before anything has been sent, so it can be answered as an error.
The subscription must be closed.
type Option ¶
type Option func(*Hub)
Option configures a Hub.
func WithBackfill ¶
WithBackfill sets how many recent lines a stream keeps.
func WithLogger ¶
WithLogger sets where the hub logs a stream it could not reopen.
func WithReauthEvery ¶
WithReauthEvery sets how often Serve checks a viewer's access again.
type Reason ¶
type Reason string
Reason says why Pando, rather than the viewer, ended a viewer's stream.
type Subscription ¶
type Subscription struct {
// Backfill is the most recent lines the stream held when the viewer
// joined, oldest first. Lines arriving after it are on Events.
Backfill []string
// contains filtered or unexported fields
}
Subscription is one viewer of a shared stream.
func (*Subscription) Close ¶
func (s *Subscription) Close()
Close leaves the stream. Safe to call more than once.
func (*Subscription) Ended ¶
func (s *Subscription) Ended() *Ended
Ended is why Pando closed Events, or nil if the viewer closed it.
func (*Subscription) Events ¶
func (s *Subscription) Events() <-chan Event
Events delivers what arrives after the backfill. It is closed when the viewer is closed or disconnected; Ended then says which.
type Viewer ¶
type Viewer interface {
Line(text string) error
Notice(text string) error
// Flush is called when there is nothing more to write for now, so a
// burst of lines is sent together rather than one network write each.
Flush() error
}
Viewer is where Serve writes one viewer's stream: the HTTP handler's server-sent events, or plain text for the CLI.