cutelyst  4.5.1
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
Logging with Cutelyst

Cutelyst uses QLoggingCategory functions to log messages to different logging categories in the cutelyst logging namespace, meaning each Cutelyt logging category starts with cutelyst like cutelyst.server.tcp. Get general information about logging with Qt at QtLogging. The default priority above that Cutelyst logs messages is QtWarningMsg inclusive, so messages of warning priority and higher will be written to the logs by default.

Logging message pattern

Cutelyst server uses the following pattern by default to generate logging messages:

%{pid}:%{threadid} %{category}[%{type}] %{message}

See qSetMessagePattern() on how to change the output of the default message handler. Cutelyst server also respects the existence of the QT_MESSAGE_PATTERN environment variable.

Logging message handler

By default, Cutelyst uses the default logging message handler set by Qt. The Qt default message handler will try to detect if the application is started inside a user visible console. If that is the case, it will write messages to stderr. If you started your Cutelyst application as eg. a systemd service, it will use systemd’s journald to log messages (if the journald feature was enabled when compiling Qt). The same is true for other systems: if there is no user facing console, the system logging mechanism will be used (if available). You can set the environment variable QT_FORCE_STDERR_LOGGING=1 to force logging to stderr. So, if you start your application with cutelystd4-qt6 on the console, you should normally get the logging output directly there.

If you want to have more control over the way your messages are logged, you can install your own message handler in the constructor of your application or in your init function (if you need more info from config for example) using qInstallMessageHandler().

Log to file

If you want to log to a specific file, you can install your own message handler.

Note
If you want to read a config entry first, like the logging file name, you have to install the message handler in your init method.
#include <stdio.h>
#include <stdlib.h>
using namespace Cutelyst;
void logToFile(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
const QString formattedMessage = qFormatLogMessage(type, context, msg);
if (formattedMessage.isEmpty()) {
return;
}
static FILE *f = fopen("log.text", "a");
fprintf(f, "%s\n", qPrintable(formattedMessage));
fflush(f);
}
MyCutelystApp::MyCutelystApp(QObject *parent) : Application(parent)
{
qInstallMessageHandler(logToFile);
}
The Cutelyst namespace holds all public Cutelyst API.
bool isEmpty() const const

Log to syslog

If you want to explicitely log to syslog, you can install your own message handler to use syslog like provided by glibc.

Note
This might already be performed automatically by your Qt installation. So, there is normally no need to force it.
#include <syslog.h>
using namespace Cutelyst;
void logToSyslog(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
const QString formattedMessage = qFormatLogMessage(type, context, message);
if (formattedMessage.isEmpty()) {
return;
}
int prio = LOG_INFO;
switch (type) {
case QtDebugMsg:
prio = LOG_DEBUG;
break;
case QtInfoMsg:
prio = LOG_INFO;
break;
case QtWarningMsg:
prio = LOG_WARNING;
break;
case QtCriticalMsg:
prio = LOG_CRIT;
break;
case QtFatalMsg:
prio = LOG_ALERT;
break;
}
openlog(context.category, LOG_NDELAY, LOG_USER)
syslog(prio, "%s", formattedMessage.toUtf8().constData());
closelog();
}
MyCutelystApp::MyCutelystApp(QObject *parent) : Application(parent)
{
qInstallMessageHandler(logToSyslog);
}
const char * constData() const const
QByteArray toUtf8() const const

Log to journald

If you want to explicitely log to journald, you can install your own message handler that uses sd_journal_send.

Note
This might already be performed automatically by your Qt installation. So, there is normally no need to force it.
// We do not want to have the source code location automatically
// stored in the generated journal message metadata as we will
// call sd_journal_send from the same place every time. We will
// add our own data for that in debug mode.
#define SD_JOURNAL_SUPPRESS_LOCATION
#include <systemd/sd-journal-h>
#include <syslog.h> // for the priority definitions
void logToJournald(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
const QString formattedMessage = qFormatLogMessage(type, context, message);
if (formattedMessage.isEmpty()) {
return;
}
int prio = LOG_INFO;
switch (type) {
case QtDebugMsg:
prio = LOG_DEBUG;
break;
case QtInfoMsg:
prio = LOG_INFO;
break;
case QtWarningMsg:
prio = LOG_WARNING;
break;
case QtCriticalMsg:
prio = LOG_CRIT;
break;
case QtFatalMsg:
prio = LOG_ALERT;
break;
}
const char *category = context.category ? context.category : "unknown";
// add some extra information if we have a debug build
#ifdef QT_DEBUG
sd_journal_send("PRIORITY=%i", prio,
"SYSLOG_FACILITY=%hhu", LOG_USER,
"SYSLOG_IDENTIFIER=%s", category,
"SYSLOG_PID=%lli", QCoreApplication::applicationPid(),
"MESSAGE=%s", formattedMessage.toUtf8().constData(),
"QT_CATEGORY", category,
"CODE_FILE=%s", context.file ? context.file : "unknown",
"CODE_LINE=%i", context.line,
"CODE_FUNC=%s", context.function ? context.function : "unknown",
NULL);
#else
sd_journal_send("PRIORITY=%i", prio,
"SYSLOG_FACILITY=%hhu", LOG_USER,
"SYSLOG_IDENTIFIER=%s", category,
"SYSLOG_PID=%lli", QCoreApplication::applicationPid(),
"MESSAGE=%s", formattedMessage.toUtf8().constData(),
"QT_CATEGORY", category,
NULL);
#endif
}
MyCutelystApp::MyCutelystApp(QObject *parent) : Application(parent)
{
qInstallMessageHandler(logToJournald);
}
qint64 applicationPid()

Logging categories

Cutelyst already defines a number of logging categories that are used to log messages from different parts of Cutelyst. All Cutelyst logging categories start with cutelyst. See QLoggingCategory if you want to add your own categories in your application. The following table gives an overview about the logging categories used by the different Cutelyst components. You can als find information about the used categories in the class/component descriptions.

Category Components
cutelyst.core Application
Context
Headers
cutelyst.component Component
cutelyst.controller Controller
cutelyst.dispatcher Dispatcher
cutelyst.dispatcher.chained DispatchTypeChained
cutelyst.dispatcher.path DispatchTypePath
cutelyst.engine Engine
EngineRequest
cutelyst.multipart MultiPartFormDataParser
cutelyst.plugin.authentication Authentication
cutelyst.plugin.authentication.htpasswd StoreHtpasswd
cutelyst.plugin.authentication.realm AuthenticationRealm
cutelyst.plugin.credentialhttp CredentialHttp
cutelyst.plugin.credentialpassword CredentialPassword
cutelyst.plugin.csrfprotection CSRFProtection
cutelyst.plugin.langselect LangSelect
cutelyst.plugin.memcached Memcached
cutelyst.plugin.session Session
cutelyst.plugin.sessionfile SessionStoreFile
cutelyst.plugin.sessionmemcached MemcachedSessionStore
cutelyst.plugin.staticcompressed StaticCompressed
cutelyst.plugin.staticsimple StaticSimple
cutelyst.plugins.statusmessage StatusMessage
cutelyst.renderview RenderView
cutelyst.request Request
cutelyst.response Response
cutelyst.server
cutelyst.server.engine
cutelyst.server.fork
cutelyst.server.proto
cutelyst.serverfcgi
cutelyst.server.http
cutelyst.serverhttp2
cutelyst.server.websocket
cutelyst.server.socket
cutelyst.server.staticmap
cutelyst.server.systemd
cutelyst.server.tcp
cutelyst.servertcpbalancer
cutelyst.server.unix
cutelyst.server.windows
Server
cutelyst.upload Upload
cutelyst.useragent UserAgent
cutelyst.utils.pagination Pagination
cutelyst.utils.sql Sql
cutelyst.utils.validator Validator
cutelyst.view View
cutelyst.view.cutelee CuteleeView
cutelyst.view.email ViewEmail
cutelyst.view.emailtemplate ViewEmailTemplate

You can use QLoggingCategory to create your own logging categories for your application.

Configure categories

See QLoggingCategory to learn how to select categories and message types to log. The easiest way to directly set this for development is to set QT_LOGGING_RULES environment variable before executing cutelystd4-qt6. By default, Cutelyst only logs messages with a priortiy of QtWarningMsg or higher. When using the development helper cutelyst4-qt6 to start a development server, all messages of all types/priorities will be logged by appending "cutelyst.*=true" to QT_LOGGING_RULES.