Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed format in metrics and implemented process metric #16

Merged
merged 5 commits into from
Feb 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion monitor-agent/core/command.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import subprocess
import psutil
import typing
import time
import os
Expand Down
88 changes: 30 additions & 58 deletions monitor-agent/core/models/metricModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import platform
import time
import datetime
import asyncio
import os


class Status:
Expand Down Expand Up @@ -31,46 +31,20 @@ class MetricDynamic:
def __init__(self):
self.cpu_freq = psutil.cpu_freq()._asdict()
self.cpu_percent = psutil.cpu_percent()
self.ram = _ram_data()
self.network_current_in, self.network_current_out = asyncio.run(
_cur_network_traffic()
)
self.ram = psutil.virtual_memory()._asdict()
self.network_current_in, self.network_current_out = _cur_network_traffic()
self.network_total_in, self.network_total_out = _total_network_traffic()
# self.connections = {}
# for index, connection in enumerate(psutil.net_connections()):
# self.connections[index] = connection
try:
self.battery = psutil.sensors_battery()._asdict()
except AttributeError:
# If no battery is installed or metrics can’t be determined None is returned.
self.battery = None
self.users = _user_list()
# self.process = {p.pid: p.info for p in psutil.process_iter(['name', 'username'])}
self.processes = _process(self.ram["total"], self.cpu_percent)
self.disk_percent = _disk_percent()
self.uptime = _uptime()


def _get_size(bytes: int, suffix="B"):
"""Scale bytes to its proper format.
e.g:
1253656 => '1.20MB'
1253656678 => '1.17GB'

Args:
bytes (int): Numeric size to format
suffix (str): Format of introduced size: 'B', 'K', 'M', 'G', 'T', 'P'

Returns:
string: Formatted size

"""
factor = 1024
for unit in ["", "K", "M", "G", "T", "P"]:
if bytes < factor:
return f"{bytes:.2f}{unit}{suffix}"
bytes /= factor


def _format_timestamp(date: float):
"""_summary_

Expand All @@ -92,7 +66,7 @@ def _uptime():
return str(datetime.timedelta(seconds=(time.time() - psutil.boot_time())))


async def _cur_network_traffic(interval=1):
def _cur_network_traffic(interval=1):
"""_summary_

Args:
Expand All @@ -105,7 +79,7 @@ async def _cur_network_traffic(interval=1):
net1_out = psutil.net_io_counters().bytes_sent
net1_in = psutil.net_io_counters().bytes_recv

await asyncio.sleep(interval)
time.sleep(interval)

# Get new net in/out
net2_out = psutil.net_io_counters().bytes_sent
Expand All @@ -115,35 +89,42 @@ async def _cur_network_traffic(interval=1):
current_in = 0 if net1_in > net2_in else net2_in - net1_in
current_out = 0 if net1_out > net2_out else net2_out - net1_out

# Final Variables
# Traffic in Megabytes
network_current_in = _get_size(round(current_in, 2))
network_current_out = _get_size(round(current_out, 2))

return network_current_in, network_current_out
return current_in, current_out


def _process(ram: int, pc_cpu_percent):
process = {}
threshold = 10
for p in psutil.process_iter(["name", "username"]):
with p.oneshot():
cpu_percent = p.cpu_percent()
ram_percent = round((p.memory_info().vms / ram) * 100, 2)
if (
cpu_percent > threshold and not cpu_percent > pc_cpu_percent
) or ram_percent > threshold:
process[p.pid] = {
"name": p.name(),
"cpu_percent": cpu_percent,
"ram_percent": ram_percent,
"username": p.username(),
"ppid": p.ppid(),
# Requires elevated permissions
# "path": p.exe()
}
return process


def _total_network_traffic():
# get IO statistics since boot
net_io = psutil.net_io_counters()
network_total_out = _get_size(net_io.bytes_sent)
network_total_in = _get_size(net_io.bytes_recv)
return network_total_in, network_total_out
return net_io.bytes_recv, net_io.bytes_sent


def _boot_date():
boot_time_timestamp = psutil.boot_time()
return _format_timestamp(boot_time_timestamp)


def _ram_data():
ram = psutil.virtual_memory()._asdict()
for key, value in ram.items():
if key != "percent":
ram[key] = _get_size(value)
return ram


def _ip_addresses():
addresses = {}
for key, value in psutil.net_if_addrs().items():
Expand Down Expand Up @@ -171,15 +152,6 @@ def _disk_list():
try:
disk_location = disk.device
disk_list[disk_location] = psutil.disk_usage(disk_location)._asdict()
disk_list[disk_location]["free"] = _get_size(
disk_list[disk_location]["free"]
)
disk_list[disk_location]["total"] = _get_size(
disk_list[disk_location]["total"]
)
disk_list[disk_location]["used"] = _get_size(
disk_list[disk_location]["used"]
)
except PermissionError as msg:
continue
return disk_list
Expand Down
27 changes: 26 additions & 1 deletion monitor-agent/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
endpoints = {
"root": "/",
"command": "/command",
"metrics_endpoint": "/metrics",
}


Expand All @@ -21,12 +22,20 @@ async def root():


@api.post(endpoints["command"])
async def command(command: str, timeout: int = 10):
async def command(command: str, timeout: int):
# if token:
# blablabla
return Command(command, timeout).__dict__


if settings.metrics_endpoint:

@api.get(endpoints["metrics_endpoint"])
async def metrics_endpoint():
elapsed_time, data = send_metrics_adapter([static, dynamic])
return {"data": data, "elapsed_time": elapsed_time}


@api.on_event("startup")
@repeat_every(seconds=settings.post_task_interval, logger=logger, wait_first=True)
def periodic():
Expand All @@ -44,4 +53,20 @@ def start():
host=settings.host,
port=settings.port,
reload=settings.reload,
workers=settings.workers,
log_level=settings.log_level,
interface="asgi3",
# workers=settings.workers,
debug=settings.debug,
ssl_keyfile=settings.ssl_keyfile,
ssl_keyfile_password=settings.ssl_keyfile_password,
ssl_certfile=settings.ssl_certfile,
ssl_version=settings.ssl_version,
ssl_cert_reqs=settings.ssl_cert_reqs,
ssl_ca_certs=settings.ssl_ca_certs,
ssl_ciphers=settings.ssl_ciphers,
limit_concurrency=settings.limit_concurrency,
limit_max_requests=settings.limit_max_requests,
backlog=settings.backlog,
timeout_keep_alive=settings.timeout_keep_alive,
)
27 changes: 24 additions & 3 deletions monitor-agent/settings.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
from pydantic import BaseSettings


# https://www.uvicorn.org/settings/
class Settings(BaseSettings):
host: str = "0.0.0.0"
port: int = 8000
workers: int = 4

reload: bool = True
debug: bool = True
log_level: str = "trace"

ssl_keyfile: str = None
ssl_keyfile_password: str = None
ssl_certfile: str = None
ssl_version: int = 3
ssl_cert_reqs: int = None
ssl_ca_certs: str = None
ssl_ciphers: str = "TLSv1"

limit_concurrency: int = None
limit_max_requests: int = None
backlog: int = 2048

timeout_keep_alive: int = 5

metrics_endpoint: bool = True
metrics_URL: str = "http://httpbin.org/post"
alerts_URL: str = ""
post_task_interval: int = 60
metrics_file: str = "metrics.json"
# metrics_file: str = "metrics.json"

alerts_URL: str = ""


settings = Settings()
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ python = ">=3.7,<4.0.0"
requests = "^2.27.1"
psutil = "^5.9.0"
fastapi = "^0.74.1"
fastapi-utils = "^0.2.1"
uvicorn = "^0.17.4"
pydantic = "^1.9.0"
fastapi-utils = "^0.2.1"

[tool.poetry.dev-dependencies]
pytest = "^7.0.0"
Expand Down