(
name: string,
options: {
readonly description?: string | undefined
readonly attributes?: Metric.Attributes | undefined
readonly maxAge: Duration.Input
readonly maxSize: number
readonly quantiles: ReadonlyArray<number>
}
): Summary<[value: number, timestamp: number]>Creates a Summary metric that records observations with explicit
timestamps and calculates quantiles.
When to use
Use when you need a metric that records statistical information about a set of values together with timestamps.
Details
Inputs to this metric are [value, timestamp] pairs; the current clock is
used when reading quantiles against the configured maxAge.
The optional description describes the summary, and attributes attach
dimensions to it. maxAge controls how long observations are retained,
maxSize controls how many observations are kept, and quantiles lists the
quantiles to calculate, such as [0.5, 0.9].
Example (Creating summaries with explicit timestamps)
import { Metric } from "effect"
const responseTimesSummary = Metric.summaryWithTimestamp(
"response_times_summary",
{
description: "Measures the distribution of response times",
maxAge: "60 seconds", // Retain observations for 60 seconds.
maxSize: 1000, // Keep a maximum of 1000 observations.
quantiles: [0.5, 0.9, 0.99] // Calculate 50th, 90th, and 99th quantiles.
}
)export const const summaryWithTimestamp: (
name: string,
options: {
readonly description?: string | undefined
readonly attributes?:
| Metric.Attributes
| undefined
readonly maxAge: Duration.Input
readonly maxSize: number
readonly quantiles: ReadonlyArray<number>
}
) => Summary<[value: number, timestamp: number]>
Creates a Summary metric that records observations with explicit
timestamps and calculates quantiles.
When to use
Use when you need a metric that records statistical information about a set
of values together with timestamps.
Details
Inputs to this metric are [value, timestamp] pairs; the current clock is
used when reading quantiles against the configured maxAge.
The optional description describes the summary, and attributes attach
dimensions to it. maxAge controls how long observations are retained,
maxSize controls how many observations are kept, and quantiles lists the
quantiles to calculate, such as [0.5, 0.9].
Example (Creating summaries with explicit timestamps)
import { Metric } from "effect"
const responseTimesSummary = Metric.summaryWithTimestamp(
"response_times_summary",
{
description: "Measures the distribution of response times",
maxAge: "60 seconds", // Retain observations for 60 seconds.
maxSize: 1000, // Keep a maximum of 1000 observations.
quantiles: [0.5, 0.9, 0.99] // Calculate 50th, 90th, and 99th quantiles.
}
)
summaryWithTimestamp = (name: stringname: string, options: {
readonly description?: string | undefined
readonly attributes?:
| Metric.Attributes
| undefined
readonly maxAge: Duration.Input
readonly maxSize: number
readonly quantiles: ReadonlyArray<number>
}
options: {
readonly description?: string | undefineddescription?: string | undefined
readonly attributes?: Metric.Attributes | undefinedattributes?: Metric.type Metric<in Input, out State>.Attributes = Readonly<Record<string, string>> | readonly [string, string][]Union type for metric attributes that can be provided as either an object or array of tuples.
Example (Providing attributes in different formats)
import { Data, Effect, Metric } from "effect"
class AttributesError extends Data.TaggedError("AttributesError")<{
readonly operation: string
}> {}
const program = Effect.gen(function*() {
// Different ways to specify attributes
const attributesAsObject = {
service: "api",
environment: "production",
version: "1.2.3"
}
const attributesAsArray: ReadonlyArray<[string, string]> = [
["service", "api"],
["environment", "production"],
["version", "1.2.3"]
]
// Create metrics with different attribute formats
const requestCounter1 = Metric.counter("requests", {
description: "Total requests",
attributes: attributesAsObject // Using object format
})
const requestCounter2 = Metric.counter("requests", {
description: "Total requests",
attributes: attributesAsArray // Using array format
})
// Function to normalize attributes to object format
const normalizeAttributes = (
attrs: typeof attributesAsObject | ReadonlyArray<[string, string]>
) => {
if (Array.isArray(attrs)) {
return Object.fromEntries(attrs)
}
return attrs
}
// Add runtime attributes using withAttributes
const contextualCounter = Metric.withAttributes(requestCounter1, {
method: "GET",
endpoint: "/api/users"
})
// Update metrics with different attribute combinations
yield* Metric.update(contextualCounter, 1)
// Both formats result in the same internal representation
const normalizedObject = normalizeAttributes(attributesAsObject)
const normalizedArray = normalizeAttributes(attributesAsArray)
return {
attributeFormats: {
object: normalizedObject, // { service: "api", environment: "production", version: "1.2.3" }
array: normalizedArray, // { service: "api", environment: "production", version: "1.2.3" }
areEqual:
JSON.stringify(normalizedObject) === JSON.stringify(normalizedArray) // true
}
}
})
Attributes | undefined
readonly maxAge: Duration.InputmaxAge: import DurationDuration.type Duration.Input = /*unresolved*/ anyInput
readonly maxSize: numbermaxSize: number
readonly quantiles: readonly number[]quantiles: interface ReadonlyArray<T>ReadonlyArray<number>
}): interface Summary<Input>A Summary metric that calculates quantiles over a sliding time window of observations.
When to use
Use when summaries provide statistical insights into value distributions by tracking specific quantiles
(percentiles) such as median (50th), 95th percentile, 99th percentile, etc. They're ideal for
understanding performance characteristics like response time distributions.
Example (Using summary metrics)
import { Data, Effect, Metric } from "effect"
class SummaryInterfaceError extends Data.TaggedError("SummaryInterfaceError")<{
readonly operation: string
}> {}
const program = Effect.gen(function*() {
// Create summaries with different quantile configurations
const responseTimeSummary: Metric.Summary<number> = Metric.summary(
"api_response_time_ms",
{
description: "API response time distribution in milliseconds",
maxAge: "5 minutes", // Keep observations for 5 minutes
maxSize: 1000, // Keep up to 1000 observations
quantiles: [0.5, 0.95, 0.99] // Track median, 95th, and 99th percentiles
}
)
const requestSizeSummary: Metric.Summary<number> = Metric.summary(
"request_size_bytes",
{
description: "Request payload size distribution",
maxAge: "10 minutes",
maxSize: 500,
quantiles: [0.25, 0.5, 0.75, 0.9] // Track quartiles and 90th percentile
}
)
// Record observations (values are stored in time-based sliding window)
yield* Metric.update(responseTimeSummary, 120) // Fast response
yield* Metric.update(responseTimeSummary, 250) // Average response
yield* Metric.update(responseTimeSummary, 45) // Very fast response
yield* Metric.update(responseTimeSummary, 890) // Slow response
yield* Metric.update(responseTimeSummary, 156) // Average response
yield* Metric.update(requestSizeSummary, 1024) // 1KB request
yield* Metric.update(requestSizeSummary, 512) // 512B request
yield* Metric.update(requestSizeSummary, 2048) // 2KB request
// Read summary state
const responseTimeState: Metric.SummaryState = yield* Metric.value(
responseTimeSummary
)
const requestSizeState: Metric.SummaryState = yield* Metric.value(
requestSizeSummary
)
// Summary state contains:
// - quantiles: Array of [quantile, optionalValue] pairs
// - count: total number of observations in window
// - min: smallest observed value in window
// - max: largest observed value in window
// - sum: sum of all observed values in window
// Extract quantile values safely
const getQuantileValue = (
quantiles: ReadonlyArray<readonly [number, number | undefined]>,
q: number
) => quantiles.find(([quantile]) => quantile === q)?.[1]
const median = getQuantileValue(responseTimeState.quantiles, 0.5)
const p95 = getQuantileValue(responseTimeState.quantiles, 0.95)
const p99 = getQuantileValue(responseTimeState.quantiles, 0.99)
return {
responseTime: {
totalRequests: responseTimeState.count, // 5
fastestResponse: responseTimeState.min, // 45
slowestResponse: responseTimeState.max, // 890
totalTime: responseTimeState.sum, // 1461
averageTime: responseTimeState.sum / responseTimeState.count, // 292.2
medianTime: median ?? null, // ~156
p95Time: p95 ?? null, // ~890
p99Time: p99 ?? null // ~890
},
requestSize: {
totalRequests: requestSizeState.count, // 3
averageSize: requestSizeState.sum / requestSizeState.count // ~1194.7
}
}
})
Summary<[numbervalue: number, numbertimestamp: number]> => new constructor SummaryMetric(id: string, options: {
readonly description?: string | undefined;
readonly attributes?: Metric.Attributes | undefined;
readonly maxAge: Duration.Input;
readonly maxSize: number;
readonly quantiles: ReadonlyArray<number>;
}): SummaryMetric
SummaryMetric(name: stringname, options: {
readonly description?: string | undefined
readonly attributes?:
| Metric.Attributes
| undefined
readonly maxAge: Duration.Input
readonly maxSize: number
readonly quantiles: ReadonlyArray<number>
}
options)