Skip to content

Tritium is a library for instrumenting applications to provide better observability at runtime

License

Notifications You must be signed in to change notification settings

palantir/tritium

Folders and files

NameName
Last commit message
Last commit date
Jan 31, 2024
Jun 3, 2024
Sep 5, 2023
Aug 3, 2023
Dec 6, 2024
Feb 6, 2025
Mar 4, 2017
Oct 3, 2024
Apr 7, 2023
Aug 29, 2024
Mar 6, 2024
Sep 6, 2023
Apr 20, 2023
Jun 15, 2024
Sep 12, 2024
Jun 15, 2024
Dec 6, 2024
Apr 7, 2023
Aug 30, 2024
Mar 6, 2024
Dec 2, 2020
Apr 7, 2023
Apr 7, 2023
Jul 29, 2020
Oct 2, 2019
Oct 18, 2023
May 13, 2021
Sep 23, 2024
Aug 16, 2016
Apr 23, 2024
Feb 24, 2025
Sep 23, 2024
Nov 12, 2024
Jul 18, 2024
Feb 12, 2025
Feb 24, 2025
Feb 24, 2025

Repository files navigation

Autorelease

Tritium is a library for instrumenting applications to provide better observability at runtime. Tritium allows for instrumentation of service interfaces through a Java proxy, providing call backs to extensible invocation event handlers. Two main invocation handlers currently provided are:

  • Metrics - records aggregate service time and call rates using Dropwizard metrics
  • Logging - logs individual service times

Why Tritium?

Tritium gives us aggregate metrics for the various services exposed and consumed by a server.

  • invocation response times (including min, average, max, percentile distribution, request count and 1, 5, and 15 rates)
  • cache effectiveness (eviction count, hit count, hit ratio, load average millis, load failure count, load success count, miss count, miss ratio, request count)

These metrics can be exposed at the Dropwizard MetricsServlet and can be exported via any of the Dropwizard provided reporters.

Basic Usage

Instrumenting a service using the Tritium annotation processor

The tritium-processor annotation processor must be applied to the annotation processor scope, and tritium-annotations must be available at both build and runtime.

Example using gradle, however all modern build systems are capable of registering annotation processors:

dependencies {
    implementation 'com.palantir.tritium:tritium-annotations'
    annotationProcessor 'com.palantir.tritium:tritium-processor'
}

Apply the @Instrument annotation to methods on an interface. Only the annotated methods will be instrumented.

interface Service {
    @Instrument
    String getGreeting();
}

You can also apply the @Instrument annotation to the interface itself to instrument all methods.

@Instrument
interface Service {
    String getGreeting();
}

If the interface is defined externally, a new interface may be defined which extends the target interface. The @Instrument annotation may be applied to either individual methods or the interface itself.

interface DelegateSupplier<T> extends Supplier<T> {
    @Instrument
    @Override
    String get();
}
@Instrument
interface DelegateSupplier<T> extends Supplier<T> {}

This generates the InstrumentedService wrapper implementation equivalent to the legacy dynamic proxy, with less overhead.

Service interestingService = ...
Service instrumentedService =
        InstrumentedService.instrument(interestingService, environment.metrics());

Instrumenting a service interface of a dropwizard application with default metrics timers and optional trace logging.

Prefer using the annotation processor whenever possible

import com.palantir.tritium.Tritium;

Service interestingService = ...
Service instrumentedService = Tritium.instrument(Service.class,
        interestingService, environment.metrics());

Instrumenting a Caffeine cache

import com.palantir.tritium.metrics.caffeine.CacheStats;

TaggedMetricRegistry taggedMetricRegistry = ...

Cache<Integer, String> cache = CacheStats.of(taggedMetricRegistry, "unique-cache-name")
        .register(stats -> Caffeine.newBuilder()
                .recordStats(stats)
                .build());

LoadingCache<String, Integer> loadingCache = CacheStats.of(taggedMetricRegistry, "unique-loading-cache-name")
        .register(stats -> Caffeine.newBuilder()
                .recordStats(stats)
                .build(key::length);

Creating a metric registry with reservoirs backed by HDR Histograms.

HDR histograms are more useful if the service is long running, so the stats represents the lifetime of the server rather than using default exponential decay which can lead to some mis-interpretations of timings (especially higher percentiles and things like max dropping over time) if the consumer isn't aware of these assumptions.

Note that the Histogram collects metrics throughout the lifetime of the service.

Dropwizard 0.9+ Integration

    @Override
    public void initialize(Bootstrap<ApplicationConfiguration> bootstrap) {
        super.initialize(bootstrap);
        bootstrap.setMetricRegistry(MetricRegistries.createWithHdrHistogramReservoirs());
        ...
    }

License

This project is made available under the Apache 2.0 License.