diff --git a/status_function/run_tests.sh b/status_function/run_tests.sh index 7224757..06866d3 100755 --- a/status_function/run_tests.sh +++ b/status_function/run_tests.sh @@ -30,10 +30,6 @@ status=$((status+$?)) # Run our unit tests with code coverage echo "Running unit tests..." -export API_URL="http://some.api.url" -export PRIVATE_KEY="-----BEGIN OPENSSH PRIVATE KEY-----mykey1234-----END OPENSSH PRIVATE KEY-----" # gitleaks:allow -export AZURE_TENANT_ID="00000000-0000-0000-0000-000000000000" -export CENTRAL_LOGGING_CONNECTION_STRING="InstrumentationKey=00000000-0000-0000-0000-000000000000" python -m coverage run \ --omit=".venv/*,tests/*" \ -m unittest discover \ diff --git a/status_function/status/__init__.py b/status_function/status/__init__.py index 6f878f3..fc9aefa 100644 --- a/status_function/status/__init__.py +++ b/status_function/status/__init__.py @@ -23,7 +23,7 @@ from status import models, settings from status.auth import BearerAuth -from status.logutils import set_log_handler +from status.logutils import add_log_handler_once from status.wrapper import CredentialWrapper logging.basicConfig( @@ -32,7 +32,6 @@ datefmt="%d/%m/%Y %I:%M:%S %p", ) logger = logging.getLogger(__name__) -set_log_handler(__name__) # We should only need one set of credentials. CREDENTIALS = DefaultAzureCredential() @@ -330,6 +329,7 @@ def main(mytimer: func.TimerRequest) -> None: format="%(asctime)s %(message)s", datefmt="%d/%m/%Y %I:%M:%S %p", ) + add_log_handler_once(__name__) logger.warning("Status function starting.") if mytimer.past_due: diff --git a/status_function/status/logutils.py b/status_function/status/logutils.py index 13e228a..aed6e53 100644 --- a/status_function/status/logutils.py +++ b/status_function/status/logutils.py @@ -37,7 +37,7 @@ def filter(self, record: logging.LogRecord) -> bool: return True -def set_log_handler(name: str = "status") -> None: +def add_log_handler_once(name: str = "status") -> None: """Add an Azure log handler to the logger with provided name. The log data is sent to the Azure Application Insights instance associated @@ -47,16 +47,14 @@ def set_log_handler(name: str = "status") -> None: Args: name: The name of the logger instance to which we add the log handler. - - Returns: - None """ logger = logging.getLogger(name) log_settings = settings.get_settings() if log_settings.CENTRAL_LOGGING_CONNECTION_STRING: for handler in logger.handlers: + # Only allow one AzureLogHandler per logger if isinstance(handler, AzureLogHandler): - raise RuntimeError("AzureLogHandler already added to logger.") + return custom_dimensions = {"logger_name": f"logger_{name}"} handler = AzureLogHandler( diff --git a/status_function/tests/test_function_app.py b/status_function/tests/test_function_app.py index 340c8f2..edccbcd 100644 --- a/status_function/tests/test_function_app.py +++ b/status_function/tests/test_function_app.py @@ -1,4 +1,5 @@ """Tests for status package.""" +import logging from datetime import datetime from types import SimpleNamespace from unittest import TestCase, main @@ -613,10 +614,15 @@ def test_bearer_auth(self): class TestLoggingUtils(TestCase): def test_called_twice(self): - """Adding multiple loggers can cause large storage bills ££££.""" - with self.assertRaises(RuntimeError): - status.logutils.set_log_handler("a") - status.logutils.set_log_handler("a") + """Adding multiple loggers could cause large storage bills.""" + with patch("status.settings.get_settings") as mock_get_settings: + mock_get_settings.return_value.CENTRAL_LOGGING_CONNECTION_STRING = "my-str" + + with patch("status.logutils.AzureLogHandler", new=MagicMock): + status.logutils.add_log_handler_once("a") + status.logutils.add_log_handler_once("a") + handlers = logging.getLogger("a").handlers + self.assertEqual(1, len(handlers)) if __name__ == "__main__":