mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-17 19:05:31 +08:00
* follow up of debug session, added failure/success to status message * return status messages instead of directly logging in functions returning CStatusMessage. * Ignore empty preformatted messages. * new log category
This commit is contained in:
committed by
Mathew Sutcliffe
parent
f490504f52
commit
144ba62572
@@ -50,6 +50,13 @@ namespace BlackMisc
|
|||||||
return cat;
|
return cat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Core/base services such as caching etc.
|
||||||
|
static const CLogCategory &services()
|
||||||
|
{
|
||||||
|
static const CLogCategory cat { "swift.services" };
|
||||||
|
return cat;
|
||||||
|
}
|
||||||
|
|
||||||
//! Contexts
|
//! Contexts
|
||||||
static const CLogCategory &context()
|
static const CLogCategory &context()
|
||||||
{
|
{
|
||||||
@@ -106,6 +113,7 @@ namespace BlackMisc
|
|||||||
static const QList<CLogCategory> cats
|
static const QList<CLogCategory> cats
|
||||||
{
|
{
|
||||||
uncategorized(),
|
uncategorized(),
|
||||||
|
services(),
|
||||||
validation(),
|
validation(),
|
||||||
context(),
|
context(),
|
||||||
contextSlot(),
|
contextSlot(),
|
||||||
|
|||||||
@@ -179,6 +179,7 @@ namespace BlackMisc
|
|||||||
|
|
||||||
void CLogMessage::preformatted(const CStatusMessage &statusMessage)
|
void CLogMessage::preformatted(const CStatusMessage &statusMessage)
|
||||||
{
|
{
|
||||||
|
if (statusMessage.isEmpty()) { return; } // just skip empty messages
|
||||||
CLogMessage msg(statusMessage.getCategories());
|
CLogMessage msg(statusMessage.getCategories());
|
||||||
msg.m_severity = statusMessage.getSeverity();
|
msg.m_severity = statusMessage.getSeverity();
|
||||||
msg.m_message = statusMessage.getMessage();
|
msg.m_message = statusMessage.getMessage();
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace BlackMisc
|
|||||||
{ "uncategorized (swift)", exactMatch(CLogCategory::uncategorized()) },
|
{ "uncategorized (swift)", exactMatch(CLogCategory::uncategorized()) },
|
||||||
{ "validation", exactMatch(CLogCategory::validation()) },
|
{ "validation", exactMatch(CLogCategory::validation()) },
|
||||||
{ "verification", exactMatch(CLogCategory::verification()) },
|
{ "verification", exactMatch(CLogCategory::verification()) },
|
||||||
|
{ "services", exactMatch(CLogCategory::services()) },
|
||||||
{ "model mapping", exactMatch(CLogCategory::mapping()) },
|
{ "model mapping", exactMatch(CLogCategory::mapping()) },
|
||||||
{ "swift contexts", exactMatch(CLogCategory::context()) },
|
{ "swift contexts", exactMatch(CLogCategory::context()) },
|
||||||
{ "swift context slots", exactMatch(CLogCategory::contextSlot()) },
|
{ "swift context slots", exactMatch(CLogCategory::contextSlot()) },
|
||||||
|
|||||||
@@ -142,6 +142,16 @@ namespace BlackMisc
|
|||||||
return c.isEmpty() ? this->getCategoriesAsString() : c;
|
return c.isEmpty() ? this->getCategoriesAsString() : c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CStatusMessage::isSuccess() const
|
||||||
|
{
|
||||||
|
return !isFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CStatusMessage::isFailure() const
|
||||||
|
{
|
||||||
|
return getSeverity() == SeverityError;
|
||||||
|
}
|
||||||
|
|
||||||
void CStatusMessage::prependMessage(const QString &msg)
|
void CStatusMessage::prependMessage(const QString &msg)
|
||||||
{
|
{
|
||||||
if (msg.isEmpty()) { return; }
|
if (msg.isEmpty()) { return; }
|
||||||
|
|||||||
@@ -107,6 +107,12 @@ namespace BlackMisc
|
|||||||
//! Warning or above
|
//! Warning or above
|
||||||
bool isWarningOrAbove() const { return this->m_severity == SeverityWarning || this->m_severity == SeverityError; }
|
bool isWarningOrAbove() const { return this->m_severity == SeverityWarning || this->m_severity == SeverityError; }
|
||||||
|
|
||||||
|
//! Operation considered successful
|
||||||
|
bool isSuccess() const;
|
||||||
|
|
||||||
|
//! Operation considered unsuccessful
|
||||||
|
bool isFailure() const;
|
||||||
|
|
||||||
//! Message
|
//! Message
|
||||||
QString getMessage() const { return this->m_message; }
|
QString getMessage() const { return this->m_message; }
|
||||||
|
|
||||||
|
|||||||
@@ -85,6 +85,12 @@ namespace BlackMisc
|
|||||||
// CValueCache
|
// CValueCache
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
|
const CLogCategoryList &CValueCache::getLogCategories()
|
||||||
|
{
|
||||||
|
static const CLogCategoryList cats({ CLogCategory("swift.valuecache") , CLogCategory::services()} );
|
||||||
|
return cats;
|
||||||
|
}
|
||||||
|
|
||||||
CValueCache::CValueCache(CValueCache::DistributionMode mode, QObject *parent) :
|
CValueCache::CValueCache(CValueCache::DistributionMode mode, QObject *parent) :
|
||||||
QObject(parent)
|
QObject(parent)
|
||||||
{
|
{
|
||||||
@@ -227,7 +233,7 @@ namespace BlackMisc
|
|||||||
QMutexLocker lock(&m_mutex);
|
QMutexLocker lock(&m_mutex);
|
||||||
auto values = getAllValues(keyPrefix);
|
auto values = getAllValues(keyPrefix);
|
||||||
auto status = saveToFiles(dir, values);
|
auto status = saveToFiles(dir, values);
|
||||||
if (! status.isEmpty()) { markAllAsSaved(keyPrefix); }
|
if (status.isSuccess()) { markAllAsSaved(keyPrefix); }
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,19 +246,19 @@ namespace BlackMisc
|
|||||||
}
|
}
|
||||||
if (! QDir::root().mkpath(dir))
|
if (! QDir::root().mkpath(dir))
|
||||||
{
|
{
|
||||||
return CLogMessage(this).error("Failed to create directory %1") << dir;
|
return CStatusMessage(this, CStatusMessage::SeverityError, "Failed to create directory " + dir);
|
||||||
}
|
}
|
||||||
for (auto it = namespaces.cbegin(); it != namespaces.cend(); ++it)
|
for (auto it = namespaces.cbegin(); it != namespaces.cend(); ++it)
|
||||||
{
|
{
|
||||||
CAtomicFile file(dir + "/" + it.key() + ".json");
|
CAtomicFile file(dir + "/" + it.key() + ".json");
|
||||||
if (! file.open(QFile::ReadWrite | QFile::Text))
|
if (! file.open(QFile::ReadWrite | QFile::Text))
|
||||||
{
|
{
|
||||||
return CLogMessage(this).error("Failed to open %1: %2") << file.fileName() << file.errorString();
|
return CStatusMessage(this, CStatusMessage::SeverityError, QString("Failed to open %1: %2").arg(file.fileName()).arg(file.errorString()));
|
||||||
}
|
}
|
||||||
auto json = QJsonDocument::fromJson(file.readAll());
|
auto json = QJsonDocument::fromJson(file.readAll());
|
||||||
if (json.isArray() || (json.isNull() && ! json.isEmpty()))
|
if (json.isArray() || (json.isNull() && ! json.isEmpty()))
|
||||||
{
|
{
|
||||||
return CLogMessage(this).error("Invalid JSON format in %1") << file.fileName();
|
return CStatusMessage(this, CStatusMessage::SeverityError, "Invalid JSON format in " + file.fileName());
|
||||||
}
|
}
|
||||||
CVariantMap storedValues;
|
CVariantMap storedValues;
|
||||||
storedValues.convertFromJson(json.object());
|
storedValues.convertFromJson(json.object());
|
||||||
@@ -261,10 +267,12 @@ namespace BlackMisc
|
|||||||
|
|
||||||
if (!(file.seek(0) && file.resize(0) && file.write(json.toJson()) > 0 && file.checkedClose()))
|
if (!(file.seek(0) && file.resize(0) && file.write(json.toJson()) > 0 && file.checkedClose()))
|
||||||
{
|
{
|
||||||
return CLogMessage(this).error("Failed to write to %1: %2") << file.fileName() << file.errorString();
|
return CStatusMessage(this, CStatusMessage::SeverityError,
|
||||||
|
QString("Failed to write to %1: %2").arg(file.fileName()).arg(file.errorString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return CStatusMessage(this, CStatusMessage::SeverityInfo,
|
||||||
|
QString("Written %1 files for value cache in %2").arg(namespaces.size()).arg(dir));
|
||||||
}
|
}
|
||||||
|
|
||||||
CStatusMessage CValueCache::loadFromFiles(const QString &dir)
|
CStatusMessage CValueCache::loadFromFiles(const QString &dir)
|
||||||
@@ -281,19 +289,21 @@ namespace BlackMisc
|
|||||||
{
|
{
|
||||||
if (! QDir(dir).isReadable())
|
if (! QDir(dir).isReadable())
|
||||||
{
|
{
|
||||||
return CLogMessage(this).error("Failed to read directory %1") << dir;
|
return CStatusMessage(this, CStatusMessage::SeverityError, "Failed to create directory " + dir);
|
||||||
}
|
}
|
||||||
for (const auto &filename : QDir(dir).entryList({ "*.json" }, QDir::Files))
|
|
||||||
|
const QStringList entries(QDir(dir).entryList({ "*.json" }, QDir::Files));
|
||||||
|
for (const auto &filename : entries)
|
||||||
{
|
{
|
||||||
QFile file(dir + "/" + filename);
|
QFile file(dir + "/" + filename);
|
||||||
if (! file.open(QFile::ReadOnly | QFile::Text))
|
if (! file.open(QFile::ReadOnly | QFile::Text))
|
||||||
{
|
{
|
||||||
return CLogMessage(this).error("Failed to open %1 : %2") << file.fileName() << file.errorString();
|
return CStatusMessage(this, CStatusMessage::SeverityError, QString("Failed to open %1: %2").arg(file.fileName()).arg(file.errorString()));
|
||||||
}
|
}
|
||||||
auto json = QJsonDocument::fromJson(file.readAll());
|
auto json = QJsonDocument::fromJson(file.readAll());
|
||||||
if (json.isArray() || (json.isNull() && ! json.isEmpty()))
|
if (json.isArray() || (json.isNull() && ! json.isEmpty()))
|
||||||
{
|
{
|
||||||
return CLogMessage(this).error("Invalid JSON format in %1") << file.fileName();
|
return CStatusMessage(this, CStatusMessage::SeverityError, "Invalid JSON format in " + file.fileName());
|
||||||
}
|
}
|
||||||
CVariantMap temp;
|
CVariantMap temp;
|
||||||
temp.convertFromJson(json.object());
|
temp.convertFromJson(json.object());
|
||||||
@@ -304,7 +314,8 @@ namespace BlackMisc
|
|||||||
temp.removeDuplicates(currentValues);
|
temp.removeDuplicates(currentValues);
|
||||||
o_values.insert(temp, QFileInfo(file).lastModified().toMSecsSinceEpoch());
|
o_values.insert(temp, QFileInfo(file).lastModified().toMSecsSinceEpoch());
|
||||||
}
|
}
|
||||||
return {};
|
return CStatusMessage(this, CStatusMessage::SeverityInfo,
|
||||||
|
QString("Loaded value cache from %1 files in %2").arg(entries.size()).arg(dir));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CValueCache::markAllAsSaved(const QString &keyPrefix)
|
void CValueCache::markAllAsSaved(const QString &keyPrefix)
|
||||||
@@ -401,12 +412,13 @@ namespace BlackMisc
|
|||||||
auto &element = *(m_elements[key] = ElementPtr(new Element(key, metaType, validator, defaultValue, slot)));
|
auto &element = *(m_elements[key] = ElementPtr(new Element(key, metaType, validator, defaultValue, slot)));
|
||||||
std::forward_as_tuple(element.m_value.uniqueWrite(), element.m_timestamp, element.m_saved) = m_cache->getValue(key);
|
std::forward_as_tuple(element.m_value.uniqueWrite(), element.m_timestamp, element.m_saved) = m_cache->getValue(key);
|
||||||
|
|
||||||
auto error = validate(element, element.m_value.read());
|
auto status = validate(element, element.m_value.read(), CStatusMessage::SeverityDebug);
|
||||||
if (! error.isEmpty())
|
if (!status.isEmpty()) // intentionally kept !empty here, debug message supposed to write default value
|
||||||
{
|
{
|
||||||
CLogMessage::preformatted(error);
|
|
||||||
element.m_value.uniqueWrite() = defaultValue;
|
element.m_value.uniqueWrite() = defaultValue;
|
||||||
|
CLogMessage::preformatted(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,8 +434,8 @@ namespace BlackMisc
|
|||||||
if (timestamp == 0) { timestamp = QDateTime::currentMSecsSinceEpoch(); }
|
if (timestamp == 0) { timestamp = QDateTime::currentMSecsSinceEpoch(); }
|
||||||
if (element.m_value.read() == value && element.m_timestamp == timestamp) { return {}; }
|
if (element.m_value.read() == value && element.m_timestamp == timestamp) { return {}; }
|
||||||
|
|
||||||
auto error = validate(element, value);
|
auto status = validate(element, value, CStatusMessage::SeverityError);
|
||||||
if (error.isEmpty())
|
if (status.isSuccess())
|
||||||
{
|
{
|
||||||
if (m_batchMode > 0)
|
if (m_batchMode > 0)
|
||||||
{
|
{
|
||||||
@@ -439,11 +451,7 @@ namespace BlackMisc
|
|||||||
emit valuesWantToCache({ { { element.m_key, value } }, timestamp, save });
|
emit valuesWantToCache({ { { element.m_key, value } }, timestamp, save });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
return status;
|
||||||
{
|
|
||||||
CLogMessage::preformatted(error);
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString &CValuePage::getKey(const Element &element) const
|
const QString &CValuePage::getKey(const Element &element) const
|
||||||
@@ -481,8 +489,8 @@ namespace BlackMisc
|
|||||||
}
|
}
|
||||||
else if (element->m_pendingChanges == 0) // ratify a change only if own change is not pending, to ensure consistency
|
else if (element->m_pendingChanges == 0) // ratify a change only if own change is not pending, to ensure consistency
|
||||||
{
|
{
|
||||||
auto error = validate(*element, it.value());
|
auto error = validate(*element, it.value(), CStatusMessage::SeverityError);
|
||||||
if (error.isEmpty())
|
if (error.isSuccess())
|
||||||
{
|
{
|
||||||
element->m_value.uniqueWrite() = it.value();
|
element->m_value.uniqueWrite() = it.value();
|
||||||
element->m_timestamp = it.timestamp();
|
element->m_timestamp = it.timestamp();
|
||||||
@@ -541,11 +549,11 @@ namespace BlackMisc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CStatusMessage CValuePage::validate(const Element &element, const CVariant &value) const
|
CStatusMessage CValuePage::validate(const Element &element, const CVariant &value, CStatusMessage::StatusSeverity invalidSeverity) const
|
||||||
{
|
{
|
||||||
if (! value.isValid())
|
if (! value.isValid())
|
||||||
{
|
{
|
||||||
return CStatusMessage(this, CStatusMessage::SeverityDebug, "Uninitialized value for " + element.m_key);
|
return CStatusMessage(this, invalidSeverity, "Uninitialized value for " + element.m_key);
|
||||||
}
|
}
|
||||||
else if (value.userType() != element.m_metaType)
|
else if (value.userType() != element.m_metaType)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -113,6 +113,9 @@ namespace BlackMisc
|
|||||||
Distributed //!< Distributed among multiple processes.
|
Distributed //!< Distributed among multiple processes.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! Log categories
|
||||||
|
static const CLogCategoryList &getLogCategories();
|
||||||
|
|
||||||
//! Constructor.
|
//! Constructor.
|
||||||
//! \param mode Whether or not the cache can be distributed among multiple processes.
|
//! \param mode Whether or not the cache can be distributed among multiple processes.
|
||||||
//! \param parent The parent of the QObject.
|
//! \param parent The parent of the QObject.
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ namespace BlackMisc
|
|||||||
CVariantMap m_batchedValues;
|
CVariantMap m_batchedValues;
|
||||||
|
|
||||||
CValuePage(QObject *parent, CValueCache *cache);
|
CValuePage(QObject *parent, CValueCache *cache);
|
||||||
CStatusMessage validate(const Element &element, const CVariant &value) const;
|
CStatusMessage validate(const Element &element, const CVariant &value, CStatusMessage::StatusSeverity invalidSeverity) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ namespace BlackMiscTest
|
|||||||
if (dir.exists()) { dir.removeRecursively(); }
|
if (dir.exists()) { dir.removeRecursively(); }
|
||||||
|
|
||||||
auto status = cache.saveToFiles(dir.absolutePath());
|
auto status = cache.saveToFiles(dir.absolutePath());
|
||||||
QVERIFY(status.isEmpty());
|
QVERIFY(status.isSuccess());
|
||||||
|
|
||||||
auto files = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot, QDir::Name);
|
auto files = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot, QDir::Name);
|
||||||
QCOMPARE(files.size(), 2);
|
QCOMPARE(files.size(), 2);
|
||||||
@@ -236,7 +236,7 @@ namespace BlackMiscTest
|
|||||||
|
|
||||||
CValueCache cache2(CValueCache::LocalOnly);
|
CValueCache cache2(CValueCache::LocalOnly);
|
||||||
status = cache2.loadFromFiles(dir.absolutePath());
|
status = cache2.loadFromFiles(dir.absolutePath());
|
||||||
QVERIFY(status.isEmpty());
|
QVERIFY(status.isSuccess());
|
||||||
QCOMPARE(cache2.getAllValues(), testData);
|
QCOMPARE(cache2.getAllValues(), testData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user