Logging in charms is useful for many reasons, from debugging as the charm developer, to tracking the progress and status of deployed charms as an administrator. There are no special logging constructs in the Charmed Operator Framework, you can simply use the standard Python logging module.

The Juju command-line tool provides many options to customise its log output, which may be useful when debugging specific applications and services.

The default template initialised by charmcraft init already includes the required set up for this, and an example of its use:

import logging
# ...
logger = logging.getLogger(__name__)

class HelloOperatorCharm(CharmBase):
    # ...

    def _on_config_changed(self, _):
        current = self.config["thing"]
        if current not in self._stored.things:
            # Note the use of the logger here
            logger.debug("found a new thing: %r", current)

As with any standard invocation of the Python logging module, there are several log levels available depending on the type of information you wish to convey. Keep developer specific logging to a minimum, and use logger.debug() for such output.

Note that some logging is performed automatically by the Juju controller, for example when an event handler is called. More information about Juju’s logging can be found in the OLM docs. Try not to replicate this behaviour in your own code. If you are debugging a problem, ensure you comment out or remove large information dumps (such as config files, etc.) from the logging once you are finished.

When passing messages to the logger, do not build the strings yourself. Allow the logger to do this for you as required by the specified log level. An example is shown below:

# Do this!
logger.info("Got some information %s", info)
# Don't do this
logger.info("Got some information {}".format(info))
# Or this ...
logger.info(f"Got some more information {more_info}")