implement a logging framework
This commit is contained in:
parent
e605a41c37
commit
240c5e36d6
@ -903,7 +903,7 @@ void DeviceManager::slotDeviceStateValueChanged(const QUuid &stateTypeId, const
|
||||
emit deviceStateChanged(device, stateTypeId, value);
|
||||
|
||||
Param valueParam("value", value);
|
||||
Event event(EventTypeId(stateTypeId.toString()), device->id(), ParamList() << valueParam);
|
||||
Event event(EventTypeId(stateTypeId.toString()), device->id(), ParamList() << valueParam, true);
|
||||
emit eventTriggered(event);
|
||||
}
|
||||
|
||||
|
||||
@ -41,6 +41,14 @@ Action::Action(const ActionTypeId &actionTypeId, const DeviceId &deviceId) :
|
||||
{
|
||||
}
|
||||
|
||||
Action::Action(const Action &other):
|
||||
m_id(other.id()),
|
||||
m_actionTypeId(other.actionTypeId()),
|
||||
m_deviceId(other.deviceId()),
|
||||
m_params(other.params())
|
||||
{
|
||||
}
|
||||
|
||||
/*! Returns the actionId for this Action. */
|
||||
ActionId Action::id() const
|
||||
{
|
||||
@ -88,3 +96,10 @@ Param Action::param(const QString ¶mName) const
|
||||
}
|
||||
return Param(QString());
|
||||
}
|
||||
|
||||
void Action::operator =(const Action &other)
|
||||
{
|
||||
m_id = other.id();
|
||||
m_actionTypeId = other.actionTypeId();
|
||||
m_params = other.params();
|
||||
}
|
||||
|
||||
@ -27,7 +27,8 @@
|
||||
class Action
|
||||
{
|
||||
public:
|
||||
explicit Action(const ActionTypeId &actionTypeId, const DeviceId &deviceId);
|
||||
explicit Action(const ActionTypeId &actionTypeId = ActionTypeId(), const DeviceId &deviceId = DeviceId());
|
||||
Action(const Action &other);
|
||||
|
||||
ActionId id() const;
|
||||
|
||||
@ -40,6 +41,7 @@ public:
|
||||
void setParams(const ParamList ¶ms);
|
||||
Param param(const QString ¶mName) const;
|
||||
|
||||
void operator=(const Action &other);
|
||||
private:
|
||||
ActionId m_id;
|
||||
ActionTypeId m_actionTypeId;
|
||||
|
||||
@ -42,11 +42,12 @@ Event::Event():
|
||||
/*! Constructs an Event reflecting the \l{Event} given by \a eventTypeId, associated with
|
||||
* the \l{Device} given by \a deviceId and the parameters given by \a params. The parameters must
|
||||
* match the description in the reflecting \l{Event}. */
|
||||
Event::Event(const EventTypeId &eventTypeId, const DeviceId &deviceId, const ParamList ¶ms):
|
||||
Event::Event(const EventTypeId &eventTypeId, const DeviceId &deviceId, const ParamList ¶ms, bool isStateChangeEvent):
|
||||
m_id(EventId::createEventId()),
|
||||
m_eventTypeId(eventTypeId),
|
||||
m_deviceId(deviceId),
|
||||
m_params(params)
|
||||
m_params(params),
|
||||
m_isStateChangeEvent(isStateChangeEvent)
|
||||
{
|
||||
}
|
||||
|
||||
@ -104,6 +105,12 @@ Param Event::param(const QString ¶mName) const
|
||||
return Param(QString());
|
||||
}
|
||||
|
||||
/*! Returns true if this event is autogenerated by a state change. */
|
||||
bool Event::isStateChangeEvent() const
|
||||
{
|
||||
return m_isStateChangeEvent;
|
||||
}
|
||||
|
||||
/*! Compare this Event to the Event given by \a other.
|
||||
* Events are equal (returns true) if eventTypeId, deviceId and params match. */
|
||||
bool Event::operator ==(const Event &other) const
|
||||
|
||||
@ -30,7 +30,7 @@ class Event
|
||||
{
|
||||
public:
|
||||
Event();
|
||||
Event(const EventTypeId &eventTypeId, const DeviceId &deviceId, const ParamList ¶ms = ParamList());
|
||||
Event(const EventTypeId &eventTypeId, const DeviceId &deviceId, const ParamList ¶ms = ParamList(), bool isStateChangeEvent = false);
|
||||
|
||||
EventId eventId() const;
|
||||
|
||||
@ -46,11 +46,15 @@ public:
|
||||
|
||||
bool operator ==(const Event &other) const;
|
||||
|
||||
bool isStateChangeEvent() const;
|
||||
|
||||
private:
|
||||
EventId m_id;
|
||||
EventTypeId m_eventTypeId;
|
||||
DeviceId m_deviceId;
|
||||
ParamList m_params;
|
||||
|
||||
bool m_isStateChangeEvent;
|
||||
};
|
||||
Q_DECLARE_METATYPE(Event)
|
||||
QDebug operator<<(QDebug dbg, const Event &event);
|
||||
|
||||
@ -277,7 +277,6 @@ void DevicePluginElro::radioData(const QList<int> &rawData)
|
||||
DeviceClass deviceClass = supportedDevices().first();
|
||||
foreach (const EventType &eventType, deviceClass.eventTypes()) {
|
||||
if (eventType.name() == button) {
|
||||
qDebug() << "got event: " << pluginName() << group << "power = " << power;
|
||||
Event event = Event(eventType.id(), device->id(), params);
|
||||
emit emitEvent(event);
|
||||
return;
|
||||
|
||||
@ -60,6 +60,7 @@
|
||||
#include "guhcore.h"
|
||||
#include "jsonrpcserver.h"
|
||||
#include "ruleengine.h"
|
||||
#include "logging/logengine.h"
|
||||
|
||||
#include "devicemanager.h"
|
||||
#include "plugin/device.h"
|
||||
@ -80,6 +81,7 @@ GuhCore *GuhCore::instance()
|
||||
/*! Destructor of the \l{GuhCore}. */
|
||||
GuhCore::~GuhCore()
|
||||
{
|
||||
m_logger->logSystemEvent(false);
|
||||
qDebug() << "Shutting down. Bye.";
|
||||
}
|
||||
|
||||
@ -182,7 +184,15 @@ DeviceManager::DeviceError GuhCore::confirmPairing(const PairingTransactionId &p
|
||||
* \sa DeviceManager::executeAction(), */
|
||||
DeviceManager::DeviceError GuhCore::executeAction(const Action &action)
|
||||
{
|
||||
return m_deviceManager->executeAction(action);
|
||||
DeviceManager::DeviceError ret = m_deviceManager->executeAction(action);
|
||||
if (ret == DeviceManager::DeviceErrorNoError) {
|
||||
m_logger->logAction(action);
|
||||
} else if (ret == DeviceManager::DeviceErrorAsync) {
|
||||
m_pendingActions.insert(action.id(), action);
|
||||
} else {
|
||||
m_logger->logAction(action, Logging::LoggingLevelAlert, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! Calls the metheod DeviceManager::findDeviceClass(\a deviceClassId).
|
||||
@ -307,6 +317,8 @@ GuhCore::GuhCore(QObject *parent) :
|
||||
qDebug() << "* GUH version:" << GUH_VERSION_STRING << "starting up. *";
|
||||
qDebug() << "*****************************************";
|
||||
|
||||
m_logger = new LogEngine(this);
|
||||
|
||||
qDebug() << "*****************************************";
|
||||
qDebug() << "* Creating Device Manager *";
|
||||
qDebug() << "*****************************************";
|
||||
@ -324,22 +336,39 @@ GuhCore::GuhCore(QObject *parent) :
|
||||
|
||||
connect(m_deviceManager, &DeviceManager::eventTriggered, this, &GuhCore::gotEvent);
|
||||
connect(m_deviceManager, &DeviceManager::deviceStateChanged, this, &GuhCore::deviceStateChanged);
|
||||
connect(m_deviceManager, &DeviceManager::actionExecutionFinished, this, &GuhCore::actionExecuted);
|
||||
connect(m_deviceManager, &DeviceManager::actionExecutionFinished, this, &GuhCore::actionExecutionFinished);
|
||||
|
||||
connect(m_deviceManager, &DeviceManager::devicesDiscovered, this, &GuhCore::devicesDiscovered);
|
||||
connect(m_deviceManager, &DeviceManager::deviceSetupFinished, this, &GuhCore::deviceSetupFinished);
|
||||
connect(m_deviceManager, &DeviceManager::pairingFinished, this, &GuhCore::pairingFinished);
|
||||
|
||||
m_logger->logSystemEvent(true);
|
||||
}
|
||||
|
||||
/*! Connected to the DeviceManager's emitEvent signal. Events received in
|
||||
here will be evaluated by the \l{RuleEngine} and the according \l{Action}{Actions} are executed.*/
|
||||
void GuhCore::gotEvent(const Event &event)
|
||||
{
|
||||
// first inform other things about it.
|
||||
m_logger->logEvent(event);
|
||||
emit eventTriggered(event);
|
||||
|
||||
// Now execute all the associated rules
|
||||
foreach (const Action &action, m_ruleEngine->evaluateEvent(event)) {
|
||||
QList<Action> actions;
|
||||
foreach (const Rule &rule, m_ruleEngine->evaluateEvent(event)) {
|
||||
if (rule.eventDescriptors().count() > 0) {
|
||||
m_logger->logRuleTriggered(rule);
|
||||
actions.append(rule.actions());
|
||||
} else {
|
||||
m_logger->logRuleActiveChanged(rule);
|
||||
if (rule.active()) {
|
||||
actions.append(rule.actions());
|
||||
} else {
|
||||
// TODO: execute state exit actions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now execute all the associated actions
|
||||
foreach (const Action &action, actions) {
|
||||
qDebug() << "executing action" << action.actionTypeId();
|
||||
DeviceManager::DeviceError status = m_deviceManager->executeAction(action);
|
||||
switch(status) {
|
||||
@ -356,3 +385,15 @@ void GuhCore::gotEvent(const Event &event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogEngine* GuhCore::logEngine() const
|
||||
{
|
||||
return m_logger;
|
||||
}
|
||||
|
||||
void GuhCore::actionExecutionFinished(const ActionId &id, DeviceManager::DeviceError status)
|
||||
{
|
||||
emit actionExecuted(id, status);
|
||||
Action action = m_pendingActions.take(id);
|
||||
m_logger->logAction(action, status == DeviceManager::DeviceErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, status);
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
|
||||
class JsonRPCServer;
|
||||
class Device;
|
||||
class LogEngine;
|
||||
|
||||
class GuhCore : public QObject
|
||||
{
|
||||
@ -72,6 +73,8 @@ public:
|
||||
RuleEngine::RuleError enableRule(const RuleId &ruleId);
|
||||
RuleEngine::RuleError disableRule(const RuleId &ruleId);
|
||||
|
||||
LogEngine* logEngine() const;
|
||||
|
||||
signals:
|
||||
void eventTriggered(const Event &event);
|
||||
void deviceStateChanged(Device *device, const QUuid &stateTypeId, const QVariant &value);
|
||||
@ -91,8 +94,12 @@ private:
|
||||
DeviceManager *m_deviceManager;
|
||||
RuleEngine *m_ruleEngine;
|
||||
|
||||
LogEngine *m_logger;
|
||||
|
||||
QHash<ActionId, Action> m_pendingActions;
|
||||
private slots:
|
||||
void gotEvent(const Event &event);
|
||||
void actionExecutionFinished(const ActionId &id, DeviceManager::DeviceError status);
|
||||
|
||||
friend class GuhTestBase;
|
||||
};
|
||||
|
||||
@ -74,6 +74,7 @@ JsonReply* ActionHandler::ExecuteAction(const QVariantMap ¶ms)
|
||||
|
||||
JsonReply *ActionHandler::GetActionType(const QVariantMap ¶ms) const
|
||||
{
|
||||
qDebug() << "asked for action type" << params;
|
||||
ActionTypeId actionTypeId(params.value("actionTypeId").toString());
|
||||
foreach (const DeviceClass &deviceClass, GuhCore::instance()->supportedDevices()) {
|
||||
foreach (const ActionType &actionType, deviceClass.actionTypes()) {
|
||||
|
||||
@ -146,6 +146,12 @@ QVariantMap JsonHandler::statusToReply(RuleEngine::RuleError status) const
|
||||
return returns;
|
||||
}
|
||||
|
||||
QVariantMap JsonHandler::statusToReply(Logging::LoggingError status) const
|
||||
{
|
||||
QVariantMap returns;
|
||||
returns.insert("loggingError", JsonTypes::loggingErrorToString(status));
|
||||
return returns;
|
||||
}
|
||||
|
||||
JsonReply::JsonReply(Type type, JsonHandler *handler, const QString &method, const QVariantMap &data):
|
||||
m_type(type),
|
||||
|
||||
@ -105,6 +105,7 @@ protected:
|
||||
JsonReply *createAsyncReply(const QString &method) const;
|
||||
QVariantMap statusToReply(DeviceManager::DeviceError status) const;
|
||||
QVariantMap statusToReply(RuleEngine::RuleError status) const;
|
||||
QVariantMap statusToReply(Logging::LoggingError status) const;
|
||||
|
||||
private:
|
||||
QHash<QString, QString> m_descriptions;
|
||||
|
||||
@ -38,11 +38,13 @@
|
||||
#include "actionhandler.h"
|
||||
#include "ruleshandler.h"
|
||||
#include "eventhandler.h"
|
||||
#include "logginghandler.h"
|
||||
#include "statehandler.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QStringList>
|
||||
|
||||
#define JSON_PROTOCOL_VERSION 10
|
||||
#define JSON_PROTOCOL_VERSION 11
|
||||
|
||||
JsonRPCServer::JsonRPCServer(QObject *parent):
|
||||
JsonHandler(parent),
|
||||
@ -140,6 +142,8 @@ void JsonRPCServer::setup()
|
||||
registerHandler(new ActionHandler(this));
|
||||
registerHandler(new RulesHandler(this));
|
||||
registerHandler(new EventHandler(this));
|
||||
registerHandler(new LoggingHandler(this));
|
||||
registerHandler(new StateHandler(this));
|
||||
}
|
||||
|
||||
void JsonRPCServer::processData(const QUuid &clientId, const QByteArray &jsonData)
|
||||
|
||||
@ -38,6 +38,10 @@ QVariantList JsonTypes::s_setupMethod;
|
||||
QVariantList JsonTypes::s_removePolicy;
|
||||
QVariantList JsonTypes::s_deviceError;
|
||||
QVariantList JsonTypes::s_ruleError;
|
||||
QVariantList JsonTypes::s_loggingError;
|
||||
QVariantList JsonTypes::s_loggingSource;
|
||||
QVariantList JsonTypes::s_loggingLevel;
|
||||
QVariantList JsonTypes::s_loggingEventType;
|
||||
|
||||
QVariantMap JsonTypes::s_paramType;
|
||||
QVariantMap JsonTypes::s_param;
|
||||
@ -57,6 +61,7 @@ QVariantMap JsonTypes::s_deviceClass;
|
||||
QVariantMap JsonTypes::s_device;
|
||||
QVariantMap JsonTypes::s_deviceDescriptor;
|
||||
QVariantMap JsonTypes::s_rule;
|
||||
QVariantMap JsonTypes::s_logEntry;
|
||||
|
||||
void JsonTypes::init()
|
||||
{
|
||||
@ -69,6 +74,10 @@ void JsonTypes::init()
|
||||
s_removePolicy = enumToStrings(RuleEngine::staticMetaObject, "RemovePolicy");
|
||||
s_deviceError = enumToStrings(DeviceManager::staticMetaObject, "DeviceError");
|
||||
s_ruleError = enumToStrings(RuleEngine::staticMetaObject, "RuleError");
|
||||
s_loggingError = enumToStrings(Logging::staticMetaObject, "LoggingError");
|
||||
s_loggingSource = enumToStrings(Logging::staticMetaObject, "LoggingSource");
|
||||
s_loggingLevel = enumToStrings(Logging::staticMetaObject, "LoggingLevel");
|
||||
s_loggingEventType = enumToStrings(Logging::staticMetaObject, "LoggingEventType");
|
||||
|
||||
// ParamType
|
||||
s_paramType.insert("name", basicTypeToString(String));
|
||||
@ -174,6 +183,17 @@ void JsonTypes::init()
|
||||
s_rule.insert("actions", QVariantList() << actionRef());
|
||||
s_rule.insert("stateEvaluator", stateEvaluatorRef());
|
||||
|
||||
// LogEntry
|
||||
s_logEntry.insert("timestamp", basicTypeToString(Int));
|
||||
s_logEntry.insert("loggingLevel", loggingLevelRef());
|
||||
s_logEntry.insert("source", loggingSourceRef());
|
||||
s_logEntry.insert("o:typeId", basicTypeToString(Uuid));
|
||||
s_logEntry.insert("o:deviceId", basicTypeToString(Uuid));
|
||||
s_logEntry.insert("o:value", basicTypeToString(String));
|
||||
s_logEntry.insert("o:active", basicTypeToString(Bool));
|
||||
s_logEntry.insert("o:eventType", loggingEventTypeRef());
|
||||
s_logEntry.insert("o:errorCode", basicTypeToString(String));
|
||||
|
||||
s_initialized = true;
|
||||
}
|
||||
|
||||
@ -207,6 +227,11 @@ QVariantMap JsonTypes::allTypes()
|
||||
allTypes.insert("RemovePolicy", removePolicy());
|
||||
allTypes.insert("DeviceError", deviceError());
|
||||
allTypes.insert("RuleError", ruleError());
|
||||
allTypes.insert("LoggingError", loggingError());
|
||||
allTypes.insert("LoggingLevel", loggingLevel());
|
||||
allTypes.insert("LoggingSource", loggingSource());
|
||||
allTypes.insert("LoggingEventType", loggingEventType());
|
||||
|
||||
allTypes.insert("StateType", stateTypeDescription());
|
||||
allTypes.insert("StateDescriptor", stateDescriptorDescription());
|
||||
allTypes.insert("StateEvaluator", stateEvaluatorDescription());
|
||||
@ -224,6 +249,7 @@ QVariantMap JsonTypes::allTypes()
|
||||
allTypes.insert("DeviceDescriptor", deviceDescriptorDescription());
|
||||
allTypes.insert("Action", actionDescription());
|
||||
allTypes.insert("Rule", ruleDescription());
|
||||
allTypes.insert("LogEntry", logEntryDescription());
|
||||
return allTypes;
|
||||
}
|
||||
|
||||
@ -461,12 +487,58 @@ QVariantMap JsonTypes::packRule(const Rule &rule)
|
||||
actionList.append(JsonTypes::packAction(action));
|
||||
}
|
||||
ruleMap.insert("actions", actionList);
|
||||
qDebug() << "packing state evaluator";
|
||||
ruleMap.insert("stateEvaluator", JsonTypes::packStateEvaluator(rule.stateEvaluator()));
|
||||
qDebug() << "done p se";
|
||||
return ruleMap;
|
||||
}
|
||||
|
||||
QVariantMap JsonTypes::packLogEntry(const LogEntry &logEntry)
|
||||
{
|
||||
QVariantMap logEntryMap;
|
||||
logEntryMap.insert("timestamp", logEntry.timestamp().toMSecsSinceEpoch());
|
||||
logEntryMap.insert("loggingLevel", s_loggingLevel.at(logEntry.level()));
|
||||
logEntryMap.insert("source", s_loggingSource.at(logEntry.source()));
|
||||
logEntryMap.insert("eventType", s_loggingEventType.at(logEntry.eventType()));
|
||||
|
||||
if (logEntry.eventType() == Logging::LoggingEventTypeActiveChange) {
|
||||
logEntryMap.insert("active", logEntry.active());
|
||||
}
|
||||
|
||||
if (logEntry.level() == Logging::LoggingLevelAlert) {
|
||||
switch (logEntry.source()) {
|
||||
case Logging::LoggingSourceRules:
|
||||
logEntryMap.insert("errorCode", s_ruleError.at(logEntry.errorCode()));
|
||||
break;
|
||||
case Logging::LoggingSourceActions:
|
||||
case Logging::LoggingSourceEvents:
|
||||
case Logging::LoggingSourceStates:
|
||||
logEntryMap.insert("errorCode", s_deviceError.at(logEntry.errorCode()));
|
||||
break;
|
||||
case Logging::LoggingSourceSystem:
|
||||
// FIXME: Update this once we support error codes for the general system
|
||||
// logEntryMap.insert("errorCode", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (logEntry.source()) {
|
||||
case Logging::LoggingSourceActions:
|
||||
case Logging::LoggingSourceEvents:
|
||||
case Logging::LoggingSourceStates:
|
||||
logEntryMap.insert("typeId", logEntry.typeId().toString());
|
||||
logEntryMap.insert("deviceId", logEntry.deviceId().toString());
|
||||
logEntryMap.insert("value", logEntry.value());
|
||||
break;
|
||||
case Logging::LoggingSourceSystem:
|
||||
logEntryMap.insert("active", logEntry.active());
|
||||
break;
|
||||
case Logging::LoggingSourceRules:
|
||||
logEntryMap.insert("typeId", logEntry.typeId().toString());
|
||||
break;
|
||||
}
|
||||
|
||||
return logEntryMap;
|
||||
}
|
||||
|
||||
QVariantList JsonTypes::packCreateMethods(DeviceClass::CreateMethods createMethods)
|
||||
{
|
||||
QVariantList ret;
|
||||
@ -748,6 +820,12 @@ QPair<bool, QString> JsonTypes::validateVariant(const QVariant &templateVariant,
|
||||
qDebug() << "evendescriptor not matching";
|
||||
return result;
|
||||
}
|
||||
} else if (refName == logEntryRef()) {
|
||||
QPair<bool, QString> result = validateMap(logEntryDescription(), variant.toMap());
|
||||
if (!result.first) {
|
||||
qDebug() << "logEntry not matching";
|
||||
return result;
|
||||
}
|
||||
} else if (refName == basicTypeRef()) {
|
||||
QPair<bool, QString> result = validateBasicType(variant);
|
||||
if (!result.first) {
|
||||
@ -755,41 +833,65 @@ QPair<bool, QString> JsonTypes::validateVariant(const QVariant &templateVariant,
|
||||
return result;
|
||||
}
|
||||
} else if (refName == stateOperatorRef()) {
|
||||
QPair<bool, QString> result = validateStateOperator(variant);
|
||||
QPair<bool, QString> result = validateEnum(s_stateOperator, variant);
|
||||
if (!result.first) {
|
||||
qDebug() << "value not allowed in" << stateOperatorRef();
|
||||
return result;
|
||||
}
|
||||
} else if (refName == createMethodRef()) {
|
||||
QPair<bool, QString> result = validateCreateMethod(variant);
|
||||
QPair<bool, QString> result = validateEnum(s_createMethod, variant);
|
||||
if (!result.first) {
|
||||
qDebug() << "value not allowed in" << createMethodRef() << variant;
|
||||
return result;
|
||||
}
|
||||
} else if (refName == setupMethodRef()) {
|
||||
QPair<bool, QString> result = validateSetupMethod(variant);
|
||||
QPair<bool, QString> result = validateEnum(s_setupMethod, variant);
|
||||
if (!result.first) {
|
||||
qDebug() << "value not allowed in" << createMethodRef();
|
||||
return result;
|
||||
}
|
||||
} else if (refName == valueOperatorRef()) {
|
||||
QPair<bool, QString> result = validateValueOperator(variant);
|
||||
QPair<bool, QString> result = validateEnum(s_valueOperator, variant);
|
||||
if (!result.first) {
|
||||
qDebug() << QString("value %1 not allowed in %2").arg(variant.toString()).arg(valueOperatorRef());
|
||||
return result;
|
||||
}
|
||||
} else if (refName == deviceErrorRef()) {
|
||||
QPair<bool, QString> result = validateDeviceError(variant);
|
||||
QPair<bool, QString> result = validateEnum(s_deviceError, variant);
|
||||
if (!result.first) {
|
||||
qDebug() << QString("value %1 not allowed in %2").arg(variant.toString()).arg(deviceErrorRef());
|
||||
return result;
|
||||
}
|
||||
} else if (refName == ruleErrorRef()) {
|
||||
QPair<bool, QString> result = validateRuleError(variant);
|
||||
QPair<bool, QString> result = validateEnum(s_ruleError, variant);
|
||||
if (!result.first) {
|
||||
qDebug() << QString("value %1 not allowed in %2").arg(variant.toString()).arg(ruleErrorRef());
|
||||
return result;
|
||||
}
|
||||
} else if (refName == loggingErrorRef()) {
|
||||
QPair<bool, QString> result = validateEnum(s_loggingError, variant);
|
||||
if (!result.first) {
|
||||
qDebug() << QString("value %1 not allowed in %2").arg(variant.toString()).arg(loggingErrorRef());
|
||||
return result;
|
||||
}
|
||||
} else if (refName == loggingSourceRef()) {
|
||||
QPair<bool, QString> result = validateEnum(s_loggingSource, variant);
|
||||
if (!result.first) {
|
||||
qDebug() << QString("value %1 not allowed in %2").arg(variant.toString()).arg(loggingSourceRef());
|
||||
return result;
|
||||
}
|
||||
} else if (refName == loggingLevelRef()) {
|
||||
QPair<bool, QString> result = validateEnum(s_loggingLevel, variant);
|
||||
if (!result.first) {
|
||||
qDebug() << QString("value %1 not allowed in %2").arg(variant.toString()).arg(loggingLevelRef());
|
||||
return result;
|
||||
}
|
||||
} else if (refName == loggingEventTypeRef()) {
|
||||
QPair<bool, QString> result = validateEnum(s_loggingEventType, variant);
|
||||
if (!result.first) {
|
||||
qDebug() << QString("value %1 not allowed in %2").arg(variant.toString()).arg(loggingEventTypeRef());
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
Q_ASSERT_X(false, "JsonTypes", QString("Unhandled ref: %1").arg(refName).toLatin1().data());
|
||||
return report(false, QString("Unhandled ref %1. Server implementation incomplete.").arg(refName));
|
||||
@ -844,32 +946,12 @@ QPair<bool, QString> JsonTypes::validateBasicType(const QVariant &variant)
|
||||
return report(false, QString("Error validating basic type %1.").arg(variant.toString()));
|
||||
}
|
||||
|
||||
QPair<bool, QString> JsonTypes::validateStateOperator(const QVariant &variant)
|
||||
QPair<bool, QString> JsonTypes::validateEnum(const QVariantList &enumDescription, const QVariant &value)
|
||||
{
|
||||
return report(s_stateOperator.contains(variant.toString()), QString("Unknown state operator %1").arg(variant.toString()));
|
||||
}
|
||||
QStringList enumStrings;
|
||||
foreach (const QVariant &variant, enumDescription) {
|
||||
enumStrings.append(variant.toString());
|
||||
}
|
||||
|
||||
QPair<bool, QString> JsonTypes::validateCreateMethod(const QVariant &variant)
|
||||
{
|
||||
return report(s_createMethod.contains(variant.toString()), QString("Unknwon createMethod type %1").arg(variant.toString()));
|
||||
}
|
||||
|
||||
QPair<bool, QString> JsonTypes::validateSetupMethod(const QVariant &variant)
|
||||
{
|
||||
return report(s_setupMethod.contains(variant.toString()), QString("Unknwon SetupMethod: %1").arg(variant.toString()));
|
||||
}
|
||||
|
||||
QPair<bool, QString> JsonTypes::validateValueOperator(const QVariant &variant)
|
||||
{
|
||||
return report(s_valueOperator.contains(variant.toString()), QString("Unknown ValueOperator: %1").arg(variant.toString()));
|
||||
}
|
||||
|
||||
QPair<bool, QString> JsonTypes::validateDeviceError(const QVariant &variant)
|
||||
{
|
||||
return report(s_deviceError.contains(variant.toString()), QString("Unknown DeviceError: %1").arg(variant.toString()));
|
||||
}
|
||||
|
||||
QPair<bool, QString> JsonTypes::validateRuleError(const QVariant &variant)
|
||||
{
|
||||
return report(s_ruleError.contains(variant.toString()), QString("Unknown RuleError: %1").arg(variant.toString()));
|
||||
return report(enumDescription.contains(value.toString()), QString("Value %1 not allowed in %2").arg(value.toString()).arg(enumStrings.join(", ")));
|
||||
}
|
||||
|
||||
@ -31,6 +31,9 @@
|
||||
#include "types/paramtype.h"
|
||||
#include "types/paramdescriptor.h"
|
||||
|
||||
#include "logging/logging.h"
|
||||
#include "logging/logentry.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <QVariantMap>
|
||||
@ -94,6 +97,10 @@ public:
|
||||
DECLARE_TYPE(deviceError, "DeviceError", DeviceManager, DeviceError)
|
||||
DECLARE_TYPE(removePolicy, "RemovePolicy", RuleEngine, RemovePolicy)
|
||||
DECLARE_TYPE(ruleError, "RuleError", RuleEngine, RuleError)
|
||||
DECLARE_TYPE(loggingError, "LoggingError", Logging, LoggingError)
|
||||
DECLARE_TYPE(loggingSource, "LoggingSource", Logging, LoggingSource)
|
||||
DECLARE_TYPE(loggingLevel, "LoggingLevel", Logging, LoggingLevel)
|
||||
DECLARE_TYPE(loggingEventType, "LoggingEventType", Logging, LoggingEventType)
|
||||
DECLARE_OBJECT(paramType, "ParamType")
|
||||
DECLARE_OBJECT(param, "Param")
|
||||
DECLARE_OBJECT(paramDescriptor, "ParamDescriptor")
|
||||
@ -112,6 +119,7 @@ public:
|
||||
DECLARE_OBJECT(device, "Device")
|
||||
DECLARE_OBJECT(deviceDescriptor, "DeviceDescriptor")
|
||||
DECLARE_OBJECT(rule, "Rule")
|
||||
DECLARE_OBJECT(logEntry, "LogEntry")
|
||||
|
||||
static QVariantMap packEventType(const EventType &eventType);
|
||||
static QVariantMap packEvent(const Event &event);
|
||||
@ -130,6 +138,7 @@ public:
|
||||
static QVariantMap packDevice(Device *device);
|
||||
static QVariantMap packDeviceDescriptor(const DeviceDescriptor &descriptor);
|
||||
static QVariantMap packRule(const Rule &rule);
|
||||
static QVariantMap packLogEntry(const LogEntry &logEntry);
|
||||
static QVariantList packCreateMethods(DeviceClass::CreateMethods createMethods);
|
||||
|
||||
static Param unpackParam(const QVariantMap ¶mMap);
|
||||
@ -144,13 +153,8 @@ public:
|
||||
static QPair<bool, QString> validateProperty(const QVariant &templateValue, const QVariant &value);
|
||||
static QPair<bool, QString> validateList(const QVariantList &templateList, const QVariantList &list);
|
||||
static QPair<bool, QString> validateVariant(const QVariant &templateVariant, const QVariant &variant);
|
||||
static QPair<bool, QString> validateEnum(const QVariantList &enumList, const QVariant &value);
|
||||
static QPair<bool, QString> validateBasicType(const QVariant &variant);
|
||||
static QPair<bool, QString> validateStateOperator(const QVariant &variant);
|
||||
static QPair<bool, QString> validateCreateMethod(const QVariant &variant);
|
||||
static QPair<bool, QString> validateSetupMethod(const QVariant &variant);
|
||||
static QPair<bool, QString> validateValueOperator(const QVariant &variant);
|
||||
static QPair<bool, QString> validateDeviceError(const QVariant &variant);
|
||||
static QPair<bool, QString> validateRuleError(const QVariant &variant);
|
||||
|
||||
private:
|
||||
static bool s_initialized;
|
||||
|
||||
69
server/jsonrpc/logginghandler.cpp
Normal file
69
server/jsonrpc/logginghandler.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* Guh is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "logginghandler.h"
|
||||
#include "logging/logengine.h"
|
||||
#include "guhcore.h"
|
||||
|
||||
LoggingHandler::LoggingHandler(QObject *parent) :
|
||||
JsonHandler(parent)
|
||||
{
|
||||
QVariantMap params;
|
||||
QVariantMap returns;
|
||||
|
||||
// Notifications
|
||||
params.clear(); returns.clear();
|
||||
setDescription("LogEntryAdded", "Emitted whenever an entry is appended to the logging system.");
|
||||
params.insert("logEntry", JsonTypes::logEntryRef());
|
||||
setParams("LogEntryAdded", params);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
setDescription("GetLogEntries", "Get the LogEntries matching the given filter.");
|
||||
// params.insert("eventTypeId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
|
||||
setParams("GetLogEntries", params);
|
||||
returns.insert("loggingError", JsonTypes::loggingErrorRef());
|
||||
returns.insert("o:logEntries", QVariantList() << JsonTypes::logEntryRef());
|
||||
setReturns("GetLogEntries", returns);
|
||||
|
||||
connect(GuhCore::instance()->logEngine(), &LogEngine::logEntryAdded, this, &LoggingHandler::logEntryAdded);
|
||||
}
|
||||
|
||||
QString LoggingHandler::name() const
|
||||
{
|
||||
return "Logging";
|
||||
}
|
||||
|
||||
void LoggingHandler::logEntryAdded(const LogEntry &logEntry)
|
||||
{
|
||||
QVariantMap params;
|
||||
params.insert("logEntry", JsonTypes::packLogEntry(logEntry));
|
||||
emit LogEntryAdded(params);
|
||||
}
|
||||
|
||||
JsonReply* LoggingHandler::GetLogEntries(const QVariantMap ¶ms) const
|
||||
{
|
||||
Q_UNUSED(params)
|
||||
|
||||
QVariantList entries;
|
||||
foreach (const LogEntry &entry, GuhCore::instance()->logEngine()->logEntries()) {
|
||||
entries.append(JsonTypes::packLogEntry(entry));
|
||||
}
|
||||
QVariantMap returns = statusToReply(Logging::LoggingErrorNoError);
|
||||
returns.insert("logEntries", entries);
|
||||
return createReply(returns);
|
||||
}
|
||||
40
server/jsonrpc/logginghandler.h
Normal file
40
server/jsonrpc/logginghandler.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* Guh is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef LOGGINGHANDLER_H
|
||||
#define LOGGINGHANDLER_H
|
||||
|
||||
#include "jsonhandler.h"
|
||||
#include "logging/logentry.h"
|
||||
|
||||
class LoggingHandler : public JsonHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LoggingHandler(QObject *parent = 0);
|
||||
QString name() const override;
|
||||
|
||||
Q_INVOKABLE JsonReply *GetLogEntries(const QVariantMap ¶ms) const;
|
||||
signals:
|
||||
void LogEntryAdded(const QVariantMap ¶ms);
|
||||
|
||||
private slots:
|
||||
void logEntryAdded(const LogEntry &entry);
|
||||
};
|
||||
|
||||
#endif // LOGGINGHANDLER_H
|
||||
@ -39,7 +39,8 @@ RulesHandler::RulesHandler(QObject *parent) :
|
||||
setDescription("GetRuleDetails", "Get details for the rule identified by ruleId");
|
||||
params.insert("ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
|
||||
setParams("GetRuleDetails", params);
|
||||
returns.insert("rule", JsonTypes::ruleRef());
|
||||
returns.insert("o:rule", JsonTypes::ruleRef());
|
||||
returns.insert("ruleError", JsonTypes::ruleErrorRef());
|
||||
setReturns("GetRuleDetails", returns);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
@ -110,13 +111,12 @@ JsonReply *RulesHandler::GetRuleDetails(const QVariantMap ¶ms)
|
||||
{
|
||||
RuleId ruleId = RuleId(params.value("ruleId").toString());
|
||||
Rule rule = GuhCore::instance()->findRule(ruleId);
|
||||
QVariantMap ruleData;
|
||||
if (!rule.id().isNull()) {
|
||||
qDebug() << "packing rule";
|
||||
ruleData.insert("rule", JsonTypes::packRule(rule));
|
||||
qDebug() << "done packing";
|
||||
if (rule.id().isNull()) {
|
||||
return createReply(statusToReply(RuleEngine::RuleErrorRuleNotFound));
|
||||
}
|
||||
return createReply(ruleData);
|
||||
QVariantMap returns = statusToReply(RuleEngine::RuleErrorNoError);
|
||||
returns.insert("rule", JsonTypes::packRule(rule));
|
||||
return createReply(returns);
|
||||
}
|
||||
|
||||
JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms)
|
||||
@ -147,7 +147,9 @@ JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms)
|
||||
foreach (const QVariant &actionVariant, actionList) {
|
||||
QVariantMap actionMap = actionVariant.toMap();
|
||||
Action action(ActionTypeId(actionMap.value("actionTypeId").toString()), DeviceId(actionMap.value("deviceId").toString()));
|
||||
qDebug() << "params from json" << actionMap.value("params");
|
||||
action.setParams(JsonTypes::unpackParams(actionMap.value("params").toList()));
|
||||
qDebug() << "params in action" << action.params();
|
||||
actions.append(action);
|
||||
}
|
||||
|
||||
|
||||
55
server/jsonrpc/statehandler.cpp
Normal file
55
server/jsonrpc/statehandler.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* Guh is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "statehandler.h"
|
||||
#include "guhcore.h"
|
||||
|
||||
StateHandler::StateHandler(QObject *parent) :
|
||||
JsonHandler(parent)
|
||||
{
|
||||
QVariantMap params;
|
||||
QVariantMap returns;
|
||||
|
||||
params.clear(); returns.clear();
|
||||
setDescription("GetStateType", "Get the StateType for the given stateTypeId.");
|
||||
params.insert("stateTypeId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
|
||||
setParams("GetStateType", params);
|
||||
returns.insert("deviceError", JsonTypes::deviceErrorRef());
|
||||
returns.insert("o:stateType", JsonTypes::stateTypeRef());
|
||||
setReturns("GetStateType", returns);
|
||||
}
|
||||
|
||||
QString StateHandler::name() const
|
||||
{
|
||||
return "States";
|
||||
}
|
||||
|
||||
JsonReply* StateHandler::GetStateType(const QVariantMap ¶ms) const
|
||||
{
|
||||
StateTypeId stateTypeId(params.value("stateTypeId").toString());
|
||||
foreach (const DeviceClass &deviceClass, GuhCore::instance()->supportedDevices()) {
|
||||
foreach (const StateType &stateType, deviceClass.stateTypes()) {
|
||||
if (stateType.id() == stateTypeId) {
|
||||
QVariantMap data = statusToReply(DeviceManager::DeviceErrorNoError);
|
||||
data.insert("stateType", JsonTypes::packStateType(stateType));
|
||||
return createReply(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
return createReply(statusToReply(DeviceManager::DeviceErrorStateTypeNotFound));
|
||||
}
|
||||
34
server/jsonrpc/statehandler.h
Normal file
34
server/jsonrpc/statehandler.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* Guh is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef STATEHANDLER_H
|
||||
#define STATEHANDLER_H
|
||||
|
||||
#include "jsonhandler.h"
|
||||
|
||||
class StateHandler : public JsonHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit StateHandler(QObject *parent = 0);
|
||||
QString name() const override;
|
||||
|
||||
Q_INVOKABLE JsonReply *GetStateType(const QVariantMap ¶ms) const;
|
||||
};
|
||||
|
||||
#endif // EVENTHANDLER_H
|
||||
209
server/logging/logengine.cpp
Normal file
209
server/logging/logengine.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* Guh is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "logengine.h"
|
||||
#include "logging.h"
|
||||
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlError>
|
||||
#include <QMetaEnum>
|
||||
#include <QDateTime>
|
||||
|
||||
#define DB_SCHEMA_VERSION 1
|
||||
|
||||
LogEngine::LogEngine(QObject *parent):
|
||||
QObject(parent)
|
||||
{
|
||||
m_db = QSqlDatabase::addDatabase("QSQLITE");
|
||||
m_db.setDatabaseName("/tmp/guhd-logs.sqlite");
|
||||
if (!m_db.open()) {
|
||||
qWarning() << "Error opening log database:" << m_db.lastError().driverText() << m_db.lastError().databaseText();
|
||||
return;
|
||||
}
|
||||
|
||||
initDB();
|
||||
}
|
||||
|
||||
QList<LogEntry> LogEngine::logEntries() const
|
||||
{
|
||||
QList<LogEntry> results;
|
||||
QSqlQuery query;
|
||||
query.exec("SELECT * FROM entries;");
|
||||
while (query.next()) {
|
||||
LogEntry entry(
|
||||
QDateTime::fromMSecsSinceEpoch(query.value("timestamp").toLongLong()),
|
||||
(Logging::LoggingLevel)query.value("loggingLevel").toInt(),
|
||||
(Logging::LoggingSource)query.value("sourceType").toInt(),
|
||||
query.value("errorCode").toInt());
|
||||
entry.setTypeId(query.value("typeId").toUuid());
|
||||
entry.setDeviceId(DeviceId(query.value("deviceId").toString()));
|
||||
entry.setValue(query.value("value").toString());
|
||||
if ((Logging::LoggingEventType)query.value("loggingEventType").toInt() == Logging::LoggingEventTypeActiveChange) {
|
||||
entry.setActive(query.value("active").toBool());
|
||||
}
|
||||
results.append(entry);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
void LogEngine::logSystemEvent(bool active, Logging::LoggingLevel level)
|
||||
{
|
||||
LogEntry entry(level, Logging::LoggingSourceSystem);
|
||||
entry.setActive(active);
|
||||
appendLogEntry(entry);
|
||||
emit logEntryAdded(entry);
|
||||
}
|
||||
|
||||
void LogEngine::logEvent(const Event &event)
|
||||
{
|
||||
QStringList valueList;
|
||||
Logging::LoggingSource sourceType;
|
||||
if (event.isStateChangeEvent()) {
|
||||
sourceType = Logging::LoggingSourceStates;
|
||||
valueList << event.param("value").value().toString();
|
||||
} else {
|
||||
sourceType = Logging::LoggingSourceEvents;
|
||||
foreach (const Param ¶m, event.params()) {
|
||||
valueList << param.value().toString();
|
||||
}
|
||||
}
|
||||
LogEntry entry(sourceType);
|
||||
entry.setTypeId(event.eventTypeId());
|
||||
entry.setDeviceId(event.deviceId());
|
||||
entry.setValue(valueList.join(", "));
|
||||
appendLogEntry(entry);
|
||||
emit logEntryAdded(entry);
|
||||
}
|
||||
|
||||
void LogEngine::logAction(const Action &action, Logging::LoggingLevel level, int errorCode)
|
||||
{
|
||||
QStringList valueList;
|
||||
foreach (const Param ¶m, action.params()) {
|
||||
valueList << param.value().toString();
|
||||
}
|
||||
LogEntry entry(level, Logging::LoggingSourceActions, errorCode);
|
||||
entry.setTypeId(action.actionTypeId());
|
||||
entry.setDeviceId(action.deviceId());
|
||||
entry.setValue(valueList.join(", "));
|
||||
appendLogEntry(entry);
|
||||
emit logEntryAdded(entry);
|
||||
}
|
||||
|
||||
void LogEngine::logRuleTriggered(const Rule &rule)
|
||||
{
|
||||
LogEntry entry(Logging::LoggingSourceRules);
|
||||
entry.setTypeId(rule.id());
|
||||
appendLogEntry(entry);
|
||||
emit logEntryAdded(entry);
|
||||
}
|
||||
|
||||
void LogEngine::logRuleActiveChanged(const Rule &rule)
|
||||
{
|
||||
LogEntry entry(Logging::LoggingSourceRules);
|
||||
entry.setTypeId(rule.id());
|
||||
entry.setActive(rule.active());
|
||||
appendLogEntry(entry);
|
||||
emit logEntryAdded(entry);
|
||||
}
|
||||
|
||||
void LogEngine::appendLogEntry(const LogEntry &entry)
|
||||
{
|
||||
QString queryString = QString("INSERT INTO entries (timestamp, loggingEventType, loggingLevel, sourceType, typeId, deviceId, value, active, errorCode) values ('%1', '%2', '%3', '%4', '%5', '%6', '%7', '%8', '%9');")
|
||||
.arg(entry.timestamp().toMSecsSinceEpoch())
|
||||
.arg(entry.eventType())
|
||||
.arg(entry.level())
|
||||
.arg(entry.source())
|
||||
.arg(entry.typeId().toString())
|
||||
.arg(entry.deviceId().toString())
|
||||
.arg(entry.value())
|
||||
.arg(entry.active())
|
||||
.arg(entry.errorCode());
|
||||
|
||||
QSqlQuery query;
|
||||
query.exec(queryString);
|
||||
|
||||
if (query.lastError().isValid()) {
|
||||
qWarning() << "Error writing log entry. Driver error:" << query.lastError().driverText() << "Database error:" << query.lastError().databaseText();
|
||||
}
|
||||
}
|
||||
|
||||
void LogEngine::initDB()
|
||||
{
|
||||
m_db.close();
|
||||
m_db.open();
|
||||
|
||||
QSqlQuery query;
|
||||
|
||||
if (!m_db.tables().contains("metadata")) {
|
||||
query.exec("CREATE TABLE metadata (key varchar(10), data varchar(40));");
|
||||
query.exec(QString("INSERT INTO metadata (key, data) VALUES('version', '%1');").arg(DB_SCHEMA_VERSION));
|
||||
}
|
||||
|
||||
query.exec("SELECT data FROM metadata WHERE key = 'version';");
|
||||
if (query.next()) {
|
||||
int version = query.value("data").toInt();
|
||||
if (version != DB_SCHEMA_VERSION) {
|
||||
qWarning() << "Log schema version not matching! Schema upgrade not implemented yet. Logging might fail.";
|
||||
} else {
|
||||
qDebug() << "version matches";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Broken log database. Version not found in metadata table.";
|
||||
}
|
||||
|
||||
if (!m_db.tables().contains("sourceTypes")) {
|
||||
query.exec("CREATE TABLE sourceTypes (id int, name varchar(20), PRIMARY KEY(id));");
|
||||
qDebug() << query.lastError().databaseText();
|
||||
QMetaEnum logTypes = Logging::staticMetaObject.enumerator(Logging::staticMetaObject.indexOfEnumerator("LoggingSource"));
|
||||
Q_ASSERT_X(logTypes.isValid(), "LogEngine", "Logging has no enum LoggingSource");
|
||||
for (int i = 0; i < logTypes.keyCount(); i++) {
|
||||
query.exec(QString("INSERT INTO sourceTypes (id, name) VALUES(%1, '%2');").arg(i).arg(logTypes.key(i)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_db.tables().contains("loggingEventTypes")) {
|
||||
query.exec("CREATE TABLE loggingEventTypes (id int, name varchar(20), PRIMARY KEY(id));");
|
||||
qDebug() << query.lastError().databaseText();
|
||||
QMetaEnum logTypes = Logging::staticMetaObject.enumerator(Logging::staticMetaObject.indexOfEnumerator("LoggingEventType"));
|
||||
Q_ASSERT_X(logTypes.isValid(), "LogEngine", "Logging has no enum LoggingEventType");
|
||||
for (int i = 0; i < logTypes.keyCount(); i++) {
|
||||
query.exec(QString("INSERT INTO loggingEventTypes (id, name) VALUES(%1, '%2');").arg(i).arg(logTypes.key(i)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_db.tables().contains("entries")) {
|
||||
query.exec("CREATE TABLE entries "
|
||||
"("
|
||||
"timestamp int,"
|
||||
"loggingLevel int,"
|
||||
"sourceType int,"
|
||||
"typeId varchar(38),"
|
||||
"deviceId varchar(38),"
|
||||
"value varchar(100),"
|
||||
"loggingEventType int,"
|
||||
"active bool,"
|
||||
"errorCode int,"
|
||||
"FOREIGN KEY(sourceType) REFERENCES sourceTypes(id),"
|
||||
"FOREIGN KEY(loggingEventType) REFERENCES loggingEventTypes(id)"
|
||||
");");
|
||||
if (query.lastError().isValid()) {
|
||||
qWarning() << "Error creating log table in database. Driver error:" << query.lastError().driverText() << "Database error:" << query.lastError().databaseText();
|
||||
}
|
||||
}
|
||||
}
|
||||
57
server/logging/logengine.h
Normal file
57
server/logging/logengine.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* Guh is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef LOGENGINE_H
|
||||
#define LOGENGINE_H
|
||||
|
||||
#include "logentry.h"
|
||||
#include "types/event.h"
|
||||
#include "types/action.h"
|
||||
#include "rule.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
class LogEngine: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LogEngine(QObject *parent = 0);
|
||||
|
||||
QList<LogEntry> logEntries() const;
|
||||
|
||||
signals:
|
||||
void logEntryAdded(const LogEntry &logEntry);
|
||||
|
||||
private:
|
||||
// Only GuhCore is allowed to log events.
|
||||
friend class GuhCore;
|
||||
void logSystemEvent(bool active, Logging::LoggingLevel level = Logging::LoggingLevelInfo);
|
||||
void logEvent(const Event &event);
|
||||
void logAction(const Action &action, Logging::LoggingLevel level = Logging::LoggingLevelInfo, int errorCode = 0);
|
||||
void logRuleTriggered(const Rule &rule);
|
||||
void logRuleActiveChanged(const Rule &rule);
|
||||
|
||||
private:
|
||||
void initDB();
|
||||
void appendLogEntry(const LogEntry &entry);
|
||||
|
||||
QSqlDatabase m_db;
|
||||
};
|
||||
|
||||
#endif
|
||||
109
server/logging/logentry.cpp
Normal file
109
server/logging/logentry.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* Guh is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "logentry.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
LogEntry::LogEntry(QDateTime timestamp, Logging::LoggingLevel level, Logging::LoggingSource source, int errorCode):
|
||||
m_timestamp(timestamp),
|
||||
m_level(level),
|
||||
m_source(source),
|
||||
m_eventType(Logging::LoggingEventTypeTrigger),
|
||||
m_active(false),
|
||||
m_errorCode(errorCode)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LogEntry::LogEntry(Logging::LoggingLevel level, Logging::LoggingSource source, int errorCode):
|
||||
LogEntry(QDateTime::currentDateTime(), level, source, errorCode)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LogEntry::LogEntry(Logging::LoggingSource source):
|
||||
LogEntry(Logging::LoggingLevelInfo, source)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QDateTime LogEntry::timestamp() const
|
||||
{
|
||||
return m_timestamp;
|
||||
}
|
||||
|
||||
Logging::LoggingLevel LogEntry::level() const
|
||||
{
|
||||
return m_level;
|
||||
}
|
||||
|
||||
Logging::LoggingSource LogEntry::source() const
|
||||
{
|
||||
return m_source;
|
||||
}
|
||||
|
||||
QUuid LogEntry::typeId() const
|
||||
{
|
||||
return m_typeId;
|
||||
}
|
||||
|
||||
void LogEntry::setTypeId(const QUuid &typeId) {
|
||||
m_typeId = typeId;
|
||||
}
|
||||
|
||||
DeviceId LogEntry::deviceId() const
|
||||
{
|
||||
return m_deviceId;
|
||||
}
|
||||
|
||||
void LogEntry::setDeviceId(const DeviceId &deviceId)
|
||||
{
|
||||
m_deviceId = deviceId;
|
||||
}
|
||||
|
||||
QString LogEntry::value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void LogEntry::setValue(const QString &value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
Logging::LoggingEventType LogEntry::eventType() const
|
||||
{
|
||||
return m_eventType;
|
||||
}
|
||||
|
||||
bool LogEntry::active() const
|
||||
{
|
||||
return m_active;
|
||||
}
|
||||
|
||||
void LogEntry::setActive(bool active)
|
||||
{
|
||||
m_eventType = Logging::LoggingEventTypeActiveChange;
|
||||
m_active = active;
|
||||
}
|
||||
|
||||
int LogEntry::errorCode() const
|
||||
{
|
||||
return m_errorCode;
|
||||
}
|
||||
77
server/logging/logentry.h
Normal file
77
server/logging/logentry.h
Normal file
@ -0,0 +1,77 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* Guh is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef LOGENTRY_H
|
||||
#define LOGENTRY_H
|
||||
|
||||
#include "logging.h"
|
||||
#include "typeutils.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QDateTime>
|
||||
|
||||
class LogEntry
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
LogEntry(QDateTime timestamp, Logging::LoggingLevel level, Logging::LoggingSource source, int errorCode = 0);
|
||||
LogEntry(Logging::LoggingLevel level, Logging::LoggingSource source, int errorCode = 0);
|
||||
LogEntry(Logging::LoggingSource source);
|
||||
|
||||
// Valid for all LoggingSources
|
||||
QDateTime timestamp() const;
|
||||
Logging::LoggingLevel level() const;
|
||||
Logging::LoggingSource source() const;
|
||||
Logging::LoggingEventType eventType() const;
|
||||
|
||||
// Valid for LoggingSourceStates, LoggingSourceEvents, LoggingSourceActions, LoggingSourceRules
|
||||
QUuid typeId() const;
|
||||
void setTypeId(const QUuid &typeId);
|
||||
|
||||
// Valid for LoggingSourceStates, LoggingSourceEvents, LoggingSourceActions
|
||||
DeviceId deviceId() const;
|
||||
void setDeviceId(const DeviceId &deviceId);
|
||||
|
||||
// Valid for LoggingSourceStates
|
||||
QString value() const;
|
||||
void setValue(const QString &value);
|
||||
|
||||
// Valid for LoggingEventTypeActiveChanged
|
||||
bool active() const;
|
||||
void setActive(bool active);
|
||||
|
||||
// Valid for LoggingLevelAlert
|
||||
int errorCode() const;
|
||||
|
||||
private:
|
||||
QDateTime m_timestamp;
|
||||
Logging::LoggingLevel m_level;
|
||||
Logging::LoggingSource m_source;
|
||||
|
||||
// RuleSource specifiv properties.
|
||||
// FIXME: If it turns out we need many more of those, we should subclass LogEntry with specific ones.
|
||||
QUuid m_typeId;
|
||||
DeviceId m_deviceId;
|
||||
QString m_value;
|
||||
Logging::LoggingEventType m_eventType;
|
||||
bool m_active;
|
||||
int m_errorCode;
|
||||
};
|
||||
|
||||
#endif
|
||||
0
server/logging/logfilter.cpp
Normal file
0
server/logging/logfilter.cpp
Normal file
31
server/logging/logfilter.h
Normal file
31
server/logging/logfilter.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* Guh is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef LOGFILTER_H
|
||||
#define LOGFILTER_H
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
class LogFilter
|
||||
{
|
||||
QDateTime m_startDate;
|
||||
QDateTime m_endDate;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
58
server/logging/logging.h
Normal file
58
server/logging/logging.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* Guh is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef LOGGING_H
|
||||
#define LOGGING_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Logging
|
||||
{
|
||||
Q_GADGET
|
||||
Q_ENUMS(LoggingError)
|
||||
Q_ENUMS(LoggingSource)
|
||||
Q_FLAGS(LoggingSources)
|
||||
Q_ENUMS(LoggingLevel)
|
||||
Q_ENUMS(LoggingEventType)
|
||||
public:
|
||||
enum LoggingError {
|
||||
LoggingErrorNoError,
|
||||
LoggingErrorLogEntryNotFound
|
||||
};
|
||||
|
||||
enum LoggingSource {
|
||||
LoggingSourceSystem,
|
||||
LoggingSourceEvents,
|
||||
LoggingSourceActions,
|
||||
LoggingSourceStates,
|
||||
LoggingSourceRules
|
||||
};
|
||||
Q_DECLARE_FLAGS(LoggingSources, LoggingSource)
|
||||
|
||||
enum LoggingLevel {
|
||||
LoggingLevelInfo,
|
||||
LoggingLevelAlert
|
||||
};
|
||||
|
||||
enum LoggingEventType {
|
||||
LoggingEventTypeTrigger,
|
||||
LoggingEventTypeActiveChange
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
0
server/logging/logsource.cpp
Normal file
0
server/logging/logsource.cpp
Normal file
0
server/logging/logsource.h
Normal file
0
server/logging/logsource.h
Normal file
@ -51,9 +51,9 @@
|
||||
#include <QDebug>
|
||||
|
||||
/*! Constructs an empty, invalid rule. */
|
||||
Rule::Rule()
|
||||
Rule::Rule():
|
||||
Rule(RuleId(), QList<EventDescriptor>(), StateEvaluator(), QList<Action>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*! Constructs a Rule with the given \a id, \a eventDescriptorList, \a stateEvaluator and \a actions.*/
|
||||
@ -61,7 +61,9 @@ Rule::Rule(const RuleId &id, const QList<EventDescriptor> &eventDescriptorList,
|
||||
m_id(id),
|
||||
m_eventDescriptors(eventDescriptorList),
|
||||
m_stateEvaluator(stateEvaluator),
|
||||
m_actions(actions)
|
||||
m_actions(actions),
|
||||
m_enabled(false),
|
||||
m_active(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -100,3 +102,13 @@ void Rule::setEnabled(bool enabled)
|
||||
{
|
||||
m_enabled = enabled;
|
||||
}
|
||||
|
||||
bool Rule::active() const
|
||||
{
|
||||
return m_active;
|
||||
}
|
||||
|
||||
void Rule::setActive(bool active)
|
||||
{
|
||||
m_active = active;
|
||||
}
|
||||
|
||||
@ -40,6 +40,12 @@ public:
|
||||
bool enabled() const;
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
bool active() const;
|
||||
|
||||
private:
|
||||
friend class RuleEngine;
|
||||
void setActive(bool active);
|
||||
|
||||
private:
|
||||
RuleId m_id;
|
||||
QList<EventDescriptor> m_eventDescriptors;
|
||||
@ -47,6 +53,7 @@ private:
|
||||
QList<Action> m_actions;
|
||||
|
||||
bool m_enabled;
|
||||
bool m_active;
|
||||
};
|
||||
|
||||
#endif // RULE_H
|
||||
|
||||
@ -160,14 +160,15 @@ RuleEngine::RuleEngine(QObject *parent) :
|
||||
/*! Ask the Engine to evaluate all the rules for the given \a event.
|
||||
This will search all the \l{Rule}{Rules} triggered by the given \a event
|
||||
and evaluate their states in the system. It will return a
|
||||
list of all \l{Action}{Actions} that should be executed. */
|
||||
QList<Action> RuleEngine::evaluateEvent(const Event &event)
|
||||
list of all \l{Rule}{Rules} that are triggered or change its active state
|
||||
because of this \a event. */
|
||||
QList<Rule> RuleEngine::evaluateEvent(const Event &event)
|
||||
{
|
||||
Device *device = GuhCore::instance()->findConfiguredDevice(event.deviceId());
|
||||
|
||||
qDebug() << "got event:" << event << device->name() << event.eventTypeId();
|
||||
|
||||
QList<Action> actions;
|
||||
QList<Rule> rules;
|
||||
foreach (const RuleId &id, m_ruleIds) {
|
||||
Rule rule = m_rules.value(id);
|
||||
if (!rule.enabled()) {
|
||||
@ -182,11 +183,14 @@ QList<Action> RuleEngine::evaluateEvent(const Event &event)
|
||||
qDebug() << "Rule" << rule.id() << "still in active state.";
|
||||
} else {
|
||||
qDebug() << "Rule" << rule.id() << "entered active state.";
|
||||
rule.setActive(true);
|
||||
m_rules[rule.id()] = rule;
|
||||
m_activeRules.append(rule.id());
|
||||
actions.append(rule.actions());
|
||||
rules.append(rule);
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Rule" << rule.id() << "left active state.";
|
||||
m_rules[rule.id()].setActive(false);
|
||||
m_activeRules.removeAll(rule.id());
|
||||
}
|
||||
}
|
||||
@ -194,12 +198,12 @@ QList<Action> RuleEngine::evaluateEvent(const Event &event)
|
||||
if (containsEvent(rule, event)) {
|
||||
if (rule.stateEvaluator().evaluate()) {
|
||||
qDebug() << "Rule" << rule.id() << "contains event" << event.eventId() << "and all states match.";
|
||||
actions.append(rule.actions());
|
||||
rules.append(rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
return rules;
|
||||
}
|
||||
|
||||
/*! Add a new \l{Rule} with the given \a ruleId , \a eventDescriptorList and \a actions to the engine.
|
||||
@ -258,7 +262,9 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QList<Even
|
||||
return RuleErrorActionTypeNotFound;
|
||||
}
|
||||
}
|
||||
|
||||
if (actions.count() > 0) {
|
||||
qDebug() << "***** actions" << actions.last().actionTypeId() << actions.last().params();
|
||||
}
|
||||
Rule rule = Rule(ruleId, eventDescriptorList, stateEvaluator, actions);
|
||||
rule.setEnabled(enabled);
|
||||
appendRule(rule);
|
||||
|
||||
@ -51,7 +51,7 @@ public:
|
||||
|
||||
explicit RuleEngine(QObject *parent = 0);
|
||||
|
||||
QList<Action> evaluateEvent(const Event &event);
|
||||
QList<Rule> evaluateEvent(const Event &event);
|
||||
|
||||
RuleError addRule(const RuleId &ruleId, const QList<EventDescriptor> &eventDescriptorList, const QList<Action> &actions, bool enabled = true);
|
||||
RuleError addRule(const RuleId &ruleId, const QList<EventDescriptor> &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList<Action> &actions, bool enabled = true);
|
||||
|
||||
@ -9,7 +9,12 @@ SOURCES += $$top_srcdir/server/guhcore.cpp \
|
||||
$$top_srcdir/server/jsonrpc/ruleshandler.cpp \
|
||||
$$top_srcdir/server/jsonrpc/actionhandler.cpp \
|
||||
$$top_srcdir/server/jsonrpc/eventhandler.cpp \
|
||||
$$top_srcdir/server/jsonrpc/statehandler.cpp \
|
||||
$$top_srcdir/server/jsonrpc/logginghandler.cpp \
|
||||
$$top_srcdir/server/stateevaluator.cpp \
|
||||
$$top_srcdir/server/logging/logengine.cpp \
|
||||
$$top_srcdir/server/logging/logfilter.cpp \
|
||||
$$top_srcdir/server/logging/logentry.cpp \
|
||||
|
||||
HEADERS += $$top_srcdir/server/guhcore.h \
|
||||
$$top_srcdir/server/tcpserver.h \
|
||||
@ -22,5 +27,11 @@ HEADERS += $$top_srcdir/server/guhcore.h \
|
||||
$$top_srcdir/server/jsonrpc/ruleshandler.h \
|
||||
$$top_srcdir/server/jsonrpc/actionhandler.h \
|
||||
$$top_srcdir/server/jsonrpc/eventhandler.h \
|
||||
$$top_srcdir/server/jsonrpc/statehandler.h \
|
||||
$$top_srcdir/server/jsonrpc/logginghandler.h \
|
||||
$$top_srcdir/server/stateevaluator.h \
|
||||
$$top_srcdir/server/jsontypes.h
|
||||
$$top_srcdir/server/jsontypes.h \
|
||||
$$top_srcdir/server/logging/logging.h \
|
||||
$$top_srcdir/server/logging/logengine.h \
|
||||
$$top_srcdir/server/logging/logfilter.h \
|
||||
$$top_srcdir/server/logging/logentry.h \
|
||||
|
||||
@ -10,7 +10,7 @@ INCLUDEPATH += ../libguh jsonrpc
|
||||
target.path = /usr/bin
|
||||
INSTALLS += target
|
||||
|
||||
QT += network
|
||||
QT += network sql
|
||||
|
||||
LIBS += -L$$top_builddir/libguh/ -lguh
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
10
|
||||
11
|
||||
{
|
||||
"methods": {
|
||||
"Actions.ExecuteAction": {
|
||||
@ -262,6 +262,17 @@
|
||||
"version": "String"
|
||||
}
|
||||
},
|
||||
"Logging.GetLogEntries": {
|
||||
"description": "Get the LogEntries matching the given filter.",
|
||||
"params": {
|
||||
},
|
||||
"returns": {
|
||||
"loggingError": "$ref:LoggingError",
|
||||
"o:logEntries": [
|
||||
"$ref:LogEntry"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Rules.AddRule": {
|
||||
"description": "Add a rule. You can describe rules by one or many EventDesciptors and a StateEvaluator. Note that onlyone of either eventDescriptor or eventDescriptorList may be passed at a time. A rule can be created but left disabled,meaning it won't actually be executed until set to enabled. If not given, enabled defaults to true.",
|
||||
"params": {
|
||||
@ -336,6 +347,16 @@
|
||||
"returns": {
|
||||
"ruleError": "$ref:RuleError"
|
||||
}
|
||||
},
|
||||
"States.GetStateType": {
|
||||
"description": "Get the StateType for the given stateTypeId.",
|
||||
"params": {
|
||||
"stateTypeId": "Uuid"
|
||||
},
|
||||
"returns": {
|
||||
"deviceError": "$ref:DeviceError",
|
||||
"o:stateType": "$ref:StateType"
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
@ -352,6 +373,12 @@
|
||||
"params": {
|
||||
"event": "$ref:Event"
|
||||
}
|
||||
},
|
||||
"Logging.LogEntryAdded": {
|
||||
"description": "Emitted whenever an entry is appended to the logging system.",
|
||||
"params": {
|
||||
"logEntry": "$ref:LogEntry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"types": {
|
||||
@ -463,6 +490,36 @@
|
||||
"$ref:ParamType"
|
||||
]
|
||||
},
|
||||
"LogEntry": {
|
||||
"loggingLevel": "$ref:LoggingLevel",
|
||||
"o:active": "Bool",
|
||||
"o:deviceId": "Uuid",
|
||||
"o:errorCode": "String",
|
||||
"o:eventType": "$ref:LoggingEventType",
|
||||
"o:typeId": "Uuid",
|
||||
"o:value": "String",
|
||||
"source": "$ref:LoggingSource",
|
||||
"timestamp": "Int"
|
||||
},
|
||||
"LoggingError": [
|
||||
"LoggingErrorNoError",
|
||||
"LoggingErrorLogEntryNotFound"
|
||||
],
|
||||
"LoggingEventType": [
|
||||
"LoggingEventTypeTrigger",
|
||||
"LoggingEventTypeActiveChange"
|
||||
],
|
||||
"LoggingLevel": [
|
||||
"LoggingLevelInfo",
|
||||
"LoggingLevelAlert"
|
||||
],
|
||||
"LoggingSource": [
|
||||
"LoggingSourceSystem",
|
||||
"LoggingSourceEvents",
|
||||
"LoggingSourceActions",
|
||||
"LoggingSourceStates",
|
||||
"LoggingSourceRules"
|
||||
],
|
||||
"Param": {
|
||||
"name": "String",
|
||||
"value": "$ref:BasicType"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
QT += testlib network
|
||||
QT += testlib network sql
|
||||
CONFIG += testcase
|
||||
|
||||
include($$top_srcdir/server/server.pri)
|
||||
|
||||
@ -206,7 +206,7 @@ void TestJSONRPC::stateChangeEmitsNotifications()
|
||||
|
||||
// Lets wait for the notification
|
||||
clientSpy.wait();
|
||||
QCOMPARE(clientSpy.count(), 2);
|
||||
QCOMPARE(clientSpy.count(), 3); // statechangeevent, state change, log entry added
|
||||
|
||||
// Make sure the notification contains all the stuff we expect
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(clientSpy.at(0).at(1).toByteArray());
|
||||
@ -216,6 +216,11 @@ void TestJSONRPC::stateChangeEmitsNotifications()
|
||||
|
||||
// Make sure the notification contains all the stuff we expect
|
||||
jsonDoc = QJsonDocument::fromJson(clientSpy.at(1).at(1).toByteArray());
|
||||
QCOMPARE(jsonDoc.toVariant().toMap().value("notification").toString(), QString("Logging.LogEntryAdded"));
|
||||
QCOMPARE(jsonDoc.toVariant().toMap().value("params").toMap().value("logEntry").toMap().value("typeId").toUuid(), stateTypeId);
|
||||
|
||||
// Make sure the notification contains all the stuff we expect
|
||||
jsonDoc = QJsonDocument::fromJson(clientSpy.at(2).at(1).toByteArray());
|
||||
QCOMPARE(jsonDoc.toVariant().toMap().value("notification").toString(), QString("Events.EventTriggered"));
|
||||
QCOMPARE(jsonDoc.toVariant().toMap().value("params").toMap().value("event").toMap().value("eventTypeId").toUuid(), stateTypeId);
|
||||
QCOMPARE(jsonDoc.toVariant().toMap().value("params").toMap().value("event").toMap().value("params").toList().first().toMap().value("value").toInt(), newVal);
|
||||
|
||||
@ -368,7 +368,11 @@ void TestRules::loadStoreConfig()
|
||||
if (actionVariant.toMap().value("actionTypeId") == replyActionVariant.toMap().value("actionTypeId") &&
|
||||
actionVariant.toMap().value("deviceId") == replyActionVariant.toMap().value("deviceId")) {
|
||||
found = true;
|
||||
QVERIFY2(actionVariant == replyActionVariant, "Action doesn't match after loading from config.");
|
||||
QJsonDocument bDoc = QJsonDocument::fromVariant(actionVariant);
|
||||
QString bString = bDoc.toJson();
|
||||
QJsonDocument aDoc = QJsonDocument::fromVariant(replyActionVariant);
|
||||
QString aString = aDoc.toJson();
|
||||
QVERIFY2(actionVariant == replyActionVariant, QString("Action doesn't match after loading from config.\nBefore storing: %1\nAfter storing:%2").arg(bString).arg(aString).toUtf8().data());
|
||||
}
|
||||
}
|
||||
QVERIFY2(found, "Action not found after loading from config.");
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
import telnetlib
|
||||
import json
|
||||
import datetime
|
||||
|
||||
HOST='localhost'
|
||||
PORT=1234
|
||||
@ -21,7 +22,9 @@ methods = {'1': 'add_device',
|
||||
'12': 'list_deviceClasses',
|
||||
'13': 'list_deviceClasses_by_vendor',
|
||||
'14': 'list_rules',
|
||||
'15': 'list_rules_containig_deviceId'}
|
||||
'15': 'list_rules_containig_deviceId',
|
||||
'16': 'list_logEntries'
|
||||
}
|
||||
|
||||
|
||||
def get_menu_selection():
|
||||
@ -50,6 +53,7 @@ def get_menu_selection():
|
||||
print " 13 -> List supported devices by vendor"
|
||||
print " 14 -> List configured rules"
|
||||
print " 15 -> List rules containing a certain device"
|
||||
print " 16 -> Print log"
|
||||
print "----------------------------------------"
|
||||
print ""
|
||||
selection = raw_input("Enter selection: ")
|
||||
@ -321,7 +325,9 @@ def get_actionType(actionTypeId):
|
||||
params = {}
|
||||
params['actionTypeId'] = actionTypeId
|
||||
response = send_command("Actions.GetActionType", params)
|
||||
return response['params']['actionType']
|
||||
if "actionType" in response['params']:
|
||||
return response['params']['actionType']
|
||||
return None
|
||||
|
||||
|
||||
def get_eventType(eventTypeId):
|
||||
@ -668,20 +674,25 @@ def list_rules():
|
||||
print response['params']['ruleIds'][i], "(", get_rule_status(ruleId), ")"
|
||||
|
||||
|
||||
def get_rule_detail(ruleId):
|
||||
params = {}
|
||||
params['ruleId'] = ruleId
|
||||
response = send_command("Rules.GetRuleDetails", params)
|
||||
if 'rule' in response['params']:
|
||||
return response['params']['rule']
|
||||
return None
|
||||
|
||||
def list_rule_detail():
|
||||
ruleId = select_rule()
|
||||
if ruleId == "":
|
||||
print "\n No rules found"
|
||||
return None
|
||||
|
||||
params = {}
|
||||
params['ruleId'] = ruleId
|
||||
response = send_command("Rules.GetRuleDetails", params)
|
||||
print response
|
||||
rule = get_rule_detail(ruleId)
|
||||
print "\nDetails for rule", ruleId, "which currently is", get_rule_status(ruleId)
|
||||
print "\nEvents ->", get_stateEvaluator_text(response['params']['rule']['stateEvaluator']['operator']), ":"
|
||||
for i in range(len(response['params']['rule']['eventDescriptors'])):
|
||||
eventDescriptor = response['params']['rule']['eventDescriptors'][i]
|
||||
print "\nEvents ->", get_stateEvaluator_text(rule['stateEvaluator']['operator']), ":"
|
||||
for i in range(len(rule['eventDescriptors'])):
|
||||
eventDescriptor = rule['eventDescriptors'][i]
|
||||
device = get_device(eventDescriptor['deviceId'])
|
||||
eventType = get_eventType(eventDescriptor['eventTypeId'])
|
||||
paramDescriptors = eventDescriptor['paramDescriptors']
|
||||
@ -690,11 +701,11 @@ def list_rule_detail():
|
||||
print "%58s %s %s" %(paramDescriptors[i]['name'], get_valueOperator_symbol(paramDescriptors[i]['operator']), paramDescriptors[i]['value'])
|
||||
|
||||
print "\nActions:"
|
||||
for i in range(len(response['params']['rule']['actions'])):
|
||||
action = response['params']['rule']['actions'][i]
|
||||
for i in range(len(rule['actions'])):
|
||||
action = rule['actions'][i]
|
||||
device = get_device(action['deviceId'])
|
||||
actionType = get_actionType(response['params']['rule']['actions'][i]['actionTypeId'])
|
||||
actionParams = response['params']['rule']['actions'][i]['params']
|
||||
actionType = get_actionType(rule['actions'][i]['actionTypeId'])
|
||||
actionParams = rule['actions'][i]['params']
|
||||
print "%5s. -> %40s -> action: %s" %(i, device['name'], actionType['name'])
|
||||
for i in range(len(actionParams)):
|
||||
print "%61s: %s" %(actionParams[i]['name'], actionParams[i]['value'])
|
||||
@ -761,7 +772,145 @@ def remove_rule():
|
||||
response = send_command("Rules.RemoveRule", params)
|
||||
print "removeRule response", response
|
||||
|
||||
def get_stateType(stateTypeId):
|
||||
params = {}
|
||||
params['stateTypeId'] = stateTypeId
|
||||
response = send_command("States.GetStateType", params);
|
||||
if "stateType" in response['params']:
|
||||
return response['params']['stateType']
|
||||
return None
|
||||
|
||||
def list_logEntries():
|
||||
params = {}
|
||||
response = send_command("Logging.GetLogEntries", params)
|
||||
stateTypeIdCache = {}
|
||||
actionTypeIdCache = {}
|
||||
eventTypeIdCache = {}
|
||||
deviceIdCache = {}
|
||||
ruleIdCache = {}
|
||||
for i in range(len(response['params']['logEntries'])):
|
||||
entry = response['params']['logEntries'][i]
|
||||
|
||||
if entry['loggingLevel'] == "LoggingLevelInfo":
|
||||
levelString = "(I)"
|
||||
error = ""
|
||||
else:
|
||||
levelString = "(A)"
|
||||
error = entry['errorCode']
|
||||
|
||||
if entry['source'] == "LoggingSourceSystem":
|
||||
deviceName = "Guh Server"
|
||||
sourceType = "System Event"
|
||||
symbolString = "->"
|
||||
sourceName = "Active changed"
|
||||
if entry['active'] == True:
|
||||
value = "active"
|
||||
else:
|
||||
value = "inactive"
|
||||
|
||||
if entry['source'] == "LoggingSourceStates":
|
||||
typeId = entry['typeId']
|
||||
sourceType = "State Changed"
|
||||
symbolString = "->"
|
||||
if typeId in stateTypeIdCache:
|
||||
sourceName = stateTypeIdCache[typeId]
|
||||
else:
|
||||
stateType = get_stateType(typeId)
|
||||
if stateType is not None:
|
||||
sourceName = stateType["name"]
|
||||
stateTypeIdCache[typeId] = sourceName
|
||||
else:
|
||||
sourceName = typeId
|
||||
value = entry['value']
|
||||
if entry['deviceId'] in deviceIdCache:
|
||||
deviceName = deviceIdCache[entry['deviceId']]
|
||||
else:
|
||||
device = get_device(entry['deviceId'])
|
||||
if device is not None:
|
||||
deviceName = device['name']
|
||||
deviceIdCache[entry['deviceId']] = deviceName
|
||||
else:
|
||||
deviceName = typeId
|
||||
|
||||
|
||||
if entry['source'] == "LoggingSourceActions":
|
||||
typeId = entry['typeId']
|
||||
sourceType = "Action executed"
|
||||
symbolString = "()"
|
||||
if typeId in actionTypeIdCache:
|
||||
sourceName = actionTypeIdCache[typeId]
|
||||
else:
|
||||
actionType = get_actionType(typeId)
|
||||
if actionType is not None:
|
||||
sourceName = actionType['name']
|
||||
else:
|
||||
sourceName = typeId
|
||||
actionTypeIdCache[typeId] = sourceName
|
||||
value = entry['value']
|
||||
if entry['deviceId'] in deviceIdCache:
|
||||
deviceName = deviceIdCache[entry['deviceId']]
|
||||
else:
|
||||
device = get_device(entry['deviceId'])
|
||||
if device is not None:
|
||||
deviceName = device['name']
|
||||
else:
|
||||
deviceName = entry['deviceId']
|
||||
deviceIdCache[entry['deviceId']] = deviceName
|
||||
|
||||
if entry['source'] == "LoggingSourceEvents":
|
||||
typeId = entry['typeId']
|
||||
sourceType = "Event triggered"
|
||||
symbolString = "()"
|
||||
if typeId in eventTypeIdCache:
|
||||
sourceName = eventTypeIdCache[typeId]
|
||||
else:
|
||||
eventType = get_eventType(typeId)
|
||||
sourceName = eventType['name']
|
||||
eventTypeIdCache[typeId] = sourceName
|
||||
value = entry['value']
|
||||
if entry['deviceId'] in deviceIdCache:
|
||||
deviceName = deviceIdCache[entry['deviceId']]
|
||||
else:
|
||||
device = get_device(entry['deviceId'])
|
||||
if device is not None:
|
||||
deviceName = device['name']
|
||||
else:
|
||||
devieName = entry['deviceId']
|
||||
deviceIdCache[entry['deviceId']] = deviceName
|
||||
|
||||
|
||||
if entry['source'] == "LoggingSourceRules":
|
||||
typeId = entry['typeId']
|
||||
if entry['eventType'] == "LoggingEventTypeTrigger":
|
||||
sourceType = "Rule triggered"
|
||||
sourceName = "triggered"
|
||||
symbolString = "()"
|
||||
value = ""
|
||||
else:
|
||||
sourceType = "Rule active changed"
|
||||
symbolString = "()"
|
||||
sourceName = "active"
|
||||
if entry['active']:
|
||||
value = "active"
|
||||
else:
|
||||
value = "inactive"
|
||||
|
||||
if typeId in ruleIdCache:
|
||||
deviceName = ruleIdCache[typeId]
|
||||
else:
|
||||
rule = get_rule_detail(typeId)
|
||||
if rule is not None and 'name' in rule:
|
||||
deviceName = rule['name']
|
||||
else:
|
||||
deviceName = typeId
|
||||
ruleIdCache[typeId] = deviceName
|
||||
|
||||
timestamp = datetime.datetime.fromtimestamp(entry['timestamp']/1000)
|
||||
sourceType = sourceType.ljust(20)
|
||||
deviceName = deviceName.ljust(38)
|
||||
sourceName = sourceName.ljust(38)
|
||||
value = value.ljust(30)
|
||||
print levelString, timestamp, ":", sourceType, ":", deviceName, ":", sourceName, symbolString, value, ":", error
|
||||
|
||||
############################################################################################
|
||||
import sys
|
||||
|
||||
Reference in New Issue
Block a user