How to manage agent logs

See also: Log

Manage the logs

Stream the logs

If you want to control the amount of logging detail first, see Manage the logging configuration.

To stream the logs in the current model, run the debug-log command:

juju debug-log

In a machine deployment, this will output logs for all the Juju machine and unit agents, starting with the last 10 lines, in the following format:

<entity (machine or unit)> <timestamp> <log level> <Juju module> <message>

In Kubernetes deployments, this will not show any logs below the model level.

See also: Kubernetes agent logs

The command has various options that allow you to control the length, appearance, amount and type of detail.


Expand to see examples

To begin with the last 30 log messages:

juju debug-log -n 30

To begin with all the log messages:

juju debug-log --replay

To begin with the last twenty log messages for the ‘lxd-pilot’ model:

juju debug-log -m lxd-pilot -n 20

To begin with the last 500 lines. The grep utility is used as a text filter:

juju debug-log -n 500 | grep amd64

To begin with the last 1000 lines and exclude messages from machine 3:

juju debug-log -n 1000 --exclude machine-3

To select all the messages emitted from a particular unit and a particular machine in the entire log:

juju debug-log --replay --include unit-mysql-0 --include machine-1

The unit can also be written ‘mysql/0’ (as shown by juju status).

To see all WARNING and ERROR messages in the entire log:

juju debug-log --replay --level WARNING

To see all logs on the cmr topic (label):

juju debug-log --include-label cmr

To progressively exclude more content from the entire log:

juju debug-log --replay --exclude-module juju.state.apiserver
juju debug-log --replay --exclude-module juju.state
juju debug-log --replay --exclude-module juju

To begin with the last 2000 lines and include messages pertaining to both the juju.cmd and juju.worker modules:

juju debug-log --lines 2000 \
    --include-module juju.cmd \
    --include-module juju.worker

See more: juju debug-log

Configure the logging level

Juju saves or discards logs according to the value of the model config key logging-config. Therefore, logging-config needs to be set before the events you want to collect logs for (i.e. before attempting to reproduce a bug).

Set values.

  • To change the logging configuration for machine and unit agents:
    Run the model-config command with the logging-config key set to a "-enclosed, semi-colon-separated list of <filter>=<verbosity level> pairs.

Example setting machine agent logs to `WARNING` and unit agent logs to `TRACE`
juju model-config logging-config="<root>=WARNING;unit=TRACE"

Example setting unit agent logs for unit `0` of `mysql` to `DEBUG`
juju model-config logging-config="unit.mysql/0=DEBUG"

See more: How to configure a model, List of model configuration keys > logging-config

To avoid filling up the database unnecessarily:
When verbose logging is no longer needed, return logging to normal levels!

  • To change the logging configuration on a per-unit-agent basis:
  1. SSH into the unit’s machine. E.g., for mysql/0:
juju ssh mysql/0
  1. Open the unit’s agent configuration file. For our example, it will be /var/lib/juju/agents/unit-mysql-0/agent.conf/ Then, find the values section, and add a line with the field LOGGING_OVERRIDE set to juju=<desired log level>, below TRACE. The bottom of the file should now look as below:
loggingconfig: <root>=WARNING;unit=DEBUG
values:
  CONTAINER_TYPE: ""
  NAMESPACE: ""
  LOGGING_OVERRIDE: juju=trace
mongoversion: "0.0"
  1. Restart the affected agent:
sudo systemctl restart jujud-unit-mysql-0.service

Get values. To verify the current logging configuration for machine and unit agents, run model-config followed by the logging-config key:

juju model-config logging-config

Sample output:

<root>=WARNING;unit=DEBUG;#http=TRACE

which means that the machine agent (<root>) log level is set to WARNING, the unit agent (unit) log level is set at DEBUG, and the http label is set to TRACE.

See more: How to configure a model, List of model configuration keys > logging-config

Forward logs to an external logsink

You can optionally forward log messages to a remote syslog server over a secure TLS connection, on a per-model basis, as below:

See Rsyslog documentation for help with security-related files (certificates, keys) and the configuration of the remote syslog server.

  1. Configure the controller for remote logging by configuring it during controller creation as below:
juju bootstrap <cloud> --config mylogconfig.yaml

where the YAML file is as below:

syslog-host: <host>:<port>
syslog-ca-cert: |
-----BEGIN CERTIFICATE-----
 <cert-contents>
-----END CERTIFICATE-----
syslog-client-cert: |
-----BEGIN CERTIFICATE-----
 <cert-contents>
-----END CERTIFICATE-----
syslog-client-key: |
-----BEGIN PRIVATE KEY-----
 <cert-contents>
-----END PRIVATE KEY-----

See more: How to configure a controller

  1. Enable log forwarding for a model by configuring it as below:
juju model-config -m <model> logforward-enabled=True

An initial 100 (maximum) existing log lines will be forwarded.

See more: How to configure a model

Pro tip: You can configure remote logging and enable log forwarding on all the controller’s models in one step by running

juju bootstrap <cloud> --config mylogconfig.yaml --config logforward-enabled=True 

Manage the log files

Only applicable for machines – for Kubernetes logs are written directly to stdout of the container and can be retrieved with native Kubernetes methods, e.g., kubectl logs -c <container-name> <pod-name> -n <model-name> .

See more: Juju agent logs – machines, Juju agent logs – Kubernetes

View the log files

To view the Juju log files in a Juju machine:

  1. Open a shell into the machine:

(1a) IfJuju can connect to the machine (i.e., the output contains Connected to <IP address>) and the machine is fully provisioned, use juju ssh. For example, to connect to machine 0:

juju ssh 0

(1b) IfJuju can connect to the machine (i.e., the output contains Connected to <IP address>) but the machine is not fully provisioned (e.g., command hangs at Running machine configuration script...), use the ssh command followed by the address of the machine and the path to the place where Juju stores your SSH keys (including the ones it generates automatically for you):

ssh ubuntu@<ip-address> -i <juju-data-dir>/ssh/juju_id_rsa

Here, <juju-data-dir> defaults to ~/.local/share/juju, but if you’ve set the JUJU_DATA environment variable, it will be equal to that instead.

(1c) If Juju cannot connect to the machine (i.e., the command never reaches Connected to <IP address>), use cloud-specific tools. For example, for the LXD cloud:


lxc exec [container-name] bash

or, for the MicroK8s cloud:

microk8s kubectl exec controller-0 -itc api-server -n [namespace] -- bash

See more: How to access a machine via SSH

  1. Examine the log files under /var/log with commands such as cat, less, or tail -f, for example:
cat /var/log/juju

Which log to look at depends on the type of failure, but generally speaking, syslog, cloud-init.log, cloud-init-output.log, and /var/log/juju are good ones to look at.


Expand to see an example for a controller machine
# SSH into machine 0 of the controller model:
juju ssh -m controller 0

# Navigate to the logs directory:
cd /var/log/juju

# List the contents:
ls

# View, e.g., the audit log file:
cat audit.log

Control the log file rotation

See also: List of controller configuration keys

Juju has settings to control the rotation of the various log files it produces.

There are two settings for each log file type: maximum size and number of backups. When the current log file of a particular type reaches the maximum size, Juju renames the log file to include a timestamp and gzips it, producing a “backup” log file.

Here’s an example of the controller’s machine agent logs with the maximum size set to 1MB, showing two timestamped backups as well as the current log file:

$ juju bootstrap localhost --config agent-logfile-max-size=1MB
$ lxc exec juju-6bf629-0 -- ls -l /var/log/juju
...
-rw-r----- 1 syslog adm   3577 Jan 12 02:01 machine-0-2022-01-12T02-01-07.995.log.gz
-rw-r----- 1 syslog adm   3578 Jan 12 02:02 machine-0-2022-01-12T02-02-08.011.log.gz
-rw-r----- 1 syslog adm 600000 Jan 12 02:02 machine-0.log

The full list of the controller settings that configure log file rotation is shown below. Normally these are set at bootstrap time with the --config option (see How to configure a controller).

  • The following config settings configure agent log files, including the API server “log sink”, the machine agent logs on controller and unit machines, and the unit agent logs:
  • agent-logfile-max-backups
  • agent-logfile-max-size
  • The following config settings configure the audit log files (note the missing “file” in the key name compared to the agent log file settings):
  • audit-log-max-backups
  • audit-log-max-size
  • The following config settings configure the model log files:
  • model-logfile-max-backups
  • model-logfile-max-size

Contributors: @hmlanigan, @jameinel, @manadart, @tmihoc

For this part in How to manage logs

Could we also mention this example from List of model configuration keys :

juju model-config -m foo logging-config="unit.mysql/0=DEBUG"

Thanks, I’ve included it under How to manage logs > Set values

image

PS The terminology used here (and in the model config doc) is a bit outdated. In the current state of the code there is no longer a separate entity called a unit agent – it’s just a machine agent that’s also running a tree of workers with unit responsibility. I’ll make a note to update it.

Hi - I ran into an issue with this command. As written in the guide it’s missing the closing " although I figured out on my own that should’ve been there.

When I ran the command though, I ended up with the exact string “unit.postgresql/0=TRACE” as the value for logging-config (not surprisingly). However, that did not set the log level to TRACE; that only happened when I set logging-config=TRACE instead.

Obviously I could’ve done something wrong - I’ll try it again when I have a minute - but I’m not 100% convinced this is working as advertised.

Thanks for catching the typo – I’ve fixed it now.

Regarding juju model-config logging-config="unit.mysql/0=TRACE": I’m not sure I fully understand the issue. Could you please clarify?

Doing:

juju model-config logging-config="unit.mysql/0=TRACE"

Turns on trace logging, but only for the unit.mysql/0 module. All of the other juju logging is configured to be WARNING by default. You can do:

juju model-config logging-config="<root>=INFO;unit.mysql/0=TRACE"

<root> is the magic string that is the root of the whole tree of logs. (We follow the python logging standard that if not otherwise set, you inherit the logging level from higher in the ‘tree’. So you can set the root to TRACE and everything will go to trace, or you can set the root to INFO and then just set one of the branches…

(We also have a special case when only setting root, which is:

juju model-config logging-config="INFO"

Which gets translated to "<root>=INFO", but it seems we don’t support "INFO;module=TRACE" you have to use <root> if you want to do complex things.

The “issue” I ran into (still not sure if it’s just me doing something wrong) I can reproduce.

I run juju debug-log in one terminal, and then in a second terminal I manipulate the logging-config setting.

If I set logging-config=INFO I see the right level of log data for the modules in my model. Then, I want to change the logging level for one of them - e.g. logging-config=<root>=INFO;unit.ingress/0=TRACE", but nothing happens.

If I change the whole model - e.g. logging-config="TRACE", I do get TRACE, but for all modules.

Then, if I change it back to logging-config=<root>=INFO;unit.ingress/0=TRACE", I don’t get anything in my log output.

Small typo s/roation/rotation

Fixed, thanks!

@simonrichardson has looked into this and concluded this is actually currently not possible. We’ll keep investigating. Either way, I expect to be able to update the docs conclusively before EOD today.

Upon further investigation, the docs are correct.

What you’re reporting

Then, if I change it back to logging-config==INFO;unit.ingress/0=TRACE", I don’t get anything in my log output.

could be due to no hooks firing.

@simonrichardson do you want to add anything?

So some of that also depends what you are typing. Note that ; is a bash special character. So you need to quote the logging configuration. You also can use either ; or : in the logging config (both are parsed as separators).

I just tested this with a bootstrapped 3.3 (and for simplicity just used the ‘controller/0’ unit):

$ juju switch controller
$ juju model-config logging-config="<root>=INFO"
$ juju exec --unit controller/0 "juju-log -l DEBUG debug message"
$ juju exec --unit controller/0 "juju-log -l INFO info message"
$ juju model-config logging-config="<root>=INFO;unit.controller/0=TRACE"
$ juju exec --unit controller/0 "juju-log -l DEBUG debug message2"
$ juju exec --unit controller/0 "juju-log -l INFO info message2"
$ juju debug-log --replay | tail -n 20
...
controller-0: 12:02:48 INFO juju.worker.logforwarder config change - log forwarding not enabled
unit-controller-0: 12:03:00 INFO unit.controller/0.juju-log info message
controller-0: 12:03:06 INFO juju.worker.logforwarder config change - log forwarding not enabled
unit-controller-0: 12:03:24 DEBUG unit.controller/0.juju-log debug message2
unit-controller-0: 12:03:28 INFO unit.controller/0.juju-log info message2

You can see that the first DEBUG message isn’t logged (but the INFO one is), and then the second DEBUG and INFO messages get logged.