QtLogger Docs > API Reference > Formatters
Formatters convert LogMessage objects into formatted strings for output. This section documents all available formatter classes and the pattern placeholder syntax.
The abstract base class for all formatters.
Handler
└── Formatter
Formatter provides the interface for converting log messages to strings. All formatter implementations must override the format() method.
| Method | Return Type | Description |
|---|---|---|
format(const LogMessage &lmsg) |
QString |
Pure virtual. Convert message to string |
| Method | Return Type | Description |
|---|---|---|
type() |
HandlerType |
Returns HandlerType::Formatter |
process(LogMessage &lmsg) |
bool |
Calls format() and sets lmsg.formattedMessage() |
#include "qtlogger.h"
class XmlFormatter : public QtLogger::Formatter
{
public:
QString format(const QtLogger::LogMessage &lmsg) override
{
return QString("<log level=\"%1\" time=\"%2\"><![CDATA[%3]]></log>\n")
.arg(QtLogger::qtMsgTypeToString(lmsg.type()))
.arg(lmsg.time().toString(Qt::ISODate))
.arg(lmsg.message());
}
};
A highly configurable formatter using placeholder patterns.
Handler
└── Formatter
└── PatternFormatter
explicit PatternFormatter(const QString &pattern);
| Parameter | Type | Description |
|---|---|---|
pattern |
QString |
Format pattern with placeholders |
SimplePipeline &format(const QString &pattern);
#include "qtlogger.h"
gQtLogger
.format("%{time yyyy-MM-dd hh:mm:ss.zzz} [%{type:>8}] [%{category}] %{message}")
.sendToStdErr();
gQtLogger.installMessageHandler();
| Placeholder | Description | Example Output |
|---|---|---|
%{message} |
Log message text | Application started |
%{type} |
Message type name | debug, info, warning, critical, fatal |
%{category} |
Logging category name | default, network, app.ui |
%{file} |
Full source file path | /home/user/project/src/main.cpp |
%{shortfile} |
File name only (no path) | main.cpp |
%{shortfile /base/path} |
File relative to base path | src/main.cpp |
%{line} |
Source line number | 42 |
%{function} |
Full function signature | void MyClass::myMethod(int, QString) |
%{func} |
Cleaned function name | MyClass::myMethod |
%{threadid} |
Thread ID | 140234567890 |
%{qthreadptr} |
QThread pointer (hex) | 0x7f8a1c002340 |
| Placeholder | Description | Example Output |
|---|---|---|
%{time} |
ISO 8601 format | 2024-01-15T14:30:45.123 |
%{time FORMAT} |
Custom Qt date/time format | See below |
%{time process} |
Seconds since process start | 12.345 |
%{time boot} |
Seconds since system boot | 86412.789 |
Use Qt’s date/time format specifiers:
| Specifier | Description | Example |
|---|---|---|
yyyy |
4-digit year | 2024 |
MM |
2-digit month | 01 |
dd |
2-digit day | 15 |
hh |
2-digit hour (24h) | 14 |
mm |
2-digit minute | 30 |
ss |
2-digit second | 45 |
zzz |
3-digit millisecond | 123 |
Examples:
%{time yyyy-MM-dd hh:mm:ss} → 2024-01-15 14:30:45
%{time hh:mm:ss.zzz} → 14:30:45.123
%{time dd.MM.yyyy} → 15.01.2024
%{time yyyy-MM-ddThh:mm:ss.zzz} → 2024-01-15T14:30:45.123
Access custom attributes added by attribute handlers:
| Placeholder | Description |
|---|---|
%{attr_name} |
Attribute value (error if missing) |
%{attr_name?} |
Optional attribute (empty if missing) |
%{attr_name?N} |
Optional, remove N chars before if missing |
%{attr_name?N,M} |
Optional, remove N chars before and M chars after if missing |
The ?N,M syntax is useful for removing surrounding punctuation when an attribute is not present:
Pattern: "#%{seq_number?1} %{message}"
With seq_number=42: "#42 Hello"
Without seq_number: " Hello" (# removed because of ?1)
Pattern: "[%{user?1,1}] %{message}"
With user="admin": "[admin] Hello"
Without user: " Hello" ([ and ] removed)
Examples:
gQtLogger
.addSeqNumber()
.addAppInfo()
.format("#%{seq_number:0>6} [%{appname}] %{message}")
.sendToStdErr();
// Output: #000001 [MyApp] Application started
Any placeholder can have a format specification after a colon for alignment and padding.
%{placeholder:[fill][align][width][!]}
| Component | Description |
|---|---|
fill |
Single character for padding (default: space) |
align |
Alignment direction: < left, > right, ^ center |
width |
Minimum field width |
! |
Enable truncation (max width) |
| Char | Alignment | Truncation Behavior |
|---|---|---|
< |
Left | Keep first N characters |
> |
Right | Keep last N characters |
^ |
Center | Keep first N characters |
!)When ! is not present, values shorter than width are padded, but longer values are NOT truncated.
| Pattern | Input | Output |
|---|---|---|
%{type:<10} |
debug |
debug |
%{type:>10} |
debug |
` debug` |
%{type:^10} |
debug |
` debug ` |
%{type:*<10} |
debug |
debug***** |
%{type:0>8} |
42 |
00000042 |
%{type:<5} |
warning |
warning (not truncated) |
! Without Fill)When ! is present without a fill character, long values are truncated but short values are NOT padded.
| Pattern | Input | Output |
|---|---|---|
%{type:10!} |
critical |
critical |
%{type:5!} |
critical |
criti |
%{type:<5!} |
critical |
criti (first 5 chars) |
%{type:>5!} |
critical |
tical (last 5 chars) |
! With Fill)When both fill and ! are present, values are truncated AND padded to exactly the specified width.
| Pattern | Input | Output |
|---|---|---|
%{type: <8!} |
debug |
debug |
%{type: <8!} |
critical |
critical (truncated to 8) |
%{type:*>10!} |
info |
******info |
%{type:*>10!} |
verylongtype |
verylongty |
// Fixed-width log level column
gQtLogger
.format("%{time hh:mm:ss} %{type:>8} | %{message}")
.sendToStdErr();
// Output:
// 14:30:45 debug | Debug message
// 14:30:46 info | Info message
// 14:30:47 warning | Warning message
// 14:30:48 critical | Critical message
// Zero-padded sequence numbers
gQtLogger
.addSeqNumber()
.format("#%{seq_number:0>6} %{message}")
.sendToStdErr();
// Output:
// #000001 First message
// #000002 Second message
// #000123 Message 123
// Truncated category with fixed width
gQtLogger
.format("[%{category:<10!}] %{message}")
.sendToStdErr();
// Output:
// [default ] Message
// [network ] Message
// [app.ui.dia] Message (truncated from app.ui.dialogs)
Include content only for specific message types.
| Block | Shows for |
|---|---|
%{if-debug}...%{endif} |
Debug messages only |
%{if-info}...%{endif} |
Info messages only |
%{if-warning}...%{endif} |
Warning messages only |
%{if-critical}...%{endif} |
Critical messages only |
%{if-fatal}...%{endif} |
Fatal messages only |
gQtLogger
.format("%{time hh:mm:ss} "
"%{if-debug}D%{endif}"
"%{if-info}I%{endif}"
"%{if-warning}W%{endif}"
"%{if-critical}E%{endif}"
"%{if-fatal}F%{endif}"
" [%{category}] %{message}")
.sendToStdErr();
// Output:
// 14:30:45 D [default] Debug message
// 14:30:46 I [default] Info message
// 14:30:47 W [network] Warning message
// 14:30:48 E [network] Error message
The content between %{if-*} and %{endif} can include any text and other placeholders:
gQtLogger
.format("%{time} %{type}: %{message}"
"%{if-warning} (check this)%{endif}"
"%{if-critical} [FILE: %{shortfile}:%{line}]%{endif}")
.sendToStdErr();
| Sequence | Output |
|---|---|
%% |
Literal % |
Outputs log messages as JSON objects.
Handler
└── Formatter
└── JsonFormatter
explicit JsonFormatter(bool compact = false);
| Parameter | Type | Default | Description |
|---|---|---|---|
compact |
bool |
false |
If true, output single-line JSON |
| Method | Return Type | Description |
|---|---|---|
instance() |
JsonFormatterPtr |
Get singleton instance (non-compact) |
SimplePipeline &formatToJson(bool compact = false);
The JSON output includes all attributes from LogMessage::allAttributes():
{
"type": "warning",
"time": "2024-01-15T14:30:45.123",
"category": "network",
"file": "/path/to/file.cpp",
"line": 42,
"function": "void MyClass::myMethod()",
"message": "Connection timeout",
"threadId": 140234567890,
"seq_number": 1,
"appname": "MyApp"
}
Compact format outputs the same data on a single line.
#include "qtlogger.h"
// Compact JSON for log aggregation
gQtLogger
.addSeqNumber()
.addAppInfo()
.addHostInfo()
.formatToJson(true)
.sendToHttp("https://logs.example.com/ingest");
gQtLogger.installMessageHandler();
// Pretty JSON to file
gQtLogger
.formatToJson(false)
.sendToFile("structured.log");
A human-readable formatter with optional ANSI colors.
Handler
└── Formatter
└── PrettyFormatter
explicit PrettyFormatter(bool colorize = false, int maxCategoryWidth = 15);
| Parameter | Type | Default | Description |
|---|---|---|---|
colorize |
bool |
false |
Enable ANSI color codes |
maxCategoryWidth |
int |
15 |
Maximum width for category column |
| Method | Return Type | Description |
|---|---|---|
instance() |
PrettyFormatterPtr |
Get singleton instance (non-colorized) |
SimplePipeline &formatPretty(bool colorize = false, int maxCategoryWidth = 15);
DD.MM.YYYY hh:mm:ss.zzz T [category ] message
Where T is a single-letter type indicator:
I for infoW for warningE for critical/errorF for fatal| Component | Color |
|---|---|
| Timestamp | Dark gray |
| Debug messages | Dark gray |
| Info indicator | Green |
| Warning indicator | Orange |
| Error indicator | Bold red |
| Fatal indicator | Dark bold red |
| Category | Normal |
| Message | Normal |
PrettyFormatter assigns short numeric indices to threads for easier identification in multi-threaded output:
15.01.2024 14:30:45.123 I 1 [network ] Connected
15.01.2024 14:30:45.124 I 2 [database ] Query started
15.01.2024 14:30:45.125 W 1 [network ] Slow response
#include "qtlogger.h"
// Development console output
gQtLogger
.formatPretty(true, 20) // Colorized, 20-char category width
.sendToStdErr();
gQtLogger.installMessageHandler();
Uses Qt’s built-in message formatting via qFormatLogMessage().
Handler
└── Formatter
└── QtLogMessageFormatter
Private. Use instance() to get the singleton.
| Method | Return Type | Description |
|---|---|---|
instance() |
QtLogMessageFormatterPtr |
Get singleton instance |
SimplePipeline &formatByQt();
This formatter uses Qt’s qFormatLogMessage() function, which respects:
QT_MESSAGE_PATTERN environment variableqSetMessagePattern() callsQtLogger::setMessagePattern() calls#include "qtlogger.h"
// Use Qt's default formatting
QtLogger::setMessagePattern("[%{type}] %{message}");
gQtLogger
.formatByQt()
.sendToStdErr();
gQtLogger.installMessageHandler();
A formatter that uses a custom function for formatting.
Handler
└── Formatter
└── FunctionFormatter
using Function = std::function<QString(const LogMessage &)>;
FunctionFormatter(const Function &func);
| Parameter | Type | Description |
|---|---|---|
func |
Function |
Formatting function |
SimplePipeline &format(std::function<QString(const LogMessage &)> func);
#include "qtlogger.h"
// Custom formatting with lambda
gQtLogger
.format([](const QtLogger::LogMessage &lmsg) {
return QString("[%1] %2: %3\n")
.arg(lmsg.time().toString("hh:mm:ss"))
.arg(lmsg.category())
.arg(lmsg.message());
})
.sendToStdErr();
gQtLogger.installMessageHandler();
// Post-processing another formatter's output
gQtLogger
.formatPretty(true)
.format([](const QtLogger::LogMessage &lmsg) {
// Mask sensitive data in already-formatted message
QString msg = lmsg.formattedMessage();
static QRegularExpression re("password=\\S+");
msg.replace(re, "password=***");
return msg;
})
.sendToStdErr();
| Category | Placeholders |
|---|---|
| Message | %{message} |
| Type | %{type} |
| Location | %{file}, %{shortfile}, %{line}, %{function}, %{func} |
| Category | %{category} |
| Time | %{time}, %{time FORMAT}, %{time process}, %{time boot} |
| Thread | %{threadid}, %{qthreadptr} |
| Attributes | %{name}, %{name?}, %{name?N}, %{name?N,M} |
| Conditional | %{if-debug}, %{if-info}, %{if-warning}, %{if-critical}, %{if-fatal}, %{endif} |
| Formatting | :[fill][align][width][!] |
| Escape | %% |
Simple timestamp and message:
%{time hh:mm:ss} %{message}
Full debug information:
%{time yyyy-MM-dd hh:mm:ss.zzz} [%{type:>8}] [%{category}] %{shortfile}:%{line} %{func}: %{message}
Compact for production:
%{time} [%{type}] %{message}
With sequence number:
#%{seq_number:0>6} %{time hh:mm:ss.zzz} %{type}: %{message}
JSON-like (but not actual JSON):
{"time":"%{time}","level":"%{type}","msg":"%{message}"}
A formatter that outputs log messages in Sentry event format for error tracking.
Handler
└── Formatter
└── SentryFormatter
explicit SentryFormatter(const QString &sdkName = "qtlogger.sentry",
const QString &sdkVersion = "1.0.0");
| Parameter | Type | Default | Description |
|---|---|---|---|
sdkName |
QString |
"qtlogger.sentry" |
SDK name reported to Sentry |
sdkVersion |
QString |
"1.0.0" |
SDK version reported to Sentry |
| Method | Return Type | Description |
|---|---|---|
instance() |
SentryFormatterPtr |
Get singleton instance with default settings |
SimplePipeline &formatToSentry(const QString &sdkName = "qtlogger.sentry",
const QString &sdkVersion = "1.0.0");
The formatter produces JSON compatible with Sentry’s Store API:
{
"event_id": "550e8400e29b41d4a716446655440000",
"timestamp": "2024-01-15T14:30:45Z",
"platform": "native",
"level": "warning",
"logger": "network",
"message": {
"formatted": "Connection timeout"
},
"culprit": "void NetworkManager::connect()",
"tags": {
"qt_version": "6.6.1",
"app_name": "MyApp",
"app_version": "1.0.0"
},
"extra": {
"line": 42,
"file": "networkmanager.cpp",
"thread_id": "140234567890"
},
"contexts": {
"os": {
"name": "linux",
"version": "22.04",
"kernel_version": "5.15.0",
"build": "x86_64-linux-gnu"
},
"device": {
"arch": "x86_64",
"name": "hostname"
},
"runtime": {
"name": "Qt",
"version": "6.6.1"
}
},
"sdk": {
"name": "qtlogger.sentry",
"version": "1.0.0"
},
"fingerprint": ["warning", "network", "Connection timeout"]
}
| Qt Message Type | Sentry Level |
|---|---|
QtDebugMsg |
debug |
QtInfoMsg |
info |
QtWarningMsg |
warning |
QtCriticalMsg |
error |
QtFatalMsg |
fatal |
For full context information, use these attribute handlers before the formatter:
| Handler | Provides |
|---|---|
addAppInfo() |
appname, appversion → tags |
addSysInfo() |
os_name, os_version, kernel_version, build_abi, cpu_arch → contexts.os, contexts.device |
addHostInfo() |
host_name → contexts.device.name |
#include "qtlogger.h"
gQtLogger
.moveToOwnThread() // Async for non-blocking HTTP
.pipeline()
.addAppInfo()
.addSysInfo()
.addHostInfo()
.filterLevel(QtWarningMsg)
.filterDuplicate()
.formatToSentry()
.sendToHttp(QtLogger::sentryUrl(), QtLogger::sentryHeaders())
.end();
gQtLogger.installMessageHandler();
QtLogger provides utility functions for Sentry integration in <qtlogger/sentry.h>.
QString sentryUrl(const QString &sentryDsn);
Parses a Sentry DSN and returns the Store API URL.
| Parameter | Type | Description |
|---|---|---|
sentryDsn |
QString |
Full Sentry DSN (e.g., https://key@o123.ingest.sentry.io/456) |
Returns: Store API URL for HTTP sink
QString sentryUrl(const QString &sentryHost,
const QString &sentryProjectId,
const QString &sentryPublicKey);
Builds the Store API URL from individual components.
| Parameter | Type | Description |
|---|---|---|
sentryHost |
QString |
Sentry host (e.g., o123456.ingest.sentry.io) |
sentryProjectId |
QString |
Project ID |
sentryPublicKey |
QString |
Public key |
Returns: Store API URL for HTTP sink
QString sentryUrl();
Reads Sentry configuration from environment variables and returns the Store API URL.
Environment Variables:
SENTRY_DSN — Full DSN (preferred)SENTRY_HOST, SENTRY_PROJECT_ID, SENTRY_PUBLIC_KEYReturns: Store API URL for HTTP sink
bool checkSentryEnv();
Checks if required Sentry environment variables are set.
Returns: true if SENTRY_DSN is set, or if all three individual variables are set
QList<QPair<QByteArray, QByteArray>> sentryHeaders();
Returns HTTP headers required for Sentry API.
Returns: List containing Content-Type: application/json; charset=utf-8
#include "qtlogger.h"
#include "qtlogger/sentry.h"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
app.setApplicationName("MyApp");
app.setApplicationVersion("1.0.0");
// Validate environment
if (!QtLogger::checkSentryEnv()) {
qWarning() << "Set SENTRY_DSN or SENTRY_HOST + SENTRY_PROJECT_ID + SENTRY_PUBLIC_KEY";
return 1;
}
gQtLogger
.moveToOwnThread()
// Console output
.pipeline()
.formatPretty(true)
.sendToStdErr()
.end()
// Sentry integration
.pipeline()
.addAppInfo()
.addSysInfo()
.addHostInfo()
.filterLevel(QtWarningMsg)
.filterDuplicate()
.formatToSentry()
.sendToHttp(QtLogger::sentryUrl(), QtLogger::sentryHeaders())
.end();
gQtLogger.installMessageHandler();
qWarning() << "This goes to Sentry";
qCritical() << "This too";
return app.exec();
}
// From DSN string
auto url = QtLogger::sentryUrl("https://abc123@o456.ingest.sentry.io/789");
// From components
auto url = QtLogger::sentryUrl("o456.ingest.sentry.io", "789", "abc123");
| Previous | Next |
|---|---|
| ← Sinks | Filters → |