From a88cc8a36a56d0370eab50f6fca1d1c7f69752c2 Mon Sep 17 00:00:00 2001 From: CasVT Date: Sun, 3 Mar 2024 16:01:15 +0100 Subject: [PATCH] Moved logging level setting to admin panel --- MIND.py | 10 ++-------- backend/db.py | 3 +++ backend/logging.py | 27 +++++++++++++++++++++++++++ backend/settings.py | 17 +++++++++++++++-- frontend/api.py | 6 +++--- frontend/input_validation.py | 25 +++++++++++++++++++++++++ frontend/static/js/admin.js | 7 +++++-- frontend/templates/admin.html | 16 ++++++++++++++++ 8 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 backend/logging.py diff --git a/MIND.py b/MIND.py index ea923b9..0a117a8 100644 --- a/MIND.py +++ b/MIND.py @@ -10,6 +10,7 @@ from backend.db import setup_db, setup_db_location from backend.helpers import check_python_version +from backend.logging import setup_logging from backend.reminders import ReminderHandler from backend.server import SERVER, handle_flags from backend.settings import get_setting @@ -24,17 +25,10 @@ URL_PREFIX = '' # Must either be empty or start with '/' e.g. '/mind' #============================= -LOGGING_LEVEL = logging.INFO - -logging.basicConfig( - level=LOGGING_LEVEL, - format='[%(asctime)s][%(threadName)s][%(levelname)s] %(message)s', - datefmt='%Y-%m-%d %H:%M:%S' -) - def MIND() -> None: """The main function of MIND """ + setup_logging() logging.info('Starting up MIND') if not check_python_version(): diff --git a/backend/db.py b/backend/db.py index c29fc33..96a9450 100644 --- a/backend/db.py +++ b/backend/db.py @@ -19,6 +19,7 @@ from backend.custom_exceptions import (AccessUnauthorized, InvalidDatabaseFile, UserNotFound) from backend.helpers import RestartVars, folder_path +from backend.logging import set_log_level DB_FILENAME = 'db', 'MIND.db' __DATABASE_VERSION__ = 10 @@ -393,6 +394,8 @@ def setup_db() -> None: ) ) + set_log_level(get_setting('log_level')) + current_db_version = get_setting('database_version') if current_db_version < __DATABASE_VERSION__: logging.debug( diff --git a/backend/logging.py b/backend/logging.py new file mode 100644 index 0000000..515b1ba --- /dev/null +++ b/backend/logging.py @@ -0,0 +1,27 @@ +#-*- coding: utf-8 -*- + +import logging + + +def setup_logging() -> None: + "Setup the basic config of the logging module" + logging.basicConfig( + level=logging.INFO, + format='[%(asctime)s][%(threadName)s][%(levelname)s] %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', + force=True + ) + return + +def set_log_level(level: int) -> None: + """Change the logging level + + Args: + level (int): The level to set the logging to. + Should be a logging level, like `logging.INFO` or `logging.DEBUG`. + """ + logging.debug(f'Setting logging level: {level}') + logging.getLogger().setLevel( + level=level + ) + return diff --git a/backend/settings.py b/backend/settings.py index 047de8f..068d609 100644 --- a/backend/settings.py +++ b/backend/settings.py @@ -4,21 +4,27 @@ Getting and setting settings """ +import logging from json import dumps, loads from typing import Any from backend.custom_exceptions import InvalidKeyValue, KeyNotFound from backend.db import __DATABASE_VERSION__, get_db from backend.helpers import folder_path +from backend.logging import set_log_level default_settings = { 'allow_new_accounts': True, 'login_time': 3600, 'login_time_reset': True, + 'database_version': __DATABASE_VERSION__, + 'host': '0.0.0.0', 'port': 8080, - 'url_prefix': '' + 'url_prefix': '', + + 'log_level': logging.INFO } def _format_setting(key: str, value): @@ -64,6 +70,9 @@ def _format_setting(key: str, value): if value: value = '/' + value.strip('/') + elif key == 'log_level' and not value in (logging.INFO, logging.DEBUG): + raise InvalidKeyValue(key, value) + return value def _reverse_format_setting(key: str, value: Any) -> Any: @@ -120,7 +129,8 @@ def get_admin_settings() -> dict: OR key = 'login_time_reset' OR key = 'host' OR key = 'port' - OR key = 'url_prefix'; + OR key = 'url_prefix' + OR key = 'log_level'; """ ) )) @@ -149,6 +159,9 @@ def set_setting(key: str, value: Any) -> None: if key == 'url_prefix': update_manifest(value) + elif key == 'log_level': + set_log_level(value) + return def update_manifest(url_base: str) -> None: diff --git a/frontend/api.py b/frontend/api.py index 02dbc83..e842f3a 100644 --- a/frontend/api.py +++ b/frontend/api.py @@ -36,8 +36,8 @@ EditTimeVariable, EditTitleVariable, EditURLVariable, HostVariable, LoginTimeResetVariable, - LoginTimeVariable, Method, Methods, - NewPasswordVariable, + LoginTimeVariable, LogLevelVariable, + Method, Methods, NewPasswordVariable, NotificationServicesVariable, PasswordCreateVariable, PasswordVariable, PortVariable, @@ -705,7 +705,7 @@ def api_settings(): put=Method( vars=[AllowNewAccountsVariable, LoginTimeVariable, LoginTimeResetVariable, HostVariable, PortVariable, - UrlPrefixVariable], + UrlPrefixVariable, LogLevelVariable], description='Edit the admin settings. Supplying a hosting setting will automatically restart MIND.' ) ), diff --git a/frontend/input_validation.py b/frontend/input_validation.py index dd62c8a..c368fec 100644 --- a/frontend/input_validation.py +++ b/frontend/input_validation.py @@ -8,6 +8,7 @@ from abc import ABC, abstractmethod from dataclasses import dataclass, field +import logging from os.path import splitext from re import compile from typing import TYPE_CHECKING, Any, Callable, Dict, List, Type, Union @@ -368,6 +369,14 @@ def validate(self) -> bool: and all(v in self._options for v in self.value) ) + def __repr__(self) -> str: + return '| {n} | {r} | {t} | {d} | {v} |'.format( + n=self.name, + r="Yes" if self.required else "No", + t=",".join(self.data_type), + d=self.description, + v=", ".join(f'`{o}`' for o in self._options) + ) class ColorVariable(NonRequiredVersion, BaseInputVariable): name = 'color' @@ -432,6 +441,22 @@ class UrlPrefixVariable(NonRequiredVersion, AdminSettingsVariable): description = 'The base url to run on. Useful for reverse proxies. Empty string to disable.' +class LogLevelVariable(NonRequiredVersion, AdminSettingsVariable): + name = 'log_level' + description = 'The level to log on.' + data_type = [DataType.INT] + _options = [logging.INFO, logging.DEBUG] + + def __repr__(self) -> str: + return '| {n} | {r} | {t} | {d} | {v} |'.format( + n=self.name, + r="Yes" if self.required else "No", + t=",".join(self.data_type), + d=self.description, + v=", ".join(f'`{o}`' for o in self._options) + ) + + class DatabaseFileVariable(BaseInputVariable): name = 'file' description = 'The MIND database file' diff --git a/frontend/static/js/admin.js b/frontend/static/js/admin.js index 8be1945..e6c9210 100644 --- a/frontend/static/js/admin.js +++ b/frontend/static/js/admin.js @@ -1,7 +1,8 @@ const setting_inputs = { allow_new_accounts: document.querySelector('#allow-new-accounts-input'), login_time: document.querySelector('#login-time-input'), - login_time_reset: document.querySelector('#login-time-reset-input') + login_time_reset: document.querySelector('#login-time-reset-input'), + log_level: document.querySelector('#log-level-input') }; const hosting_inputs = { @@ -53,6 +54,7 @@ function loadSettings() { setting_inputs.allow_new_accounts.checked = json.result.allow_new_accounts; setting_inputs.login_time.value = Math.round(json.result.login_time / 60); setting_inputs.login_time_reset.value = json.result.login_time_reset.toString(); + setting_inputs.log_level.value = json.result.log_level; hosting_inputs.host.value = json.result.host; hosting_inputs.port.value = json.result.port; hosting_inputs.url_prefix.value = json.result.url_prefix; @@ -63,7 +65,8 @@ function submitSettings() { const data = { 'allow_new_accounts': setting_inputs.allow_new_accounts.checked, 'login_time': setting_inputs.login_time.value * 60, - 'login_time_reset': setting_inputs.login_time_reset.value === 'true' + 'login_time_reset': setting_inputs.login_time_reset.value === 'true', + 'log_level': parseInt(setting_inputs.log_level.value) }; fetch(`${url_prefix}/api/admin/settings?api_key=${api_key}`, { 'method': 'PUT', diff --git a/frontend/templates/admin.html b/frontend/templates/admin.html index e0b3cbe..c1f5213 100644 --- a/frontend/templates/admin.html +++ b/frontend/templates/admin.html @@ -78,6 +78,22 @@

Authentication

+

Logging

+
+ + + + + + + +
+ +
+

Hosting