178 lines · 5.7 KB · TypeScript
RawDownload
import * as Clock from "effect/Clock";import * as Duration from "effect/Duration";import * as Effect from "effect/Effect";import * as Exit from "effect/Exit";import * as Metric from "effect/Metric";import { dual } from "effect/Function"; import {  compactMetricAttributes,  normalizeModelMetricLabel,  outcomeFromExit,} from "./Attributes.ts"; export const rpcRequestsTotal = Metric.counter("t3_rpc_requests_total", {  description: "Total RPC requests handled by the websocket RPC server.",}); export const rpcRequestDuration = Metric.timer("t3_rpc_request_duration", {  description: "RPC request handling duration.",}); export const orchestrationCommandsTotal = Metric.counter("t3_orchestration_commands_total", {  description: "Total orchestration commands dispatched.",}); export const orchestrationCommandDuration = Metric.timer("t3_orchestration_command_duration", {  description: "Orchestration command dispatch duration.",}); export const orchestrationCommandAckDuration = Metric.timer(  "t3_orchestration_command_ack_duration",  {    description:      "Time from orchestration command dispatch to the first committed domain event emitted for that command.",  },); export const orchestrationEventsProcessedTotal = Metric.counter(  "t3_orchestration_events_processed_total",  {    description: "Total orchestration intent events processed by runtime reactors.",  },); export const orchestrationEffectClaimsTotal = Metric.counter(  "t3_orchestration_effect_claims_total",  {    description: "Total completed orchestration effect outbox claim attempts by result.",  },); export const orchestrationEffectQueueWait = Metric.timer("t3_orchestration_effect_queue_wait", {  description:    "Time from an orchestration effect's temporal availability until claim, including same-thread blocking.",}); export const providerSessionsTotal = Metric.counter("t3_provider_sessions_total", {  description: "Total provider session lifecycle operations.",}); export const providerTurnsTotal = Metric.counter("t3_provider_turns_total", {  description: "Total provider turn lifecycle operations.",}); export const providerTurnDuration = Metric.timer("t3_provider_turn_duration", {  description: "Provider turn request duration.",}); export const providerRuntimeEventsTotal = Metric.counter("t3_provider_runtime_events_total", {  description: "Total canonical provider runtime events processed.",}); export const gitCommandsTotal = Metric.counter("t3_git_commands_total", {  description: "Total git commands executed by the server runtime.",}); export const gitCommandDuration = Metric.timer("t3_git_command_duration", {  description: "Git command execution duration.",}); export const terminalSessionsTotal = Metric.counter("t3_terminal_sessions_total", {  description: "Total terminal sessions started.",}); export const terminalRestartsTotal = Metric.counter("t3_terminal_restarts_total", {  description: "Total terminal restart requests handled.",}); export const metricAttributes = (  attributes: Readonly<Record<string, unknown>>,): ReadonlyArray<[string, string]> => Object.entries(compactMetricAttributes(attributes)); export const increment = (  metric: Metric.Metric<number, unknown>,  attributes: Readonly<Record<string, unknown>>,  amount = 1,) => Metric.update(Metric.withAttributes(metric, metricAttributes(attributes)), amount); export interface WithMetricsOptions {  readonly counter?: Metric.Metric<number, unknown>;  readonly timer?: Metric.Metric<Duration.Duration, unknown>;  readonly attributes?:    | Readonly<Record<string, unknown>>    | (() => Readonly<Record<string, unknown>>);  readonly outcomeAttributes?: (    outcome: ReturnType<typeof outcomeFromExit>,  ) => Readonly<Record<string, unknown>>;} const withMetricsImpl = <A, E, R>(  effect: Effect.Effect<A, E, R>,  options: WithMetricsOptions,): Effect.Effect<A, E, R> =>  Effect.gen(function* () {    const startedAt = yield* Clock.currentTimeNanos;    const exit = yield* Effect.exit(effect);    const endedAt = yield* Clock.currentTimeNanos;    const elapsedNanos = endedAt > startedAt ? endedAt - startedAt : 0n;    const duration = Duration.nanos(elapsedNanos);    const baseAttributes =      typeof options.attributes === "function" ? options.attributes() : (options.attributes ?? {});     if (options.timer) {      yield* Metric.update(        Metric.withAttributes(options.timer, metricAttributes(baseAttributes)),        duration,      );    }     if (options.counter) {      const outcome = outcomeFromExit(exit);      yield* Metric.update(        Metric.withAttributes(          options.counter,          metricAttributes({            ...baseAttributes,            outcome,            ...(options.outcomeAttributes ? options.outcomeAttributes(outcome) : {}),          }),        ),        1,      );    }     if (Exit.isSuccess(exit)) {      return exit.value;    }    return yield* Effect.failCause(exit.cause);  }); export const withMetrics: {  <A, E, R>(    options: WithMetricsOptions,  ): (effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;  <A, E, R>(effect: Effect.Effect<A, E, R>, options: WithMetricsOptions): Effect.Effect<A, E, R>;} = dual(2, withMetricsImpl); export const providerMetricAttributes = (  provider: string,  extra?: Readonly<Record<string, unknown>>,) =>  compactMetricAttributes({    provider,    ...extra,  }); export const providerTurnMetricAttributes = (input: {  readonly provider: string;  readonly model: string | null | undefined;  readonly extra?: Readonly<Record<string, unknown>>;}) => {  const modelFamily = normalizeModelMetricLabel(input.model);  return compactMetricAttributes({    provider: input.provider,    ...(modelFamily ? { modelFamily } : {}),    ...input.extra,  });};