Logging is important for observability of the platform. Stackable provides human-readable plaintext logs for each running container, as well as aggregated and persisted logs with identical structure across the whole platform. Log levels can be set for individual modules and configuration is identical across all products, but custom logging configuration files can be supplied as well.

logging overview.drawio


Aggregate and persist - The logging on the platform was designed to aggregate logs from all parts of the platform to make it easy to correlate events from different parts. For this, logs should share the same structure, and should be viewable in a central location. Logs should also be persisted in a central location, so if a component crashes, the logs are still there to identify the reason.

Easy to read on the fly - At the same time, logs should still be accessible in an easy to read format on the containers, to allow for easy on the fly inspection of each part of the platform. The logging configuration also supports setting different thresholds for the logs readable on the container and the aggregated logs. This way you can get a detailed view of the operations of a component while viewing it on the container, but aggregate logs at a coarser granularity when aggregating across the whole platform.

Consistent configuration - Finally, logging should be always configured the same way, no matter which product and which underlying technology is used to produce the logs. Logging for each product is configured in the ProductCluster resource. It is still supported to supply custom logging configuration files, these are then product specific.


Below you can see the overall architecture using ZooKeeper as an example. Stackable uses Vector for log aggregation and OpenSearch as the sink to persist logs in.

logging architecture.drawio

You configure your logging in the resource describing the cluster, seen in the top left in the diagram (see the configuration section below). The operator reads this resource and creates the appropriate log configuration files in the ConfigMap which also holds other product configuration. The ConfigMap is then mounted into the containers. The ZooKeeper Pod has three containers: The prepare sidecar container, the zookeeper container and the vector sidecar container. All logs get written into a shared mounted directory, from which the Vector agent reads them and sends them to the vector aggregator.

The aggregator is configured to use the OpenSearch sink. It sends all logs to the sink. If the sink is unavailable, it will buffer the log messages. It is also the single point where the sink is configured, so the sink is decoupled from the individual product configurations and only needs to be configured in this single location for the whole platform.

Identical configuration in each product

Logging configuration usually requires configuration what to log, where to log it and in which format. Usually you want to persist logs but also view them on the fly in a console, and possibly both of these in different formats. Stackable provides configuration for this out of the box. You only need to enable log aggregation and configure what you want to log. As part of the logging configuration, individual modules can be configured with different log levels:

vectorAggregatorConfigMapName: vector-aggregator-discovery  (1)
  logging:                   (2)
    enableVectorAgent: true  (3)
    containers:              (4)
        console:             (5)
          level: DEBUG
          level: INFO
        loggers:             (6)
            level: INFO
            level: DEBUG
            level: NONE
1 The discovery ConfigMap of the Vector aggregator to publish the logs to. This is set at cluster level.
2 The logging configuration fragment, can be set at role or role group level.
3 Enable the Vector agent to aggregate logs.
4 Logging is defined for each container.
5 Console and file appenders can have different log level thresholds.
6 Setting log levels for individual modules is also possible.

Log levels per module - In the loggers section the log levels for each module are configured. Note the ROOT module. This is a special module and refers to the default log level for the container. The log levels are the commonly used ones (TRACE, DEBUG, INFO, WARN, ERROR, FATAL) as well as the NONE level to turn of logging. The default log level is INFO.

Log levels for console and file - The configuration supports setting another level threshold for the console and the file output from which the aggregation is done. A typical use case is that the log level for the console is set to a more detailed level to allow for detailed inspection of a container, but less information in the aggregated log store.

Per container configuration - A Pod actually consists of multiple containers and you might want different log levels for each of them. Also the log levels per module are container specific.

Following the Stackable roles and role groups concept, this configuration fragment can be set either at role or role group level.

Configuring the aggregator location

Every product also has a vectorAggregatorConfigMapName property in its spec that needs to be set to the name of the ConfigMap that contains the address of the aggregator. The field is called ADDRESS and the value could be vector-aggregator:6000 if you’re running the aggregator behind a service named vector-aggregator.

Custom overrides

As with many parts of the Stackable platform, custom overrides are supported as well, by supplying your own logging configuration file. This is then product specific.

  enableVectorAgent: false       (1)
        configMap: my-configmap  (2)
1 The vector logging agent is not deployed
2 A custom logging configuration is loaded from a ConfigMap called my-configmap

Further Reading

To get some hands on experience and see logging in action, try out the logging demo.