#java #prometheus #prometheus-java
#java #prometheus #prometheus-java
Вопрос:
Я использую Prometheus Java simpleclient в веб-службе, чтобы отслеживать, сколько событий приводят к тому или иному статусу.
Я могу проверить в журналах, что счетчик вызывается и увеличивается внутренне, но кажется, что часто данные не доходят до конечной точки / metrics.
Например, только что, после увеличения счетчика в 3 раза для одного и того же состояния с интервалом в несколько минут каждый, журнал трижды напечатает «Текущее значение = 0, новое значение = 1». Первые два раза не отображалось никаких данных в конечной точке /metrics, и после 3-го увеличения оно, наконец, показало значение 1, что означает, что я потерял запись о первых 2 событиях.
Код, который у меня есть, следующий ниже, помимо некоторых изменений имени.
private static final Counter myCounter = Counter.build()
.name("myMetric")
.help("My metric")
.labelNames("status").register();
...
private static void incrementCounter(String status) {
Counter.Child counter = myCounter.labels(status);
Logger.info("Before Incrementing counter for status= " status ". Current value=" counter.get());
counter.inc();
Logger.info("After Incrementing counter for status= " status ". New value=" counter.get());
}
Я в недоумении относительно того, почему Prometheus, похоже, не может последовательно отслеживать эти счетчики. Кто-нибудь может увидеть, что не так, или лучший способ записать эти показатели счетчика?
Комментарии:
1. Вы создаете дочерние счетчики
Counter.Child counter = myCounter.labels(status);
, поэтому у вас в основном есть отдельный счетчик для каждого статуса.2. Я это понимаю. Все это было для одного и того же статуса.
3. Есть ли что-нибудь, вызывающее remove или clear в myCounter?
4. Ничего из того, что мы написали явно, нет. Единственные методы, которые мы использовали, это . labels(), а затем .inc(), .get() для дочернего объекта счетчика. Не уверен, есть ли что-нибудь в библиотеке Prometheus, что могло бы это делать.
Ответ №1:
Единственная причина, о которой я могу догадаться, — это одновременные incrementCounter
вызовы. io.prometheus.client.SimpleCollector#labels
Метод не является потокобезопасным (несмотря на то, что у children
поля есть ConcurrentMap
тип), поэтому при каждом вызове можно получать разные данные io.prometheus.client.Counter.Child
.
Что касается получения показателей через http — каждый вызов /metrics
конечной точки приводит к io.prometheus.client.Counter#collect
вызову метода, который извлекает значение только одного дочернего элемента.
Я бы посоветовал вам использовать вашу собственную параллельную карту для хранения счетчиков:
private static final ConcurrentMap<String, Counter.Child> counters = new ConcurrentHashMap<>();
// ...
private static void incrementCounter(String status) {
Counter.Child counter = counters.computeIfAbsent(status, myCounter::labels) ;
// ...
}