Ctrl K
ComunidadGuías…

codersdk/disconnect.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package codersdk

import "cdr.dev/slog/v3"

// SlogDisconnectDetail is the slog field for the free-form, human-readable
// detail string that supplements the structured reason. Use it for
// "exited with code 137" style information that does not fit a category.
func SlogDisconnectDetail(detail string) slog.Field {
	return slog.F("disconnect_detail", detail)
}

// DisconnectReason categorizes why a workspace connection ended. It is
// emitted as a slog field at every disconnect log site so operators can
// filter and aggregate disconnects without parsing free-form reason
// strings.
//
// The set of values intentionally stays small. Use DisconnectReasonUnknown
// when no other value applies; do not invent ad-hoc strings. Add a new
// constant here (and update its godoc) when a new disconnect class is
// genuinely distinct from the existing ones.
type DisconnectReason string

func (r DisconnectReason) SlogField() slog.Field {
	if r == "" {
		return slog.F("disconnect_reason", "unknown")
	}
	return slog.F("disconnect_reason", r)
}

func (r DisconnectReason) SlogExpectedField() slog.Field {
	return slog.F("disconnect_expected", r.Expected())
}

const (
	// DisconnectReasonUnknown is the zero value. Use it when the disconnect
	// path cannot determine a more specific reason. Treat any disconnect
	// logged with this value as a bug to investigate, not as a normal
	// outcome.
	DisconnectReasonUnknown DisconnectReason = ""

	// DisconnectReasonGraceful indicates the connection ended cleanly: the
	// remote side acknowledged a Disconnect message, an SSH session exited
	// with status 0, or a PTY closed without error. This is the expected
	// "happy path" outcome.
	DisconnectReasonGraceful DisconnectReason = "graceful"

	// DisconnectReasonClientClosed indicates the client side closed the
	// connection without an error (for example, the user closed their
	// terminal or quit their IDE). The session ran to a natural end from
	// the client's perspective.
	DisconnectReasonClientClosed DisconnectReason = "client_closed"

	// DisconnectReasonServerShutdown indicates the workspace agent or
	// coderd is shutting down and is closing connections as part of that
	// shutdown. The connection itself was healthy; the process is going
	// away.
	DisconnectReasonServerShutdown DisconnectReason = "server_shutdown"

	// DisconnectReasonNetworkError indicates the transport failed: an EOF,
	// a read or write error, a context cancellation caused by a timeout,
	// or a similar I/O failure. The connection did not end cleanly.
	DisconnectReasonNetworkError DisconnectReason = "network_error"

	// DisconnectReasonProtocolError indicates a dRPC, SSH, or tailnet
	// protocol violation by the peer. Distinct from network errors because
	// the bytes flowed but the contents were unparsable or unexpected.
	DisconnectReasonProtocolError DisconnectReason = "protocol_error"

	// DisconnectReasonWorkspaceStopped indicates the workspace itself was
	// stopped or deleted while the connection was open, so coderd closed
	// outstanding sessions on its behalf.
	DisconnectReasonWorkspaceStopped DisconnectReason = "workspace_stopped"

	// DisconnectReasonControlPlaneLost indicates the agent or client lost
	// its coordination RPC to coderd. The data plane (peer-to-peer or
	// DERP) may still be functional; this records the control plane
	// outcome specifically.
	DisconnectReasonControlPlaneLost DisconnectReason = "control_plane_lost"
)

// Valid reports whether r is a known DisconnectReason. The zero value
// (DisconnectReasonUnknown) is considered valid since it is the explicit
// "no information" reason.
func (r DisconnectReason) Valid() bool {
	switch r {
	case DisconnectReasonUnknown,
		DisconnectReasonGraceful,
		DisconnectReasonClientClosed,
		DisconnectReasonServerShutdown,
		DisconnectReasonNetworkError,
		DisconnectReasonProtocolError,
		DisconnectReasonWorkspaceStopped,
		DisconnectReasonControlPlaneLost:
		return true
	default:
		return false
	}
}

// Expected reports whether a disconnect with this reason is part of
// normal operation. Operators can use this to split dashboards or alerts
// into "expected" and "investigate" buckets without enumerating every
// reason.
func (r DisconnectReason) Expected() bool {
	switch r {
	case DisconnectReasonGraceful,
		DisconnectReasonClientClosed,
		DisconnectReasonServerShutdown,
		DisconnectReasonWorkspaceStopped:
		return true
	case DisconnectReasonUnknown,
		DisconnectReasonNetworkError,
		DisconnectReasonProtocolError,
		DisconnectReasonControlPlaneLost:
		return false
	default:
		// Unknown reason values are treated as not expected so that
		// new emit sites that forget to classify themselves surface
		// in the "investigate" bucket by default.
		return false
	}
}

// DisconnectInitiator identifies which side caused the disconnect. It
// pairs with DisconnectReason: the reason describes what happened, the
// initiator describes who started it.
type DisconnectInitiator string

const (
	// DisconnectInitiatorUnknown means the disconnect site cannot
	// attribute the close to a specific side. Avoid this where possible.
	DisconnectInitiatorUnknown DisconnectInitiator = ""

	// DisconnectInitiatorClient means the user-facing side (CLI, VS Code
	// extension, JetBrains plugin, Coder Desktop) closed the connection.
	DisconnectInitiatorClient DisconnectInitiator = "client"

	// DisconnectInitiatorAgent means the workspace agent closed the
	// connection.
	DisconnectInitiatorAgent DisconnectInitiator = "agent"

	// DisconnectInitiatorServer means coderd (or a workspace proxy)
	// closed the connection.
	DisconnectInitiatorServer DisconnectInitiator = "server"

	// DisconnectInitiatorNetwork means an underlying network or transport
	// fault caused the close. Neither end deliberately initiated it.
	DisconnectInitiatorNetwork DisconnectInitiator = "network"
)

func (i DisconnectInitiator) SlogField() slog.Field {
	return slog.F("disconnect_initiator", i)
}

// Valid reports whether i is a known DisconnectInitiator.
func (i DisconnectInitiator) Valid() bool {
	switch i {
	case DisconnectInitiatorUnknown,
		DisconnectInitiatorClient,
		DisconnectInitiatorAgent,
		DisconnectInitiatorServer,
		DisconnectInitiatorNetwork:
		return true
	default:
		return false
	}
}

// ConnectionDirection identifies which layer a disconnect log belongs to.
// It tells operators at a glance whether a log is about the control plane
// (server to agent) or the data plane (agent to client).
type ConnectionDirection string

func (d ConnectionDirection) SlogField() slog.Field {
	return slog.F("connect_type", d)
}

const (
	// ConnectionDirectionServerToAgent is the control-plane connection
	// between coderd and the workspace agent (coordination RPC, DERP map
	// subscriber, agent runLoop).
	ConnectionDirectionServerToAgent ConnectionDirection = "server_to_agent"

	// ConnectionDirectionAgentToClient is a data-plane session between
	// the workspace agent and a user's client (SSH, reconnecting PTY,
	// JetBrains port-forwarding).
	ConnectionDirectionAgentToClient ConnectionDirection = "agent_to_client"

	// ConnectionDirectionClientToServer is a connection from a user's
	// client to coderd (e.g. the CLI's WebSocket to the coordinator).
	// Not yet instrumented.
	ConnectionDirectionClientToServer ConnectionDirection = "client_to_server"
)

// ConnectionMethod describes the network path a workspace connection
// took at the moment a disconnect log was emitted. It is intended for
// observability only; do not switch behavior on it.
type ConnectionMethod string

func (m ConnectionMethod) SlogField() slog.Field {
	return slog.F("connection_method", m)
}

const (
	// ConnectionMethodUnknown means the disconnect site does not have
	// the information to determine the connection path.
	ConnectionMethodUnknown ConnectionMethod = ""

	// ConnectionMethodDirect means the peers were communicating over a
	// direct, peer-to-peer connection (NAT-traversed via STUN).
	ConnectionMethodDirect ConnectionMethod = "direct"

	// ConnectionMethodDERP means the peers were communicating through a
	// DERP relay rather than directly.
	ConnectionMethodDERP ConnectionMethod = "derp"
)

// Valid reports whether m is a known ConnectionMethod.
func (m ConnectionMethod) Valid() bool {
	switch m {
	case ConnectionMethodUnknown,
		ConnectionMethodDirect,
		ConnectionMethodDERP:
		return true
	default:
		return false
	}
}