Telemetry
Every hyperlink-ts node already writes into Effects Metric registry — WorkPools, Daemons, HTTP clients, runtime gauges. Telemetry serves that registry as a Hyperlink: leaf fields for this node, fleet folds when the tag is meshed. OTEL stays the professional sink; Telemetry is for custom glass (CLI, TUI, web) over the same tags.
Declare the glass
One tag. Distribute it across the droplets you actually run — Context service keys, not nicknames.
class class DropletEastclass DropletEast {
key: Identifier;
Service: {
protocol: Context.Service.Shape<typeof RpcClient.Protocol>;
ping: Effect.Effect<number, NodeUnreachable>;
status: { readonly get: Effect.Effect<NodeStatusSnapshot, NodeUnreachable>; readonly changes: Stream.Stream<NodeStatusSnapshot, NodeUnreachable> };
logs: { readonly stream: Stream.Stream<LogEntry, NodeUnreachable>; readonly query: (options: { readonly limit: number }) => Effect.Effect<ReadonlyArray<LogEntry>, NodeUnreachable> };
};
}
DropletEast extends import NodeNode.Tag<Self, ROut = never>(): { (key: string): NodeTagClass<Self, ROut, BareAddress>; (key: string, target: { readonly path: string; readonly kind?: 'IpcSocket'; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, IpcAddress>; (key: string, target: number | `:${number}`): NodeTagClass<Self, ROut, HttpAddress>; (key: string, target: `ws://${string}` | `wss://${string}`): NodeTagClass<Self, ROut, WsAddress>; (key: string, target: `http://${string}` | `https://${string}`): NodeTagClass<Self, ROut, HttpAddress>; (key: string, target: { readonly url: `ws://${string}` | `wss://${string}`; readonly kind?: 'WebSocket'; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, WsAddress>; (key: string, target: { readonly url: string; readonly kind: 'WebSocket'; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, WsAddress>; (key: string, target: { readonly url: string; readonly kind: 'Http'; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, HttpAddress>; <T extends ShorthandTarget>(key: string, target: T): NodeTagClass<Self, ROut, MultiAddress<KindsOf<T>>>; (key: string, target: string | { readonly url: string; readonly kind?: ProtocolKind; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, UrlAddressLoose>; (key: string, target?: LooseNodeTarget): NodeTagClass<Self, ROut, BareAddress | IpcAddress | HttpAddress | WsAddress | UrlAddressLoose | MultiAddress<ProtocolKind>> }Declare a node — a named transport endpoint a HyperService connects to. Two-stage and keyed by
a string, mirroring Effect's Context.Service<Self, Shape>()(key) (a node is a Context.Key,
resolved by its key in the Context map) and every sibling factory (Hyperlink.Tag<Self>(), …).
The second call infers the target shape, so the { http, ws } shorthand types its
ProtocolKind
set precisely. Optional catalog type param ROut (C2) — prefer import type
for those handles (C4). Templates (no address until cloned) live on
Node
.Prototype:
class EdgeNode extends Node.Tag<EdgeNode>()("edge") {} // no address yet
class Worker extends Node.Tag<Worker>()("worker", 3001) {} // → http://localhost:3001/rpc, kind "Http"
class Mail extends Node.Tag<Mail>()("mail", "https://mail.internal/rpc") {} // full url, as-is, kind "Http"
class Live extends Node.Tag<Live>()("live", { url: "wss://live/rpc" }) {} // kind "WebSocket" (inferred from ws url)
class Push extends Node.Tag<Push>()("push", { url: "/rpc", kind: "WebSocket" }) {} // same-origin path, explicit kind
class Local extends Node.Tag<Local>()("local", { path: "/tmp/local.sock" }) {} // kind "IpcSocket" (Unix domain)
class Droplet extends Node.Tag<Droplet>()("droplet", { http: "http://d/rpc", ws: "ws://d/rpc" }) {} // multi-protocol
import type { Jobs, Emails } from "@app/contracts"
class AppWorker extends Node.Tag<AppWorker, Jobs | Emails>()("app/Worker", { path: "/tmp/w.sock" }) {}
class MailWorker extends Node.Prototype<MailWorker, Mail>("app/MailWorker") {}
The key is the service key. The optional address matches a dial target: a port
(3001 or ":3001" → http://localhost:3001/rpc), a full url (used as-is), { url, kind } for
an explicit endpoint, { path } for a Unix-domain socket (kind: "IpcSocket"), or the
{ http, ws, ipc } multi-protocol shorthand. The node carries
ProtocolKind
so the topology
is self-describing about where AND how:
connect
(node) derives the transport with no
protocol argument.
Dialable targets return an
AddressedNode
(kind: ProtocolKind) so
Hyperlink.client(Tag, Worker) can auto-wire
connect
. Bare Node.Tag()("x")
stays address-less (kind: undefined) — still needs explicit connect / lookup.
Tag<class DropletEastclass DropletEast {
key: Identifier;
Service: {
protocol: Context.Service.Shape<typeof RpcClient.Protocol>;
ping: Effect.Effect<number, NodeUnreachable>;
status: { readonly get: Effect.Effect<NodeStatusSnapshot, NodeUnreachable>; readonly changes: Stream.Stream<NodeStatusSnapshot, NodeUnreachable> };
logs: { readonly stream: Stream.Stream<LogEntry, NodeUnreachable>; readonly query: (options: { readonly limit: number }) => Effect.Effect<ReadonlyArray<LogEntry>, NodeUnreachable> };
};
}
DropletEast>()("app/DropletEast") {}
class class DropletWestclass DropletWest {
key: Identifier;
Service: {
protocol: Context.Service.Shape<typeof RpcClient.Protocol>;
ping: Effect.Effect<number, NodeUnreachable>;
status: { readonly get: Effect.Effect<NodeStatusSnapshot, NodeUnreachable>; readonly changes: Stream.Stream<NodeStatusSnapshot, NodeUnreachable> };
logs: { readonly stream: Stream.Stream<LogEntry, NodeUnreachable>; readonly query: (options: { readonly limit: number }) => Effect.Effect<ReadonlyArray<LogEntry>, NodeUnreachable> };
};
}
DropletWest extends import NodeNode.Tag<Self, ROut = never>(): { (key: string): NodeTagClass<Self, ROut, BareAddress>; (key: string, target: { readonly path: string; readonly kind?: 'IpcSocket'; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, IpcAddress>; (key: string, target: number | `:${number}`): NodeTagClass<Self, ROut, HttpAddress>; (key: string, target: `ws://${string}` | `wss://${string}`): NodeTagClass<Self, ROut, WsAddress>; (key: string, target: `http://${string}` | `https://${string}`): NodeTagClass<Self, ROut, HttpAddress>; (key: string, target: { readonly url: `ws://${string}` | `wss://${string}`; readonly kind?: 'WebSocket'; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, WsAddress>; (key: string, target: { readonly url: string; readonly kind: 'WebSocket'; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, WsAddress>; (key: string, target: { readonly url: string; readonly kind: 'Http'; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, HttpAddress>; <T extends ShorthandTarget>(key: string, target: T): NodeTagClass<Self, ROut, MultiAddress<KindsOf<T>>>; (key: string, target: string | { readonly url: string; readonly kind?: ProtocolKind; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, UrlAddressLoose>; (key: string, target?: LooseNodeTarget): NodeTagClass<Self, ROut, BareAddress | IpcAddress | HttpAddress | WsAddress | UrlAddressLoose | MultiAddress<ProtocolKind>> }Declare a node — a named transport endpoint a HyperService connects to. Two-stage and keyed by
a string, mirroring Effect's Context.Service<Self, Shape>()(key) (a node is a Context.Key,
resolved by its key in the Context map) and every sibling factory (Hyperlink.Tag<Self>(), …).
The second call infers the target shape, so the { http, ws } shorthand types its
ProtocolKind
set precisely. Optional catalog type param ROut (C2) — prefer import type
for those handles (C4). Templates (no address until cloned) live on
Node
.Prototype:
class EdgeNode extends Node.Tag<EdgeNode>()("edge") {} // no address yet
class Worker extends Node.Tag<Worker>()("worker", 3001) {} // → http://localhost:3001/rpc, kind "Http"
class Mail extends Node.Tag<Mail>()("mail", "https://mail.internal/rpc") {} // full url, as-is, kind "Http"
class Live extends Node.Tag<Live>()("live", { url: "wss://live/rpc" }) {} // kind "WebSocket" (inferred from ws url)
class Push extends Node.Tag<Push>()("push", { url: "/rpc", kind: "WebSocket" }) {} // same-origin path, explicit kind
class Local extends Node.Tag<Local>()("local", { path: "/tmp/local.sock" }) {} // kind "IpcSocket" (Unix domain)
class Droplet extends Node.Tag<Droplet>()("droplet", { http: "http://d/rpc", ws: "ws://d/rpc" }) {} // multi-protocol
import type { Jobs, Emails } from "@app/contracts"
class AppWorker extends Node.Tag<AppWorker, Jobs | Emails>()("app/Worker", { path: "/tmp/w.sock" }) {}
class MailWorker extends Node.Prototype<MailWorker, Mail>("app/MailWorker") {}
The key is the service key. The optional address matches a dial target: a port
(3001 or ":3001" → http://localhost:3001/rpc), a full url (used as-is), { url, kind } for
an explicit endpoint, { path } for a Unix-domain socket (kind: "IpcSocket"), or the
{ http, ws, ipc } multi-protocol shorthand. The node carries
ProtocolKind
so the topology
is self-describing about where AND how:
connect
(node) derives the transport with no
protocol argument.
Dialable targets return an
AddressedNode
(kind: ProtocolKind) so
Hyperlink.client(Tag, Worker) can auto-wire
connect
. Bare Node.Tag()("x")
stays address-less (kind: undefined) — still needs explicit connect / lookup.
Tag<class DropletWestclass DropletWest {
key: Identifier;
Service: {
protocol: Context.Service.Shape<typeof RpcClient.Protocol>;
ping: Effect.Effect<number, NodeUnreachable>;
status: { readonly get: Effect.Effect<NodeStatusSnapshot, NodeUnreachable>; readonly changes: Stream.Stream<NodeStatusSnapshot, NodeUnreachable> };
logs: { readonly stream: Stream.Stream<LogEntry, NodeUnreachable>; readonly query: (options: { readonly limit: number }) => Effect.Effect<ReadonlyArray<LogEntry>, NodeUnreachable> };
};
}
DropletWest>()("app/DropletWest") {}
class class DropletCentralclass DropletCentral {
key: Identifier;
Service: {
protocol: Context.Service.Shape<typeof RpcClient.Protocol>;
ping: Effect.Effect<number, NodeUnreachable>;
status: { readonly get: Effect.Effect<NodeStatusSnapshot, NodeUnreachable>; readonly changes: Stream.Stream<NodeStatusSnapshot, NodeUnreachable> };
logs: { readonly stream: Stream.Stream<LogEntry, NodeUnreachable>; readonly query: (options: { readonly limit: number }) => Effect.Effect<ReadonlyArray<LogEntry>, NodeUnreachable> };
};
}
DropletCentral extends import NodeNode.Tag<Self, ROut = never>(): { (key: string): NodeTagClass<Self, ROut, BareAddress>; (key: string, target: { readonly path: string; readonly kind?: 'IpcSocket'; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, IpcAddress>; (key: string, target: number | `:${number}`): NodeTagClass<Self, ROut, HttpAddress>; (key: string, target: `ws://${string}` | `wss://${string}`): NodeTagClass<Self, ROut, WsAddress>; (key: string, target: `http://${string}` | `https://${string}`): NodeTagClass<Self, ROut, HttpAddress>; (key: string, target: { readonly url: `ws://${string}` | `wss://${string}`; readonly kind?: 'WebSocket'; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, WsAddress>; (key: string, target: { readonly url: string; readonly kind: 'WebSocket'; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, WsAddress>; (key: string, target: { readonly url: string; readonly kind: 'Http'; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, HttpAddress>; <T extends ShorthandTarget>(key: string, target: T): NodeTagClass<Self, ROut, MultiAddress<KindsOf<T>>>; (key: string, target: string | { readonly url: string; readonly kind?: ProtocolKind; readonly onConflict?: OnConflict }): NodeTagClass<Self, ROut, UrlAddressLoose>; (key: string, target?: LooseNodeTarget): NodeTagClass<Self, ROut, BareAddress | IpcAddress | HttpAddress | WsAddress | UrlAddressLoose | MultiAddress<ProtocolKind>> }Declare a node — a named transport endpoint a HyperService connects to. Two-stage and keyed by
a string, mirroring Effect's Context.Service<Self, Shape>()(key) (a node is a Context.Key,
resolved by its key in the Context map) and every sibling factory (Hyperlink.Tag<Self>(), …).
The second call infers the target shape, so the { http, ws } shorthand types its
ProtocolKind
set precisely. Optional catalog type param ROut (C2) — prefer import type
for those handles (C4). Templates (no address until cloned) live on
Node
.Prototype:
class EdgeNode extends Node.Tag<EdgeNode>()("edge") {} // no address yet
class Worker extends Node.Tag<Worker>()("worker", 3001) {} // → http://localhost:3001/rpc, kind "Http"
class Mail extends Node.Tag<Mail>()("mail", "https://mail.internal/rpc") {} // full url, as-is, kind "Http"
class Live extends Node.Tag<Live>()("live", { url: "wss://live/rpc" }) {} // kind "WebSocket" (inferred from ws url)
class Push extends Node.Tag<Push>()("push", { url: "/rpc", kind: "WebSocket" }) {} // same-origin path, explicit kind
class Local extends Node.Tag<Local>()("local", { path: "/tmp/local.sock" }) {} // kind "IpcSocket" (Unix domain)
class Droplet extends Node.Tag<Droplet>()("droplet", { http: "http://d/rpc", ws: "ws://d/rpc" }) {} // multi-protocol
import type { Jobs, Emails } from "@app/contracts"
class AppWorker extends Node.Tag<AppWorker, Jobs | Emails>()("app/Worker", { path: "/tmp/w.sock" }) {}
class MailWorker extends Node.Prototype<MailWorker, Mail>("app/MailWorker") {}
The key is the service key. The optional address matches a dial target: a port
(3001 or ":3001" → http://localhost:3001/rpc), a full url (used as-is), { url, kind } for
an explicit endpoint, { path } for a Unix-domain socket (kind: "IpcSocket"), or the
{ http, ws, ipc } multi-protocol shorthand. The node carries
ProtocolKind
so the topology
is self-describing about where AND how:
connect
(node) derives the transport with no
protocol argument.
Dialable targets return an
AddressedNode
(kind: ProtocolKind) so
Hyperlink.client(Tag, Worker) can auto-wire
connect
. Bare Node.Tag()("x")
stays address-less (kind: undefined) — still needs explicit connect / lookup.
Tag<class DropletCentralclass DropletCentral {
key: Identifier;
Service: {
protocol: Context.Service.Shape<typeof RpcClient.Protocol>;
ping: Effect.Effect<number, NodeUnreachable>;
status: { readonly get: Effect.Effect<NodeStatusSnapshot, NodeUnreachable>; readonly changes: Stream.Stream<NodeStatusSnapshot, NodeUnreachable> };
logs: { readonly stream: Stream.Stream<LogEntry, NodeUnreachable>; readonly query: (options: { readonly limit: number }) => Effect.Effect<ReadonlyArray<LogEntry>, NodeUnreachable> };
};
}
DropletCentral>()("app/DropletCentral") {}
class class FleetMetricsclass FleetMetrics {
key: Identifier;
Service: {
snapshot: Effect<Telemetry.MetricsSnapshot, never, never>;
live: Stream<Telemetry.MetricsSnapshot, never, never>;
inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>;
fleetInFlight: Effect<number, never, never>;
};
}
FleetMetrics extends import TelemetryTelemetry.const Tag: <Self>() => {
(): TelemetryTag<Self>
<HSelf>(options: {
readonly node: NodeKey<HSelf>
readonly description?: string
}): TelemetryNodeTag<Self, HSelf>
}
Declare a Telemetry tag: class FleetTelemetry extends Telemetry.Tag<FleetTelemetry>()() {} (nodeless
— the dashboard reaches each node via Hyperlink.client(FleetTelemetry, node)), or
…Tag<FleetTelemetry>()({ node: MiniNode }) to bind + serve it on a specific node.
Tag<class FleetMetricsclass FleetMetrics {
key: Identifier;
Service: {
snapshot: Effect<Telemetry.MetricsSnapshot, never, never>;
live: Stream<Telemetry.MetricsSnapshot, never, never>;
inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>;
fleetInFlight: Effect<number, never, never>;
};
}
FleetMetrics>()().Pipeable.pipe<Telemetry.TelemetryTag<FleetMetrics>, Telemetry.TelemetryTag<FleetMetrics>>(this: Telemetry.TelemetryTag<FleetMetrics>, ab: (_: Telemetry.TelemetryTag<FleetMetrics>) => Telemetry.TelemetryTag<FleetMetrics>): Telemetry.TelemetryTag<FleetMetrics> (+21 overloads)pipe(
import HyperlinkHyperlink.const nodes: {
<HSelf>(
nodeSet: readonly [AddressedNode<HSelf>]
): <T extends PipeableTag>(
tag: T
) => SoleNodeBind<T, AddressedNode<HSelf>>
<HSelf>(nodeSet: readonly [NodeKey<HSelf>]): <
T extends PipeableTag
>(
tag: T
) => SoleNodeBind<T, NodeKey<HSelf>>
<T extends PipeableTag>(
nodeSet: ReadonlyArray<AnyNode>
): (tag: T) => T
<Self, S extends Spec, HSelf>(
tag:
| HyperlinkTag<Self, S>
| NodeBoundTag<Self, S, HSelf>,
nodeSet: readonly [AddressedNode<HSelf>]
): SoleNodeBind<
NodeBoundTag<Self, S, HSelf>,
AddressedNode<HSelf>
>
<Self, S extends Spec, HSelf>(
tag:
| HyperlinkTag<Self, S>
| NodeBoundTag<Self, S, HSelf>,
nodeSet: readonly [NodeKey<HSelf>]
): SoleNodeBind<
NodeBoundTag<Self, S, HSelf>,
NodeKey<HSelf>
>
<Self, S extends Spec, HSelf>(
tag: NodeBoundTag<Self, S, HSelf>,
nodeSet: ReadonlyArray<AnyNode>
): NodeBoundTag<Self, S, HSelf>
<Self, S extends Spec>(
tag: HyperlinkTag<Self, S>,
nodeSet: ReadonlyArray<AnyNode>
): HyperlinkTag<Self, S>
}
nodes([class DropletEastclass DropletEast {
key: Identifier;
Service: {
protocol: Context.Service.Shape<typeof RpcClient.Protocol>;
ping: Effect.Effect<number, NodeUnreachable>;
status: { readonly get: Effect.Effect<NodeStatusSnapshot, NodeUnreachable>; readonly changes: Stream.Stream<NodeStatusSnapshot, NodeUnreachable> };
logs: { readonly stream: Stream.Stream<LogEntry, NodeUnreachable>; readonly query: (options: { readonly limit: number }) => Effect.Effect<ReadonlyArray<LogEntry>, NodeUnreachable> };
};
of: (this: void, self: NodeProtocol) => NodeProtocol;
context: (self: NodeProtocol) => Context<DropletEast>;
use: (f: (service: NodeProtocol) => Effect<A, E, R>) => Effect<A, E, DropletEast | R>;
useSync: (f: (service: NodeProtocol) => A) => Effect<A, never, DropletEast>;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
url: undefined;
path: undefined;
kind: undefined;
logs: unknown;
onConflict: OnConflict;
}
DropletEast, class DropletWestclass DropletWest {
key: Identifier;
Service: {
protocol: Context.Service.Shape<typeof RpcClient.Protocol>;
ping: Effect.Effect<number, NodeUnreachable>;
status: { readonly get: Effect.Effect<NodeStatusSnapshot, NodeUnreachable>; readonly changes: Stream.Stream<NodeStatusSnapshot, NodeUnreachable> };
logs: { readonly stream: Stream.Stream<LogEntry, NodeUnreachable>; readonly query: (options: { readonly limit: number }) => Effect.Effect<ReadonlyArray<LogEntry>, NodeUnreachable> };
};
of: (this: void, self: NodeProtocol) => NodeProtocol;
context: (self: NodeProtocol) => Context<DropletWest>;
use: (f: (service: NodeProtocol) => Effect<A, E, R>) => Effect<A, E, DropletWest | R>;
useSync: (f: (service: NodeProtocol) => A) => Effect<A, never, DropletWest>;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
url: undefined;
path: undefined;
kind: undefined;
logs: unknown;
onConflict: OnConflict;
}
DropletWest, class DropletCentralclass DropletCentral {
key: Identifier;
Service: {
protocol: Context.Service.Shape<typeof RpcClient.Protocol>;
ping: Effect.Effect<number, NodeUnreachable>;
status: { readonly get: Effect.Effect<NodeStatusSnapshot, NodeUnreachable>; readonly changes: Stream.Stream<NodeStatusSnapshot, NodeUnreachable> };
logs: { readonly stream: Stream.Stream<LogEntry, NodeUnreachable>; readonly query: (options: { readonly limit: number }) => Effect.Effect<ReadonlyArray<LogEntry>, NodeUnreachable> };
};
of: (this: void, self: NodeProtocol) => NodeProtocol;
context: (self: NodeProtocol) => Context<DropletCentral>;
use: (f: (service: NodeProtocol) => Effect<A, E, R>) => Effect<A, E, DropletCentral | R>;
useSync: (f: (service: NodeProtocol) => A) => Effect<A, never, DropletCentral>;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
url: undefined;
path: undefined;
kind: undefined;
logs: unknown;
onConflict: OnConflict;
}
DropletCentral]),
) {}Serve it on a droplet
Telemetry.serve forks the sampler and mounts leaf + fleet handlers. Discharge the mesh with Hyperlink.peersLayer so fleet fields can fold the other nodes leaf snapshots.
const const east: Layer.Layer<
| FleetMetrics
| Hyperlink.Local<FleetMetrics>
| Handler<"snapshot">
| Handler<"live">
| Handler<"inFlightByNode">
| Handler<"fleetInFlight">,
ServeError,
Scope
>
const east: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<FleetMetrics | Local<FleetMetrics> | Handler<'snapshot'> | Handler<'live'> | Handler<'inFlightByNode'> | Handler<'fleetInFlight'>>, ServeError, Scope.Scope>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
east = import TelemetryTelemetry.const serve: <Self>(
tag: TelemetryTag<Self>,
options?: TelemetryOptions
) => Layer.Layer<
| Self
| Hyperlink.Local<Self>
| Handler<"snapshot">
| Handler<"live">
| Handler<"inFlightByNode">
| Handler<"fleetInFlight">,
never,
| Hyperlink.PeersId<Self>
| Hyperlink.SelfNodeId<Self>
| Scope.Scope
>
Serve this Telemetry resource and grant its local instance from one materialization —
counterpart to
Hyperlink.serve
. Forks one sampling fiber, mounts leaf + fleet handlers,
and grants Self | Local<Self>. Requires the mesh capability (
alone
or
Telemetry.serve(FleetMetrics).pipe(
Layer.provide(Hyperlink.peersLayer(FleetMetrics, DropletEast)),
)
serve(class FleetMetricsclass FleetMetrics {
key: Identifier;
Service: {
snapshot: Effect<Telemetry.MetricsSnapshot, never, never>;
live: Stream<Telemetry.MetricsSnapshot, never, never>;
inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>;
fleetInFlight: Effect<number, never, never>;
};
description: string | undefined;
of: (this: void, self: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; reado…;
context: (self: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; readonly fleetInF…;
use: (f: (service: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; readonly f…;
useSync: (f: (service: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; readonly f…;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
FleetMetrics, {
TelemetryOptions.interval?: Duration.Duration(property) TelemetryOptions.interval?: {
value: DurationValue;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
Live-stream sampling cadence.
interval: import DurationDuration.const seconds: (
seconds: number
) => Duration
Creates a Duration from seconds.
Example (Creating durations from seconds)
import { Duration } from "effect"
const duration = Duration.seconds(30)
console.log(Duration.toMillis(duration)) // 30000
seconds(1),
}).Pipeable.pipe<Layer.Layer<FleetMetrics | Hyperlink.Local<FleetMetrics> | Handler<"snapshot"> | Handler<"live"> | Handler<"inFlightByNode"> | Handler<"fleetInFlight">, never, Hyperlink.PeersId<FleetMetrics> | Hyperlink.SelfNodeId<FleetMetrics> | Scope>, Layer.Layer<FleetMetrics | Hyperlink.Local<FleetMetrics> | Handler<"snapshot"> | Handler<"live"> | Handler<...> | Handler<...>, never, Scope>, Layer.Layer<...>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<...>) => Layer.Layer<...>, bc: (_: Layer.Layer<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)pipe(
import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(import HyperlinkHyperlink.const peersLayer: <
Self,
S extends Spec,
EIn = never,
RIn = never
>(
tag: HyperlinkTag<Self, S>,
self: AnyNode,
options?: {
readonly nodes?: ReadonlyArray<AnyNode>
readonly url?: (
node: AnyNode
) => Effect.Effect<
string | undefined,
EIn,
RIn
>
}
) => Layer.Layer<
PeersId<Self> | SelfNodeId<Self>,
EIn,
RIn
>
Provide the
peers
capability on this node: connect every OTHER node in the tag's
distributed
/
nodes
set and expose them as the peer clients. Also provides the
selfNode
capability (this node's key) for byNode-style folds. The opt-in mesh — add
it to a node's serve only where the HyperService's own logic reaches across nodes. self is the node
you are, so you're excluded from your own peer set.
Membership (D3):
- Fixed — non-empty
options.nodes or stamped nodes([…]) / distributed([…]).
- Directory — stamped empty set (bare
.pipe(Hyperlink.distributed) / nodes([])): read
Lookup Directory.nodesServing(tag.key) at layer build. Soft empty map when Directory is absent.
- Undeclared — no
nodesSym and no options.nodes → empty static peers (not directory).
Peer addresses: each
Node
's own url / path is the default. Pass options.url to
override the url per node — an env-specific port, a tunnel, or a value from Effect Config —
falling back to Node.url when the resolver returns undefined. A node with no dialable address
is skipped (never a throw), so a partial mesh degrades cleanly. IpcSocket peers dial via
protocolIpc
when only path is set. The resolver's error and requirements flow to the
layer (typed).
peersLayer(class FleetMetricsclass FleetMetrics {
key: Identifier;
Service: {
snapshot: Effect<Telemetry.MetricsSnapshot, never, never>;
live: Stream<Telemetry.MetricsSnapshot, never, never>;
inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>;
fleetInFlight: Effect<number, never, never>;
};
description: string | undefined;
of: (this: void, self: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; reado…;
context: (self: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; readonly fleetInF…;
use: (f: (service: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; readonly f…;
useSync: (f: (service: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; readonly f…;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
FleetMetrics, class DropletEastclass DropletEast {
key: Identifier;
Service: {
protocol: Context.Service.Shape<typeof RpcClient.Protocol>;
ping: Effect.Effect<number, NodeUnreachable>;
status: { readonly get: Effect.Effect<NodeStatusSnapshot, NodeUnreachable>; readonly changes: Stream.Stream<NodeStatusSnapshot, NodeUnreachable> };
logs: { readonly stream: Stream.Stream<LogEntry, NodeUnreachable>; readonly query: (options: { readonly limit: number }) => Effect.Effect<ReadonlyArray<LogEntry>, NodeUnreachable> };
};
of: (this: void, self: NodeProtocol) => NodeProtocol;
context: (self: NodeProtocol) => Context<DropletEast>;
use: (f: (service: NodeProtocol) => Effect<A, E, R>) => Effect<A, E, DropletEast | R>;
useSync: (f: (service: NodeProtocol) => A) => Effect<A, never, DropletEast>;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
url: undefined;
path: undefined;
kind: undefined;
logs: unknown;
onConflict: OnConflict;
}
DropletEast)),
const nodeServer: (
port: number
) => <A, E, R>(
serviceKey: Layer.Layer<A, E, R>
) => Layer.Layer<
A,
E | ServeError,
Exclude<
R,
| HttpServer
| NodeServices
| HttpPlatform
| Generator
>
>
nodeServer(3001),
)
// east: Layer — this droplet samples its registry and reaches West + Central for fleet foldsA single-node app with no peers uses Telemetry.alone instead of peersLayer:
const const local: Layer.Layer<
FleetTelemetry | Local<FleetTelemetry>,
never,
never
>
const local: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<FleetTelemetry | Local<FleetTelemetry>>, never, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
local = import TelemetryTelemetry.const layer: <Self>(
tag: TelemetryTag<Self>,
options?: TelemetryOptions
) => Layer.Layer<
Self | Hyperlink.Local<Self>,
never,
PeersId<Self> | SelfNodeId<Self>
>
Local layer for a Telemetry tag — forks one sampling fiber and wires leaf + fleet fields.
Requires the mesh capability (
alone
or
Hyperlink.peersLayer
).
layer(class FleetTelemetryclass FleetTelemetry {
key: Identifier;
Service: {
snapshot: Effect<Telemetry.MetricsSnapshot, never, never>;
live: Stream<Telemetry.MetricsSnapshot, never, never>;
inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>;
fleetInFlight: Effect<number, never, never>;
};
description: string | undefined;
of: (this: void, self: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; reado…;
context: (self: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; readonly fleetInF…;
use: (f: (service: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; readonly f…;
useSync: (f: (service: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; readonly f…;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
FleetTelemetry).Pipeable.pipe<Layer.Layer<FleetTelemetry | Local<FleetTelemetry>, never, PeersId<FleetTelemetry> | SelfNodeId<FleetTelemetry>>, Layer.Layer<FleetTelemetry | Local<FleetTelemetry>, never, never>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<FleetTelemetry | Local<FleetTelemetry>, never, PeersId<FleetTelemetry> | SelfNodeId<FleetTelemetry>>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)pipe(
import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(import TelemetryTelemetry.const alone: <Self>(
tag: TelemetryTag<Self>
) => Layer.Layer<PeersId<Self> | SelfNodeId<Self>>
Discharge the mesh with no peers — this node's registry alone. Pair with
layer
/
serve
when Telemetry is not distributed:
Telemetry.layer(FleetTelemetry).pipe(Layer.provide(Telemetry.alone(FleetTelemetry)))
For a fleet, provide
Hyperlink.peersLayer
instead (bundled selfNode + peers).
alone(class FleetTelemetryclass FleetTelemetry {
key: Identifier;
Service: {
snapshot: Effect<Telemetry.MetricsSnapshot, never, never>;
live: Stream<Telemetry.MetricsSnapshot, never, never>;
inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>;
fleetInFlight: Effect<number, never, never>;
};
description: string | undefined;
of: (this: void, self: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; reado…;
context: (self: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; readonly fleetInF…;
use: (f: (service: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; readonly f…;
useSync: (f: (service: { readonly snapshot: Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect<{ readonly [x: string]: number }, never, never>; readonly f…;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
FleetTelemetry)),
)
// local: Layer — leaf snapshot/live + fleet fields that only see this nodeRead this nodes registry
snapshot is point-in-time. live is a ~1s push of the same envelope. Same handle, local or remote.
const const glass: {
readonly snapshot: Effect.Effect<
Telemetry.MetricsSnapshot,
never,
never
>
readonly live: Stream<
Telemetry.MetricsSnapshot,
never,
never
>
readonly inFlightByNode: Effect.Effect<
{
readonly [x: string]: number
},
never,
never
>
readonly fleetInFlight: Effect.Effect<
number,
never,
never
>
}
glass = yield* class FleetMetricsclass FleetMetrics {
key: Identifier;
Service: {
snapshot: Effect.Effect<Telemetry.MetricsSnapshot, never, never>;
live: Stream<Telemetry.MetricsSnapshot, never, never>;
inFlightByNode: Effect.Effect<{ readonly [x: string]: number }, never, never>;
fleetInFlight: Effect.Effect<number, never, never>;
};
description: string | undefined;
of: (this: void, self: { readonly snapshot: Effect.Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect.Effect<{ readonly [x: string]: number }, never,…;
context: (self: { readonly snapshot: Effect.Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect.Effect<{ readonly [x: string]: number }, never, never>; rea…;
use: (f: (service: { readonly snapshot: Effect.Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect.Effect<{ readonly [x: string]: number }, never, neve…;
useSync: (f: (service: { readonly snapshot: Effect.Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect.Effect<{ readonly [x: string]: number }, never, neve…;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
FleetMetrics
const const snap: Telemetry.MetricsSnapshotconst snap: {
ts: number;
metrics: ReadonlyArray<Telemetry.CounterDatum | Telemetry.GaugeDatum | Telemetry.HistogramDatum>;
}
snap = yield* const glass: {
readonly snapshot: Effect.Effect<
Telemetry.MetricsSnapshot,
never,
never
>
readonly live: Stream<
Telemetry.MetricsSnapshot,
never,
never
>
readonly inFlightByNode: Effect.Effect<
{
readonly [x: string]: number
},
never,
never
>
readonly fleetInFlight: Effect.Effect<
number,
never,
never
>
}
glass.snapshot: Effect.Effect<
Telemetry.MetricsSnapshot,
never,
never
>
(property) snapshot: {
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
snapshot // MetricsSnapshot { ts, metrics }
const const probe:
| Telemetry.CounterDatum
| Telemetry.GaugeDatum
| Telemetry.HistogramDatum
| undefined
probe = const snap: Telemetry.MetricsSnapshotconst snap: {
ts: number;
metrics: ReadonlyArray<Telemetry.CounterDatum | Telemetry.GaugeDatum | Telemetry.HistogramDatum>;
}
snap.metrics: readonly (
| Telemetry.CounterDatum
| Telemetry.GaugeDatum
| Telemetry.HistogramDatum
)[]
metrics.ReadonlyArray<CounterDatum | GaugeDatum | HistogramDatum>.find(predicate: (value: Telemetry.CounterDatum | Telemetry.GaugeDatum | Telemetry.HistogramDatum, index: number, obj: readonly (Telemetry.CounterDatum | Telemetry.GaugeDatum | Telemetry.HistogramDatum)[]) => unknown, thisArg?: any): Telemetry.CounterDatum | Telemetry.GaugeDatum | Telemetry.HistogramDatum | undefined (+1 overload)Returns the value of the first element in the array where predicate is true, and undefined
otherwise.
find((m: | Telemetry.CounterDatum
| Telemetry.GaugeDatum
| Telemetry.HistogramDatum
m) => m: | Telemetry.CounterDatum
| Telemetry.GaugeDatum
| Telemetry.HistogramDatum
m.id: stringid === "queue_enqueued_total")
const const mine: numbermine = import TelemetryTelemetry.const inFlightOf: (
snap: MetricsSnapshot
) => number
Read
inFlightMetricId
from a snapshot (missing ⇒ 0). Used by fleet folds and demos.
inFlightOf(const snap: Telemetry.MetricsSnapshotconst snap: {
ts: number;
metrics: ReadonlyArray<Telemetry.CounterDatum | Telemetry.GaugeDatum | Telemetry.HistogramDatum>;
}
snap) // number — queue_in_flight on this node (0 if absent)
Show the fleet
Fleet fields fold each peers leaf snapshot (peers never expose fleet fields, so a fold cant recurse). One yield, columns + total:
const const glass: {
readonly snapshot: Effect.Effect<
Telemetry.MetricsSnapshot,
never,
never
>
readonly live: Stream<
Telemetry.MetricsSnapshot,
never,
never
>
readonly inFlightByNode: Effect.Effect<
{
readonly [x: string]: number
},
never,
never
>
readonly fleetInFlight: Effect.Effect<
number,
never,
never
>
}
glass = yield* class FleetMetricsclass FleetMetrics {
key: Identifier;
Service: {
snapshot: Effect.Effect<Telemetry.MetricsSnapshot, never, never>;
live: Stream<Telemetry.MetricsSnapshot, never, never>;
inFlightByNode: Effect.Effect<{ readonly [x: string]: number }, never, never>;
fleetInFlight: Effect.Effect<number, never, never>;
};
description: string | undefined;
of: (this: void, self: { readonly snapshot: Effect.Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect.Effect<{ readonly [x: string]: number }, never,…;
context: (self: { readonly snapshot: Effect.Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect.Effect<{ readonly [x: string]: number }, never, never>; rea…;
use: (f: (service: { readonly snapshot: Effect.Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect.Effect<{ readonly [x: string]: number }, never, neve…;
useSync: (f: (service: { readonly snapshot: Effect.Effect<Telemetry.MetricsSnapshot, never, never>; readonly live: Stream<Telemetry.MetricsSnapshot, never, never>; readonly inFlightByNode: Effect.Effect<{ readonly [x: string]: number }, never, neve…;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
FleetMetrics
const const columns: {
readonly [x: string]: number
}
columns = yield* const glass: {
readonly snapshot: Effect.Effect<
Telemetry.MetricsSnapshot,
never,
never
>
readonly live: Stream<
Telemetry.MetricsSnapshot,
never,
never
>
readonly inFlightByNode: Effect.Effect<
{
readonly [x: string]: number
},
never,
never
>
readonly fleetInFlight: Effect.Effect<
number,
never,
never
>
}
glass.inFlightByNode: Effect.Effect<
{ readonly [x: string]: number },
never,
never
>
(property) inFlightByNode: {
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
inFlightByNode
// columns: Record<string, number> — e.g. { "app/DropletEast": 5, "app/DropletWest": 3 }
const const total: numbertotal = yield* const glass: {
readonly snapshot: Effect.Effect<
Telemetry.MetricsSnapshot,
never,
never
>
readonly live: Stream<
Telemetry.MetricsSnapshot,
never,
never
>
readonly inFlightByNode: Effect.Effect<
{
readonly [x: string]: number
},
never,
never
>
readonly fleetInFlight: Effect.Effect<
number,
never,
never
>
}
glass.fleetInFlight: Effect.Effect<number, never, never>(property) fleetInFlight: {
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
fleetInFlight
// total: number — sum of queue_in_flight across self + peers
Telemetry.inFlightMetricId is "queue_in_flight" — the gauge queue engines already emit.
OTEL stays the grown-up sink
Telemetry does not retain, alert, or query history. Wire @effect/opentelemetry when you need collectors; keep Telemetry when you want the registry on a Hyperlink tag your CLI / TUI / web already speak.
Runnable form: pnpm run example:telemetry-fleet-glass. For readiness across the same mesh (Reachable / Unreachable, not metric skip-omit), see Fleet Health. Also Fleets & Peers.