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

com.github.loki4j.client.pipeline.Loki4jMetrics Maven / Gradle / Ivy

package com.github.loki4j.client.pipeline;

import java.time.Duration;
import java.util.Arrays;
import java.util.function.Supplier;

import com.github.loki4j.client.util.Cache.UnboundAtomicMapCache;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Counter.Builder;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Timer;

/**
 * Provides an ability to report logging performance metrics using Micrometer framework
 */
public class Loki4jMetrics {

    private Timer appendTimer;
    private Timer encodeTimer;
    private Timer sendTimer;

    private DistributionSummary eventsEncodedSummary;
    private DistributionSummary bytesSentSummary;

    private Counter batchesEncodedCounter;
    private Counter batchesSentCounter;
    private Counter droppedEventsCounter;

    private Builder encodeErrorsCounterBuilder;
    private final UnboundAtomicMapCache encodeErrorsCounterCache = new UnboundAtomicMapCache<>();

    private Builder retryErrorsCounterBuilder;
    private final UnboundAtomicMapCache retryErrorsCounterCache = new UnboundAtomicMapCache<>();

    private Builder sendErrorsCounterBuilder;
    private final UnboundAtomicMapCache sendErrorsCounterCache = new UnboundAtomicMapCache<>();

    public Loki4jMetrics(String appenderName, Supplier unsentEvents) {
        var tags = Arrays.asList(
            Tag.of("appender", appenderName));

        appendTimer = Timer
            .builder("loki4j.append.time")
            .description("Time for a single event append operation")
            .tags(tags)
            .register(Metrics.globalRegistry);

        encodeTimer = Timer
            .builder("loki4j.encode.time")
            .description("Time for a batch encode operation")
            .tags(tags)
            .register(Metrics.globalRegistry);

        sendTimer = Timer
            .builder("loki4j.send.time")
            .description("Time for a HTTP send operation")
            .tags(tags)
            .register(Metrics.globalRegistry);

        eventsEncodedSummary = DistributionSummary
            .builder("loki4j.encode.events")
            .description("Number of log events processed by encoder")
            .tags(tags)
            .register(Metrics.globalRegistry);

        bytesSentSummary = DistributionSummary
            .builder("loki4j.send.bytes")
            .description("Size of batches sent to Loki")
            .baseUnit("bytes")
            .tags(tags)
            .register(Metrics.globalRegistry);

        batchesEncodedCounter = Counter
            .builder("loki4j.encode.batches")
            .description("Number of batches processed by encoder")
            .tags(tags)
            .register(Metrics.globalRegistry);

        batchesSentCounter = Counter
            .builder("loki4j.send.batches")
            .description("Number of batches sent to Loki")
            .tags(tags)
            .register(Metrics.globalRegistry);

        droppedEventsCounter = Counter
            .builder("loki4j.drop.events")
            .description("Number of events dropped due to backpressure settings")
            .tags(tags)
            .register(Metrics.globalRegistry);

        Gauge
            .builder("loki4j.unsent.events", () -> unsentEvents.get())
            .description("Current number of accepted but not yet sent events")
            .tags(tags)
            .register(Metrics.globalRegistry);

        encodeErrorsCounterBuilder = Counter
            .builder("loki4j.encode.errors")
            .description("Number of errors occurred while encoding batches")
            .tags(tags);

        retryErrorsCounterBuilder = Counter
            .builder("loki4j.retry.errors")
            .description("Number of errors occurred while retrying to send failed batches to Loki")
            .tags(tags);

        sendErrorsCounterBuilder = Counter
            .builder("loki4j.send.errors")
            .description("Number of errors occurred while sending batches to Loki")
            .tags(tags);
    }

    private void recordTimer(Timer timer, long startedNs) {
        timer.record(Duration.ofNanos(System.nanoTime() - startedNs));
    }

    public void eventAppended(long startedNs, boolean dropped) {
        recordTimer(appendTimer, startedNs);
        if (dropped) droppedEventsCounter.increment();
    }
    
    public void batchEncoded(long startedNs, int count) {
        recordTimer(encodeTimer, startedNs);
        eventsEncodedSummary.record(count);
        batchesEncodedCounter.increment();
    }

    public void batchEncodeFailed(Supplier failure) {
        incrementErrorCounter(encodeErrorsCounterBuilder, encodeErrorsCounterCache, failure);
    }

    public void sendRetryFailed(Supplier failure) {
        incrementErrorCounter(retryErrorsCounterBuilder, retryErrorsCounterCache, failure);
    }

    public void batchSendFailed(Supplier failure) {
        incrementErrorCounter(sendErrorsCounterBuilder, sendErrorsCounterCache, failure);
    }

    public void batchSent(long startedNs, int bytesCount) {
        recordTimer(sendTimer, startedNs);
        bytesSentSummary.record(bytesCount);
        batchesSentCounter.increment();
    }

    private void incrementErrorCounter(Builder builder, UnboundAtomicMapCache counterCache, Supplier failure) {
        var failKey = failure.get();
        var errorCounter = counterCache.get(failKey, () -> {
            return builder
                .tag("reason", failKey)
                .register(Metrics.globalRegistry);
        });
        errorCounter.increment();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy