Skip to content
Open
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ env/
__pycache__/
*.py[cod]
*$py.class
.idea/
venv/

logs/
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,32 @@ Make sure you have the following installed on your system:
- InfluxDB
- [InfluxDB Python Client](https://github.com/influxdata/influxdb-client-python)

## VM Preparation

Install `kvmtop`
```commandline
wget https://github.com/cha87de/kvmtop/releases/download/2.1.3/kvmtop_2.1.3_linux_amd64.deb
sudo dpkg -i kvmtop_2.1.3_linux_amd64.deb
```
Try kvmtop it may fail with error saying missing package libncurses5.so
To fix it add below lines to `/etc/apt/sources.list`
```commandline
deb http://security.ubuntu.com/ubuntu focal-security main
deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse
```
And execute below commands:
```commandline
sudo apt update
sudo apt upgrade
sudo apt-get install libncurses5 libncurses5:i386
```
It will resolve this issue, try `kvmtop` command in terminal and verify everything working as expected

Note: If you got stuck with the above error then, remove `libncurses5:i386` and install only `libncurses5` (Sample Error message: E: Unable to locate package libncurses5:i386)


## Usage

1. Set up your InfluxDB configuration by creating a `.env` file with the following variables:
Expand All @@ -19,10 +45,22 @@ Make sure you have the following installed on your system:
INFLUX_TOKEN="your-influxdb-token"
INFLUX_ORG="your-influxdb-organization"
INFLUX_BUCKET="your-influxdb-bucket"
ROOT_PASS="user-passof-ubuntu-terminal"
DISK_PATH="disk-path-to-be-monitored"
```
2. Run the script:

```bash
python main.py
python system_monitor.py
```

## Configure systemd service
1. Pull latest changes to the machine.
2. Update and validate `libmon.service` file in the Libmon directory
3. Copy the directory to `sudo cp libmon.service /etc/systemd/system/libmon.service`
4. Enable the service by `sudo systemctl enable libmon.service`
5. Start the service by `sudo systemctl start libmon.service`
6. Validate the process status by `sudo systemctl status libmon.service and tail -f /home/dev/Libmon/logs/system_monitor.log`.



10 changes: 6 additions & 4 deletions config/modules_config.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{
"modules": [
{"name": "uptime", "interval_seconds": 600},
{"name": "disk", "interval_seconds": 600},
{"name": "partition", "interval_seconds": 3600},
{"name": "sensors", "interval_seconds": 60}
{"name": "uptime", "interval_seconds": 30},
{"name": "disk", "interval_seconds": 30},
{"name": "partition", "interval_seconds": 30},
{"name": "sensors", "interval_seconds": 30},
{"name": "kvm_monitor", "interval_seconds": 30},
{"name": "network", "interval_seconds": 30}
]
}
29 changes: 29 additions & 0 deletions connection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import os
import influxdb_client

from dotenv import load_dotenv
from influxdb_client.client.write_api import SYNCHRONOUS

load_dotenv()

INFLUX_URL = os.getenv("INFLUX_URL")
INFLUX_TOKEN = os.getenv("INFLUX_TOKEN")
INFLUX_ORG = os.getenv("INFLUX_ORG")
INFLUX_BUCKET = os.getenv("INFLUX_BUCKET")

client = influxdb_client.InfluxDBClient(url=INFLUX_URL, token=INFLUX_TOKEN, org=INFLUX_ORG, verify_ssl=False)
write_api = client.write_api(write_options=SYNCHRONOUS)


def create_influxdb_point(measurement, data):
point = influxdb_client.Point(measurement)
for key, value in data.items():
if key == 'host':
# hotfix for dot in hostname
point = point.tag(key, value.split('.')[0])
if key == 'vm_name':
point = point.tag(key, value)
else:
point = point.field(key, value)

return point
32 changes: 32 additions & 0 deletions launch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/bash

# Name of the process to check (without path)
PROCESS_NAME="system_monitor.py"

# Directory of your Python virtual environment
VENV_DIR="/path/to/your/venv"

# Directory where your Python script is located
SCRIPT_DIR="/path/to/your/script"

# Name of your Python script
SCRIPT_NAME="your_script.py"

# Check if the process is running
if ! pgrep -f "$PROCESS_NAME" > /dev/null
then
echo "Process $PROCESS_NAME is not running. Starting it..."

# Activate virtual environment
source "$VENV_DIR/bin/activate"

# Change directory to the script location
cd "$SCRIPT_DIR"

# Launch the Python script
nohup python "$SCRIPT_NAME" &

echo "Process $PROCESS_NAME started."
else
echo "Process $PROCESS_NAME is already running."
fi
66 changes: 0 additions & 66 deletions main.py

This file was deleted.

20 changes: 20 additions & 0 deletions modules/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import logging
import os

MONITORING_INTERVAL = 30

if not os.path.exists('./logs'):
os.makedirs('logs')

# Configure logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("./logs/system_monitor.log"),
logging.StreamHandler()
]
)

# Create a logger instance
logger = logging.getLogger(__name__)
58 changes: 42 additions & 16 deletions modules/disk.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import os
import socket
import subprocess
import json

import ujson

from modules import logger


def get_nvme_disk_names():
try:
Expand All @@ -12,20 +16,37 @@ def get_nvme_disk_names():
return nvme_disks

except subprocess.CalledProcessError as e:
print(f"Error: {e}")
logger.debug(f"Error: {e}")
return []


def get_disk_stats(disk_path):
try:
output = subprocess.check_output(
args=['sudo', '-S', 'smartctl', '-j', '-a', disk_path],
input=f'{os.getenv("ROOT_PASS")}\n',
universal_newlines=True
)
if output and output.startswith('{ "'):
data = ujson.loads(output)
return data
except subprocess.CalledProcessError as e:
logger.debug(f"Command failed with exit status {e.returncode}")
if e.output and e.output.startswith('{\n'):
data = ujson.loads(e.output)
return data
except Exception as e:
logger.debug(str(e))
return {}


def get_smartctl_data(disk_path):

if disk_path is None:
print("DISK_PATH environment variable is not set.")
logger.debug("DISK_PATH environment variable is not set.")
return None

command_output = subprocess.check_output(['smartctl', '-j', '-a', disk_path]).decode('utf-8')

# Parse JSON output
smart_data = json.loads(command_output)
smart_data = get_disk_stats(disk_path)

# Extract relevant values from the JSON data
hostname = socket.gethostname()
Expand Down Expand Up @@ -57,18 +78,23 @@ def get_smartctl_data(disk_path):
"media_and_data_integrity_errors": int(media_and_data_integrity_errors)
}


def collect_data():
if os.getenv("STORAGE_SERVER"):
disks = get_nvme_disk_names()
disk_data = []
for disk in disks:
disk_data.append(get_smartctl_data(f"/dev/{disk}"))
try:
if os.getenv("STORAGE_SERVER"):
disks = get_nvme_disk_names()
disk_data = []
for disk in disks:
disk_data.append(get_smartctl_data(f"/dev/{disk}"))

return disk_data
return disk_data

disk_path = os.getenv("DISK_PATH")
return get_smartctl_data(disk_path)
disk_path = os.getenv("DISK_PATH")
return get_smartctl_data(disk_path)
except Exception as e:
logger.debug(str(e))
return {}


if __name__=="__main__":
print(collect_data())
logger.debug(collect_data())
Loading