LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
QsLogCategories.cpp
Go to the documentation of this file.
1// Copyright 2002-2019 CEA LIST
2// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
6#include "QsLogCategories.h"
9
10#ifdef WIN32
11#pragma warning(disable: 4127)
12#endif
13#include <QFile>
14#include <QList>
15#include <QDateTime>
16#include <QtGlobal>
17#include <QStringList>
18#include <QFileInfo>
19#include <QDir>
20#include <cassert>
21#include <cstdlib>
22#include <stdexcept>
23
24using namespace Lima;
25using namespace Lima::Common::Misc;
26
27namespace QsLogging
28{
29
30//static const int init = initQsLog();
31
33{
34public:
36 {
37 }
38 QMap<QString,Level> categories;
40 QMap< QString, QString > m_categorySources;
41
43 bool m_initialized = false;
44
47 QStringList m_configuredFiles;
48};
49
50Categories::Categories(QObject* parent) :
51 QObject(parent),
52 d(new CategoriesImpl())
53{
54 const QString category = "FilesReporting";
55#ifdef DEBUG_CD
56 d->categories.insert(category, QsLogging::InfoLevel);
57#else
58 d->categories.insert(category, QsLogging::ErrorLevel);
59#endif
60 d->categories.insert("Logging", QsLogging::TraceLevel);
61
62}
63
65{
66 connect(&d->m_configFileWatcher, SIGNAL(fileChanged(QString)),
67 this, SLOT(configureFileChanged(QString)));
68}
69
70Categories::~Categories()
71{
72 delete d;
73}
74
75void Categories::configureFileChanged( const QString & path )
76{
77 if (QFile(path).exists())
78 {
79 configure(path, true);
80 }
81}
82
83bool Categories::configure(const QString& fileName, bool reload)
84{
85 d->m_initialized = true;
86 const QString local_zone("FilesReporting");
87 static LogInit logInit(local_zone.toUtf8().constData());
88 auto& logger = *(logInit.pLogger);
89
90// std::cerr << "Categories::configure " << fileName.toStdString() << " " << reload << std::endl;
91
92 QFile file(fileName);
93 QFileInfo fileInfo(fileName);
94 QDir configDir = fileInfo.dir();
95
96 if (!file.open(QIODevice::ReadOnly))
97 {
98 std::cerr << "Unable to open qslog configuration file: \"" << fileName.toUtf8().data() << "\"" << std::endl;
99 return false;
100 }
101 if (!reload && d->m_configuredFiles.contains(fileName))
102 {
103 LOGINIT("Logging");
104 LDEBUG << "Categories::configure configuration file: \"" << fileName << "\" already configured";
105 return true;
106 }
107 d->m_configFileWatcher.addPath(fileName);
108 d->m_configuredFiles.append(fileName);
109 d->m_configuredFiles.removeDuplicates();
110
111 bool res = true;
112 QTextStream in(&file);
113 auto line = in.readLine();
114 while (!line.isNull())
115 {
116 if (!line.startsWith("#"))
117 {
118 auto elts = line.split("=");
119 if (elts.size()==2 && elts.at(0).trimmed().startsWith("log4j.category."))
120 {
121 auto category = elts.at(0).trimmed().remove(0, QLatin1String("log4j.category.").size());
122 auto value = elts.at(1).trimmed();
123 if (d->m_categorySources.contains(category))
124 {
125 LOGINIT("Logging");
126 LDEBUG << fileName << "overwrites category definition"
127 << category << "from"
128 << d->m_categorySources[category];
129 }
130 d->m_categorySources.insert(category, fileName);
131 if (value == "TRACE")
132 d->categories.insert(category,QsLogging::TraceLevel);
133 else if (value == "DEBUG")
134 d->categories.insert(category,QsLogging::DebugLevel);
135 else if (value == "INFO")
136 d->categories.insert(category,QsLogging::InfoLevel);
137 else if (value == "WARN")
138 d->categories.insert(category,QsLogging::WarnLevel);
139 else if (value == "ERROR")
140 d->categories.insert(category,QsLogging::ErrorLevel);
141 else if (value == "FATAL")
142 d->categories.insert(category,QsLogging::FatalLevel);
143 else
144 {
145 std::cerr << "Error reading \"" << fileName.toUtf8().constData()
146 << "\": unknown level \"" << value.toUtf8().constData()
147 << "\". Using TRACE" << std::endl;
148 res = false;
149 d->categories.insert(category,QsLogging::TraceLevel);
150 }
151 if(category == local_zone) {
152 // Ensure the local logger knows all the latest declared destinations
153 for (auto& destination: Destinations::instance().destinations())
154 {
155 logger.addDestination(destination);
156 }
157 // Ensure the local logger has its latest declared level
159 logger.setLoggingLevel(lvl);
160 }
161 }
162 else if (elts.size()==2 && elts.at(0).trimmed() == "include")
163 {
164 auto includedFileName = elts.at(1).trimmed();
165 auto includedInitFileName = includedFileName;
166 if (!QFileInfo(includedInitFileName).isAbsolute())
167 {
168 includedInitFileName = configDir.filePath(includedInitFileName);
169 }
170 res &= configure(includedInitFileName);
171 }
172 }
173 line = in.readLine();
174 }
175 LINFO << "QsLog conf file loaded:" << fileName;
176 return res;
177}
178
179Level Categories::levelFor(const QString& category) const
180{
181 if (!d->m_initialized) initQsLog();
182#ifdef DEBUG_CD
183 // Do not compile this costly check in release
184 if (!d->categories.contains(category))
185 {
186 std::cerr << "Error: unknown category. Using TRACE for \""
187 << category.toUtf8().constData() << "\"" << std::endl;
188 }
189#endif
190 return d->categories.value(category, QsLogging::TraceLevel);
191}
192
193LIMA_COMMONQSLOG_EXPORT bool initQsLog(const QString& configString)
194{
195// std::cerr << "initQsLog " << configString.toStdString() << std::endl;
198
199// bool atLeastOneSuccessfulLoad = false;
200 bool atLeastOneDestinationSuccessfulLoad = false;
201 QStringList configDirsList;
202 if (configString.isEmpty())
203 {
204 configDirsList = buildConfigurationDirectoriesList(QStringList({"lima"}),
205 QStringList());
206 }
207 else
208 {
209 configDirsList = configString.split(LIMA_PATH_SEPARATOR);
210 }
211 try
212 {
213 while (! configDirsList.isEmpty() )
214 {
215 QString configDir = configDirsList.last();
216 configDirsList.pop_back();
217 QString initFileName = configDir + "/log4cpp.properties";
218 if (QFileInfo::exists(initFileName))
219 {
220 if (QsLogging::Destinations::instance().configure(initFileName))
221 {
222 atLeastOneDestinationSuccessfulLoad = true;
224 }
225// else
226// {
227// std::cerr << "Configure Problem \"" << initFileName.toUtf8().constData() << "\"" << std::endl;
228// return false;
229// }
230 QsLogging::Categories::instance().configure(initFileName); // return value ignored on will
231// if (QsLogging::Categories::instance().configure(initFileName))
232// {
233// atLeastOneSuccessfulLoad = true;
234// }
235// else
236// {
237// std::cerr << "Configure Problem \"" << initFileName.toUtf8().constData() << "\"" << std::endl;
238// return false;
239// }
240 }
241 QDir initDir( configDir + "/log4cpp", "*.properties",
242 QDir::Unsorted, QDir::Files);
243 if (initDir.exists())
244 {
245 QStringList entryList = initDir.entryList();
246 for(QString& entry : entryList)
247 {
248 if (QsLogging::Destinations::instance().configure(configDir + "/log4cpp/" + entry))
249 {
250 atLeastOneDestinationSuccessfulLoad = true;
252 }
253 else
254 {
255// std::cerr << "Configure Problem \"" << entry.toUtf8().constData() << "\". No destination available" << std::endl;
256 return false;
257 }
258 if (!QsLogging::Categories::instance().configure(configDir + "/log4cpp/" + entry))
259 {
260// std::cerr << "Configure Problem \"" << entry.toUtf8().constData() << "\". No category loaded" << std::endl;
261 return false;
262 }
263// else
264// {
265// atLeastOneSuccessfulLoad = true;
266// }
267 }
268 }
269
270 }
271 }
272 catch(...)
273 {
274 std::cerr << "Exception during logging system configuration" << std::endl;
275 return false;
276 }
277// if (!atLeastOneSuccessfulLoad)
278// {
279// std::cerr << "Configure Problem: no log configuration file has been found in \"" << configString.toStdString() << "\"" << std::endl;
280// return false;
281// }
282 if (atLeastOneDestinationSuccessfulLoad)
283 {
285 }
286
287 return true;
288}
289
290} // end namespace
#define LIMA_PATH_SEPARATOR
Definition FileUtils.h:25
#define LOGINIT(X)
Definition LimaCommon.h:187
#define LDEBUG
Definition LimaCommon.h:157
#define LINFO
Definition LimaCommon.h:158
#define LIMA_COMMONQSLOG_EXPORT
LimaFileSystemWatcher extends QFileSystemWatcher to work on replaced files
void addPath(const QString &path)
QsLogging::Logger * pLogger
Definition LimaCommon.h:185
QMap< QString, Level > categories
QStringList m_configuredFiles
Store the list of configuration files already loaded.
QMap< QString, QString > m_categorySources
Association category name / file name. Allows to inform of overwrites.
LimaFileSystemWatcher m_configFileWatcher
static Categories & instance()
Level levelFor(const QString &category) const
bool configure(const QString &fileName, bool reload=false)
bool configure(const QString &fileName, bool reload=false)
const QMap< QString, DestinationPtr > & destinations() const
Definition QsLogDest.cpp:82
static Destinations & instance()
Definition QsLogDest.h:57
QStringList buildConfigurationDirectoriesList(const QStringList &projects, const QStringList &paths)
Build a list of configuration directories from a list of project names and a list of paths.
NAUTITIA.
@ TraceLevel
Definition QsLog.h:48
@ DebugLevel
Definition QsLog.h:49
@ ErrorLevel
Definition QsLog.h:52
@ InfoLevel
Definition QsLog.h:50
@ FatalLevel
Definition QsLog.h:53
@ WarnLevel
Definition QsLog.h:51
LIMA_COMMONQSLOG_EXPORT bool initQsLog(const QString &configString)