squakez commented on code in PR #25444:
URL: https://github.com/apache/camel/pull/25444#discussion_r3758029312


##########
components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/json/AbstractMicrometerService.java:
##########
@@ -243,19 +264,165 @@ static Map<String, Object> convertMeterToMap(Meter 
meter) {
     }
 
     void logMetricsOnShutdown(String... filters) {
-        meterRegistry.getMeters().stream()
-                .filter(m -> 
AbstractMicrometerService.matchesFilter(m.getId().getName(), filters))
-                .map(AbstractMicrometerService::convertMeterToMap)
-                .forEach(logEntry -> {
-                    try {
-                        // we include a start and end tag to make sure the
-                        // scraper can more easily identify the metric content.
-                        String metric = "#METRIC-START#" + 
mapper.writeValueAsString(logEntry) + "#METRIC-END#";
-                        LOG.info(metric);
-                    } catch (Exception e) {
-                        LOG.error("Error logging metric " + 
logEntry.get("name"), e);
+        if ("prometheus".equalsIgnoreCase(logMetricsOnShutdownFormat)) {
+            List<Meter> meters = meterRegistry.getMeters().stream()
+                    .filter(m -> AbstractMicrometerService.matchesFilter(
+                            m.getId().getName(), filters))
+                    .sorted(Comparator.comparing(m -> {
+                        return normalizePrometheusName(m);
+                    }))
+                    .toList();
+
+            String previousPromName = null;
+
+            for (Meter meter : meters) {
+                String promName = normalizePrometheusName(meter);
+
+                List<String> lines = convertMeterToPrometheusLines(promName, 
meter);
+                boolean newMetric = !promName.equals(previousPromName);
+
+                for (String line : lines) {
+                    if (!newMetric
+                            && (line.startsWith("# HELP ")
+                                    || line.startsWith("# TYPE "))) {
+                        continue;
                     }
-                });
+
+                    LOG.info("#METRIC-START#{}#METRIC-END#", line);
+                }
+
+                previousPromName = promName;
+            }
+
+        } else {
+            meterRegistry.getMeters().stream()
+                    .filter(m -> 
AbstractMicrometerService.matchesFilter(m.getId().getName(), filters))
+                    .map(AbstractMicrometerService::convertMeterToMap)
+                    .forEach(this::logMetricsAsJson);
+        }
+    }
+
+    private void logMetricsAsJson(Map<String, Object> logEntry) {
+        try {
+            // we include a start and end tag to make sure the
+            // scraper can more easily identify the metric content.
+            String metric = "#METRIC-START#" + 
mapper.writeValueAsString(logEntry) + "#METRIC-END#";
+            LOG.info(metric);
+        } catch (Exception e) {
+            LOG.error("Error logging metric {}", logEntry.get("name"), e);
+        }
+    }
+
+    /**
+     * Converts a single {@link Meter} into one or more Prometheus 
text-exposition lines.
+     * <p>
+     * The output follows the Prometheus text format specification:
+     *
+     * <pre>
+     * # HELP &lt;name&gt; &lt;description&gt;
+     * # TYPE &lt;name&gt; &lt;type&gt;
+     * &lt;name&gt;{labels} &lt;value&gt;
+     * </pre>
+     *
+     * Metric names use underscores in place of dots/hyphens as required by 
Prometheus naming rules.
+     */
+    static List<String> convertMeterToPrometheusLines(String promName, Meter 
meter) {
+        String description = meter.getId().getDescription() != null ? 
meter.getId().getDescription() : promName;
+        String labels = buildPrometheusLabels(meter.getId().getTags());
+
+        List<String> lines = new ArrayList<>();
+
+        if (meter instanceof Gauge g) {
+            lines.add("# HELP " + promName + " " + description);
+            lines.add("# TYPE " + promName + " gauge");
+            lines.add(promName + labels + " " + 
formatPrometheusDouble(g.value()));
+        } else if (meter instanceof Counter c) {
+            lines.add("# HELP " + promName + "_total " + description);
+            lines.add("# TYPE " + promName + "_total counter");
+            lines.add(promName + "_total" + labels + " " + 
formatPrometheusDouble(c.count()));
+        } else if (meter instanceof Timer t) {
+            lines.add("# HELP " + promName + "_seconds " + description);
+            lines.add("# TYPE " + promName + "_seconds summary");
+            lines.add(promName + "_seconds_count" + labels + " " + t.count());
+            lines.add(promName + "_seconds_sum" + labels + " " + 
formatPrometheusDouble(t.totalTime(TimeUnit.SECONDS)));
+            lines.add(promName + "_seconds_max" + labels + " " + 
formatPrometheusDouble(t.max(TimeUnit.SECONDS)));
+        } else if (meter instanceof DistributionSummary ds) {
+            lines.add("# HELP " + promName + " " + description);
+            lines.add("# TYPE " + promName + " summary");
+            lines.add(promName + "_count" + labels + " " + ds.count());
+            lines.add(promName + "_sum" + labels + " " + 
formatPrometheusDouble(ds.totalAmount()));
+            lines.add(promName + "_max" + labels + " " + 
formatPrometheusDouble(ds.max()));
+        } else if (meter instanceof FunctionCounter fc) {
+            lines.add("# HELP " + promName + "_total " + description);
+            lines.add("# TYPE " + promName + "_total counter");
+            lines.add(promName + "_total" + labels + " " + 
formatPrometheusDouble(fc.count()));
+        } else if (meter instanceof FunctionTimer ft) {
+            lines.add("# HELP " + promName + "_seconds " + description);
+            lines.add("# TYPE " + promName + "_seconds summary");
+            lines.add(promName + "_seconds_count" + labels + " " + 
formatPrometheusDouble(ft.count()));
+            lines.add(promName + "_seconds_sum" + labels + " " + 
formatPrometheusDouble(ft.totalTime(TimeUnit.SECONDS)));
+        } else if (meter instanceof LongTaskTimer ltt) {
+            lines.add("# HELP " + promName + "_active_seconds " + description);
+            lines.add("# TYPE " + promName + "_active_seconds gauge");
+            lines.add(promName + "_active_seconds_active" + labels + " " + 
ltt.activeTasks());
+            lines.add(promName + "_active_seconds_duration" + labels + " "
+                      + 
formatPrometheusDouble(ltt.duration(TimeUnit.SECONDS)));
+            lines.add(promName + "_active_seconds_max" + labels + " "

Review Comment:
   Refactorying to remove the "active" suffix



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to