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