Effect CommunityEC
Effect Community2y ago
2 replies
Patrick Roza

Utilizing Labels to Differentiate Metrics with Identical Keys in Effect Metrics

In Effect Metrics, you can have many times the same metric key, with different attributes via labels/tags etc.

For example:
const makeCarriers = <Type, In, Out>(
  _: Metric.Metric<Type, In, Out>
) => ({
  DPD: Metric.taggedWithLabels(_, [MetricLabel.make("carrier", "DPD")]).register(),
  GLS: Metric.taggedWithLabels(_, [MetricLabel.make("carrier", "GLS")]).register(),
  GLSEXPRESS: Metric.taggedWithLabels(_, [MetricLabel.make("carrier", "GLS Express")]).register()
})
const addCarriers = <Type, In, Out>(
  _: Metric.Metric<Type, In, Out>
) => Object.assign(_, makeCarriers(_))

const makeSuccessFail = (_: Metric.Metric.Frequency<"success" | "failed">) => ({
  success: _.pipe(Metric.withConstantInput("success" as const)).register().pipe((_) =>
    Object.assign(_, { update: _(Effect.unit) })
  ),
  failed: _.pipe(Metric.withConstantInput("failed" as const)).register().pipe((_) =>
    Object.assign(_, { update: _(Effect.unit) })
  )
})

const addSuccessFail = (_: Metric.Metric.Frequency<"success" | "failed">) => Object.assign(_, makeSuccessFail(_))

const makeCarriersSuccessFail = (
  _: Metric.Metric.Frequency<"success" | "failed">
) => ({
  DPD: Metric.taggedWithLabels(_, [MetricLabel.make("carrier", "DPD")]).pipe(addSuccessFail).register(),
  GLS: Metric.taggedWithLabels(_, [MetricLabel.make("carrier", "GLS")]).pipe(addSuccessFail).register(),
  GLSEXPRESS: Metric.taggedWithLabels(_, [MetricLabel.make("carrier", "GLS Express")]).pipe(addSuccessFail)
    .register()
})

const addCarriersSuccessFail = (_: Metric.Metric.Frequency<string>) => Object.assign(_, makeCarriersSuccessFail(_))

export const labelCreationCounter = Metric.frequency("labels.created", "A counter for tracking label creation")
  .register().pipe(addCarriersSuccessFail)


export const reportSuccessOrFailure = <A, E, R>(
  metric: Metric.Metric.Frequency<"success" | "failed"> & {
    success: { update: Effect<void> }
    failed: { update: Effect<void> }
  }
) =>
(self: Effect<A, E, R>) =>
  Effect.tapBoth(self, {
    onFailure: () => metric.failed.update,
    onSuccess: () => metric.success.update
  })

.pipe(reportSuccessOrFailure(labelCreationCounter[item.carrier])

Isn't it strange to export the ones that share the same key, as separate metrics in otel?
https://github.com/effect-ts/effect/blob/main/packages/opentelemetry/src/internal/metrics.ts#L38

e.g the console metric exporter shows multiple entries for the same key, with different datapoints, instead of a single entry with the datapoints merged.

In otel you would create a metric, pass it around, call it with different labels/attributes. In Effect you create fine grained easy to use specialised versions of the same metric, and use those.
Was this page helpful?