Observability adds common observability primitives to fusion server.

Observability

Observability stack is composed of these primitives:

  • Logging: Yupiik Logging : it enables to configure your logging using system properties even using GraalVM native-image. It is also a good companion for container based deployments (Kubernetes) since you can switch very easily logging to JSON (-Djava.util.logging.manager=io.yupiik.logging.jul.YupiikLogManager -Dio.yupiik.logging.jul.handler.StandardHandler.formatter=json).

  • Healthcheck(s): this is the capacity to test through HTTP the server state, mainly used by Kubernetes to check if the application is ready (can get traffic) and if it is in a broken state (pod should be killed and restarted for ex.). It is part of fusion-observability module.

  • Metrics: often coupled to prometheus or opentelemetry, it enables to collect metrics (think time series) about your application. It can be technical (CPU usage for ex.) or business (number of downloads, number of open pages by session). It is part of fusion-observability module.

  • Tracing: this is the ability to trace a business request (a trace) end to end through all the system. Main collectors/UI are Jaegger and Zipkin. Fusion supports that through its fusion-tracing HTTP Client modules).

HTTP Server

By default, observability module adds another web server for observability purposes. Default port is 8181, but you can set fusion.observability.server.port configuration (system property, environment variable using underscores and uppercasing it) to override it.

The goal to not reuse the same server is to not have to secure this one (it will stay an internal port in your cluster/infrastructure). Since some Kubernetes tooling does not like adding headers to gather the data (prometheus for ex.) it is a good compromise.

Health checks

A health check implements io.yupiik.fusion.observability.health.HealthCheck API.

Then the observability server will expose a /health endpoint which will return an HTTP 200 if all health checks are successful and an HTTP 503 if there is at least one failure.

If you need to distinguish between health check types, you can implement type() method and return something different from live.

Then you can call the particular endpoints using /health?type=<my type>. To get the live checks, for example, use /health?type=live. Without type query parameter, all checks are executed.

Metrics

Metrics exposes an endpoint /metrics on observability server which renders the openmetrics stored in io.yupiik.fusion.observability.metrics.MetricsRegistry.

It supports Gauge and Counter metric types.

Here is a common way to use it in your application:

@DefaultScoped
public class MyService {
  private final LongAdder myCounter;

  public MyService(final MetricsRegistry registry) {
    this.myCounter = registry.registerCounter("my-service-counter");
  }

  public void save(final MyEntity entity) {
    // do the normal business code
    myCounter.increment();
  }
}
TIP

you can unregister your counter on the registry if it is a short live counter (to use with a session for example), it will then no more be available but using that with prometheus, you have no guarantee it will be polled, so it can be neat to delay the un-registration until next polling. Gauge can make it easy using registerReadOnlyGauge since you then pass a LongSupplier you control.