diff --git a/aiomisc/entrypoint.py b/aiomisc/entrypoint.py index 952d0c46..0c074cd7 100644 --- a/aiomisc/entrypoint.py +++ b/aiomisc/entrypoint.py @@ -48,6 +48,9 @@ class Entrypoint: DEFAULT_LOG_FORMAT: str = os.getenv( "AIOMISC_LOG_FORMAT", LogFormat.default(), ) + DEFAULT_LOG_DATE_FORMAT: Optional[str] = os.getenv( + "AIOMISC_LOG_DATE_FORMAT" + ) DEFAULT_AIOMISC_DEBUG: bool = _get_env_bool("AIOMISC_DEBUG", "0") DEFAULT_AIOMISC_LOG_CONFIG: bool = _get_env_bool( @@ -80,6 +83,7 @@ async def _start(self) -> None: basic_config( level=self.log_level, log_format=self.log_format, + date_format=self.log_date_format, buffered=self.log_buffering, loop=self.loop, buffer_size=self.log_buffer_size, @@ -108,6 +112,7 @@ def __init__( log_format: Union[str, LogFormat] = DEFAULT_LOG_FORMAT, log_buffering: bool = DEFAULT_AIOMISC_BUFFERING, log_buffer_size: int = DEFAULT_AIOMISC_BUFFER_SIZE, + log_date_format: Optional[str] = DEFAULT_LOG_DATE_FORMAT, log_flush_interval: float = DEFAULT_AIOMISC_LOG_FLUSH, log_config: bool = DEFAULT_AIOMISC_LOG_CONFIG, policy: asyncio.AbstractEventLoopPolicy = event_loop_policy, @@ -138,6 +143,7 @@ def __init__( self.log_buffer_size = log_buffer_size self.log_buffering = log_buffering self.log_config = log_config + self.log_date_format = log_date_format self.log_flush_interval = log_flush_interval self.log_format = log_format self.log_level = log_level @@ -155,6 +161,7 @@ def __init__( aiomisc_log.basic_config( level=self.log_level, log_format=self.log_format, + date_format=log_date_format ) if self._loop is not None: @@ -206,6 +213,7 @@ def __exit__( basic_config( level=self.log_level, log_format=self.log_format, + date_format=self.log_date_format, buffered=False, ) diff --git a/docs/source/entrypoint.rst b/docs/source/entrypoint.rst index 06eb78ef..7fb9a0b1 100644 --- a/docs/source/entrypoint.rst +++ b/docs/source/entrypoint.rst @@ -122,6 +122,7 @@ Module support configuration from environment variables: * `AIOMISC_LOG_LEVEL` - default logging level * `AIOMISC_LOG_FORMAT` - default log format +* `AIOMISC_LOG_DATE_FORMAT` - default logging date format * `AIOMISC_LOG_CONFIG` - should logging be configured * `AIOMISC_LOG_FLUSH` - interval between logs flushing from buffer * `AIOMISC_LOG_BUFFERING` - should logging be buffered @@ -154,8 +155,8 @@ but handle ``Service``'s and other ``entrypoint``'s kwargs. Logging configuration ===================== -``entrypoint`` accepts a specific set of formats in which logs will be -written to stderr. +``entrypoint`` accepts ``log_format`` argument with a specific set of formats, +in which logs will be written to stderr: * ``stream`` - Python's default logging handler * ``color`` - logging with `colorlog` module @@ -164,13 +165,16 @@ written to stderr. * ``plain`` - just log messages, without date or level info * ``journald`` - available only when `logging-journald` module has been installed. -* ``rich``/``rich_tb` - available only when `rich` module has been installed. +* ``rich``/``rich_tb`` - available only when `rich` module has been installed. ``rich_tb`` it's the same as ``rich`` but with fully expanded tracebacks. +Additionally, you can specify log level using ``log_level`` argument and date +format using ``log_date_format`` parameters. + An ``entrypoint`` will call ``aiomisc.log.basic_config`` function implicitly -using passed ``log_level=`` and ``log_format=`` parameters. -Alternatively you can call ``aiomisc.log.basic_config`` function manually -passing it already created eventloop. +using passed ``log_*`` parameters. Alternatively you can call +``aiomisc.log.basic_config`` function manually passing it already created +eventloop. However, you can configure logging earlier using ``aiomisc_log.basic_config``, but you will lose log buffering and flushing in a separate thread. diff --git a/tests/test_entrypoint.py b/tests/test_entrypoint.py index b9fc1abf..95ba9223 100644 --- a/tests/test_entrypoint.py +++ b/tests/test_entrypoint.py @@ -7,18 +7,21 @@ from contextlib import ExitStack, suppress from tempfile import mktemp from typing import Any, Optional, Set, Tuple +from unittest import mock import aiohttp.web import fastapi import pytest import aiomisc -from aiomisc.entrypoint import Entrypoint +from aiomisc.entrypoint import Entrypoint, entrypoint from aiomisc.service import TCPServer, TLSServer, UDPServer from aiomisc.service.aiohttp import AIOHTTPService from aiomisc.service.asgi import ASGIApplicationType, ASGIHTTPService from aiomisc.service.tcp import RobustTCPClient, TCPClient from aiomisc.service.tls import RobustTLSClient, TLSClient +from aiomisc_log import LogFormat +from aiomisc_log.enum import DateFormat, LogLevel from tests import unix_only @@ -884,3 +887,38 @@ async def test_add_remove_service(entrypoint: aiomisc.Entrypoint): await entrypoint.start_services(service) assert len(StorageService.INSTANCES) == 10 + + +@pytest.mark.parametrize('entrypoint_logging_kwargs,basic_config_kwargs', [ + ( + {}, + { + 'level': LogLevel.info.name, + 'log_format': LogFormat.plain.name, + 'date_format': None + } + ), + ( + { + 'log_level': LogLevel.debug, + 'log_format': LogFormat.stream, + 'log_date_format': DateFormat.stream + }, + { + 'level': LogLevel.debug, + 'log_format': LogFormat.stream, + 'date_format': DateFormat.stream + } + ) +]) +def test_entrypoint_log_params(entrypoint_logging_kwargs, basic_config_kwargs): + with mock.patch("aiomisc_log.basic_config") as basic_config_mock: + with entrypoint(**entrypoint_logging_kwargs): + pass + + # unbuffered logging is configured on init, buffered on start, + # unbuffered on stop. + assert basic_config_mock.call_count == 3 + for call_args, call_kwargs in basic_config_mock.call_args_list: + for key, value in basic_config_kwargs.items(): + assert call_kwargs[key] == value