java.lang.Object
net.i2p.stat.StatManager

public class StatManagerextends Object
Coordinate the management of various frequencies and rates within I2P components, both allowing central update and retrieval, as well as distributed creation and use. This does not provide any persistence, but the data structures exposed can be read and updated to manage the complete state.
  • Field Details

    • _context

      private final I2PAppContext _context
      The context whose stats are managed.
    • _log

      private final Log _log
      Logger for this class.
    • _frequencyStats

      private final ConcurrentHashMap<String, FrequencyStat> _frequencyStats
      Stat name to FrequencyStat.
    • _rateStats

      private final ConcurrentHashMap<String,RateStat> _rateStats
      Stat name to RateStat.
    • _delivery

      private final RateSampleDelivery _delivery
      Off-timer queue for summary listener delivery, shared by every rate this manager creates. One thread serves the whole table; a per-rate queue would mean a thread per rate.
    • _coalesceFailures

      private final AtomicLong _coalesceFailures
      Total coalesce failures isolated since startup, across all stats.

      Nonzero means at least one stat stopped recording. It is reported rather than absorbed because the failure it counts is silent by nature: a skipped rate produces no exception for anyone to notice.

    • _lastCoalesceSweepAt

      private volatile long _lastCoalesceSweepAt
      Clock value of the last completed coalesce sweep, or 0 if none has run.

      This is a heartbeat for the whole stat subsystem. The sweep runs on the shared coalesce timer, so it can stop without any exception: the task is simply queued behind other work and never runs. Nothing inside the stats package can detect its own non-execution, so an observer outside it needs this to tell "a rate failed to coalesce" apart from "no rate was asked to coalesce at all". GraphGenerator's health watchdog reads it, from a scheduler independent of the timer that could be wedged.

    • _coalesceSweeps

      private final AtomicLong _coalesceSweeps
      Number of completed coalesce sweeps, used by tests and by the watchdog to distinguish "never ran" from "ran once then stopped".
    • COALESCE_FAILURE_LOG_INTERVAL

      private static final long COALESCE_FAILURE_LOG_INTERVAL
      Log one coalesce-failure line per this many failures. The first is always logged; after that a stat failing every cycle would otherwise emit one ERROR per coalesce period for the life of the router.
      See Also:
    • coalesceCounter

      private int coalesceCounter
      Writes since the stats files were last coalesced.
    • FREQ_COALESCE_RATE

      private static final int FREQ_COALESCE_RATE
      Frequency stats are coalesced every this many minutes.
      See Also:
    • PROP_STAT_FULL

      public static final String PROP_STAT_FULL
      Enables full stat collection; default false.
      See Also:
  • Constructor Details

    • StatManager

      public StatManager(I2PAppContext context)
      The stat manager should only be constructed and accessed through the application context. This constructor should only be used by the appropriate application context itself.
      Parameters:
      context - the application context
  • Method Details

    • shutdown

      public void shutdown()
      Shut down the statistics manager and clear all statistics.
    • createFrequencyStat

      public void createFrequencyStat(String name, String description, String group, long[] periods)
      Create a new statistic to monitor the frequency of some event. The stat is ONLY created if the stat.full property is true or we are not in the router context.
      Parameters:
      name - unique name of the statistic
      description - simple description of the statistic
      group - used to group statistics together
      periods - array of period lengths (in milliseconds)
    • createRequiredFrequencyStat

      public void createRequiredFrequencyStat(String name, String description, String group, long[] periods)
      Create a new statistic to monitor the frequency of some event. The stat is always created, independent of the stat.full setting or context.
      Parameters:
      name - unique name of the statistic
      description - simple description of the statistic
      group - used to group statistics together
      periods - array of period lengths (in milliseconds)
    • getOrCreateFrequencyStat

      public FrequencyStat getOrCreateFrequencyStat(String name, String description, String group, long[] periods)
      Resolve a frequency stat by name, creating it if it does not exist yet, and return the handle to it.

      Lets a caller on a repeated event stop re-resolving the name. The handle stays valid until removeFrequencyStat(String) or shutdown(); there is deliberately no handle-invalidation step, because dropping one would cost the very lookup it was meant to remove.

      Parameters:
      name - unique name of the statistic
      description - simple description of the statistic, used only if the stat has to be created
      group - used to group statistics together
      periods - array of period lengths (in milliseconds)
      Returns:
      the stat for name, never null
    • removeFrequencyStat

      public void removeFrequencyStat(String name)
      Remove a frequency stat by name.

      Any handle previously returned by getOrCreateFrequencyStat(String, String, String, long[]) is orphaned by this and must not be used again.

      Parameters:
      name - the stat name to remove
    • createRateStat

      public void createRateStat(String name, String description, String group, long[] periods)
      Create a new statistic to monitor the average value and confidence of some action. The stat is ONLY created if the stat.full property is true or we are not in the router context.
      Parameters:
      name - unique name of the statistic
      description - simple description of the statistic
      group - used to group statistics together
      periods - array of period lengths (in milliseconds)
    • createRequiredRateStat

      public void createRequiredRateStat(String name, String description, String group, long[] periods)
      Create a new statistic to monitor the average value and confidence of some action. The stat is always created, independent of the stat.full setting or context.
      Parameters:
      name - unique name of the statistic
      description - simple description of the statistic
      group - used to group statistics together
      periods - array of period lengths (in milliseconds)
    • getOrCreateRateStat

      public RateStat getOrCreateRateStat(String name, String description, String group, long[] periods)
      Resolve a rate stat by name, creating it if it does not exist yet, and return the handle to it.

      Lets a caller reporting the same stat repeatedly avoid the string-keyed map lookup that addRateData(String, long) pays on every call. Resolution is check-then-act, not a single ConcurrentMap.computeIfAbsent(K, Function): the creation itself goes through createRequiredRateStat(String, String, String, long[]), which does use computeIfAbsent, so concurrent callers may both attempt it but exactly one stat is built and the delivery queue is attached before that stat is published. The handle is therefore usable the instant this returns.

      The handle is not invalidated when the stat is removed: a stale handle keeps updating an orphaned stat, which is inert rather than harmful, and detecting that would cost the lookup this exists to remove. It is valid until removeRateStat(String) or shutdown().

      Parameters:
      name - unique name of the statistic
      description - simple description of the statistic, used only if the stat has to be created
      group - used to group statistics together
      periods - array of period lengths (in milliseconds)
      Returns:
      the stat for name, or null if this manager is not collecting it and it does not already exist
    • getCoalesceSkips

      public long getCoalesceSkips()
      Sum of Rate.getCoalesceSkips() across every rate in the table.

      A rate normally skips one coalesce per period, so this grows steadily and is not by itself a problem. It is reported so that a rate which stopped coalescing entirely can be told apart from one that is merely visited early.

      Returns:
      total coalesce skips across all rates
    • getCoalesceBacklogCollapses

      public long getCoalesceBacklogCollapses()
      Sum of Rate.getCoalesceBacklogCollapses() across every rate in the table.

      Unlike a skip, a collapse is permanent: the steps it abandoned can never be written, so every count here is a gap in the graph data. Zero is the healthy state. A nonzero value points at the shared coalesce timer rather than at any one rate, since all rates are coalesced from the same SimpleTimer2 pool.

      Returns:
      total backlog collapses across all rates
    • getSampleOverruns

      public long getSampleOverruns()
      Samples evicted because the delivery queue hit its hard capacity.

      Unlike RateSampleDelivery.getSuperseded() this must never happen: same-step supersession means a slow consumer does not grow the queue, so reaching the cap means the consumer is not draining at all. Surfaced here because the delivery queue is package-private and the console watchdog, which is the only thing positioned to act on it, lives in another package.

      Returns:
      eviction count since startup, zero in the healthy state
    • getSampleSuperseded

      public long getSampleSuperseded()
      Samples replaced in place by a newer value for the same archive step.

      High but non-zero is normal under load and is not loss - only one value per step is storable and the newest is the correct one. A count that stops advancing while getSamplePending() climbs means the consumer has stopped draining.

      Returns:
      supersession count since startup
    • getSamplePending

      public int getSamplePending()
      Coalesced samples waiting to be handed to their listener.
      Returns:
      current queue depth, zero when delivery is keeping up
    • getSampleOldestPendingAgeMs

      public long getSampleOldestPendingAgeMs()
      Age of the oldest sample still waiting for delivery.

      The direct measure of delivery lag, and therefore the only signal that distinguishes a stalled consumer from a rate that has stopped coalescing: both leave the graph frozen, but only the second one drains this queue.

      Returns:
      ms since the oldest pending sample was submitted, zero when idle
    • removeRateStat

      public void removeRateStat(String name)
      Remove a rate stat by name.

      Any handle previously returned by getOrCreateRateStat(String, String, String, long[]) is orphaned by this and must not be used again.

      Parameters:
      name - the stat name to remove
    • updateFrequency

      public void updateFrequency(String name)
      Update the given frequency statistic, taking note that an event occurred (and recalculating all frequencies).
      Parameters:
      name - the stat name
    • addRateData

      public void addRateData(String name, long data, long eventDuration)
      Update the given rate statistic, taking note that the given data point was received (and recalculating all rates).
      Parameters:
      name - the stat name
      data - the data point value
      eventDuration - how long the event took, or 0
    • addRateData

      public void addRateData(String name, long data)
      Update the given rate statistic, taking note that the given data point was received (and recalculating all rates). Zero duration.
      Parameters:
      name - the stat name
      data - the data point value
    • coalesceStats

      public void coalesceStats()
      Coalesce all rate stats and periodically coalesce frequency stats, isolating every stat from every other.

      Isolation is the whole point of this method. It runs as one pass over the whole table on the shared coalesce timer, so a single exception escaping a stat would abandon every stat later in the pass: their rates would stop coalescing, their listeners would receive nothing, and their graphs would freeze while every health check still reported them healthy. One broken stat must therefore be able to affect only itself.

    • getCoalesceSweepAgeMs

      public long getCoalesceSweepAgeMs(long now)
      How long ago the last coalesce sweep completed, or -1 if none ever has.

      Callers use this to distinguish a rate that will not coalesce from a coalesce task that is not running. A sweep older than a few rate periods means the latter, which no counter inside this package can report.

      Parameters:
      now - current clock value in ms
      Returns:
      ms since the last completed sweep, or -1 if there has never been one
    • hasCoalesced

      public boolean hasCoalesced()
      Whether any coalesce sweep has ever completed.
      Returns:
      true if at least one sweep has completed
    • noteCoalesceFailure

      private void noteCoalesceFailure(String statName, String period, Throwable cause)
      Count an isolated coalesce failure and log it, naming the stat at fault.

      ERROR rather than WARN because the failure is silent data loss, and logger.defaultLevel is ERROR: a WARN would be suppressed in a default configuration and the loss would go unnoticed. ERROR also reaches the console's error log page, so the stat is identifiable without reading the log file.

      Parameters:
      statName - name of the stat that failed
      period - the failing rate's period in ms, or null if not per-rate
      cause - what went wrong
    • getCoalesceFailures

      public long getCoalesceFailures()
      Total coalesce failures isolated since startup.

      Zero is the healthy state. Nonzero means at least one stat has silently stopped recording; the log line names which one.

      Returns:
      the running failure count across all stats
    • getFrequency

      public FrequencyStat getFrequency(String name)
      Misnamed, as it returns a FrequencyStat, not a Frequency.
      Parameters:
      name - the stat name
      Returns:
      the FrequencyStat, or null if no stat of that name is registered
    • getRate

      public RateStat getRate(String name)
      Misnamed, as it returns a RateStat, not a Rate.
      Parameters:
      name - the stat name
      Returns:
      the RateStat, or null if no stat of that name is registered
    • getFrequencyNames

      public Set<String> getFrequencyNames()
      Names of all frequency statistics.
      Returns:
      a copy of the frequency stat names
    • getRateNames

      public Set<String> getRateNames()
      Names of all rate statistics.
      Returns:
      a copy of the rate stat names
    • isRate

      public boolean isRate(String statName)
      Whether the given stat is a monitored rate.
      Parameters:
      statName - the stat name
      Returns:
      true if a RateStat is registered under that name
    • isFrequency

      public boolean isFrequency(String statName)
      Whether the given stat is a monitored frequency.
      Parameters:
      statName - the stat name
      Returns:
      true if a FrequencyStat is registered under that name
    • getStatsByGroup

      public Map<String, SortedSet<String>> getStatsByGroup()
      Group name (untranslated String) to a SortedSet of untranslated stat names. Map is unsorted.
      Returns:
      the stats by group
    • ignoreStat

      public boolean ignoreStat(String statName)
      Save memory by not creating stats unless they are required for router operation. For backward compatibility of any external clients, always returns false if not in router context.
      Parameters:
      statName - stat being registered; the decision applies to every name, so none is examined
      Returns:
      true if the stat should be ignored.
    • store

      public void store(OutputStream out, String prefix) throws IOException
      Serializes all Frequencies and Rates to the provided OutputStream.
      Parameters:
      out - to write to
      prefix - to use when serializing
      Throws:
      IOException - if something goes wrong