How to Integrate spdlog with Qt Applications Using the qt_sink

Use spdlog::qt_logger_mt or spdlog::qt_logger_st to forward log messages to any Qt widget that exposes a slot accepting QString, leveraging Qt's meta-object system for thread-safe UI updates.

The gabime/spdlog library provides dedicated Qt sinks that bridge high-performance C++ logging with Qt's GUI framework. To integrate spdlog with Qt applications, you use the qt_sink or qt_color_sink classes defined in include/spdlog/sinks/qt_sinks.h. These sinks marshal log entries across thread boundaries using Qt's QMetaObject::invokeMethod, ensuring your UI updates safely even when logging occurs from background worker threads.

Understanding the Qt-Specific Sinks

The spdlog Qt integration centers on two sink types that derive from spdlog::sinks::base_sink<Mutex>, inheriting the same thread-safety policies as standard spdlog sinks.

qt_sink for Plain Text Output

The qt_sink forwards formatted log messages as plain text to any QObject that implements a compatible Qt slot. You typically target QPlainTextEdit or QTextEdit widgets using their append(const QString&) slot. Because the sink stores a raw pointer to the Qt object, it performs a null check in the constructor and throws spdlog_ex if the widget pointer is invalid.

qt_color_sink for Styled Output

The qt_color_sink extends this functionality to support per-log-level color customization in QTextEdit widgets. It maintains an internal mapping of spdlog::level to QTextCharFormat, allowing you to set foreground colors, background colors, and font styles via the set_color() method.

Implementing spdlog Qt Integration Step by Step

Include the Header

Add the Qt sinks header to your source file. This header declares both sink classes and the convenience factory functions.

#include <spdlog/sinks/qt_sinks.h>

Create the Logger

Instantiate a logger using one of the factory functions that match your thread-safety requirements:

  • spdlog::qt_logger_mt(name, qt_object, meta_method) – Creates a multi-threaded logger safe for concurrent access.
  • spdlog::qt_logger_st(name, qt_object, meta_method) – Creates a single-threaded logger for use in one thread only.

The meta_method parameter must be the fully-qualified Qt slot signature, such as "append(const QString&)".

QPlainTextEdit *logView = new QPlainTextEdit(parent);
auto logger = spdlog::qt_logger_mt("qt_ui_logger", logView, "append(const QString&)");
logger->info("Application started successfully");

Configure Color Formatting (Optional)

For colored output, instantiate qt_color_logger_mt instead, then customize the appearance:

QTextEdit *colorLogView = new QTextEdit(parent);
auto color_logger = spdlog::qt_color_logger_mt("color_logger", colorLogView, 1000);

// Customize warning level to appear in dark yellow
QTextCharFormat warnFmt;
warnFmt.setForeground(Qt::darkYellow);
color_logger->set_color(spdlog::level::warn, warnFmt);

Thread Safety and Lifetime Management

Under the hood, both sinks use Qt::AutoConnection when calling QMetaObject::invokeMethod. This automatically queues the log message onto the widget's owning thread if the logger runs in a different context, preventing race conditions during GUI updates.

Because the sink holds a raw pointer (QObject*) and does not manage the widget's lifetime, you must ensure the logger is destroyed or reset before the target widget is deleted. Failure to do so results in dangling pointer dereferences. Tie the logger's scope to the widget's parent or explicitly call spdlog::drop() in your widget destructor.

Complete Code Examples

The following examples demonstrate practical implementation patterns found in the example/qt_example.cpp file of the spdlog repository.

Plain Text Logger with QPlainTextEdit:

#include <QPlainTextEdit>
#include <spdlog/sinks/qt_sinks.h>

// ... inside your MainWindow or Widget constructor
QPlainTextEdit *logView = new QPlainTextEdit(this);
auto logger = spdlog::qt_logger_mt("qt_logger", logView, "append(const QString&)");
logger->set_level(spdlog::level::debug);
logger->info("spdlog integrated with Qt!");

Colored Logger with QTextEdit:

#include <QTextEdit>
#include <spdlog/sinks/qt_sinks.h>

QTextEdit *colorLogView = new QTextEdit(this);
auto color_logger = spdlog::qt_color_logger_mt("qt_color_logger", colorLogView, 1000);
color_logger->set_level(spdlog::level::trace);

// Custom formatting for warnings
QTextCharFormat warnFmt;
warnFmt.setForeground(Qt::darkYellow);
color_logger->set_color(spdlog::level::warn, warnFmt);

color_logger->warn("This warning appears in yellow!");

Summary

  • Include include/spdlog/sinks/qt_sinks.h to access Qt-specific logging functionality.
  • Choose between qt_sink for plain text or qt_color_sink for per-level color customization.
  • Instantiate using spdlog::qt_logger_mt() or spdlog::qt_logger_st() with the target widget and slot signature.
  • Manage lifetimes carefully: destroy the logger before destroying the target QWidget to avoid dangling pointers.
  • Rely on Qt's meta-object system via QMetaObject::invokeMethod with Qt::AutoConnection for automatic thread marshalling.

Frequently Asked Questions

What Qt widgets can receive spdlog messages?

Any QObject that exposes a slot accepting const QString& can receive messages, but QPlainTextEdit and QTextEdit are the most common targets using their native append(const QString&) slots.

Is spdlog's qt_sink thread-safe?

Yes. The *_mt variants use mutex-protected base sinks, and internally the sink calls QMetaObject::invokeMethod with Qt::AutoConnection, which safely marshals calls to the GUI thread if logging occurs from a background thread.

How do I prevent crashes when closing my Qt application?

Reset or drop the spdlog logger in your widget destructor before deleting the Qt widget. The sink validates the QObject* pointer at construction but does not track widget destruction; logging to a destroyed widget causes undefined behavior.

Can I use custom colors for different log levels with qt_sink?

Only qt_color_sink supports color customization via set_color(spdlog::level, QTextCharFormat). The standard qt_sink forwards plain text without formatting. Use spdlog::qt_color_logger_mt() to instantiate the colored variant.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →