util/LogConfigurator.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "util/LogConfigurator.h" | ||
| 2 | |||
| 3 | #include <QCommandLineOption> | ||
| 4 | #include <QCommandLineParser> | ||
| 5 | #include <QLoggingCategory> | ||
| 6 | #include <QString> | ||
| 7 | #include <QStringView> | ||
| 8 | |||
| 9 | namespace { | ||
| 10 | // Environment variable names — kept private, accessed only via apply(). | ||
| 11 | constexpr const char *kEnvLogLevel = "MAILJD_LOG_LEVEL"; | ||
| 12 | constexpr const char *kEnvLogRules = "MAILJD_LOG_RULES"; | ||
| 13 | |||
| 14 | // CLI option names — exposed via QCommandLineParser only. | ||
| 15 | constexpr const char *kOptLogLevel = "log-level"; | ||
| 16 | constexpr const char *kOptLogRules = "log-rules"; | ||
| 17 | constexpr const char *kOptVerbose = "verbose"; | ||
| 18 | // NOTE: --verbose is intentionally long-only. main.cpp calls | ||
| 19 | // QCommandLineParser::addVersionOption(), which claims the short name | ||
| 20 | // "-v" (for --version). Registering verbose as ["v","verbose"] made Qt | ||
| 21 | // reject the whole option with "already having an option named 'v'", | ||
| 22 | // which silently broke --verbose entirely. "-v" stays reserved for | ||
| 23 | // --version (the standard Qt/CLI convention). | ||
| 24 | } // namespace | ||
| 25 | |||
| 26 | 13 | void LogConfigurator::registerOptions(QCommandLineParser &parser) { | |
| 27 | QCommandLineOption levelOption( | ||
| 28 |
1/1✓ Branch 14 → 15 taken 13 times.
|
26 | QString::fromLatin1(kOptLogLevel), |
| 29 | 26 | QStringLiteral("Log verbosity: off|error|warning|info|debug " | |
| 30 | "(default: error). Env: %1.") | ||
| 31 |
2/2✓ Branch 11 → 12 taken 13 times.
✓ Branch 12 → 13 taken 13 times.
|
26 | .arg(QString::fromLatin1(kEnvLogLevel)), |
| 32 |
1/1✓ Branch 15 → 16 taken 13 times.
|
52 | QStringLiteral("level")); |
| 33 | QCommandLineOption rulesOption( | ||
| 34 |
1/1✓ Branch 36 → 37 taken 13 times.
|
26 | QString::fromLatin1(kOptLogRules), |
| 35 | 26 | QStringLiteral("Raw Qt filter rules (overrides --log-level). " | |
| 36 | "Env: %1.") | ||
| 37 |
2/2✓ Branch 33 → 34 taken 13 times.
✓ Branch 34 → 35 taken 13 times.
|
26 | .arg(QString::fromLatin1(kEnvLogRules)), |
| 38 |
1/1✓ Branch 37 → 38 taken 13 times.
|
52 | QStringLiteral("rules")); |
| 39 | QCommandLineOption verboseOption( | ||
| 40 |
1/1✓ Branch 52 → 53 taken 13 times.
|
26 | QString::fromLatin1(kOptVerbose), |
| 41 |
1/1✓ Branch 53 → 54 taken 13 times.
|
52 | QStringLiteral("Shortcut for --log-level=info")); |
| 42 |
1/1✓ Branch 59 → 60 taken 13 times.
|
13 | parser.addOption(levelOption); |
| 43 |
1/1✓ Branch 60 → 61 taken 13 times.
|
13 | parser.addOption(rulesOption); |
| 44 |
1/1✓ Branch 61 → 62 taken 13 times.
|
13 | parser.addOption(verboseOption); |
| 45 | 13 | } | |
| 46 | |||
| 47 | 11 | QString LogConfigurator::apply(const QCommandLineParser &parser) { | |
| 48 | // S106-220: the documented order, first one set wins — --log-rules, | ||
| 49 | // --log-level / --verbose, MAILJD_LOG_RULES, MAILJD_LOG_LEVEL, Error. The | ||
| 50 | // environment used to beat an explicit command-line level. | ||
| 51 |
2/2✓ Branch 3 → 4 taken 11 times.
✓ Branch 4 → 5 taken 11 times.
|
11 | const bool cliRules = parser.isSet(QString::fromLatin1(kOptLogRules)); |
| 52 |
11/16✓ Branch 7 → 8 taken 11 times.
✓ Branch 8 → 9 taken 11 times.
✓ Branch 9 → 10 taken 7 times.
✓ Branch 9 → 14 taken 4 times.
✓ Branch 11 → 12 taken 7 times.
✓ Branch 12 → 13 taken 7 times.
✓ Branch 13 → 14 taken 2 times.
✓ Branch 13 → 15 taken 5 times.
✓ Branch 16 → 17 taken 7 times.
✓ Branch 16 → 18 taken 4 times.
✓ Branch 18 → 19 taken 11 times.
✗ Branch 18 → 20 not taken.
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 82 not taken.
✗ Branch 85 → 86 not taken.
✗ Branch 85 → 87 not taken.
|
11 | const bool cliLevel = parser.isSet(QString::fromLatin1(kOptLogLevel)) || parser.isSet(QString::fromLatin1(kOptVerbose)); |
| 53 | 11 | QString customRules; | |
| 54 | 11 | Level level = Error; | |
| 55 |
2/2✓ Branch 20 → 21 taken 1 time.
✓ Branch 20 → 28 taken 10 times.
|
11 | if (cliRules) { |
| 56 |
2/2✓ Branch 22 → 23 taken 1 time.
✓ Branch 23 → 24 taken 1 time.
|
1 | customRules = parser.value(QString::fromLatin1(kOptLogRules)); |
| 57 |
2/2✓ Branch 28 → 29 taken 5 times.
✓ Branch 28 → 45 taken 5 times.
|
10 | } else if (cliLevel) { |
| 58 |
2/2✓ Branch 30 → 31 taken 5 times.
✓ Branch 31 → 32 taken 5 times.
|
10 | level = parser.isSet(QString::fromLatin1(kOptLogLevel)) |
| 59 |
9/13✓ Branch 32 → 33 taken 3 times.
✓ Branch 32 → 38 taken 2 times.
✓ Branch 34 → 35 taken 3 times.
✓ Branch 35 → 36 taken 3 times.
✓ Branch 36 → 37 taken 3 times.
✓ Branch 39 → 40 taken 3 times.
✓ Branch 39 → 41 taken 2 times.
✓ Branch 41 → 42 taken 3 times.
✓ Branch 41 → 43 taken 2 times.
✗ Branch 95 → 96 not taken.
✗ Branch 95 → 97 not taken.
✗ Branch 99 → 100 not taken.
✗ Branch 99 → 101 not taken.
|
5 | ? parseLevelName(parser.value(QString::fromLatin1(kOptLogLevel))) |
| 60 | : Info; | ||
| 61 |
9/12✓ Branch 45 → 46 taken 5 times.
✓ Branch 47 → 48 taken 1 time.
✓ Branch 47 → 52 taken 4 times.
✓ Branch 48 → 49 taken 1 time.
✓ Branch 50 → 51 taken 1 time.
✗ Branch 50 → 52 not taken.
✓ Branch 53 → 54 taken 1 time.
✓ Branch 53 → 55 taken 4 times.
✓ Branch 55 → 56 taken 1 time.
✓ Branch 55 → 60 taken 4 times.
✗ Branch 108 → 109 not taken.
✗ Branch 108 → 110 not taken.
|
5 | } else if (const QByteArray envRules = qgetenv(kEnvLogRules); !envRules.isNull() && !envRules.trimmed().isEmpty()) { |
| 62 |
1/1✓ Branch 56 → 57 taken 1 time.
|
1 | customRules = QString::fromUtf8(envRules); |
| 63 |
3/3✓ Branch 60 → 61 taken 4 times.
✓ Branch 62 → 63 taken 1 time.
✓ Branch 62 → 67 taken 3 times.
|
4 | } else if (const QByteArray envLevel = qgetenv(kEnvLogLevel); !envLevel.isNull()) { |
| 64 |
2/2✓ Branch 63 → 64 taken 1 time.
✓ Branch 64 → 65 taken 1 time.
|
1 | level = parseLevelName(QString::fromUtf8(envLevel)); |
| 65 | 9 | } | |
| 66 | |||
| 67 |
1/1✓ Branch 71 → 72 taken 11 times.
|
11 | const QString rules = composeRules(level, customRules); |
| 68 |
1/1✓ Branch 72 → 73 taken 11 times.
|
11 | QLoggingCategory::setFilterRules(rules); |
| 69 | 11 | return rules; | |
| 70 | 11 | } | |
| 71 | |||
| 72 | LogConfigurator::Level | ||
| 73 | 26 | LogConfigurator::parseLevelName(const QString &name) { | |
| 74 |
2/2✓ Branch 2 → 3 taken 26 times.
✓ Branch 3 → 4 taken 26 times.
|
26 | const QString normalized = name.trimmed().toLower(); |
| 75 |
12/14✓ Branch 9 → 10 taken 23 times.
✓ Branch 9 → 15 taken 3 times.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 16 taken 22 times.
✓ Branch 17 → 18 taken 23 times.
✓ Branch 17 → 19 taken 3 times.
✓ Branch 19 → 20 taken 23 times.
✓ Branch 19 → 21 taken 3 times.
✓ Branch 21 → 22 taken 26 times.
✗ Branch 21 → 23 not taken.
✓ Branch 23 → 24 taken 26 times.
✗ Branch 23 → 25 not taken.
✓ Branch 25 → 26 taken 4 times.
✓ Branch 25 → 27 taken 22 times.
|
75 | if (normalized == QStringLiteral("off") || normalized == QStringLiteral("none")) |
| 76 | 4 | return Off; | |
| 77 |
5/6✓ Branch 36 → 37 taken 17 times.
✓ Branch 36 → 47 taken 1 time.
✓ Branch 63 → 64 taken 22 times.
✗ Branch 63 → 65 not taken.
✓ Branch 65 → 66 taken 6 times.
✓ Branch 65 → 67 taken 16 times.
|
62 | if (normalized == QStringLiteral("error") || |
| 78 |
4/6✓ Branch 41 → 42 taken 17 times.
✗ Branch 41 → 47 not taken.
✓ Branch 59 → 60 taken 18 times.
✓ Branch 59 → 61 taken 4 times.
✓ Branch 61 → 62 taken 22 times.
✗ Branch 61 → 63 not taken.
|
57 | normalized == QStringLiteral("critical") || |
| 79 |
8/8✓ Branch 31 → 32 taken 18 times.
✓ Branch 31 → 47 taken 4 times.
✓ Branch 46 → 47 taken 1 time.
✓ Branch 46 → 48 taken 16 times.
✓ Branch 55 → 56 taken 17 times.
✓ Branch 55 → 57 taken 5 times.
✓ Branch 57 → 58 taken 18 times.
✓ Branch 57 → 59 taken 4 times.
|
101 | normalized == QStringLiteral("err") || |
| 80 |
6/6✓ Branch 49 → 50 taken 17 times.
✓ Branch 49 → 51 taken 5 times.
✓ Branch 51 → 52 taken 17 times.
✓ Branch 51 → 53 taken 5 times.
✓ Branch 53 → 54 taken 17 times.
✓ Branch 53 → 55 taken 5 times.
|
39 | normalized == QStringLiteral("fatal")) |
| 81 | 6 | return Error; | |
| 82 |
7/8✓ Branch 71 → 72 taken 13 times.
✓ Branch 71 → 77 taken 3 times.
✓ Branch 76 → 77 taken 1 time.
✓ Branch 76 → 78 taken 12 times.
✓ Branch 85 → 86 taken 16 times.
✗ Branch 85 → 87 not taken.
✓ Branch 87 → 88 taken 4 times.
✓ Branch 87 → 89 taken 12 times.
|
61 | if (normalized == QStringLiteral("warning") || |
| 83 |
5/6✓ Branch 79 → 80 taken 13 times.
✓ Branch 79 → 81 taken 3 times.
✓ Branch 81 → 82 taken 13 times.
✓ Branch 81 → 83 taken 3 times.
✓ Branch 83 → 84 taken 16 times.
✗ Branch 83 → 85 not taken.
|
29 | normalized == QStringLiteral("warn")) |
| 84 | 4 | return Warning; | |
| 85 |
2/2✓ Branch 95 → 96 taken 3 times.
✓ Branch 95 → 97 taken 9 times.
|
12 | if (normalized == QStringLiteral("info")) |
| 86 | 3 | return Info; | |
| 87 |
5/6✓ Branch 106 → 107 taken 4 times.
✓ Branch 106 → 112 taken 1 time.
✓ Branch 124 → 125 taken 9 times.
✗ Branch 124 → 126 not taken.
✓ Branch 126 → 127 taken 6 times.
✓ Branch 126 → 128 taken 3 times.
|
23 | if (normalized == QStringLiteral("debug") || |
| 88 |
7/8✓ Branch 101 → 102 taken 5 times.
✓ Branch 101 → 112 taken 4 times.
✓ Branch 111 → 112 taken 1 time.
✓ Branch 111 → 113 taken 3 times.
✓ Branch 120 → 121 taken 5 times.
✓ Branch 120 → 122 taken 4 times.
✓ Branch 122 → 123 taken 9 times.
✗ Branch 122 → 124 not taken.
|
37 | normalized == QStringLiteral("trace") || |
| 89 |
6/6✓ Branch 114 → 115 taken 4 times.
✓ Branch 114 → 116 taken 5 times.
✓ Branch 116 → 117 taken 4 times.
✓ Branch 116 → 118 taken 5 times.
✓ Branch 118 → 119 taken 5 times.
✓ Branch 118 → 120 taken 4 times.
|
13 | normalized == QStringLiteral("all")) |
| 90 | 6 | return Debug; | |
| 91 | // Unrecognized → project default. | ||
| 92 | 3 | return Error; | |
| 93 | 26 | } | |
| 94 | |||
| 95 | 20 | QString LogConfigurator::levelName(LogConfigurator::Level level) { | |
| 96 |
5/6✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 8 taken 5 times.
✓ Branch 2 → 13 taken 4 times.
✓ Branch 2 → 18 taken 4 times.
✓ Branch 2 → 23 taken 4 times.
✗ Branch 2 → 28 not taken.
|
20 | switch (level) { |
| 97 | 3 | case Off: | |
| 98 | 3 | return QStringLiteral("off"); | |
| 99 | 5 | case Error: | |
| 100 | 5 | return QStringLiteral("error"); | |
| 101 | 4 | case Warning: | |
| 102 | 4 | return QStringLiteral("warning"); | |
| 103 | 4 | case Info: | |
| 104 | 4 | return QStringLiteral("info"); | |
| 105 | 4 | case Debug: | |
| 106 | 4 | return QStringLiteral("debug"); | |
| 107 | } | ||
| 108 | ✗ | return QStringLiteral("error"); | |
| 109 | } | ||
| 110 | |||
| 111 | 23 | QString LogConfigurator::rulesForLevel(LogConfigurator::Level level) { | |
| 112 | // Qt's default rules: *.debug=false, *.info=false (warnings+criticals on). | ||
| 113 | // We only ever constrain mailjd.* so Qt's own warnings stay visible. | ||
| 114 |
5/6✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 8 taken 9 times.
✓ Branch 2 → 13 taken 2 times.
✓ Branch 2 → 18 taken 6 times.
✓ Branch 2 → 23 taken 3 times.
✗ Branch 2 → 28 not taken.
|
23 | switch (level) { |
| 115 | 3 | case Off: | |
| 116 | // Silence every mailjd.* category at every level. | ||
| 117 | 3 | return QStringLiteral("mailjd.*=false\n"); | |
| 118 | 9 | case Error: | |
| 119 | // Default: only qCCritical(lc...) reaches the output. | ||
| 120 | 9 | return QStringLiteral("mailjd.*.debug=false\n" | |
| 121 | "mailjd.*.info=false\n" | ||
| 122 | "mailjd.*.warning=false\n"); | ||
| 123 | 2 | case Warning: | |
| 124 | // Qt default behaviour for mailjd.* (explicit). | ||
| 125 | 2 | return QStringLiteral("mailjd.*.debug=false\n" | |
| 126 | "mailjd.*.info=false\n"); | ||
| 127 | 6 | case Info: | |
| 128 | 6 | return QStringLiteral("mailjd.*.debug=false\n" | |
| 129 | "mailjd.*.info=true\n"); | ||
| 130 | 3 | case Debug: | |
| 131 | 3 | return QStringLiteral("mailjd.*.debug=true\n" | |
| 132 | "mailjd.*.info=true\n"); | ||
| 133 | } | ||
| 134 | ✗ | return QStringLiteral("mailjd.*.warning=false\n"); | |
| 135 | } | ||
| 136 | |||
| 137 | 15 | QString LogConfigurator::composeRules(LogConfigurator::Level level, | |
| 138 | const QString &customRules) { | ||
| 139 |
3/3✓ Branch 2 → 3 taken 15 times.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 11 times.
|
15 | if (!customRules.trimmed().isEmpty()) |
| 140 | 4 | return customRules.trimmed(); | |
| 141 | 11 | return rulesForLevel(level); | |
| 142 | } | ||
| 143 |