All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.camel.component.kafka.KafkaDevConsole Maven / Gradle / Ivy

There is a newer version: 4.9.0
Show newest version
/*
 * 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.component.kafka;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.apache.camel.Route;
import org.apache.camel.component.kafka.consumer.devconsole.DefaultMetricsCollector;
import org.apache.camel.component.kafka.consumer.devconsole.DevConsoleMetricsCollector;
import org.apache.camel.spi.annotations.DevConsole;
import org.apache.camel.support.console.AbstractDevConsole;
import org.apache.camel.util.StopWatch;
import org.apache.camel.util.TimeUtils;
import org.apache.camel.util.json.JsonArray;
import org.apache.camel.util.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@DevConsole(name = "kafka", displayName = "Kafka", description = "Apache Kafka")
public class KafkaDevConsole extends AbstractDevConsole {

    private static final Logger LOG = LoggerFactory.getLogger(KafkaDevConsole.class);

    private static final long COMMITTED_TIMEOUT = 10000;

    /**
     * Whether to include committed offset (sync operation to Kafka broker)
     */
    public static final String COMMITTED = "committed";

    public KafkaDevConsole() {
        super("camel", "kafka", "Kafka", "Apache Kafka");
    }

    @Override
    protected String doCallText(Map options) {
        final boolean committed = "true".equals(options.getOrDefault(COMMITTED, "false"));

        StringBuilder sb = new StringBuilder();
        for (Route route : getCamelContext().getRoutes()) {
            if (route.getConsumer() instanceof KafkaConsumer kc) {
                sb.append(String.format("\n    Route Id: %s", route.getRouteId()));
                sb.append(String.format("\n    From: %s", route.getEndpoint().getEndpointUri()));
                for (KafkaFetchRecords t : kc.tasks()) {
                    final DevConsoleMetricsCollector metricsCollector = t.getMetricsCollector();
                    sb.append(String.format("\n        Worked Thread: %s", metricsCollector.getThreadId()));
                    sb.append(String.format("\n        Worker State: %s", t.getState()));
                    TaskHealthState hs = t.healthState();
                    if (!hs.isReady()) {
                        sb.append(String.format("\n        Worker Last Error: %s", hs.buildStateMessage()));
                    }
                    DefaultMetricsCollector.GroupMetadata meta = metricsCollector.getGroupMetadata();
                    if (meta != null) {
                        sb.append(String.format("\n        Group Id: %s", meta.groupId()));
                        sb.append(String.format("\n        Group Instance Id: %s", meta.groupInstanceId()));
                        sb.append(String.format("\n        Member Id: %s", meta.memberId()));
                        sb.append(String.format("\n        Generation Id: %d", meta.generationId()));
                    }
                    if (metricsCollector.getLastRecord() != null) {
                        sb.append(String.format("\n        Last Topic: %s", metricsCollector.getLastRecord().topic()));
                        sb.append(String.format("\n        Last Partition: %d", metricsCollector.getLastRecord().partition()));
                        sb.append(String.format("\n        Last Offset: %d", metricsCollector.getLastRecord().offset()));
                    }
                    if (committed) {
                        List l = fetchCommitOffsets(kc, metricsCollector);
                        if (l != null) {
                            for (DefaultMetricsCollector.KafkaTopicPosition r : l) {
                                sb.append(String.format("\n        Commit Topic: %s", r.topic()));
                                sb.append(String.format("\n        Commit Partition: %s", r.partition()));
                                sb.append(String.format("\n        Commit Offset: %s", r.offset()));
                                if (r.epoch() > 0) {
                                    long delta = System.currentTimeMillis() - r.epoch();
                                    sb.append(String.format("\n        Commit Offset Since: %s",
                                            TimeUtils.printDuration(delta, true)));
                                }
                            }
                        }
                    }
                }
                sb.append("\n");
            }
        }

        return sb.toString();
    }

    private static List fetchCommitOffsets(
            KafkaConsumer kc, DevConsoleMetricsCollector collector) {
        StopWatch watch = new StopWatch();

        CountDownLatch latch = collector.fetchCommitRecords();
        long timeout = Math.min(kc.getEndpoint().getConfiguration().getPollTimeoutMs(), COMMITTED_TIMEOUT);
        try {
            latch.await(timeout, TimeUnit.MILLISECONDS);
            var answer = collector.getCommitRecords();
            LOG.debug("Fetching commit offsets took: {} ms", watch.taken());
            return answer;
        } catch (Exception e) {
            // ignore
        }
        return null;
    }

    @Override
    protected Map doCallJson(Map options) {
        final boolean committed = "true".equals(options.getOrDefault(COMMITTED, "false"));

        JsonObject root = new JsonObject();

        List list = new ArrayList<>();
        root.put("kafkaConsumers", list);

        for (Route route : getCamelContext().getRoutes()) {
            if (route.getConsumer() instanceof KafkaConsumer kc) {
                JsonObject jo = new JsonObject();
                jo.put("routeId", route.getRouteId());
                jo.put("uri", route.getEndpoint().getEndpointUri());

                JsonArray arr = new JsonArray();
                jo.put("workers", arr);

                for (KafkaFetchRecords t : kc.tasks()) {
                    final DevConsoleMetricsCollector metricsCollector = t.getMetricsCollector();

                    JsonObject wo = new JsonObject();
                    arr.add(wo);
                    wo.put("threadId", metricsCollector.getThreadId());
                    wo.put("state", t.getState());
                    TaskHealthState hs = t.healthState();
                    if (!hs.isReady()) {
                        wo.put("lastError", hs.buildStateMessage());
                    }
                    DefaultMetricsCollector.GroupMetadata meta = metricsCollector.getGroupMetadata();
                    if (meta != null) {
                        wo.put("groupId", meta.groupId());
                        wo.put("groupInstanceId", meta.groupInstanceId());
                        wo.put("memberId", meta.memberId());
                        wo.put("generationId", meta.generationId());
                    }
                    if (metricsCollector.getLastRecord() != null) {
                        wo.put("lastTopic", metricsCollector.getLastRecord().topic());
                        wo.put("lastPartition", metricsCollector.getLastRecord().partition());
                        wo.put("lastOffset", metricsCollector.getLastRecord().offset());
                    }
                    if (committed) {
                        List l = fetchCommitOffsets(kc, metricsCollector);
                        if (l != null) {
                            JsonArray ca = new JsonArray();
                            for (DefaultMetricsCollector.KafkaTopicPosition r : l) {
                                JsonObject cr = new JsonObject();
                                cr.put("topic", r.topic());
                                cr.put("partition", r.partition());
                                cr.put("offset", r.offset());
                                cr.put("epoch", r.epoch());
                                ca.add(cr);
                            }
                            if (!ca.isEmpty()) {
                                wo.put("committed", ca);
                            }
                        }
                    }
                }
                list.add(jo);
            }
        }
        return root;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy