Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Goals

...

  • Allow routing measurements to statistics, Micrometer meters, or both as appropriate, to allow publishing each measurement to the appropriate places.

...

  • Minimize the intrusiveness of new and existing metrics instrumentation.

...

  • Minimize the amount of code that must know how to route measurements to stats and meters.

...

  • Maintain Geode performance.

...

  • Not preclude any options for deprecating and removing Geode’s statistics mechanism in the future. And take steps to make deprecating and removing the existing statistics mechanism easier.

Proposal

...

  • Continue to use Geode’s existing style of instrumentation class (e.g. CachePerfStats) to instrument code.

...

  • Enhance the instrumentation classes to create and register meters when appropriate, and to route each measurement to the appropriate stats and meters.

...

  • When we want to route a given measurement to both a statistic and a meter, use the "legacy meter" wrapper mechanism (described below).

...

  • Incrementally improve the instrumentation classes to focus more on reporting domain events (e.g. regionAdded()) and less on reporting measurements (e.g. incRegions()).

Legacy Meter Wrappers

To route a given measurement to both a Micrometer meter and a Geode statistic, do the following in the instrumentation class's constructor:-

  • Create and register a normal Micrometer meter in the cache's meter registry.

...

  • Wrap the registered meter in a custom "legacy meter" that reads and writes the stat, and also writes to the registered meter.

In the instrumentation methods (e.g. endPut()):-

  • Use the legacy meter to report measurements.

Diagrams

...

These diagrams show an example of how the wrapper mechanism works for "counter" style stats and meters. The first is a class diagram, showing how the parts relate in general. The second is a sequence diagram that shows in some detail how the parts interact to route a given measurement to both a meter and a stat.

PlantUML
titleLegacy Meter Structure
@startuml
skinparam dpi 300

hide footbox

MeterRegistry *-- Counter

class InstrumentationClass {
MeterRegistry registry
Statistics statistics
}
note right of InstrumentationClass: e.g. CacheServerStats

class LegacyCounterBuilder {
intStatistic(statistics, id)
longStatistic(statistics, id)
register(registry)
}

class LegacyCounter {
LegacyCounter(counter, binding)
increment(amount)
count()
Counter counter
StatisticsBinding binding
}

class Counter {
increment(amount)
count()
}

class StatisticsBinding {
Statistics statistics
int statId
increment(amount)
long longValue()
double doubleValue()
}

InstrumentedCode --> InstrumentationClass

InstrumentationClass --> LegacyCounterBuilder
InstrumentationClass --> LegacyCounter : increment(amount)
InstrumentationClass *-- Statistics

LegacyCounterBuilder --> MeterRegistry
LegacyCounterBuilder --> LegacyCounter

LegacyCounter --> StatisticsBinding : increment(amount)
LegacyCounter --> Counter : increment(amount)

StatisticsBinding --> Statistics : incInt(id, amount)

note right of LegacyCounterBuilder : New class
note right of LegacyCounter : New class (implements Counter)
note right of StatisticsBinding : New class

@enduml

Legacy Meter Information Flow


PlantUML
titleLegacy Meter Information Flow
@startuml
skinparam dpi 300

hide footbox

actor InstrumentedCode

create MyStatistics
InstrumentedCode -> MyStatistics : new(registry, …)
create statistics
MyStatistics -> statistics : new

== Creating a Legacy Meter ==
create LegacyCounter.Builder
MyStatistics -> LegacyCounter.Builder : new(name)
MyStatistics -> LegacyCounter.Builder : …
MyStatistics -> LegacyCounter.Builder : intStatistic(statistics, statId)
MyStatistics -> LegacyCounter.Builder : register(registry)

participant legacyCounter
participant statisticsBinding
participant statistics

LegacyCounter.Builder -> registry : counter(id, …)
create counter
registry -> counter : new(id, …)
registry --> LegacyCounter.Builder : counter

create statisticsBinding
LegacyCounter.Builder -> statisticsBinding : new(statistics, statId)

create legacyCounter
LegacyCounter.Builder -> legacyCounter : new(counter, statisticsBinding)
LegacyCounter.Builder --> MyStatistics : legacyCounter
MyStatistics --> InstrumentedCode

== Updating a Legacy Meter ==

InstrumentedCode -> MyStatistics : myEventJustHappened()
MyStatistics -> legacyCounter : increment()
legacyCounter -> statisticsBinding : increment()
statisticsBinding -> statistics : incInt(statId, 1)
legacyCounter -> counter : increment()
legacyCounter --> MyStatistics
MyStatistics --> InstrumentedCode

== Reading a Legacy Meter ==
InstrumentedCode -> MyStatistics : getMyEventCount()
MyStatistics -> legacyCounter : count()
legacyCounter -> statistics : getInt(statId)
statistics --> legacyCounter : stat value
legacyCounter --> MyStatistics : stat value
MyStatistics --> InstrumentedCode : stat value

== Deleting a Legacy Meter ==
InstrumentedCode -> MyStatistics : close()
MyStatistics -> registry : remove(legacyCounter)
note left
  Note: legacyCounter has
  the same Id as counter
end note
registry -> counter !!:
registry --> MyStatistics
MyStatistics--> InstrumentedCode

@enduml

...