diff --git a/platypush/backend/http/webapp/src/components/panels/Entities/MemoryStats.vue b/platypush/backend/http/webapp/src/components/panels/Entities/MemoryStats.vue
new file mode 100644
index 000000000..b013df2c6
--- /dev/null
+++ b/platypush/backend/http/webapp/src/components/panels/Entities/MemoryStats.vue
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platypush/backend/http/webapp/src/components/panels/Entities/SwapStats.vue b/platypush/backend/http/webapp/src/components/panels/Entities/SwapStats.vue
new file mode 120000
index 000000000..fedbe17ed
--- /dev/null
+++ b/platypush/backend/http/webapp/src/components/panels/Entities/SwapStats.vue
@@ -0,0 +1 @@
+MemoryStats.vue
\ No newline at end of file
diff --git a/platypush/backend/http/webapp/src/components/panels/Entities/meta.json b/platypush/backend/http/webapp/src/components/panels/Entities/meta.json
index cbaa8bf8d..49e45a605 100644
--- a/platypush/backend/http/webapp/src/components/panels/Entities/meta.json
+++ b/platypush/backend/http/webapp/src/components/panels/Entities/meta.json
@@ -47,6 +47,22 @@
}
},
+ "memory_stats": {
+ "name": "System",
+ "name_plural": "System",
+ "icon": {
+ "class": "fas fa-memory"
+ }
+ },
+
+ "swap_stats": {
+ "name": "System",
+ "name_plural": "System",
+ "icon": {
+ "class": "fas fa-memory"
+ }
+ },
+
"current_sensor": {
"name": "Sensor",
"name_plural": "Sensors",
diff --git a/platypush/entities/system.py b/platypush/entities/system.py
index 60525a207..687f81ac9 100644
--- a/platypush/entities/system.py
+++ b/platypush/entities/system.py
@@ -1,4 +1,4 @@
-from sqlalchemy import Column, ForeignKey, Integer, JSON, String
+from sqlalchemy import Column, Float, ForeignKey, Integer, JSON, String
from platypush.common.db import Base
@@ -88,3 +88,55 @@ if 'cpu_stats' not in Base.metadata:
__mapper_args__ = {
'polymorphic_identity': __tablename__,
}
+
+
+if 'memory_stats' not in Base.metadata:
+
+ class MemoryStats(Entity):
+ """
+ ``MemoryStats`` ORM model.
+ """
+
+ __tablename__ = 'memory_stats'
+
+ id = Column(
+ Integer, ForeignKey(Entity.id, ondelete='CASCADE'), primary_key=True
+ )
+
+ total = Column(Integer)
+ available = Column(Integer)
+ used = Column(Integer)
+ free = Column(Integer)
+ active = Column(Integer)
+ inactive = Column(Integer)
+ buffers = Column(Integer)
+ cached = Column(Integer)
+ shared = Column(Integer)
+ percent = Column(Float)
+
+ __mapper_args__ = {
+ 'polymorphic_identity': __tablename__,
+ }
+
+
+if 'swap_stats' not in Base.metadata:
+
+ class SwapStats(Entity):
+ """
+ ``SwapStats`` ORM model.
+ """
+
+ __tablename__ = 'swap_stats'
+
+ id = Column(
+ Integer, ForeignKey(Entity.id, ondelete='CASCADE'), primary_key=True
+ )
+
+ total = Column(Integer)
+ used = Column(Integer)
+ free = Column(Integer)
+ percent = Column(Float)
+
+ __mapper_args__ = {
+ 'polymorphic_identity': __tablename__,
+ }
diff --git a/platypush/message/response/system/__init__.py b/platypush/message/response/system/__init__.py
index 45c7d51f5..ac9b4157a 100644
--- a/platypush/message/response/system/__init__.py
+++ b/platypush/message/response/system/__init__.py
@@ -28,66 +28,6 @@ class SensorResponse(SystemResponse):
pass
-class VirtualMemoryUsageResponse(MemoryResponse):
- def __init__(
- self,
- total: int,
- available: int,
- percent: float,
- used: int,
- free: int,
- active: int,
- inactive: int,
- buffers: int,
- cached: int,
- shared: int,
- *args,
- **kwargs
- ):
- super().__init__(
- *args,
- output={
- 'total': total,
- 'available': available,
- 'percent': percent,
- 'used': used,
- 'free': free,
- 'active': active,
- 'inactive': inactive,
- 'buffers': buffers,
- 'cached': cached,
- 'shared': shared,
- },
- **kwargs
- )
-
-
-class SwapMemoryUsageResponse(MemoryResponse):
- def __init__(
- self,
- total: int,
- percent: float,
- used: int,
- free: int,
- sin: int,
- sout: int,
- *args,
- **kwargs
- ):
- super().__init__(
- *args,
- output={
- 'total': total,
- 'percent': percent,
- 'used': used,
- 'free': free,
- 'sin': sin,
- 'sout': sout,
- },
- **kwargs
- )
-
-
class DiskPartitionResponse(DiskResponse):
def __init__(
self,
diff --git a/platypush/plugins/system/__init__.py b/platypush/plugins/system/__init__.py
index 20e5392e4..dc455936d 100644
--- a/platypush/plugins/system/__init__.py
+++ b/platypush/plugins/system/__init__.py
@@ -13,10 +13,10 @@ from platypush.entities.system import (
CpuInfo as CpuInfoModel,
CpuStats as CpuStatsModel,
CpuTimes as CpuTimesModel,
+ MemoryStats as MemoryStatsModel,
+ SwapStats as SwapStatsModel,
)
from platypush.message.response.system import (
- VirtualMemoryUsageResponse,
- SwapMemoryUsageResponse,
DiskResponseList,
DiskPartitionResponse,
DiskUsageResponse,
@@ -46,6 +46,10 @@ from platypush.schemas.system import (
CpuStatsSchema,
CpuTimes,
CpuTimesSchema,
+ MemoryStats,
+ MemoryStatsSchema,
+ SwapStats,
+ SwapStatsSchema,
SystemInfoSchema,
)
@@ -203,45 +207,35 @@ class SystemPlugin(SensorPlugin, EntityManager):
return psutil.getloadavg()
- @action
- def mem_virtual(self) -> VirtualMemoryUsageResponse:
- """
- Get the current virtual memory usage stats.
- :return: list of :class:`platypush.message.response.system.VirtualMemoryUsageResponse`
- """
+ def _mem_virtual(self) -> MemoryStats:
import psutil
- mem = psutil.virtual_memory()
- return VirtualMemoryUsageResponse(
- total=mem.total,
- available=mem.available,
- percent=mem.percent,
- used=mem.used,
- free=mem.free,
- active=mem.active,
- inactive=mem.inactive,
- buffers=mem.buffers,
- cached=mem.cached,
- shared=mem.shared,
- )
+ return MemoryStatsSchema().load(
+ psutil.virtual_memory()._asdict()
+ ) # type: ignore
@action
- def mem_swap(self) -> SwapMemoryUsageResponse:
+ def mem_virtual(self) -> dict:
"""
Get the current virtual memory usage stats.
- :return: list of :class:`platypush.message.response.system.SwapMemoryUsageResponse`
+
+ :return: .. schema:: system.MemoryStatsSchema
"""
+ return MemoryStatsSchema().dump(self._mem_virtual()) # type: ignore
+
+ def _mem_swap(self) -> SwapStats:
import psutil
- mem = psutil.swap_memory()
- return SwapMemoryUsageResponse(
- total=mem.total,
- percent=mem.percent,
- used=mem.used,
- free=mem.free,
- sin=mem.sin,
- sout=mem.sout,
- )
+ return SwapStatsSchema().load(psutil.swap_memory()._asdict()) # type: ignore
+
+ @action
+ def mem_swap(self) -> dict:
+ """
+ Get the current swap memory usage stats.
+
+ :return: .. schema:: system.SwapStatsSchema
+ """
+ return SwapStatsSchema().dump(self._mem_swap()) # type: ignore
@action
def disk_partitions(self) -> DiskResponseList:
@@ -793,11 +787,13 @@ class SystemPlugin(SensorPlugin, EntityManager):
'cpu': {
'frequency': self._cpu_frequency_avg(),
'info': self._cpu_info,
- 'load_avg': self.load_avg().output,
+ 'load_avg': self.load_avg().output, # type: ignore
'stats': self._cpu_stats(),
'times': self._cpu_times_avg(),
'percent': self.cpu_percent().output / 100.0, # type: ignore
},
+ 'memory': self._mem_virtual(),
+ 'swap': self._mem_swap(),
}
)
@@ -867,7 +863,17 @@ class SystemPlugin(SensorPlugin, EntityManager):
value=cpu['percent'],
),
],
- )
+ ),
+ MemoryStatsModel(
+ id='system:memory',
+ name='Memory',
+ **entities['memory'],
+ ),
+ SwapStatsModel(
+ id='system:swap',
+ name='Swap',
+ **entities['swap'],
+ ),
]
diff --git a/platypush/schemas/system.py b/platypush/schemas/system.py
index fb4963820..927272c10 100644
--- a/platypush/schemas/system.py
+++ b/platypush/schemas/system.py
@@ -9,6 +9,9 @@ from platypush.schemas.dataclasses import DataClassSchema
def percent_field(**kwargs):
+ """
+ Field used to model percentage float fields between 0 and 1.
+ """
return field(
default_factory=float,
metadata={
@@ -33,6 +36,19 @@ class CpuInfoBaseSchema(DataClassSchema):
return data
+class MemoryStatsBaseSchema(DataClassSchema):
+ """
+ Base schema for memory stats.
+ """
+
+ @pre_load
+ def pre_load(self, data: dict, **_) -> dict:
+ # Normalize the percentage between 0 and 1
+ if data.get('percent') is not None:
+ data['percent'] /= 100
+ return data
+
+
class CpuTimesBaseSchema(DataClassSchema):
"""
Base schema for CPU times.
@@ -226,6 +242,120 @@ class CpuData:
percent: float = percent_field()
+@dataclass
+class MemoryStats:
+ """
+ Memory stats data class.
+ """
+
+ total: int = field(
+ metadata={
+ 'metadata': {
+ 'description': 'Total available memory, in bytes',
+ }
+ }
+ )
+
+ available: int = field(
+ metadata={
+ 'metadata': {
+ 'description': 'Available memory, in bytes',
+ }
+ }
+ )
+
+ used: int = field(
+ metadata={
+ 'metadata': {
+ 'description': 'Used memory, in bytes',
+ }
+ }
+ )
+
+ free: int = field(
+ metadata={
+ 'metadata': {
+ 'description': 'Free memory, in bytes',
+ }
+ }
+ )
+
+ active: int = field(
+ metadata={
+ 'metadata': {
+ 'description': 'Size of the active memory, in bytes',
+ }
+ }
+ )
+
+ inactive: int = field(
+ metadata={
+ 'metadata': {
+ 'description': 'Size of the inactive memory, in bytes',
+ }
+ }
+ )
+
+ buffers: int = field(
+ metadata={
+ 'metadata': {
+ 'description': 'Size of the buffered memory, in bytes',
+ }
+ }
+ )
+
+ cached: int = field(
+ metadata={
+ 'metadata': {
+ 'description': 'Size of the cached memory, in bytes',
+ }
+ }
+ )
+
+ shared: int = field(
+ metadata={
+ 'metadata': {
+ 'description': 'Size of the shared memory, in bytes',
+ }
+ }
+ )
+
+ percent: float = percent_field()
+
+
+@dataclass
+class SwapStats:
+ """
+ Swap memory stats data class.
+ """
+
+ total: int = field(
+ metadata={
+ 'metadata': {
+ 'description': 'Total available memory, in bytes',
+ }
+ }
+ )
+
+ used: int = field(
+ metadata={
+ 'metadata': {
+ 'description': 'Used memory, in bytes',
+ }
+ }
+ )
+
+ free: int = field(
+ metadata={
+ 'metadata': {
+ 'description': 'Free memory, in bytes',
+ }
+ }
+ )
+
+ percent: float = percent_field()
+
+
@dataclass
class SystemInfo:
"""
@@ -233,10 +363,14 @@ class SystemInfo:
"""
cpu: CpuData
+ memory: MemoryStats
+ swap: SwapStats
CpuFrequencySchema = class_schema(CpuFrequency, base_schema=DataClassSchema)
CpuInfoSchema = class_schema(CpuInfo, base_schema=CpuInfoBaseSchema)
CpuTimesSchema = class_schema(CpuTimes, base_schema=CpuTimesBaseSchema)
CpuStatsSchema = class_schema(CpuStats, base_schema=DataClassSchema)
+MemoryStatsSchema = class_schema(MemoryStats, base_schema=MemoryStatsBaseSchema)
+SwapStatsSchema = class_schema(SwapStats, base_schema=MemoryStatsBaseSchema)
SystemInfoSchema = class_schema(SystemInfo, base_schema=DataClassSchema)