Skip to content

Commit c9b56ab

Browse files
authored
Fix Metric linear boundary spacing (#6821)
1 parent ace903e commit c9b56ab

3 files changed

Lines changed: 19 additions & 36 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"effect": patch
3+
---
4+
5+
Fix `Metric.linearBoundaries` to space boundaries by the configured width.

packages/effect/src/Metric.ts

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ export interface GaugeState<in Input extends number | bigint> {
556556
* "http_response_time_ms",
557557
* {
558558
* description: "HTTP response time distribution in milliseconds",
559-
* boundaries: Metric.linearBoundaries({ start: 0, width: 50, count: 20 }) // 0, 50, 100, ..., 950
559+
* boundaries: Metric.linearBoundaries({ start: 0, width: 50, count: 20 }) // 50, 100, ..., 900, Infinity
560560
* }
561561
* )
562562
*
@@ -635,7 +635,7 @@ export interface Histogram<Input> extends Metric<Input, HistogramState> {}
635635
* // Create histogram with linear boundaries
636636
* const responseTimeHistogram = Metric.histogram("api_response_time_ms", {
637637
* description: "API response time distribution",
638-
* boundaries: Metric.linearBoundaries({ start: 0, width: 100, count: 10 }) // 0, 100, 200, ..., 900
638+
* boundaries: Metric.linearBoundaries({ start: 0, width: 100, count: 10 }) // 100, 200, ..., 800, Infinity
639639
* })
640640
*
641641
* // Record observations
@@ -2302,7 +2302,7 @@ export const frequency = (name: string, options?: {
23022302
* const responseTimeHistogram = Metric.histogram("api_response_time", {
23032303
* description: "Distribution of API response times in milliseconds",
23042304
* boundaries: Metric.linearBoundaries({ start: 0, width: 50, count: 10 })
2305-
* // Creates buckets: 0-50ms, 50-100ms, 100-150ms, ..., 400-450ms, 450ms+
2305+
* // Creates buckets: 0-50ms, 50-100ms, 100-150ms, ..., 350-400ms, 400ms+
23062306
* })
23072307
*
23082308
* // Create a histogram for request payload sizes
@@ -3164,46 +3164,17 @@ export const boundariesFromIterable = (iterable: Iterable<number>): ReadonlyArra
31643164
*
31653165
* **Details**
31663166
*
3167-
* Generates `count - 1` finite boundaries using `start + width + index` for
3167+
* Generates `count - 1` candidate boundaries using `start + index * width` for
31683168
* each zero-based index, then applies the same normalization as
31693169
* `boundariesFromIterable`: non-positive values are removed, duplicates are
31703170
* collapsed, and `Infinity` is appended.
31713171
*
31723172
* **Example** (Creating linear boundaries)
31733173
*
31743174
* ```ts import.meta.vitest
3175-
* import { Data, Effect, Metric } from "effect"
3176-
*
3177-
* class BoundaryError extends Data.TaggedError("BoundaryError")<{
3178-
* readonly operation: string
3179-
* }> {}
3180-
*
3181-
* // Create boundaries for response time histogram
3182-
* const responseBoundaries = Metric.linearBoundaries({
3183-
* start: 0, // Starting point
3184-
* width: 100, // Offset used for the first boundary
3185-
* count: 5 // Creates 4 boundaries + infinity
3186-
* })
3187-
* const boundaries = responseBoundaries // => [100, 101, 102, 103, Infinity]
3188-
*
3189-
* // Create a histogram using these boundaries
3190-
* const responseTimeHistogram = Metric.histogram("api_response_time", {
3191-
* description: "API response time distribution",
3192-
* boundaries: responseBoundaries
3193-
* })
3194-
*
3195-
* const program = Effect.gen(function*() {
3196-
* // Record some response times
3197-
* yield* Metric.update(responseTimeHistogram, 85)
3198-
* yield* Metric.update(responseTimeHistogram, 101)
3199-
* yield* Metric.update(responseTimeHistogram, 450)
3200-
*
3201-
* const value = yield* Metric.value(responseTimeHistogram)
3202-
* return value
3203-
* })
3175+
* import { Metric } from "effect"
32043176
*
3205-
* const state = await Effect.runPromise(Effect.provideService(program, Metric.MetricRegistry, new Map()))
3206-
* const stateValues = [state.count, state.min, state.max, state.sum] // => [3, 85, 450, 636]
3177+
* Metric.linearBoundaries({ start: 10, width: 20, count: 5 }) // => [10, 30, 50, 70, Infinity]
32073178
* ```
32083179
*
32093180
* @category boundaries
@@ -3214,7 +3185,7 @@ export const linearBoundaries = (options: {
32143185
readonly width: number
32153186
readonly count: number
32163187
}): ReadonlyArray<number> =>
3217-
boundariesFromIterable(Arr.makeBy(options.count - 1, (n) => options.start + n + options.width))
3188+
boundariesFromIterable(Arr.makeBy(options.count - 1, (n) => options.start + n * options.width))
32183189

32193190
/**
32203191
* Creates histogram bucket boundaries with exponentially increasing values.

packages/effect/test/Metric.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,13 @@ describe("Metric", () => {
366366
)
367367
}))
368368

369+
it("creates evenly spaced linear boundaries", () => {
370+
assert.deepStrictEqual(
371+
Metric.linearBoundaries({ start: 10, width: 20, count: 5 }),
372+
[10, 30, 50, 70, Number.POSITIVE_INFINITY]
373+
)
374+
})
375+
369376
describe("Histogram", () => {
370377
it.effect("reports the maximum for negative-only observations", () =>
371378
Effect.gen(function*() {

0 commit comments

Comments
 (0)