2

I am trying to replace PrometheusMeterRegistry with micormeter's LoggingMeterRegistry in order to export metrics as log events in a specific format. When executing my unittests I have noticed that the Counter meters are not showing the correct counts after retrieving the measurments with Meter#measure(). Here you can find a minimal example reproducing the behaviour described. The test case work5 calls a methode 5 times, withing the method a counter is registered and incremented. The expected counter value is then 5, with the PrometheusMeterRegistry the actual value is also 5, with LoggingMeterRegistry the actual value is 0.

  • Is something wrong with my test setup or usage of the LoggingMeterRegistry and thus the expectation is wrong?
  • If not, then how to make LoggingMeterRegistry behave correctly?
A4L
  • 17,353
  • 6
  • 49
  • 70
  • In my opinion it's better to continue using the `PrometheusMeterRegistry` or any other suitable registry that maintains the state of the metrics and `LoggingMeterRegistry` can still be useful for debugging and logging metric events, but it is not designed to provide accurate metric values for assertions or calculations! – Freeman Aug 11 '23 at 13:54

2 Answers2

2

As I need the counter to reflect the count the same way the prometheus meter registry does for the usecase shown in the sample project and also the fact that the registry pushes the measurments to its sink, I have decided to create a custom logging meter registry CustomLoggingMeterRegistry extending LoggingMeterRegistry where I can control what implementation of Counter is used by overriding the newCounter method.

@Override
protected Counter newCounter(Id id) {
  CountingMode countingMode = getCountingMode();
  switch (countingMode) {
    case CUMULATIVE:
      return new CumulativeCounter(id);
    case STEP:
      return new StepCounter(id, clock, config.step().toMillis());
    default:
      throw new UnsupportedOperationException(String
          .format("Unsupported counting mode '%s'",
              countingMode.name()));
  }

}

StepCounter is only one instance of the issue, it may technically be the case for anything that is a StepMeter and needs to be handled accordingly.

Sample project updated with an impelemntation draft.

EDIT (2023-08-18):

As some issues have arised with the implementation above, because Counters are used for statistics in other Meters, for example Timer, I have abandoned the CustomLoggingMeterRegistry in favour of a SimplePushMeterRegistry which is a PushMeterRegistry that delegates the creation of new Meter instances to the implementation SimpleMeterRegistry. Pursuing CustomLoggingMeterRegistry would have required providing an implementation for all newXxx(...) methods, which by looking at available implementations is not trivial as in the case of Counter.

Sample project updated with an impelemntation draft.

A4L
  • 17,353
  • 6
  • 49
  • 70
1

Please, consider read this related SO answer I wrote recently, it is related to InfluxDB and the associated registry but I think the reasoning behind the explanation provided is the same for LoggingMeterRegistry.

As indicated in the answer, I think the behavior you are describing could be explained because LoggingMeterRegistry uses as in the case of InfluxDB a step based approach for performing rate aggregation, in client side. Note that the Prometheus registry provides a full fledged implementation - not step based - and the aggregation is being performed on server side.

jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • Thanks for your answer, I was also suspecting it was related to the `StepCounter` implementation that the logging registry is using. I think I will end up using a custom logging registry where I can control which counter implementation is used. I wil post my workaround as response aswell and wait if there are any other suggestions. – A4L Aug 15 '23 at 14:54
  • 1
    You are welcome @A4L, thank you very much for the feedback. Yes, as said, I think it is related with the step concept. In this specific use case it is difficult to test because in addition there are different pools of thread working on publishing and polling the values: I was able to successfully run your test but only including `meterRegistry.close()` after your five `worker.run()` invocations: behind the scenes it causes the step meters to be flushed. Your approach looks fine. In fact is very similar to the one implemented in the default ... – jccampanero Aug 15 '23 at 22:08
  • [`SimpleMeterRegistry`](https://github.com/micrometer-metrics/micrometer/blob/main/micrometer-core/src/main/java/io/micrometer/core/instrument/simple/SimpleConfig.java) by the library authors. – jccampanero Aug 15 '23 at 22:09
  • The workaround is inspired by the `SimpleMeterRegistry` which not a `PushMeterRegistry` registry, otherwise I would just have used it as is. – A4L Aug 16 '23 at 07:19
  • Bounty awarded for pointing at the right direction ;-) – A4L Aug 18 '23 at 12:29
  • 1
    Sorry for the late reply @A4L. Thank you very much, I really I appreciate it. I am happy to hear that the answer was helpful and that at least it provided you some guidance about the resolution of the issue. – jccampanero Aug 18 '23 at 22:11