java.lang.Object
com.darkcollective.relix.events.EventMetrics

public final class EventMetrics extends Object
The numbers an observed decision can carry — what a QueryEvent's text cannot say.

An event's description is prose for a human reading a trace. A consumer that wants to compute with what a run observed — comparing an estimate against the cardinality actually produced, or totalling the work a stage did — needs the quantity itself, not a sentence containing it.

Why this is a class and not a record

It exists so that measuring something new later does not change QueryEvent again, and that only works if adding a measurement does not break this type either. A record cannot deliver that: its canonical constructor is part of its public API and cannot be made less accessible than the record itself, so a second component would change a signature callers may already use. A final class with a private constructor can — every construction goes through a named factory or wither, so a new measurement is a new method and never a changed signature.

Instances are immutable and compare by value; every wither returns a new one.

Not being a record has a cost worth knowing about: equals, hashCode, toString and isEmpty() are hand-written, and each one enumerates the measurements — so a new measurement is four edits, three of which fail silently if forgotten. EventMetricsTest enumerates the fields reflectively and checks all four against each one, so the omission fails the build instead.

  • Field Details

    • NONE

      public static final EventMetrics NONE
      Measures nothing — the shape an event carries when no quantity was observed.
  • Method Details

    • rows

      public static EventMetrics rows(long rows)
      Metrics recording a row count.
      Parameters:
      rows - the number of rows delivered; must not be negative
      Returns:
      metrics carrying rows
    • duration

      public static EventMetrics duration(Duration elapsed)
      Metrics recording elapsed time.
      Parameters:
      elapsed - how long the observed step took; must not be null or negative
      Returns:
      metrics carrying elapsed
    • of

      public static EventMetrics of(long rows, Duration elapsed)
      Metrics recording both — the shape every step that counts rows as it runs produces, since it knows the count and the elapsed time at the same moment.
      Parameters:
      rows - the number of rows delivered; must not be negative
      elapsed - how long the observed step took; must not be null or negative
      Returns:
      metrics carrying both quantities
    • rows

      public OptionalLong rows()
      The number of rows the observed step delivered, when it counted them.

      Empty and zero are different answers: a query that returned nothing measured 0, while an event that counted nothing at all measures neither.

      Returns:
      the row count, or empty when nothing was counted
    • duration

      public Optional<Duration> duration()
      How long the observed step took, when it was timed.

      Wall clock, and therefore a number for a human diagnosing a slow query rather than one a test asserts on: it varies with the machine, the cache and whatever else the host is doing. What each producer claims to have timed differs and is documented where it is emitted — a scan reports the time it spent producing rows, excluding the work its consumer did with them, while a query's ROWS event reports the run's own elapsed time from first pull to last.

      Returns:
      the elapsed time, or empty when nothing was timed
    • withRows

      public EventMetrics withRows(long rowCount)
      Returns a copy also recording rowCount.
      Parameters:
      rowCount - the number of rows delivered; must not be negative
      Returns:
      a new instance; this one is unchanged
    • withDuration

      public EventMetrics withDuration(Duration elapsed)
      Returns a copy also recording elapsed.
      Parameters:
      elapsed - how long the observed step took; must not be null or negative
      Returns:
      a new instance; this one is unchanged
    • isEmpty

      public boolean isEmpty()
      Whether any measurement was recorded.
      Returns:
      true when nothing was measured
    • equals

      public boolean equals(Object o)
      Overrides:
      equals in class Object
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object
    • toString

      public String toString()
      Overrides:
      toString in class Object