mirror of
https://github.com/zap-proto/zip.git
synced 2026-10-19 15:38:57 +00:00
Every program built on zip now emits one log line per request through its own
luxfi/log logger — method, path, status, duration, trace and span, plus the
caller when the environment parked one — and RED metrics through luxfi/metric,
with W3C trace context joined when a request carries it, minted when it does
not, and propagated on Call with no handler code. /metrics renders the one
registry, and export speaks the shipped ZAP exporter, which is what o11y
ingests. Config.Telemetry{Addr, Off} is the only switch; the default is on.
The boundary is installed outermost by materialise, so requests that match
nothing — 404s, preflights — are still counted; per-route composition cannot
see them. Two defects the tests forced out: the status is derived from the
handler's error, because at the boundary the response still reads 200 (fiber
writes the real status after unwinding, so every refusal would have recorded
as success); and the route label reads the not-found sentinel, because an
unmatched request leaves the middleware's own registration in place and would
otherwise be indistinguishable from a real root leaf.
middleware.Logger and middleware.Telemetry are deleted, not deprecated:
telemetry an app can lack is the defect this closes.
luxfi/metric moves to v1.9.1 — v1.9.0 is the published build whose registry
constructors sit behind a build tag nothing sets, so counters accepted Inc()
into a registry nothing gathers and /metrics served empty.
Co-authored-by: Hanzo Dev <[email protected]>
70 lines
2.7 KiB
Go
70 lines
2.7 KiB
Go
package zip
|
|
|
|
// The peer surface — one app's ops as another app may invoke them.
|
|
//
|
|
// A typed op rides EVERY transport its app listens on. So an internal op
|
|
// registered on the edge-facing app is an internal op served on :8000, and the
|
|
// separation between "what the world may call" and "what a peer may call" has to
|
|
// be structural rather than a check somebody remembers to write.
|
|
//
|
|
// It is a second [App], listening only on [SocketPath], and it is reached with
|
|
// [Ask]. That is the whole of the internal call plane: no registry, no discovery,
|
|
// no address in a caller's configuration — the name IS the address.
|
|
|
|
// Peer is this app's peer sibling: the ops a peer may invoke, served ONLY on
|
|
// this app's canonical socket and never on the edge.
|
|
//
|
|
// svc.ops(app) // the world's surface
|
|
// svc.plane(app.Peer()) // the fleet's surface
|
|
// return app.Listen(zip.Addr(":9653"))
|
|
//
|
|
// [App.Listen] brings it up, so there is one serve verb and no second Listen to
|
|
// forget. It exists only when something registered on it: an app with no peer
|
|
// ops binds no peer socket, and one that has them binds exactly the path every
|
|
// caller's [Ask] resolves.
|
|
//
|
|
// Memoized, because two peer apps would be two answers to one op name.
|
|
func (a *App) Peer() *App {
|
|
a.peerOnce.Do(func() {
|
|
p := New(Config{
|
|
AppName: a.cfg.AppName,
|
|
Logger: a.logger,
|
|
DisableStartupMessage: true,
|
|
// A peer surface publishes no document and serves no agent door: it is
|
|
// reached by name and op token from inside the fleet, and its schema is
|
|
// the Go types both ends import.
|
|
OpenAPI: OpenAPIConfig{Disabled: true},
|
|
MCP: MCPConfig{Disabled: true},
|
|
})
|
|
p.sibling = true
|
|
// The peer surface reports into the primary's instruments: a call a peer
|
|
// makes is work this process did, and it belongs in the same numbers as
|
|
// the work the edge asked for. See [App.Ops] for the same reasoning.
|
|
p.telemetry = a.telemetry
|
|
a.peer = p
|
|
})
|
|
return a.peer
|
|
}
|
|
|
|
// servePeer binds the peer sibling to this app's canonical socket. Called from
|
|
// Listen on the PRIMARY app only, and only when peer ops were registered — a
|
|
// plugin that answers no peer op should not create a socket other processes can
|
|
// dial and get nothing from.
|
|
func (a *App) servePeer() {
|
|
if a.sibling || a.peer == nil || len(a.peer.Registry()) == 0 {
|
|
return
|
|
}
|
|
if a.cfg.AppName == "" {
|
|
a.logger.Error("zip: peer ops registered on an app with no AppName — " +
|
|
"the name IS the socket, so there is nowhere to serve them")
|
|
return
|
|
}
|
|
sock := SocketPath(a.cfg.AppName)
|
|
peer := a.peer
|
|
go func() {
|
|
if err := peer.Listen(sock); err != nil {
|
|
a.logger.Error("zip peer listener stopped", "addr", sock, "err", err)
|
|
}
|
|
}()
|
|
}
|