You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/10/31 08:51:13 UTC
[camel] branch main updated: CAMEL-18651: camel-jbang - CLI command to get micrometer metrics
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 814c5c9e81f CAMEL-18651: camel-jbang - CLI command to get micrometer metrics
814c5c9e81f is described below
commit 814c5c9e81fd8b9f90b4f76116c88c4efa872d95
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Oct 31 09:50:58 2022 +0100
CAMEL-18651: camel-jbang - CLI command to get micrometer metrics
---
.../camel/cli/connector/LocalCliConnector.java | 7 +
.../dsl/jbang/core/commands/CamelJBangMain.java | 2 +
.../core/commands/process/ListMicrometer.java | 208 +++++++++++++++++++++
3 files changed, 217 insertions(+)
diff --git a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
index a611e9bac59..1d9d82dc330 100644
--- a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
+++ b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
@@ -398,6 +398,13 @@ public class LocalCliConnector extends ServiceSupport implements CliConnector, C
root.put("blocked", json);
}
}
+ DevConsole dc9 = dcr.resolveById("micrometer");
+ if (dc9 != null) {
+ JsonObject json = (JsonObject) dc9.call(DevConsole.MediaType.JSON);
+ if (json != null && !json.isEmpty()) {
+ root.put("micrometer", json);
+ }
+ }
}
// various details
JsonObject services = collectServices();
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
index 44edb4a1862..38645ac1c88 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
@@ -53,6 +53,7 @@ import org.apache.camel.dsl.jbang.core.commands.process.ListBlocked;
import org.apache.camel.dsl.jbang.core.commands.process.ListEvent;
import org.apache.camel.dsl.jbang.core.commands.process.ListHealth;
import org.apache.camel.dsl.jbang.core.commands.process.ListInflight;
+import org.apache.camel.dsl.jbang.core.commands.process.ListMicrometer;
import org.apache.camel.dsl.jbang.core.commands.process.ListProcess;
import org.apache.camel.dsl.jbang.core.commands.process.ListService;
import org.apache.camel.dsl.jbang.core.commands.process.ListVault;
@@ -81,6 +82,7 @@ public class CamelJBangMain implements Callable<Integer> {
.addSubcommand("inflight", new CommandLine(new ListInflight(main)))
.addSubcommand("blocked", new CommandLine(new ListBlocked(main)))
.addSubcommand("route-controller", new CommandLine(new RouteControllerAction(main)))
+ .addSubcommand("micrometer", new CommandLine(new ListMicrometer(main)))
.addSubcommand("service", new CommandLine(new ListService(main)))
.addSubcommand("source", new CommandLine(new CamelSourceAction(main)))
.addSubcommand("vault", new CommandLine(new ListVault(main))))
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMicrometer.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMicrometer.java
new file mode 100644
index 00000000000..5c37eb718ae
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMicrometer.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.process;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.github.freva.asciitable.AsciiTable;
+import com.github.freva.asciitable.Column;
+import com.github.freva.asciitable.HorizontalAlign;
+import com.github.freva.asciitable.OverflowBehaviour;
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.TimeUtils;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+
+@Command(name = "micrometer",
+ description = "Get metrics (micrometer) of running Camel integrations")
+public class ListMicrometer extends ProcessBaseCommand {
+
+ @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
+ String name = "*";
+
+ @CommandLine.Option(names = { "--sort" },
+ description = "Sort by pid, name or age", defaultValue = "pid")
+ String sort;
+
+ public ListMicrometer(CamelJBangMain main) {
+ super(main);
+ }
+
+ @Override
+ public Integer call() throws Exception {
+ List<Row> rows = new ArrayList<>();
+
+ List<Long> pids = findPids(name);
+ ProcessHandle.allProcesses()
+ .filter(ph -> pids.contains(ph.pid()))
+ .forEach(ph -> {
+ JsonObject root = loadStatus(ph.pid());
+ // there must be a status file for the running Camel integration
+ if (root != null) {
+ Row row = new Row();
+ JsonObject context = (JsonObject) root.get("context");
+ if (context == null) {
+ return;
+ }
+ row.name = context.getString("name");
+ if ("CamelJBang".equals(row.name)) {
+ row.name = extractName(root, ph);
+ }
+ row.pid = "" + ph.pid();
+ row.uptime = extractSince(ph);
+ row.age = TimeUtils.printSince(row.uptime);
+ Row baseRow = row.copy();
+
+ JsonObject mo = (JsonObject) root.get("micrometer");
+ if (mo != null) {
+ JsonArray arr = (JsonArray) mo.get("counters");
+ if (arr != null) {
+ for (int i = 0; i < arr.size(); i++) {
+ row = baseRow.copy();
+ JsonObject jo = (JsonObject) arr.get(i);
+ row.type = "counter";
+ row.metricName = jo.getString("name");
+ row.metricDescription = jo.getString("description");
+ row.count = jo.getDouble("count");
+ rows.add(row);
+ }
+ }
+ arr = (JsonArray) mo.get("timers");
+ if (arr != null) {
+ for (int i = 0; i < arr.size(); i++) {
+ row = baseRow.copy();
+ JsonObject jo = (JsonObject) arr.get(i);
+ row.type = "timer";
+ row.metricName = jo.getString("name");
+ row.metricDescription = jo.getString("description");
+ row.count = jo.getDouble("count");
+ row.mean = jo.getDouble("mean");
+ row.max = jo.getDouble("max");
+ row.total = jo.getDouble("total");
+ rows.add(row);
+ }
+ }
+ arr = (JsonArray) mo.get("gauges");
+ if (arr != null) {
+ for (int i = 0; i < arr.size(); i++) {
+ row = baseRow.copy();
+ JsonObject jo = (JsonObject) arr.get(i);
+ row.type = "gauge";
+ row.metricName = jo.getString("name");
+ row.metricDescription = jo.getString("description");
+ row.count = jo.getDouble("value");
+ rows.add(row);
+ }
+ }
+ arr = (JsonArray) mo.get("distribution");
+ if (arr != null) {
+ for (int i = 0; i < arr.size(); i++) {
+ row = baseRow.copy();
+ JsonObject jo = (JsonObject) arr.get(i);
+ row.type = "distribution";
+ row.metricName = jo.getString("name");
+ row.metricDescription = jo.getString("description");
+ row.count = jo.getDouble("value");
+ row.mean = jo.getDouble("mean");
+ row.max = jo.getDouble("max");
+ row.total = jo.getDouble("totalAmount");
+ rows.add(row);
+ }
+ }
+ }
+ }
+ });
+
+ // sort rows
+ rows.sort(this::sortRow);
+
+ if (!rows.isEmpty()) {
+ System.out.println(AsciiTable.getTable(AsciiTable.NO_BORDERS, rows, Arrays.asList(
+ new Column().header("PID").headerAlign(HorizontalAlign.CENTER).with(r -> r.pid),
+ new Column().header("NAME").dataAlign(HorizontalAlign.LEFT).maxWidth(30, OverflowBehaviour.ELLIPSIS_RIGHT)
+ .with(r -> r.name),
+ new Column().header("TYPE").dataAlign(HorizontalAlign.LEFT).with(r -> r.type),
+ new Column().header("NAME").dataAlign(HorizontalAlign.LEFT).with(r -> r.metricName),
+ new Column().header("VALUE").headerAlign(HorizontalAlign.RIGHT).dataAlign(HorizontalAlign.RIGHT)
+ .with(r -> getNumber(r.count)),
+ new Column().header("MEAN").headerAlign(HorizontalAlign.RIGHT).dataAlign(HorizontalAlign.RIGHT)
+ .with(r -> getNumber(r.mean)),
+ new Column().header("MAX").headerAlign(HorizontalAlign.RIGHT).dataAlign(HorizontalAlign.RIGHT)
+ .with(r -> getNumber(r.max)),
+ new Column().header("TOTAL").headerAlign(HorizontalAlign.RIGHT).dataAlign(HorizontalAlign.RIGHT)
+ .with(r -> getNumber(r.total)))));
+ }
+
+ return 0;
+ }
+
+ protected int sortRow(Row o1, Row o2) {
+ String s = sort;
+ int negate = 1;
+ if (s.startsWith("-")) {
+ s = s.substring(1);
+ negate = -1;
+ }
+ switch (s) {
+ case "pid":
+ return Long.compare(Long.parseLong(o1.pid), Long.parseLong(o2.pid)) * negate;
+ case "name":
+ return o1.name.compareToIgnoreCase(o2.name) * negate;
+ case "age":
+ return Long.compare(o1.uptime, o2.uptime) * negate;
+ default:
+ return 0;
+ }
+ }
+
+ private String getNumber(double d) {
+ String s = "" + d;
+ if (s.equals("0.0") || s.equals("0,0")) {
+ return "";
+ } else if (s.endsWith(".0") || s.endsWith(",0")) {
+ return s.substring(0, s.length() - 2);
+ }
+ return s;
+ }
+
+ private static class Row implements Cloneable {
+ String pid;
+ String name;
+ String age;
+ long uptime;
+ String type;
+ String metricName;
+ String metricDescription;
+ double count;
+ double mean;
+ double max;
+ double total;
+
+ Row copy() {
+ try {
+ return (Row) clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+ }
+
+}