qtcronqdebug

Qt output (qDebug qWarning etc) does not work if application is executed via cronjob


I created a reproduction sample for this:

#include <iostream>
#include <QtCore/QLoggingCategory>
#include <QtCore/QDebug>
#include <QtCore/QtCore>
using namespace std;
int main () {
  int i;
  QLoggingCategory::setFilterRules("*.debug=true\n");
  QLoggingCategory LogO(NULL);
  if (LogO.isDebugEnabled()) {
        cout << "QDebug enabled\n";
  } else {
        cout << "QDebug disabled!\n";
  }
  cout << "Start!\n";
  qDebug() << "qStart!";
  cerr << "print to stderr.\n";
  qWarning() << "qWarning";
  return 0;
}

Build steps:

g++ -c -fPIC -I/usr/include/qt5 main.cpp -o main.o
g++ -fPIC main.o -L /usr/lib64 -lQt5Core -o testapp

When executing the application in an interactive shell, output redirection works as expected:

Setup:

./testapp > out 2> err

Output:

>>cat out:
QDebug enabled
Start!

>>cat err:
qStart!
print to stderr.
qWarning

However, it does not work if the application is executed as a cronjob, the output of qDebug() and qWarning() is missing:

Setup:

* * * * * username /home/username/temp/build/testapp 1> /home/username/temp/log/out 2> /home/username/temp/log/err

Output:

>>cat /home/username/temp/log/out
QDebug enabled
Start!

>>cat home/username/temp/log/err
print to stderr.

Enviroment vars

The output of env in the interative shell is as follows:

LS_COLORS=*long string*
SSH_CONNECTION=*censored*
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
HOSTNAME=*censored*
XDG_SESSION_ID=492
USER=username
SELINUX_ROLE_REQUESTED=
PWD=/home/username/temp/build
HOME=/home/username
SSH_CLIENT=*censored*
SELINUX_LEVEL_REQUESTED=
SSH_TTY=/dev/pts/0
MAIL=/var/spool/mail/username
TERM=xterm
SHELL=/bin/bash
SELINUX_USE_CURRENT_RANGE=
SHLVL=1
LOGNAME=username
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
XDG_RUNTIME_DIR=/run/user/1000
PATH=/usr/lib64/ccache:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/username/.local/bin:/home/username/bin
HISTSIZE=1000
LESSOPEN=||/usr/bin/lesspipe.sh %s
_=/usr/bin/env
OLDPWD=/home/username/temp/build/logs

The output of env when called via cronjob is as follows:

LS_COLORS=*long string*
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
HOSTNAME=*censored*
XDG_SESSION_ID=995
USER=username
PWD=/home/username
HOME=/home/username
MAIL=/var/spool/mail/username
TERM=xterm
SHELL=/bin/bash
SHLVL=1
LOGNAME=username
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
XDG_RUNTIME_DIR=/run/user/1000
PATH=/usr/lib64/ccache:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/username/.local/bin:/home/username/bin
LESSOPEN=||/usr/bin/lesspipe.sh %s
_=/usr/bin/env

Solution

  • The issue is that qt behaves differently depending if it thinks that it is running in an (interactive?) terminal or not.

    Quote:

    One pitfall to be aware of: the destination of logging depends on an environment variable. If the variable QT_LOGGING_TO_CONSOLE is set to 1, the message functions will always log to the console. If set to 0, they will not log to the console, and will instead log to syslog, if enabled. When the environment variable is not set, the message functions log to a console if one is present (i.e. if the program is attached to a terminal). Thus, to ensure that the output of our example program goes to syslog, I set the environment variable to 0 within the program.

    Therefore, the output of qDebug, QWarning etc. when executed from cron was not output via stderr, but directly handed over to journald.

    TL;DR: quickfix: add QT_LOGGING_TO_CONSOLE=1 to /etc/crontab

    .

    .

    PS: note if you need to debug an issue with QDebug:

    1. be aware of this: https://bugzilla.redhat.com/show_bug.cgi?id=1227295
    2. you can add QT_LOGGING_DEBUG=1 as an environment variable to make qt output changes in logging behavior during execution.