cutelyst 5.0.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 cutelystd5-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 application.
Definition application.h:66
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.

CategoryComponents
cutelyst.coreApplication
Context
Headers
cutelyst.componentComponent
cutelyst.controllerController
cutelyst.dispatcherDispatcher
cutelyst.dispatcher.chainedDispatchTypeChained
cutelyst.dispatcher.pathDispatchTypePath
cutelyst.engineEngine
EngineRequest
cutelyst.multipartMultiPartFormDataParser
cutelyst.plugin.authenticationAuthentication
cutelyst.plugin.authentication.htpasswdStoreHtpasswd
cutelyst.plugin.authentication.realmAuthenticationRealm
cutelyst.plugin.credentialhttpCredentialHttp
cutelyst.plugin.credentialpasswordCredentialPassword
cutelyst.plugin.csrfprotectionCSRFProtection
cutelyst.plugin.langselectLangSelect
cutelyst.plugin.memcachedMemcached
cutelyst.plugin.sessionSession
cutelyst.plugin.sessionfileSessionStoreFile
cutelyst.plugin.sessionmemcachedMemcachedSessionStore
cutelyst.plugin.staticcompressedStaticCompressed
cutelyst.plugin.staticsimpleStaticSimple
cutelyst.plugins.statusmessageStatusMessage
cutelyst.renderviewRenderView
cutelyst.requestRequest
cutelyst.responseResponse
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.uploadUpload
cutelyst.useragentUserAgent
cutelyst.utils.paginationPagination
cutelyst.utils.sqlSql
cutelyst.utils.validatorValidator
cutelyst.viewView
cutelyst.view.cuteleeCuteleeView
cutelyst.view.emailViewEmail
cutelyst.view.emailtemplateViewEmailTemplate

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 cutelystd5-qt6. By default, Cutelyst only logs messages with a priortiy of QtWarningMsg or higher. When using the development helper cutelyst5-qt6 to start a development server, all messages of all types/priorities will be logged by appending "cutelyst.*=true" to QT_LOGGING_RULES.