Clarify desktop logging contracts and retain early log path
This commit is contained in:
1 parent
d22bae19b4
commit
b2addca5ce
5 files changed
+78
-12
No files matched your search
+2
-1
@@ -21,7 +21,8 @@ struct UASYNC;
|
||||
void video_ffmpeg_init(void);
|
||||
|
||||
/* Проба доступности codec: begin/end парные, вложенные, только для текущего потока.
|
||||
* Ожидаемые отказы FFmpeg выводятся на debug с подсчётом повторов; рабочие потоки не затрагиваются. */
|
||||
* Ожидаемые отказы FFmpeg и сводка повторов выводятся на trace категории video;
|
||||
* рабочие потоки сохраняют error/warn. begin/end должны выполняться в одном потоке. */
|
||||
void video_codec_probe_begin(void);
|
||||
void video_codec_probe_end(void);
|
||||
/* Возвращает debug вместо error/warn/info внутри пробы; level — DEBUG_LEVEL_* из debug_config.h. */
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
// Диагностика Qt через общий лог ядра: уровни/категории и debug_file применяются как к остальным сообщениям.
|
||||
/* Диагностика Qt через общий logger ядра, с его фильтрами уровней/категорий и текущим файлом вывода.
|
||||
* Qt debug/info/warning → debug/info/warn; critical/fatal → error. Категории с префиксом
|
||||
* qt.multimedia направляются в video, остальные — в general. Контекст file/line/function
|
||||
* сохраняется; QString синхронно преобразуется в UTF-8. Старый handler не вызывается.
|
||||
* Qt может вызывать обработчик из разных потоков; он использует общий debug_config.
|
||||
* Настройка logger-а и время жизни заимствованного пути его файла остаются у вызывающего. */
|
||||
#pragma once
|
||||
#include <QtGlobal>
|
||||
|
||||
// Вызывать до создания QApplication; возвращает прежний Qt handler (для восстановления в тестах).
|
||||
// Установить handler на весь процесс, желательно до QApplication. Вернуть прежний handler;
|
||||
// для восстановления передать возвращённый указатель в qInstallMessageHandler().
|
||||
QtMessageHandler installGuiLogHandler();
|
||||
@@ -346,7 +346,8 @@ int main(int argc, char *argv[]) {
|
||||
* конструкторе MainWindow ДО старта utun-потока, поэтому без этого его диагностика
|
||||
* (ma_engine_init и т.п.) в лог-файл не попадёт. */
|
||||
debug_enable_function_name(0);
|
||||
debug_enable_file_output(debugFile.toUtf8().constData(), 0);
|
||||
const QByteArray debugFilePath = debugFile.toUtf8(); // Logger заимствует путь до закрытия/замены файла.
|
||||
debug_enable_file_output(debugFilePath.constData(), 0);
|
||||
QString lvl = cfg.debugLevel().trimmed();
|
||||
if (lvl.isEmpty()) lvl = QStringLiteral("info");
|
||||
debug_apply_global_level(lvl.toUtf8().constData());
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
// Диагностика codec: scoped-проба понижает ожидаемые отказы до debug только в своём потоке.
|
||||
// Создать VideoCodecProbe на время проверки; CODEC_LOG сохраняет обычный уровень вне неё.
|
||||
/* Диагностика codec: VideoCodecProbe задаёт вложенную scoped-пробу в текущем потоке.
|
||||
* Создать/уничтожить в одном потоке; копирование и перенос запрещены. Конструктор возвращает
|
||||
* общий FFmpeg callback после возможной замены Qt Multimedia; деструктор завершает одну вложенность.
|
||||
* CODEC_LOG внутри пробы переводит error/warn/info в debug; debug/trace не меняются.
|
||||
* Подробности FFmpeg-пробы и сводка повторов идут на trace категории video, вне пробы — error/warn.
|
||||
* Глобальные уровни не меняются, ошибки рабочего codec в соседнем потоке сохраняют свой уровень. */
|
||||
#pragma once
|
||||
#include "../../../src/video/video.h"
|
||||
#include "debug_config.h"
|
||||
@@ -12,6 +16,8 @@ public:
|
||||
VideoCodecProbe& operator=(const VideoCodecProbe&) = delete;
|
||||
};
|
||||
|
||||
// level/category — DEBUG_LEVEL_*/DEBUG_CATEGORY_*, далее printf-формат и аргументы;
|
||||
// аргументы форматирования вычисляются только после фильтрации по итоговому уровню.
|
||||
#define CODEC_LOG(level, category, ...) do { \
|
||||
const auto codecLevel = static_cast<debug_level_t>(video_codec_log_level(level)); \
|
||||
if (debug_should_output(codecLevel, category)) \
|
||||
|
||||
@@ -13,11 +13,11 @@ extern "C" {
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct Message { int level; QString text; };
|
||||
struct Message { int level; QString text, category; };
|
||||
std::mutex lock;
|
||||
std::vector<Message> messages;
|
||||
void capture(int level, const char*, const char* text) {
|
||||
std::lock_guard<std::mutex> guard(lock); messages.push_back({level, QString::fromUtf8(text)});
|
||||
void capture(int level, const char* category, const char* text) {
|
||||
std::lock_guard<std::mutex> guard(lock); messages.push_back({level, QString::fromUtf8(text), QString::fromUtf8(category)});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ private slots:
|
||||
}
|
||||
void cleanup() { debug_set_log_hook(nullptr); }
|
||||
void probeLevelsRepeatsAndConcurrentErrors() {
|
||||
debug_set_category_level(DEBUG_CATEGORY_VIDEO, DEBUG_LEVEL_TRACE);
|
||||
{
|
||||
VideoCodecProbe probe;
|
||||
av_log(nullptr, AV_LOG_ERROR, "GPU unavailable\n");
|
||||
@@ -44,10 +45,10 @@ private slots:
|
||||
}
|
||||
av_log(nullptr, AV_LOG_ERROR, "runtime failure after probe\n");
|
||||
QCOMPARE(messages.size(), size_t(5));
|
||||
QCOMPARE(messages[0].level, int(DEBUG_LEVEL_DEBUG)); QVERIFY(messages[0].text.contains("GPU unavailable"));
|
||||
QCOMPARE(messages[0].level, int(DEBUG_LEVEL_TRACE)); QVERIFY(messages[0].text.contains("GPU unavailable"));
|
||||
QCOMPARE(messages[1].level, int(DEBUG_LEVEL_DEBUG)); QVERIFY(messages[1].text.contains("expected probe failure"));
|
||||
QCOMPARE(messages[2].level, int(DEBUG_LEVEL_ERROR)); QVERIFY(messages[2].text.contains("live decoder failure"));
|
||||
QCOMPARE(messages[3].level, int(DEBUG_LEVEL_DEBUG)); QVERIFY(messages[3].text.contains("repeated=2"));
|
||||
QCOMPARE(messages[3].level, int(DEBUG_LEVEL_TRACE)); QVERIFY(messages[3].text.contains("repeated=2"));
|
||||
QCOMPARE(messages[4].level, int(DEBUG_LEVEL_ERROR)); QVERIFY(messages[4].text.contains("runtime failure after probe"));
|
||||
}
|
||||
void infoLevelSkipsProbeDetails() {
|
||||
@@ -62,6 +63,17 @@ private slots:
|
||||
CODEC_LOG(DEBUG_LEVEL_WARN, DEBUG_CATEGORY_CALL, "actual playback warning");
|
||||
QCOMPARE(messages.size(), size_t(1)); QCOMPARE(messages[0].level, int(DEBUG_LEVEL_WARN));
|
||||
}
|
||||
void debugShowsCodecDecisionsAndTraceIsRequiredForFfmpegDetails() {
|
||||
{
|
||||
VideoCodecProbe probe;
|
||||
av_log(nullptr, AV_LOG_ERROR, "detailed FFmpeg probe error\n");
|
||||
av_log(nullptr, AV_LOG_ERROR, "detailed FFmpeg probe error\n");
|
||||
CODEC_LOG(DEBUG_LEVEL_WARN, DEBUG_CATEGORY_CALL, "codec decision during probe");
|
||||
}
|
||||
QCOMPARE(messages.size(), size_t(1)); QCOMPARE(messages[0].level, int(DEBUG_LEVEL_DEBUG));
|
||||
QVERIFY(messages[0].text.contains("codec decision during probe"));
|
||||
QCOMPARE(video_codec_log_level(DEBUG_LEVEL_ERROR), int(DEBUG_LEVEL_ERROR));
|
||||
}
|
||||
void restoresFfmpegCallback() {
|
||||
av_log_set_callback(av_log_default_callback);
|
||||
video_ffmpeg_init();
|
||||
@@ -70,7 +82,9 @@ private slots:
|
||||
}
|
||||
void qtAndFfmpegUseCommonFile() {
|
||||
QTemporaryDir directory; QVERIFY(directory.isValid());
|
||||
const auto path = directory.filePath("chatgui.log"); debug_enable_file_output(path.toUtf8().constData(), 0);
|
||||
const auto path = directory.filePath("chatgui.log");
|
||||
const QByteArray filePath = path.toUtf8(); debug_enable_file_output(filePath.constData(), 0);
|
||||
QCOMPARE(QByteArray(g_debug_config.output_file), filePath); QCOMPARE(debug_reopen_log(), 0);
|
||||
const auto previous = installGuiLogHandler();
|
||||
const QLoggingCategory category("qt.multimedia.test");
|
||||
qWarning("portal diagnostic");
|
||||
@@ -82,6 +96,44 @@ private slots:
|
||||
QVERIFY(text.contains("[WARN] [video]")); QVERIFY(text.contains("Qt[qt.multimedia.test]: codec diagnostic"));
|
||||
QVERIFY(text.contains("[ERROR] [video]")); QVERIFY(text.contains("ffmpeg: FFmpeg diagnostic"));
|
||||
}
|
||||
|
||||
void qtSeverityAndCategory_data() {
|
||||
QTest::addColumn<int>("type"); QTest::addColumn<int>("level"); QTest::addColumn<QByteArray>("category");
|
||||
QTest::newRow("debug") << int(QtDebugMsg) << int(DEBUG_LEVEL_DEBUG) << QByteArray("default");
|
||||
QTest::newRow("info") << int(QtInfoMsg) << int(DEBUG_LEVEL_INFO) << QByteArray("default");
|
||||
QTest::newRow("warning") << int(QtWarningMsg) << int(DEBUG_LEVEL_WARN) << QByteArray("default");
|
||||
QTest::newRow("critical") << int(QtCriticalMsg) << int(DEBUG_LEVEL_ERROR) << QByteArray("qt.network");
|
||||
QTest::newRow("fatal-handler") << int(QtFatalMsg) << int(DEBUG_LEVEL_ERROR) << QByteArray("default");
|
||||
QTest::newRow("multimedia") << int(QtWarningMsg) << int(DEBUG_LEVEL_WARN) << QByteArray("qt.multimedia");
|
||||
QTest::newRow("multimedia-child") << int(QtWarningMsg) << int(DEBUG_LEVEL_WARN) << QByteArray("qt.multimedia.test");
|
||||
}
|
||||
|
||||
void qtSeverityAndCategory() {
|
||||
QFETCH(int, type); QFETCH(int, level); QFETCH(QByteArray, category);
|
||||
const auto previous = installGuiLogHandler();
|
||||
const auto handler = qInstallMessageHandler(previous); // Получить callback, восстановив QtTest handler.
|
||||
QVERIFY(handler);
|
||||
const QMessageLogContext context("gui-source.cpp", 42, "guiFunction", category.constData());
|
||||
// Вызываем сам callback: QtFatalMsg здесь не запускает внешнее завершение qFatal.
|
||||
handler(static_cast<QtMsgType>(type), context, QString::fromUtf8("Проверка UTF-8"));
|
||||
QCOMPARE(messages.size(), size_t(1)); QCOMPARE(messages[0].level, level);
|
||||
QCOMPARE(messages[0].category, category.startsWith("qt.multimedia") ? QStringLiteral("video") : QStringLiteral("general"));
|
||||
QVERIFY(messages[0].text.contains("gui-source.cpp:42")); QVERIFY(messages[0].text.contains("guiFunction"));
|
||||
QVERIFY(messages[0].text.contains(QString::fromUtf8("Проверка UTF-8")));
|
||||
}
|
||||
|
||||
void qtHonorsCategoryOverrides() {
|
||||
const auto previous = installGuiLogHandler();
|
||||
const auto handler = qInstallMessageHandler(previous); QVERIFY(handler);
|
||||
debug_set_level(DEBUG_LEVEL_ERROR);
|
||||
debug_set_category_level(DEBUG_CATEGORY_VIDEO, DEBUG_LEVEL_DEBUG);
|
||||
debug_set_category_level(DEBUG_CATEGORY_GENERAL, DEBUG_LEVEL_DISABLED);
|
||||
handler(QtWarningMsg, QMessageLogContext(), QStringLiteral("filtered general warning"));
|
||||
QVERIFY(messages.empty());
|
||||
handler(QtDebugMsg, QMessageLogContext(nullptr, 0, nullptr, "qt.multimedia"), QStringLiteral("video override"));
|
||||
QCOMPARE(messages.size(), size_t(1)); QCOMPARE(messages[0].category, QStringLiteral("video"));
|
||||
QCOMPARE(messages[0].level, int(DEBUG_LEVEL_DEBUG));
|
||||
}
|
||||
};
|
||||
QTEST_GUILESS_MAIN(DiagnosticsTest)
|
||||
#include "test_video_diagnostics.moc"
|
||||
Reference in new issue
Block a user