SystemMonitor: Extend plugin

Renames the old systemMonitor thingClass into processMonitor as that's
what it actually did and allow monitoring other processes, not just
nymead.

Adds a new thingClass named systemMonitor to allow fetching total
CPU, memory and Disk stats.
master
Michael Zanetti 2022-06-20 23:57:39 +02:00
parent 5b57ae2faa
commit 646240549c
6 changed files with 422 additions and 134 deletions

View File

@ -1,19 +1,18 @@
# System monitor
This integration plug-in displays the system usage of nymea.
This integration plugin allows to monitor system resources and processes on the host running nymea.
## Supported Things
* Process monitor
* Process status (running/stopped)
* Process CPU usage
* Process memory usage (percent to available physical memory)
* Process RSS memory usage
* Process virtual memory usage
* Process shared memory usage
* System monitor
* CPU usage (in percent)
* Memory usage (in percent)
* RSS memory usage (in KiloByte)
* Virtual memory usage (in KiloByte)
## Requirements
* The package “nymea-plugin-systemmonitor” must be installed
## More
This plug-in uses "ps" to gather the required system information: http://man7.org/linux/man-pages/man1/ps.1.html
* System CPU usage
* System memory usage
* System disk usage

View File

@ -31,6 +31,10 @@
#include "integrationpluginsystemmonitor.h"
#include "plugininfo.h"
#include <QStorageInfo>
#include <sys/types.h>
#include <sys/sysinfo.h>
#include <unistd.h>
IntegrationPluginSystemMonitor::IntegrationPluginSystemMonitor()
{
@ -48,7 +52,18 @@ void IntegrationPluginSystemMonitor::setupThing(ThingSetupInfo *info)
{
if (!m_refreshTimer) {
m_refreshTimer = hardwareManager()->pluginTimerManager()->registerTimer(2);
connect(m_refreshTimer, &PluginTimer::timeout, this, &IntegrationPluginSystemMonitor::onRefreshTimer);
connect(m_refreshTimer, &PluginTimer::timeout, this, [=](){
foreach (Thing *thing, myThings()) {
if (thing->thingClassId() == systemMonitorThingClassId) {
updateSystemMonitor(thing);
} else if (thing->thingClassId() == processMonitorThingClassId) {
updateProcessMonitor(thing);
}
}
});
}
info->finish(Thing::ThingErrorNoError);
}
@ -60,58 +75,247 @@ void IntegrationPluginSystemMonitor::thingRemoved(Thing *thing)
if (myThings().isEmpty()) {
hardwareManager()->pluginTimerManager()->unregisterTimer(m_refreshTimer);
m_refreshTimer = nullptr;
}
m_oldTotalJiffies.remove(thing);
m_oldWorkJiffies.remove(thing);
m_oldProcessWorkJiffies.remove(thing);
}
void IntegrationPluginSystemMonitor::onRefreshTimer()
void IntegrationPluginSystemMonitor::updateSystemMonitor(Thing *thing)
{
QProcess *p = new QProcess(this);
connect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onProcessFinished(int,QProcess::ExitStatus)));
p->start("ps", {"-C", "nymead", "-o", "%mem=,vsz=,rss=,pcpu="});
double cpuPercentage = readTotalCpuUsage(thing);
if (cpuPercentage >= 0) {
thing->setStateValue(systemMonitorCpuUsageStateTypeId, cpuPercentage);
}
thing->setStateValue(systemMonitorPercentMemoryStateTypeId, readTotalMemoryUsage());
QStorageInfo storageInfo = QStorageInfo::root();
double percentage = 100.0 * (storageInfo.bytesTotal() - storageInfo.bytesFree()) / storageInfo.bytesTotal();
thing->setStateValue(systemMonitorPercentStorageStateTypeId, percentage);
}
void IntegrationPluginSystemMonitor::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
void IntegrationPluginSystemMonitor::updateProcessMonitor(Thing *thing)
{
QProcess *p = static_cast<QProcess*>(sender());
p->deleteLater();
QString processName = thing->paramValue(processMonitorThingProcessNameParamTypeId).toString();
// For backwards compatibility we'll use nymead if the new parameter (version 1.3) isn't set at all yet.
if (processName.isEmpty()) {
processName = "nymead";
}
qint32 pid = getPidByName(processName);
if (pid == -1) {
thing->setStateValue(processMonitorRunningStateTypeId, false);
return;
}
thing->setStateValue(processMonitorRunningStateTypeId, true);
if (exitCode != 0 || exitStatus != QProcess::NormalExit) {
qWarning(dcSystemMonitor) << "Error reading process memory usage:" << p->readAllStandardError();
return;
}
QString data = QString(p->readAllStandardOutput().trimmed()).replace(QRegExp("[ ]{2,}"), " ");
QStringList parts = data.split(' ');
if (parts.count() != 4) {
qCWarning(dcSystemMonitor()) << "Unexpected result from ps" << data << parts;
return;
}
bool ok;
qreal percentMem = parts.at(0).toDouble(&ok);
if (!ok) {
qWarning(dcSystemMonitor) << "Failed to parse % memory value to a number:" << parts.at(0);
return;
}
qint64 virtualMem = parts.at(1).toLongLong(&ok);
if (!ok) {
qWarning(dcSystemMonitor) << "Failed to parse virtual memory value to a number:" << parts.at(1);
return;
}
quint64 rssMem = parts.at(2).toLongLong(&ok);
if (!ok) {
qWarning(dcSystemMonitor) << "Failed to parse RSS memory value to a number:" << data;
return;
}
qreal cpuUsage = parts.at(3).toDouble(&ok);
if (!ok) {
qWarning(dcSystemMonitor) << "Failed to parse CPU usage value to a number:" << parts.at(3);
return;
}
foreach (Thing *dev, myThings()) {
dev->setStateValue(systemMonitorRssMemoryStateTypeId, rssMem);
dev->setStateValue(systemMonitorPercentMemoryStateTypeId, percentMem);
dev->setStateValue(systemMonitorVirtualMemoryStateTypeId, virtualMem);
dev->setStateValue(systemMonitorCpuUsageStateTypeId, cpuUsage);
quint32 total, rss, shared;
double percentage;
if (readProcessMemoryUsage(pid, total, rss, shared, percentage)) {
thing->setStateValue(processMonitorPercentMemoryStateTypeId, percentage);
thing->setStateValue(processMonitorRssMemoryStateTypeId, rss);
thing->setStateValue(processMonitorVirtualMemoryStateTypeId, total);
thing->setStateValue(processMonitorSharedMemoryStateTypeId, shared);
}
thing->setStateValue(processMonitorCpuUsageStateTypeId, readProcessCpuUsage(pid, thing));
}
double IntegrationPluginSystemMonitor::readTotalCpuUsage(Thing *thing)
{
QFile f("/proc/stat");
if (!f.open(QFile::ReadOnly)) {
qCWarning(dcSystemMonitor()) << "Unable to open /proc/stat. Cannot read CPU usage";
return -1;
}
QByteArray cpuStat = f.readLine().replace(" ", " ");
f.close();
qCDebug(dcSystemMonitor()) << "SystemCPU:" << "stat:" << cpuStat;
QList<QByteArray> parts = cpuStat.split(' ');
if (parts.first() != "cpu" || parts.count() < 8) {
qCWarning(dcSystemMonitor()) << "/proc/stat not in expected format";
return -1;
}
qulonglong systemJiffies = parts.at(1).toULong();
// qulonglong niceJiffies = parts.at(2).toULong();
qulonglong userJiffies = parts.at(3).toULong();
qulonglong idleJiffies = parts.at(4).toULong();
// qulonglong ioWaitJiffies = parts.at(5).toULong();
// qulonglong irqJiffies = parts.at(6).toULong();
// qulonglong softirqJiffies = parts.at(7).toULong();
qulonglong workJiffies = systemJiffies + userJiffies;
qulonglong totalJiffies = workJiffies + idleJiffies;
double cpuPercentage = 0;
if (m_oldTotalJiffies.contains(thing)) {
qulonglong oldTotalJiffies = m_oldTotalJiffies.value(thing);
qulonglong oldWorkJiffies = m_oldWorkJiffies.value(thing);
qCDebug(dcSystemMonitor()) << "SystemCPU:" << "Current work:" << workJiffies << "total:" << totalJiffies << "Old work:" << oldWorkJiffies << "total:" << oldTotalJiffies;
if (workJiffies < oldWorkJiffies || totalJiffies < oldTotalJiffies) {
// One of the values overflowed. Skipping this cycle
m_oldTotalJiffies[thing] = totalJiffies;
m_oldWorkJiffies[thing] = workJiffies;
return -1;
}
qulonglong totalJiffDiff = totalJiffies - oldTotalJiffies;
qulonglong workJiffDiff = workJiffies - oldWorkJiffies;
cpuPercentage = 100.0 * workJiffDiff / totalJiffDiff;
}
m_oldTotalJiffies[thing] = totalJiffies;
m_oldWorkJiffies[thing] = workJiffies;
return cpuPercentage;
}
double IntegrationPluginSystemMonitor::readTotalMemoryUsage()
{
struct sysinfo memInfo;
sysinfo(&memInfo);
qulonglong totalPhysicalMem = memInfo.totalram;
// Multiply in next statement to avoid int overflow on right hand side...
totalPhysicalMem *= memInfo.mem_unit;
qulonglong physicalMemUsed = (memInfo.totalram - memInfo.freeram - memInfo.bufferram);
// Multiply in next statement to avoid int overflow on right hand side...
physicalMemUsed *= memInfo.mem_unit;
// qCDebug(dcSystemMonitor()) << "Total RAM" << totalPhysicalMem << "used:" << physicalMemUsed;
return 100.0 * physicalMemUsed / totalPhysicalMem;
}
bool IntegrationPluginSystemMonitor::readProcessMemoryUsage(qint32 pid, quint32 &total, quint32 &rss, quint32 &shared, double &percentage)
{
QFile f(QString("/proc/%1/statm").arg(pid));
if (!f.open(QFile::ReadOnly)) {
qCWarning(dcSystemMonitor()).nospace() << "Unable to open " << f.fileName() << ". Cannot read memory usage.";
return false;
}
QByteArray memStat = f.readLine();
f.close();
QList<QByteArray> parts = memStat.split(' ');
if (parts.count() < 3) {
qCWarning(dcSystemMonitor()) << f.fileName() << "not in expected format";
return false;
}
int tsize = parts.at(0).toInt();
int resident = parts.at(1).toInt();
int share = parts.at(2).toInt();
long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024;
total = tsize;
total *= page_size_kb;
rss = resident;
rss *= page_size_kb;
shared = share;
shared *= page_size_kb;
struct sysinfo memInfo;
sysinfo(&memInfo);
qulonglong totalMem = memInfo.totalram;
totalMem *= memInfo.mem_unit;
// totalMem is in Bytes, rss in kb
percentage = 100000.0 * rss / totalMem;
// qCDebug(dcSystemMonitor()) << "totalMem:" << totalMem << "total:" << total << "rss" << rss << "shared" << shared << "%" << percentage;
return true;
}
double IntegrationPluginSystemMonitor::readProcessCpuUsage(qint32 pid, Thing *thing)
{
QFile systemFile("/proc/stat");
if (!systemFile.open(QFile::ReadOnly)) {
qCWarning(dcSystemMonitor()) << "Unable to open /proc/stat. Cannot read CPU usage";
return 0;
}
QByteArray cpuStat = systemFile.readLine().replace(" ", " ");
systemFile.close();
qCDebug(dcSystemMonitor()) << "ProcessCPU:" << "System stat:" << cpuStat;
QList<QByteArray> parts = cpuStat.split(' ');
if (parts.first() != "cpu" || parts.count() < 8) {
qCWarning(dcSystemMonitor()) << "/proc/stat not in expected format";
return 0;
}
parts.removeFirst();
qulonglong systemJiffies = parts.at(1).toULong();
qulonglong userJiffies = parts.at(3).toULong();
// qulonglong idleJiffies = parts.at(4).toULong();
qulonglong totalJiffies = systemJiffies + userJiffies;// + idleJiffies;
QFile f(QString("/proc/%1/stat").arg(pid));
if (!f.open(QFile::ReadOnly)) {
qCWarning(dcSystemMonitor()).nospace() << "Unable to open " << f.fileName() << ". Cannot read CPU usage.";
return 0;
}
QByteArray stat = f.readLine();
f.close();
qCDebug(dcSystemMonitor()) << "ProcessCPU:" << "Process stat:" << stat;
parts = stat.split(' ');
if (parts.length() < 15) {
qCWarning(dcSystemMonitor()) << f.fileName() << "not in expected format";
return 0;
}
qulonglong processUserJiffies = parts.at(13).toULongLong();
qulonglong processKernelJiffies = parts.at(14).toULongLong();
qulonglong processChildUserJiffies = parts.at(15).toULongLong();
qulonglong processChildKernelJiffies = parts.at(16).toULongLong();
qulonglong processWorkJiffies = processUserJiffies + processKernelJiffies + processChildUserJiffies + processChildKernelJiffies;
double percentage = 0;
if (m_oldTotalJiffies.contains(thing)) {
qulonglong oldTotalJiffies = m_oldTotalJiffies.value(thing);
qulonglong oldProcessWorkJiffies = m_oldProcessWorkJiffies.value(thing);
qCDebug(dcSystemMonitor()) << "ProcessCPU:" << "Current total:" << totalJiffies << "process:" << processWorkJiffies << "Old total:" << oldTotalJiffies << "process:" << oldProcessWorkJiffies;
qulonglong totalJiffDiff = totalJiffies - oldTotalJiffies;
qulonglong processWorkJiffDiff = processWorkJiffies - oldProcessWorkJiffies;
if (totalJiffDiff > 0) {
percentage = 100.0 * processWorkJiffDiff / totalJiffDiff;
}
}
m_oldTotalJiffies[thing] = totalJiffies;
m_oldProcessWorkJiffies[thing] = processWorkJiffies;
return percentage;
}
qint32 IntegrationPluginSystemMonitor::getPidByName(const QString &processName)
{
QDir proc("/proc");
foreach (const QString dirName, proc.entryList(QDir::AllDirs | QDir::NoDotAndDotDot)) {
QFile statusFile(proc.absoluteFilePath(dirName + QDir::separator() + "status"));
if (!statusFile.open(QFile::ReadOnly)) {
continue;
}
QString line = statusFile.readLine().trimmed();
line.remove(QRegExp("Name:(\\s)*"));
// qCDebug(dcSystemMonitor()) << "Found process:" << line << "looking for" << processName.left(15);
// names in /proc/<pid>/status are trimmed to 15 characters...
if (processName.left(15) == line.left(15)) {
return dirName.toInt();
}
}
return -1;
}

View File

@ -38,6 +38,7 @@
#include <QProcess>
#include <QUrlQuery>
#include "extern-plugininfo.h"
class IntegrationPluginSystemMonitor: public IntegrationPlugin {
Q_OBJECT
@ -51,13 +52,24 @@ public:
void setupThing(ThingSetupInfo *info) override;
void thingRemoved(Thing *thing) override;
private slots:
void onRefreshTimer();
void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
private:
void updateSystemMonitor(Thing *thing);
void updateProcessMonitor(Thing *thing);
double readTotalCpuUsage(Thing *thing);
double readTotalMemoryUsage();
bool readProcessMemoryUsage(qint32 pid, quint32 &total, quint32 &rss, quint32 &shared, double &percentage);
double readProcessCpuUsage(qint32 pid, Thing *thing);
qint32 getPidByName(const QString &processName);
private:
PluginTimer *m_refreshTimer = nullptr;
QHash<Thing*, qulonglong> m_oldTotalJiffies;
QHash<Thing*, qulonglong> m_oldWorkJiffies;
QHash<Thing*, qulonglong> m_oldProcessWorkJiffies;
};
#endif // INTEGRATIONPLUGINSYSTEMMONITOR_H

View File

@ -10,11 +10,27 @@
"thingClasses": [
{
"id": "a3a15700-c251-4803-a608-0f3ddfcbd7a8",
"name": "systemMonitor",
"displayName": "System monitor",
"interfaces": [ "system" ],
"paramTypes": [ ],
"name": "processMonitor",
"displayName": "Process monitor",
"paramTypes": [
{
"id": "794a2a7e-01dc-4383-8110-4d1cd59c421f",
"name": "processName",
"displayName": "Process name",
"type": "QString",
"defaultValue": "nymead"
}
],
"stateTypes": [
{
"id": "8b8b6b38-79ed-4f0e-bdc7-445f073fa4b7",
"name": "running",
"displayName": "Running",
"displayNameEvent": "Running changed",
"type": "bool",
"defaultValue": false,
"suggestLogging": true
},
{
"id": "56f8fac2-1021-4b96-bf15-23b21bb85b4c",
"name": "cpuUsage",
@ -31,8 +47,8 @@
{
"id": "efe2d520-3b35-4668-b6f5-db3df0c8bf0d",
"name": "percentMemory",
"displayName": "memory usage",
"displayNameEvent": "memory usage changed",
"displayName": "Memory usage",
"displayNameEvent": "Memory usage changed",
"type": "double",
"unit": "Percentage",
"defaultValue": 0,
@ -55,13 +71,68 @@
{
"id": "6d71b001-c7fe-4f08-941d-47009b710d94",
"name": "virtualMemory",
"displayName": "virtual memory usage",
"displayName": "Virtual memory usage",
"displayNameEvent": "virtual memory usage changed",
"type": "int",
"unit": "KiloByte",
"defaultValue": 0,
"suggestLogging": true,
"cached": false
},
{
"id": "fcdae649-dcc2-4f5b-a241-fe40fb07c071",
"name": "sharedMemory",
"displayName": "Shared memory usage",
"displayNameEvent": "Shared memory usage changed",
"type": "int",
"unit": "KiloByte",
"defaultValue": 0,
"suggestLogging": true,
"cached": false
}
]
},
{
"id": "181d852a-6290-434d-891a-35d2c3435f47",
"name": "systemMonitor",
"displayName": "System monitor",
"paramTypes": [],
"stateTypes": [
{
"id": "0744b84a-f9dc-4e53-a6f3-3533e909c533",
"name": "cpuUsage",
"displayName": "CPU usage",
"displayNameEvent": "CPU usage changed",
"type": "double",
"unit": "Percentage",
"defaultValue": 0,
"minValue": 0,
"maxValue": 100,
"suggestLogging": true,
"cached": false
},
{
"id": "672748c1-dbd0-4c65-8983-d0dd34892176",
"name": "percentMemory",
"displayName": "Memory usage",
"displayNameEvent": "Memory usage changed",
"type": "double",
"unit": "Percentage",
"defaultValue": 0,
"minValue": 0,
"maxValue": 100,
"suggestLogging": true,
"cached": false
},
{
"id": "47d6e6fb-5dc9-4e3f-ad24-c9d7eab320bd",
"name": "percentStorage",
"displayName": "Storage usage",
"displayNameEvent": "Storage usage changed",
"type": "double",
"unit": "Percentage",
"defaultValue": 0,
"suggestLogging": true
}
]
}

View File

@ -5,26 +5,14 @@
<name>systemMonitor</name>
<message>
<source>CPU usage</source>
<extracomment>The name of the ParamType (ThingClass: systemMonitor, EventType: cpuUsage, ID: {56f8fac2-1021-4b96-bf15-23b21bb85b4c})
<extracomment>The name of the StateType ({0744b84a-f9dc-4e53-a6f3-3533e909c533}) of ThingClass systemMonitor
----------
The name of the StateType ({56f8fac2-1021-4b96-bf15-23b21bb85b4c}) of ThingClass systemMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>CPU usage changed</source>
<extracomment>The name of the EventType ({56f8fac2-1021-4b96-bf15-23b21bb85b4c}) of ThingClass systemMonitor</extracomment>
The name of the StateType ({56f8fac2-1021-4b96-bf15-23b21bb85b4c}) of ThingClass processMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>RSS memory usage</source>
<extracomment>The name of the ParamType (ThingClass: systemMonitor, EventType: rssMemory, ID: {d9671ee3-51be-4cf8-8601-125c0684aec9})
----------
The name of the StateType ({d9671ee3-51be-4cf8-8601-125c0684aec9}) of ThingClass systemMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>RSS memory usage changed</source>
<extracomment>The name of the EventType ({d9671ee3-51be-4cf8-8601-125c0684aec9}) of ThingClass systemMonitor</extracomment>
<extracomment>The name of the StateType ({d9671ee3-51be-4cf8-8601-125c0684aec9}) of ThingClass processMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
@ -34,19 +22,7 @@ The name of the StateType ({d9671ee3-51be-4cf8-8601-125c0684aec9}) of ThingClass
</message>
<message>
<source>System monitor</source>
<extracomment>The name of the ThingClass ({a3a15700-c251-4803-a608-0f3ddfcbd7a8})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>memory usage</source>
<extracomment>The name of the ParamType (ThingClass: systemMonitor, EventType: percentMemory, ID: {efe2d520-3b35-4668-b6f5-db3df0c8bf0d})
----------
The name of the StateType ({efe2d520-3b35-4668-b6f5-db3df0c8bf0d}) of ThingClass systemMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>memory usage changed</source>
<extracomment>The name of the EventType ({efe2d520-3b35-4668-b6f5-db3df0c8bf0d}) of ThingClass systemMonitor</extracomment>
<extracomment>The name of the ThingClass ({181d852a-6290-434d-891a-35d2c3435f47})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
@ -55,15 +31,40 @@ The name of the StateType ({efe2d520-3b35-4668-b6f5-db3df0c8bf0d}) of ThingClass
<translation type="unfinished"></translation>
</message>
<message>
<source>virtual memory usage</source>
<extracomment>The name of the ParamType (ThingClass: systemMonitor, EventType: virtualMemory, ID: {6d71b001-c7fe-4f08-941d-47009b710d94})
<source>Memory usage</source>
<extracomment>The name of the StateType ({672748c1-dbd0-4c65-8983-d0dd34892176}) of ThingClass systemMonitor
----------
The name of the StateType ({6d71b001-c7fe-4f08-941d-47009b710d94}) of ThingClass systemMonitor</extracomment>
The name of the StateType ({efe2d520-3b35-4668-b6f5-db3df0c8bf0d}) of ThingClass processMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>virtual memory usage changed</source>
<extracomment>The name of the EventType ({6d71b001-c7fe-4f08-941d-47009b710d94}) of ThingClass systemMonitor</extracomment>
<source>Process monitor</source>
<extracomment>The name of the ThingClass ({a3a15700-c251-4803-a608-0f3ddfcbd7a8})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Process name</source>
<extracomment>The name of the ParamType (ThingClass: processMonitor, Type: thing, ID: {794a2a7e-01dc-4383-8110-4d1cd59c421f})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Running</source>
<extracomment>The name of the StateType ({8b8b6b38-79ed-4f0e-bdc7-445f073fa4b7}) of ThingClass processMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Shared memory usage</source>
<extracomment>The name of the StateType ({fcdae649-dcc2-4f5b-a241-fe40fb07c071}) of ThingClass processMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Storage usage</source>
<extracomment>The name of the StateType ({47d6e6fb-5dc9-4e3f-ad24-c9d7eab320bd}) of ThingClass systemMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Virtual memory usage</source>
<extracomment>The name of the StateType ({6d71b001-c7fe-4f08-941d-47009b710d94}) of ThingClass processMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
</context>

View File

@ -5,26 +5,14 @@
<name>systemMonitor</name>
<message>
<source>CPU usage</source>
<extracomment>The name of the ParamType (ThingClass: systemMonitor, EventType: cpuUsage, ID: {56f8fac2-1021-4b96-bf15-23b21bb85b4c})
<extracomment>The name of the StateType ({0744b84a-f9dc-4e53-a6f3-3533e909c533}) of ThingClass systemMonitor
----------
The name of the StateType ({56f8fac2-1021-4b96-bf15-23b21bb85b4c}) of ThingClass systemMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>CPU usage changed</source>
<extracomment>The name of the EventType ({56f8fac2-1021-4b96-bf15-23b21bb85b4c}) of ThingClass systemMonitor</extracomment>
The name of the StateType ({56f8fac2-1021-4b96-bf15-23b21bb85b4c}) of ThingClass processMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>RSS memory usage</source>
<extracomment>The name of the ParamType (ThingClass: systemMonitor, EventType: rssMemory, ID: {d9671ee3-51be-4cf8-8601-125c0684aec9})
----------
The name of the StateType ({d9671ee3-51be-4cf8-8601-125c0684aec9}) of ThingClass systemMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>RSS memory usage changed</source>
<extracomment>The name of the EventType ({d9671ee3-51be-4cf8-8601-125c0684aec9}) of ThingClass systemMonitor</extracomment>
<extracomment>The name of the StateType ({d9671ee3-51be-4cf8-8601-125c0684aec9}) of ThingClass processMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
@ -34,19 +22,7 @@ The name of the StateType ({d9671ee3-51be-4cf8-8601-125c0684aec9}) of ThingClass
</message>
<message>
<source>System monitor</source>
<extracomment>The name of the ThingClass ({a3a15700-c251-4803-a608-0f3ddfcbd7a8})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>memory usage</source>
<extracomment>The name of the ParamType (ThingClass: systemMonitor, EventType: percentMemory, ID: {efe2d520-3b35-4668-b6f5-db3df0c8bf0d})
----------
The name of the StateType ({efe2d520-3b35-4668-b6f5-db3df0c8bf0d}) of ThingClass systemMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>memory usage changed</source>
<extracomment>The name of the EventType ({efe2d520-3b35-4668-b6f5-db3df0c8bf0d}) of ThingClass systemMonitor</extracomment>
<extracomment>The name of the ThingClass ({181d852a-6290-434d-891a-35d2c3435f47})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
@ -55,15 +31,40 @@ The name of the StateType ({efe2d520-3b35-4668-b6f5-db3df0c8bf0d}) of ThingClass
<translation type="unfinished"></translation>
</message>
<message>
<source>virtual memory usage</source>
<extracomment>The name of the ParamType (ThingClass: systemMonitor, EventType: virtualMemory, ID: {6d71b001-c7fe-4f08-941d-47009b710d94})
<source>Memory usage</source>
<extracomment>The name of the StateType ({672748c1-dbd0-4c65-8983-d0dd34892176}) of ThingClass systemMonitor
----------
The name of the StateType ({6d71b001-c7fe-4f08-941d-47009b710d94}) of ThingClass systemMonitor</extracomment>
The name of the StateType ({efe2d520-3b35-4668-b6f5-db3df0c8bf0d}) of ThingClass processMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>virtual memory usage changed</source>
<extracomment>The name of the EventType ({6d71b001-c7fe-4f08-941d-47009b710d94}) of ThingClass systemMonitor</extracomment>
<source>Process monitor</source>
<extracomment>The name of the ThingClass ({a3a15700-c251-4803-a608-0f3ddfcbd7a8})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Process name</source>
<extracomment>The name of the ParamType (ThingClass: processMonitor, Type: thing, ID: {794a2a7e-01dc-4383-8110-4d1cd59c421f})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Running</source>
<extracomment>The name of the StateType ({8b8b6b38-79ed-4f0e-bdc7-445f073fa4b7}) of ThingClass processMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Shared memory usage</source>
<extracomment>The name of the StateType ({fcdae649-dcc2-4f5b-a241-fe40fb07c071}) of ThingClass processMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Storage usage</source>
<extracomment>The name of the StateType ({47d6e6fb-5dc9-4e3f-ad24-c9d7eab320bd}) of ThingClass systemMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Virtual memory usage</source>
<extracomment>The name of the StateType ({6d71b001-c7fe-4f08-941d-47009b710d94}) of ThingClass processMonitor</extracomment>
<translation type="unfinished"></translation>
</message>
</context>