From 3ba5c70045f3ef5d662729c75b12b615a4fdbee4 Mon Sep 17 00:00:00 2001 From: jokob-sk Date: Sat, 22 Feb 2025 09:54:43 +1100 Subject: [PATCH] docs --- docs/COMMON_ISSUES.md | 15 +++- docs/PERFORMANCE.md | 87 +++++++++++++++------- front/img/NetAlertX_logo_b_w_info.png | Bin 0 -> 8457 bytes front/php/templates/language/ca_ca.json | 0 front/php/templates/language/ru_ru.json | 0 front/plugins/newdev_template/config.json | 2 +- mkdocs.yml | 2 +- 7 files changed, 76 insertions(+), 30 deletions(-) create mode 100755 front/img/NetAlertX_logo_b_w_info.png mode change 100644 => 100755 front/php/templates/language/ca_ca.json mode change 100644 => 100755 front/php/templates/language/ru_ru.json diff --git a/docs/COMMON_ISSUES.md b/docs/COMMON_ISSUES.md index 7e83fd5f..073fe573 100755 --- a/docs/COMMON_ISSUES.md +++ b/docs/COMMON_ISSUES.md @@ -1,6 +1,6 @@ ### Loading... -Often if the application is misconfigured the `Loading...` dialog is continuously displayed. This is most likely caused by the backed failing to start. The **Maintenance -> Logs** section should give you more details on what's happenning. If there is no exception, check the Portainer log, or start the container in the foreground (without the `-d` parameter) to observe any exceptions. It's advisable to enable `trace` or `debug`. Check the [Debug tips](./DEBUG_TIPS.md) on detailed instructions. +Often if the application is misconfigured the `Loading...` dialog is continuously displayed. This is most likely caused by the backed failing to start. The **Maintenance -> Logs** section should give you more details on what's happening. If there is no exception, check the Portainer log, or start the container in the foreground (without the `-d` parameter) to observe any exceptions. It's advisable to enable `trace` or `debug`. Check the [Debug tips](./DEBUG_TIPS.md) on detailed instructions. ### Incorrect SCAN_SUBNETS @@ -8,7 +8,7 @@ One of the most common issues is not configuring `SCAN_SUBNETS` correctly. If th ### Duplicate devices and notifications -The app uses the MAC address as an unique identifier for devices. If a new MAC is detected a new device is added to the application and corresponding notifications are triggered. This means that if the MAC of an existing device changes, the device will be logged as a new device. You can usually prevent this from happenning by changing the device configuration (in Android, iOS, or Windows) for your network. See the [Random Macs](./RANDOM_MAC.md) guide for details. +The app uses the MAC address as an unique identifier for devices. If a new MAC is detected a new device is added to the application and corresponding notifications are triggered. This means that if the MAC of an existing device changes, the device will be logged as a new device. You can usually prevent this from happening by changing the device configuration (in Android, iOS, or Windows) for your network. See the [Random Macs](./RANDOM_MAC.md) guide for details. ### Permissions @@ -45,4 +45,13 @@ The link above will probably break in time too. Go to https://packages.debian.or ### Only Router and own device show up -Make sure that the subnet and interface in `SCAN_SUBNETS` are correct. If your device/NAS has multiple ethernet ports, you probably need to change `eth0` to something else. \ No newline at end of file +Make sure that the subnet and interface in `SCAN_SUBNETS` are correct. If your device/NAS has multiple ethernet ports, you probably need to change `eth0` to something else. + +### Losing my settings and devices after an update + +If you lose your devices and/or settings after an update that means you don't have the `/app/db` and `/app/config` folders mapped to a permanent storage. That means every time you update these folders are re-created. Make sure you have the [volumes specified correctly](./DOCKER_COMPOSE.md) in your `docker-compose.yml` or run command. + + +### The application is slow + +Slowness is usually caused by incorrect settings (the app might restart, so check the `app.log`), too many background processes (disable unnecessary scanners), too long scans (limit the number of scanned devices), too many disk operations, or some maintenance plugins might have failed. See the [Performance tips](./PERFORMANCE.md) docs for details. \ No newline at end of file diff --git a/docs/PERFORMANCE.md b/docs/PERFORMANCE.md index 44ba494f..25375a85 100755 --- a/docs/PERFORMANCE.md +++ b/docs/PERFORMANCE.md @@ -1,59 +1,96 @@ -# Performance tips +# Performance Optimization Guide -The application runs regular maintenance and DB cleanup tasks. If these tasks fail, you might encounter performance issues. +There are several ways to improve the application's performance. The application has been tested on a range of devices, from a Raspberry Pi 4 to NAS and NUC systems. If you are running the application on a lower-end device, carefully fine-tune the performance settings to ensure an optimal user experience. -Most performance issues are caused by a big database or large log files. Enabling unnecessary plugins will also lead to performance degradation. +## Common Causes of Slowness -You can always check the size of your database and database tables under the Maintenance page. +Performance issues are usually caused by: -![Db size check](./img/PERFORMANCE/db_size_check.png) +- **Incorrect settings** – The app may restart unexpectedly. Check `app.log` under **Maintenance → Logs** for details. +- **Too many background processes** – Disable unnecessary scanners. +- **Long scan durations** – Limit the number of scanned devices. +- **Excessive disk operations** – Optimize scanning and logging settings. +- **Failed maintenance plugins** – Ensure maintenance tasks are running properly. + +The application performs regular maintenance and database cleanup. If these tasks fail, performance may degrade. + +### Database and Log File Size + +A large database or oversized log files can slow down performance. You can check database and table sizes on the **Maintenance** page. + +![DB size check](./img/PERFORMANCE/db_size_check.png) > [!NOTE] -> For around 100 devices the database should be approximately `50MB` and none of the entries (rows) should exceed the value of `10 000` on a healthy system. These numbers will depend on your network activity and settings. +> - For **~100 devices**, the database should be around **50MB**. +> - No table should exceed **10,000 rows** in a healthy system. +> - These numbers vary based on network activity and settings. -## Maintenance plugins +--- -There are 2 plugins responsible for maintaining the overal health of the application. One is responsible for the database cleanup and one for other tasks, such as log cleanup. +## Maintenance Plugins -### DB Cleanup (DBCLNP) +Two plugins help maintain the application’s performance: -The database cleanup plugin. Check details and related setting in the [DB Cleanup plugin docs](/front/plugins/db_cleanup/README.md). Make sure the plugin is not failing by checking the logs. Try changing the schedule `DBCLNP_RUN_SCHD` and the timeout `DBCLNP_RUN_TIMEOUT` (increase) if the plugin is failing to execute. +### **1. Database Cleanup (DBCLNP)** +- Responsible for database maintenance. +- Check settings in the [DB Cleanup Plugin Docs](/front/plugins/db_cleanup/README.md). +- Ensure it’s not failing by checking logs. +- Adjust the schedule (`DBCLNP_RUN_SCHD`) and timeout (`DBCLNP_RUN_TIMEOUT`) if needed. -### Maintenance (MAINT) +### **2. Maintenance (MAINT)** +- Handles log cleanup and other maintenance tasks. +- Check settings in the [Maintenance Plugin Docs](/front/plugins/maintenance/README.md). +- Ensure it’s running correctly by checking logs. +- Adjust the schedule (`MAINT_RUN_SCHD`) and timeout (`MAINT_RUN_TIMEOUT`) if needed. -The maintenance plugin. Check details and related setting in the [Maintenance plugin docs](/front/plugins/maintenance/README.md). Make sure the plugin is not failing by checking the logs. Try changing the schedule `MAINT_RUN_SCHD` and the timeout `MAINT_RUN_TIMEOUT` (increase) if the plugin is failing to execute. +--- -## Scan frequency and coverage +## Scan Frequency and Coverage -The more often you scan the networks the more resources, traffic and DB read/write cycles are executed. Especially on busy networks and lower end hardware, consider increasing scan intervals (`_RUN_SCHD`) and timeouts (`_RUN_TIMEOUT`). +Frequent scans increase resource usage, network traffic, and database read/write cycles. -Also consider decreasing the scanned subnet, e.g. from `/16` to `/24` if need be. +### **Optimizations** +- **Increase scan intervals** (`_RUN_SCHD`) on busy networks or low-end hardware. +- **Extend scan timeouts** (`_RUN_TIMEOUT`) to prevent failures. +- **Reduce the subnet size** – e.g., from `/16` to `/24` to lower scan loads. -# Store temporary files in memory +Some plugins have additional options to limit the number of scanned devices. If certain plugins take too long to complete, check if you can optimize scan times by selecting a scan range. + +For example, the **ICMP plugin** allows you to specify a regular expression to scan only IPs that match a specific pattern. + +--- + +## Storing Temporary Files in Memory + +On systems with slower I/O speeds, you can optimize performance by storing temporary files in memory. This primarily applies to the `/app/api` and `/app/log` folders. + +Using `tmpfs` reduces disk writes and improves performance. However, it should be **disabled** if persistent logs or API data storage are required. + +Below is an optimized `docker-compose.yml` snippet: -You can also store temporary files in application memory (`/app/api` and `/app/log` folders). See highlighted lines `◀` below. ```yaml version: "3" services: netalertx: container_name: netalertx - # use the below line if you want to test the latest dev image - # image: "jokobsk/netalertx-dev:latest" + # Uncomment the line below to test the latest dev image + # image: "jokobsk/netalertx-dev:latest" image: "jokobsk/netalertx:latest" network_mode: "host" restart: unless-stopped volumes: - local/path/config:/app/config - local/path/db:/app/db - # (optional) useful for debugging if you have issues setting up the container + # (Optional) Useful for debugging setup issues - local/path/logs:/app/log - # (API: OPTION 1) use for performance - - type: tmpfs # ◀ - target: /app/api # ◀ - # (API: OPTION 2) use when debugging issues - # - local/path/api:/app/api + # (API: OPTION 1) Store temporary files in memory (recommended for performance) + - type: tmpfs # ◀ + target: /app/api # ◀ + # (API: OPTION 2) Store API data on disk (useful for debugging) + # - local/path/api:/app/api environment: - TZ=Europe/Berlin - PORT=20211 + ``` diff --git a/front/img/NetAlertX_logo_b_w_info.png b/front/img/NetAlertX_logo_b_w_info.png new file mode 100755 index 0000000000000000000000000000000000000000..42eff54b6484a24a3a4f42b0d0a34c5c204a3a72 GIT binary patch literal 8457 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 rnP$(xm8RX$J