(
name: string,
options: {
readonly description?: string | undefined
readonly attributes?: Metric.Attributes | undefined
readonly boundaries: ReadonlyArray<number>
}
): Histogram<number>Represents a Histogram metric that records observations into buckets.
When to use
Use when you need a metric for measuring the distribution of values within a range.
Details
The optional description describes the histogram, and attributes attach
dimensions to it. The required boundaries option defines the histogram
bucket boundaries.
Example (Creating histogram metrics)
import { Data, Effect, Metric } from "effect"
class HistogramError extends Data.TaggedError("HistogramError")<{
readonly operation: string
}> {}
const program = Effect.gen(function*() {
// Create a histogram for API response times
const responseTimeHistogram = Metric.histogram("api_response_time", {
description: "Distribution of API response times in milliseconds",
boundaries: Metric.linearBoundaries({ start: 0, width: 50, count: 10 })
// Creates buckets: 0-50ms, 50-100ms, 100-150ms, ..., 400-450ms, 450ms+
})
// Create a histogram for request payload sizes
const payloadSizeHistogram = Metric.histogram("payload_size", {
description: "Distribution of request payload sizes in KB",
boundaries: Metric.exponentialBoundaries({ start: 1, factor: 2, count: 8 }),
// Creates exponential buckets: 1KB, 2KB, 4KB, 8KB, 16KB, 32KB, 64KB, 128KB+
attributes: { service: "api-gateway" }
})
// Create a histogram with custom boundaries
const customHistogram = Metric.histogram("custom_metric", {
description: "Custom distribution metric",
boundaries: [0.1, 0.5, 1, 2.5, 5, 10, 25, 50, 100]
})
// Record various response times
yield* Metric.update(responseTimeHistogram, 25) // Goes in 0-50ms bucket
yield* Metric.update(responseTimeHistogram, 75) // Goes in 50-100ms bucket
yield* Metric.update(responseTimeHistogram, 125) // Goes in 100-150ms bucket
yield* Metric.update(responseTimeHistogram, 200) // Goes in 150-200ms bucket
yield* Metric.update(responseTimeHistogram, 75) // Another 50-100ms
// Record payload sizes
yield* Metric.update(payloadSizeHistogram, 3) // Goes in 2-4KB bucket
yield* Metric.update(payloadSizeHistogram, 15) // Goes in 8-16KB bucket
yield* Metric.update(payloadSizeHistogram, 0.5) // Goes in 0-1KB bucket
// Get histogram state with distribution data
const responseTimeState = yield* Metric.value(responseTimeHistogram)
const payloadSizeState = yield* Metric.value(payloadSizeHistogram)
// responseTimeState will contain:
// - buckets: [[50, 1], [100, 3], [150, 4], [200, 5], ...]
// - count: 5, min: 25, max: 200, sum: 500
// - Useful for calculating percentiles, averages, etc.
return { responseTimeState, payloadSizeState }
})export const const histogram: (
name: string,
options: {
readonly description?: string | undefined
readonly attributes?:
| Metric.Attributes
| undefined
readonly boundaries: ReadonlyArray<number>
}
) => Histogram<number>
Represents a Histogram metric that records observations into buckets.
When to use
Use when you need a metric for measuring the distribution of values within a
range.
Details
The optional description describes the histogram, and attributes attach
dimensions to it. The required boundaries option defines the histogram
bucket boundaries.
Example (Creating histogram metrics)
import { Data, Effect, Metric } from "effect"
class HistogramError extends Data.TaggedError("HistogramError")<{
readonly operation: string
}> {}
const program = Effect.gen(function*() {
// Create a histogram for API response times
const responseTimeHistogram = Metric.histogram("api_response_time", {
description: "Distribution of API response times in milliseconds",
boundaries: Metric.linearBoundaries({ start: 0, width: 50, count: 10 })
// Creates buckets: 0-50ms, 50-100ms, 100-150ms, ..., 400-450ms, 450ms+
})
// Create a histogram for request payload sizes
const payloadSizeHistogram = Metric.histogram("payload_size", {
description: "Distribution of request payload sizes in KB",
boundaries: Metric.exponentialBoundaries({ start: 1, factor: 2, count: 8 }),
// Creates exponential buckets: 1KB, 2KB, 4KB, 8KB, 16KB, 32KB, 64KB, 128KB+
attributes: { service: "api-gateway" }
})
// Create a histogram with custom boundaries
const customHistogram = Metric.histogram("custom_metric", {
description: "Custom distribution metric",
boundaries: [0.1, 0.5, 1, 2.5, 5, 10, 25, 50, 100]
})
// Record various response times
yield* Metric.update(responseTimeHistogram, 25) // Goes in 0-50ms bucket
yield* Metric.update(responseTimeHistogram, 75) // Goes in 50-100ms bucket
yield* Metric.update(responseTimeHistogram, 125) // Goes in 100-150ms bucket
yield* Metric.update(responseTimeHistogram, 200) // Goes in 150-200ms bucket
yield* Metric.update(responseTimeHistogram, 75) // Another 50-100ms
// Record payload sizes
yield* Metric.update(payloadSizeHistogram, 3) // Goes in 2-4KB bucket
yield* Metric.update(payloadSizeHistogram, 15) // Goes in 8-16KB bucket
yield* Metric.update(payloadSizeHistogram, 0.5) // Goes in 0-1KB bucket
// Get histogram state with distribution data
const responseTimeState = yield* Metric.value(responseTimeHistogram)
const payloadSizeState = yield* Metric.value(payloadSizeHistogram)
// responseTimeState will contain:
// - buckets: [[50, 1], [100, 3], [150, 4], [200, 5], ...]
// - count: 5, min: 25, max: 200, sum: 500
// - Useful for calculating percentiles, averages, etc.
return { responseTimeState, payloadSizeState }
})
histogram = (name: stringname: string, options: {
readonly description?: string | undefined
readonly attributes?:
| Metric.Attributes
| undefined
readonly boundaries: 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 boundaries: readonly number[]boundaries: interface ReadonlyArray<T>ReadonlyArray<number>
}): interface Histogram<Input>A Histogram metric that records observations in configurable buckets to analyze value distributions.
When to use
Use when histograms are ideal for measuring request durations, response sizes, and other continuous values
where you need to understand the distribution of values rather than just aggregates.
Example (Using histogram metrics)
import { Data, Effect, Metric } from "effect"
class HistogramInterfaceError
extends Data.TaggedError("HistogramInterfaceError")<{
readonly operation: string
}>
{}
const program = Effect.gen(function*() {
// Create histograms with different boundary strategies
const responseTimeHistogram: Metric.Histogram<number> = Metric.histogram(
"http_response_time_ms",
{
description: "HTTP response time distribution in milliseconds",
boundaries: Metric.linearBoundaries({ start: 0, width: 50, count: 20 }) // 0, 50, 100, ..., 950
}
)
const fileSizeHistogram: Metric.Histogram<number> = Metric.histogram(
"file_size_bytes",
{
description: "File size distribution in bytes",
boundaries: Metric.exponentialBoundaries({
start: 1,
factor: 2,
count: 10
}) // 1, 2, 4, 8, ..., 512
}
)
// Record observations (values get placed into appropriate buckets)
yield* Metric.update(responseTimeHistogram, 125) // Goes into 100-150ms bucket
yield* Metric.update(responseTimeHistogram, 75) // Goes into 50-100ms bucket
yield* Metric.update(responseTimeHistogram, 200) // Goes into 150-200ms bucket
yield* Metric.update(responseTimeHistogram, 45) // Goes into 0-50ms bucket
yield* Metric.update(fileSizeHistogram, 3) // Goes into 2-4 bytes bucket
yield* Metric.update(fileSizeHistogram, 15) // Goes into 8-16 bytes bucket
yield* Metric.update(fileSizeHistogram, 100) // Goes into 64-128 bytes bucket
// Read histogram state
const responseTimeState: Metric.HistogramState = yield* Metric.value(
responseTimeHistogram
)
const fileSizeState: Metric.HistogramState = yield* Metric.value(
fileSizeHistogram
)
// Histogram state contains:
// - buckets: Array of [boundary, cumulativeCount] pairs
// - count: total number of observations
// - min: smallest observed value
// - max: largest observed value
// - sum: sum of all observed values
return {
responseTime: {
totalRequests: responseTimeState.count, // 4
fastestRequest: responseTimeState.min, // 45
slowestRequest: responseTimeState.max, // 200
totalTime: responseTimeState.sum, // 445
averageTime: responseTimeState.sum / responseTimeState.count // 111.25
},
fileSize: {
totalFiles: fileSizeState.count, // 3
smallestFile: fileSizeState.min, // 3
largestFile: fileSizeState.max, // 100
totalBytes: fileSizeState.sum // 118
}
}
})
Histogram<number> => new constructor HistogramMetric(id: string, options: {
readonly description?: string | undefined;
readonly attributes?: Metric.Attributes | undefined;
readonly boundaries: ReadonlyArray<number>;
}): HistogramMetric
HistogramMetric(name: stringname, options: {
readonly description?: string | undefined
readonly attributes?:
| Metric.Attributes
| undefined
readonly boundaries: ReadonlyArray<number>
}
options)