All logging in Gallium Data is done using the Apache log4j 2 framework, which is very powerful and flexible.

In case you're wondering, Gallium Data upgraded immediately when the infamous CVE-2021-44228 bug was discovered in November 2021, so if you're running a recent version of Gallium Data (1.0.3-823 or later), you're running a safe version of log4j.

By default, all logging goes to the console, which can be seen by running the Docker command:

docker logs -f <container-name>

This will keep printing out new log messages as they occur. You can hit ctrl-c to regain control of the command line.

Logging can also be seen in the Logs page of the Gallium Data admin app.

Logging is organized around loggers: a logger is a specific object used by Gallium Data to log events in a specific category, such as database connections, or filter logic.

Logging levels

Each logger has a logging level, which specifies how verbose this logger is. The logging levels are:

  • fatal: used only for catastrophic errors that threaten the stability of the Gallium Data service

  • error: for serious errors that may cause unexpected behavior, but should not affect the general operation of Gallium Data

  • warning: for unexpected errors that may be of interest, but are not too serious

  • info: for messages that are part of normal operation, and may be of interest to administrators

  • debug: used to log low-level messages which can be useful for debugging purposes

  • trace: used for very low-level messages

The higher the logging level, the less logging you get. In production systems, the logging level is commonly set to error or warning. When working on filters, it is commonly set to debug or trace.

In your filter code, you can log messages using the predefined logger, e.g. :

log.info("Rejecting query because etc...");

It is important to select the appropriate logging level, otherwise the logs can be cluttered with irrelevant messages.


Logging can affect performance if there is a lot of logging output. The lower the logging level, the more logging output, which can affect performance adversely. You should therefore set each logger to the level that provides you with information you will use, but no more.

In your filter code, when logging a fixed string, you usually don't have to worry about performance -- the logging call will result in an actual log message only if the logger is set to the level you choose. For instance, if you have the following code in a filter:

log.debug("The user is based in North America");

this will result in a logging message only if the logger is set to debug or trace. If the logger is set to a higher level , this logging call will do nothing.

However, if you have a logging call that is going to be executed a lot (meaning thousands or millions of time), you can optimize things a fair amount if you avoid logging something that is not a fixed string. For instance:

if (log.isDebugEnabled()) {
log.debug("Customer ID is " + pkt.cust_id + ", balance is: " + pkt.balance);

Having the conditional if (log.isDebugEnabled()) will make sure the logging statement only runs if the logging level warrants it. This avoids the creation of a complex string which might then be thrown away if the logging level is high.

This is not an issue for code that executes occasionally, but it can make a real difference for code that is executed a lot.


By default, the following loggers are present in Gallium Data:

  • galliumdata.core : for messages from Gallium Data's core operations.

  • galliumdata.dbproto : for messages from database protocol handlers.

  • galliumdata.uselog : for messages logged from filter logic. This is the logger that is available as the log variable in your filter code.

  • galliumdata.rest : for messages from the REST interface (if active). Normally relevant only only to Gallium Data engineers.

  • galliumdata.ssl : for messages from any SSL interactions with databases. SSL/TLS is complex enough to warrant its own logger, which can be helpful in debugging SSL issues.

It is possible for you to define your own logger(s), if you feel that is necessary:

const LogManager = Java.type("org.apache.logging.log4j.LogManager");
let myLogger = LogManager.getLogger("com.acme.mylogger");

You can also define your own loggers in the log4j configuration file (see below for details).

This can be useful to isolate certain types of logging entries, or direct them using the log4j2.properties configuration file.


Logging is configured on startup by the log4j2.properties file, which is in the /galliumdata/settings/ directory in the Docker image. You can map your own file to override the default, or you can create your own Docker image to include your own file.

At runtime, if you are using the admin app, you can change the logging levels (on the Logs page). This will not be persistent unless you publish.

Note that all the loggers may not show up on that page at all times: it shows only loggers that have been used so far. You may need to exercise Gallium Data a bit before all the loggers show up.

The configuration file allows enormous flexibility, such as integration with enterprise logging solutions. Please refer to the log4j documentation for details.