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 | ||
---|---|---|
| ||
@startuml 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 |
...