// SPDX-License-Identifier: LGPL-3.0-or-later /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2013 - 2024, nymea GmbH * Copyright (C) 2024 - 2025, chargebyte austria GmbH * * This file is part of nymea. * * nymea is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * nymea 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with nymea. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "logginghandler.h" #include "logging/logengine.h" #include "logging/logentry.h" #include "loggingcategories.h" #include "nymeacore.h" namespace nymeaserver { LoggingHandler::LoggingHandler(LogEngine *logEngine, QObject *parent) : JsonHandler(parent), m_logEngine(logEngine) { // Enums registerEnum(); registerEnum(); // Objects registerObject(); // Methods QString description; QVariantMap params; QVariantMap returns; description = "Get the LogEntries matching the given filter. \n" "\"sources\": Builtin sources are: \"core\", \"rules\", \"scripts\", \"integrations\". May be extended by experience plugins.\n" "\"columns\": Columns to be returned.\n" "\"filter\": A map of column:value entries. Only = is supported currently.\n" "\"startTime\": The datetime of the oldest entry, in ms.\n" "\"endTime\": The datetime of the newest entry, in ms.\n" "\"sampleRate\": If given, returns a sampled series of the values, filling in gaps with the previous value.\n" "\"sortOrder\": Sort order of results. Note that this impacts the filling of gaps when resampling.\n" "\"limit\": Maximum amount of entries to be returned.\n" "\"offset\": Offset to be skipped before returning entries."; params.insert("sources", QVariantList() << enumValueName(String)); params.insert("o:columns", QVariantList() << enumValueName(String)); params.insert("o:filter", enumValueName(Variant)); params.insert("o:startTime", enumValueName(Uint)); params.insert("o:endTime", enumValueName(Uint)); params.insert("o:sampleRate", enumRef()); params.insert("o:sortOrder", enumRef()); params.insert("o:limit", enumValueName(Int)); params.insert("o:offset", enumValueName(Int)); returns.insert("o:logEntries", objectRef()); returns.insert("count", enumValueName(Int)); returns.insert("offset", enumValueName(Int)); registerMethod("GetLogEntries", description, params, returns, Types::PermissionScopeControlThings); // Notifications params.clear(); description = "Emitted when a log entry is added. This will only be emitted for discrete series, not for resampled entries"; params.insert("logEntry", objectRef()); registerNotification("LogEntryAdded", description, params); connect(m_logEngine, &LogEngine::logEntryAdded, this, [this](const LogEntry &logEntry){ emit LogEntryAdded({{"logEntry", packLogEntry(logEntry)}}); }); } QString LoggingHandler::name() const { return "Logging"; } JsonReply* LoggingHandler::GetLogEntries(const QVariantMap ¶ms) const { JsonReply *reply = createAsyncReply("GetLogEntries"); QVariantMap filter = params.value("filter").toMap(); QDateTime startTime; if (params.contains("startTime")) { startTime = QDateTime::fromMSecsSinceEpoch(params.value("startTime").toULongLong()); } QDateTime endTime; if (params.contains("endTime")) { endTime = QDateTime::fromMSecsSinceEpoch(params.value("endTime").toULongLong()); } Types::SampleRate sampleRate = Types::SampleRateAny; if (params.contains("sampleRate")) { QMetaEnum sampleRateEnum = QMetaEnum::fromType(); sampleRate = static_cast(sampleRateEnum.keyToValue(params.value("sampleRate").toByteArray())); } QStringList columns; if (params.contains("columns")) { columns = params.value("columns").toStringList(); } int offset = params.value("offset").toInt(); int limit = params.value("limit").toInt(); Qt::SortOrder sortOrder = Qt::AscendingOrder; if (params.contains("sortOrder")) { sortOrder = enumNameToValue(params.value("sortOrder").toString()); } QStringList sources = params.value("sources").toStringList(); LogFetchJob *job = m_logEngine->fetchLogEntries(sources, columns, startTime, endTime, filter, sampleRate, sortOrder, offset, limit); connect(job, &LogFetchJob::finished, reply, [reply](const LogEntries &entries){ QVariantList entryMaps; foreach (const LogEntry &logEntry, entries) { QVariantMap logEntryMap; logEntryMap.insert("timestamp", logEntry.timestamp().toMSecsSinceEpoch()); logEntryMap.insert("source", logEntry.source()); QVariantMap values; foreach (const QString &valueKey, logEntry.values().keys()) { values.insert(valueKey, logEntry.values().value(valueKey)); } logEntryMap.insert("values", values); entryMaps.append(logEntryMap); } QVariantMap params { {"count", entries.count()}, {"offset", 0}, {"logEntries", entryMaps} }; reply->setData(params); reply->finished(); }); return reply; } QVariantMap LoggingHandler::packLogEntry(const LogEntry &logEntry) { QVariantMap logEntryMap; logEntryMap.insert("timestamp", logEntry.timestamp().toMSecsSinceEpoch()); logEntryMap.insert("source", logEntry.source()); QVariantMap values; foreach (const QString &valueKey, logEntry.values().keys()) { values.insert(valueKey, logEntry.values().value(valueKey)); } logEntryMap.insert("values", values); return logEntryMap; } }