Branch data Line data Source code
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 : 7 : void LogConfigurator::registerOptions(QCommandLineParser &parser) {
27 : : QCommandLineOption levelOption(
28 [ + - ]: 14 : QString::fromLatin1(kOptLogLevel),
29 : 14 : QStringLiteral("Log verbosity: off|error|warning|info|debug "
30 : : "(default: error). Env: %1.")
31 [ + - + - ]: 14 : .arg(QString::fromLatin1(kEnvLogLevel)),
32 [ + - ]: 28 : QStringLiteral("level"));
33 : : QCommandLineOption rulesOption(
34 [ + - ]: 14 : QString::fromLatin1(kOptLogRules),
35 : 14 : QStringLiteral("Raw Qt filter rules (overrides --log-level). "
36 : : "Env: %1.")
37 [ + - + - ]: 14 : .arg(QString::fromLatin1(kEnvLogRules)),
38 [ + - ]: 28 : QStringLiteral("rules"));
39 : : QCommandLineOption verboseOption(
40 [ + - ]: 14 : QString::fromLatin1(kOptVerbose),
41 [ + - ]: 28 : QStringLiteral("Shortcut for --log-level=info"));
42 [ + - ]: 7 : parser.addOption(levelOption);
43 [ + - ]: 7 : parser.addOption(rulesOption);
44 [ + - ]: 7 : parser.addOption(verboseOption);
45 : 7 : }
46 : :
47 : 5 : QString LogConfigurator::apply(const QCommandLineParser &parser) {
48 : : // 1. Free-form Qt rules win outright (CLI over env).
49 : 5 : QString customRules;
50 [ + - + - : 5 : if (parser.isSet(QString::fromLatin1(kOptLogRules))) {
+ + ]
51 [ + - + - ]: 1 : customRules = parser.value(QString::fromLatin1(kOptLogRules));
52 : : } else {
53 [ + - ]: 4 : const QByteArray envRules = qgetenv(kEnvLogRules);
54 [ - + ]: 4 : if (!envRules.isNull())
55 [ # # ]: 0 : customRules = QString::fromUtf8(envRules);
56 : 4 : }
57 : :
58 : : // 2. Otherwise resolve a named level (CLI flag → CLI --log-level → env → default).
59 : 5 : Level level = Error;
60 [ + - + - : 5 : if (parser.isSet(QString::fromLatin1(kOptVerbose))) {
+ + ]
61 : 2 : level = Info;
62 : : }
63 [ + - + - : 5 : if (parser.isSet(QString::fromLatin1(kOptLogLevel))) {
+ + ]
64 [ + - + - : 3 : level = parseLevelName(parser.value(QString::fromLatin1(kOptLogLevel)));
+ - ]
65 : : } else {
66 [ + - ]: 2 : const QByteArray envLevel = qgetenv(kEnvLogLevel);
67 [ - + ]: 2 : if (!envLevel.isNull())
68 [ # # # # ]: 0 : level = parseLevelName(QString::fromUtf8(envLevel));
69 : 2 : }
70 : :
71 [ + - ]: 5 : const QString rules = composeRules(level, customRules);
72 [ + - ]: 5 : QLoggingCategory::setFilterRules(rules);
73 : 5 : return rules;
74 : 5 : }
75 : :
76 : : LogConfigurator::Level
77 : 25 : LogConfigurator::parseLevelName(const QString &name) {
78 [ + - + - ]: 25 : const QString normalized = name.trimmed().toLower();
79 [ + + + + : 72 : if (normalized == QStringLiteral("off") || normalized == QStringLiteral("none"))
+ + + + +
- + - +
+ ]
80 : 4 : return Off;
81 [ + + + - : 59 : if (normalized == QStringLiteral("error") ||
+ + ]
82 [ + - + + : 54 : normalized == QStringLiteral("critical") ||
+ - ]
83 [ + + + + : 96 : normalized == QStringLiteral("err") ||
+ + + + ]
84 [ + + + + : 37 : normalized == QStringLiteral("fatal"))
+ + ]
85 : 6 : return Error;
86 [ + + + + : 57 : if (normalized == QStringLiteral("warning") ||
+ - + + ]
87 [ + + + + : 27 : normalized == QStringLiteral("warn"))
+ - ]
88 : 4 : return Warning;
89 [ + + ]: 11 : if (normalized == QStringLiteral("info"))
90 : 3 : return Info;
91 [ + + + - : 21 : if (normalized == QStringLiteral("debug") ||
+ + ]
92 [ + + + + : 34 : normalized == QStringLiteral("trace") ||
+ + + - ]
93 [ + + + + : 12 : normalized == QStringLiteral("all"))
+ + ]
94 : 5 : return Debug;
95 : : // Unrecognized → project default.
96 : 3 : return Error;
97 : 25 : }
98 : :
99 : 20 : QString LogConfigurator::levelName(LogConfigurator::Level level) {
100 [ + + + + : 20 : switch (level) {
+ - ]
101 : 3 : case Off:
102 : 3 : return QStringLiteral("off");
103 : 5 : case Error:
104 : 5 : return QStringLiteral("error");
105 : 4 : case Warning:
106 : 4 : return QStringLiteral("warning");
107 : 4 : case Info:
108 : 4 : return QStringLiteral("info");
109 : 4 : case Debug:
110 : 4 : return QStringLiteral("debug");
111 : : }
112 : 0 : return QStringLiteral("error");
113 : : }
114 : :
115 : 18 : QString LogConfigurator::rulesForLevel(LogConfigurator::Level level) {
116 : : // Qt's default rules: *.debug=false, *.info=false (warnings+criticals on).
117 : : // We only ever constrain mailjd.* so Qt's own warnings stay visible.
118 [ + + + + : 18 : switch (level) {
+ - ]
119 : 2 : case Off:
120 : : // Silence every mailjd.* category at every level.
121 : 2 : return QStringLiteral("mailjd.*=false\n");
122 : 7 : case Error:
123 : : // Default: only qCCritical(lc...) reaches the output.
124 : 7 : return QStringLiteral("mailjd.*.debug=false\n"
125 : : "mailjd.*.info=false\n"
126 : : "mailjd.*.warning=false\n");
127 : 2 : case Warning:
128 : : // Qt default behaviour for mailjd.* (explicit).
129 : 2 : return QStringLiteral("mailjd.*.debug=false\n"
130 : : "mailjd.*.info=false\n");
131 : 5 : case Info:
132 : 5 : return QStringLiteral("mailjd.*.debug=false\n"
133 : : "mailjd.*.info=true\n");
134 : 2 : case Debug:
135 : 2 : return QStringLiteral("mailjd.*.debug=true\n"
136 : : "mailjd.*.info=true\n");
137 : : }
138 : 0 : return QStringLiteral("mailjd.*.warning=false\n");
139 : : }
140 : :
141 : 9 : QString LogConfigurator::composeRules(LogConfigurator::Level level,
142 : : const QString &customRules) {
143 [ + - + + ]: 9 : if (!customRules.trimmed().isEmpty())
144 : 3 : return customRules.trimmed();
145 : 6 : return rulesForLevel(level);
146 : : }
|