Skip to content

Commit

Permalink
Add log-level option to the cli app (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
voro6yov authored Mar 25, 2024
1 parent 245b8ff commit b001e98
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 60 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ rebuild-lockfiles: .pdm

.PHONY: format ## Auto-format python source files
format: .pdm
pdm run ruff --fix $(sources)
pdm run ruff check --fix $(sources)
pdm run ruff format $(sources)

.PHONY: lint ## Lint python source files
Expand Down
27 changes: 25 additions & 2 deletions pdm.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 11 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "message-flow"
version = "0.3.2"
version = "0.3.3"
description = "Asynchronous Communication Framework"
authors = [
{name = "Valentin Vorobyev", email = "[email protected]"},
Expand All @@ -18,8 +18,8 @@ requires = ["pdm-backend"]
build-backend = "pdm.backend"

[project.optional-dependencies]
reload = [
"watchfiles>=0.21.0",
rabbitmq = [
"message-flow-rabbitmq>=0.2.2",
]


Expand Down Expand Up @@ -56,23 +56,23 @@ testing = [

[tool.ruff]
line-length = 120
extend-select = ['Q', 'RUF100', 'C90', 'UP', 'I', 'T']
extend-ignore = ['D105', 'D107', 'D205', 'D415']
flake8-quotes = {inline-quotes = 'double', multiline-quotes = 'double'}
mccabe = { max-complexity = 14 }
isort = { known-first-party = ['message_flow', 'tests'] }
lint.extend-select = ['Q', 'RUF100', 'C90', 'UP', 'I', 'T']
lint.extend-ignore = ['D105', 'D107', 'D205', 'D415']
lint.flake8-quotes = {inline-quotes = 'double', multiline-quotes = 'double'}
lint.mccabe = { max-complexity = 14 }
lint.isort = { known-first-party = ['message_flow', 'tests'] }
target-version = "py37"

[tool.ruff.extend-per-file-ignores]
[tool.ruff.lint.extend-per-file-ignores]
"tests/**/*.py" = ['T', 'E721', 'F811']

[tool.ruff.format]
quote-style = 'double'

[tool.ruff.pydocstyle]
[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.ruff.per-file-ignores]
[tool.ruff.lint.per-file-ignores]
'*/__init__.py' = ['F405', 'F403', 'D']
'*/__init__.pyi' = ['F405', 'F403', 'D']
'tests/*' = ['D']
Expand Down
9 changes: 0 additions & 9 deletions src/message_flow/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
import logging

from .app import *
from .channel import *
from .message import *

__all__ = app.__all__ + channel.__all__ + message.__all__

logger = logging.getLogger(__name__)

ch = logging.StreamHandler()
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
ch.setFormatter(formatter)
logger.addHandler(ch)
10 changes: 6 additions & 4 deletions src/message_flow/app/_message_management/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,22 @@
@final
@internal
class Dispatcher:
def __init__(self, channels: Channels, message_consumer: MessageConsumer, producer: Producer) -> None:
self._logger = logging.getLogger(__name__)
def __init__(
self, channels: Channels, message_consumer: MessageConsumer, producer: Producer, logger: logging.Logger
) -> None:
self._logger = logger

self._channels = channels
self._message_consumer = message_consumer
self._producer = producer

def initialize(self) -> None:
self._logger.info("Initializing dispatcher")
self._logger.debug("Initializing dispatcher")
self._message_consumer.subscribe(
self._channels.addresses,
self.message_handler,
)
self._logger.info("Initialized dispatcher")
self._logger.debug("Initialized dispatcher")

def message_handler(self, payload: bytes, headers: dict[str, str]) -> None:
if (
Expand Down
12 changes: 8 additions & 4 deletions src/message_flow/app/_simple_messaging/simple_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@
@internal
class SimpleMessageConsumer(MessageConsumer):
def __init__(
self, file_path: str = "/tmp/message-flow-queue.txt", dry_run: bool = False, throw_error: bool = False
self,
logger: logging.Logger,
file_path: str = "/tmp/message-flow-queue.txt",
dry_run: bool = False,
throw_error: bool = False,
) -> None:
self._logger = logging.getLogger(__name__)
self._logger = logger

self._dry_run = dry_run
self._throw_error = throw_error
Expand Down Expand Up @@ -60,10 +64,9 @@ def _process_message(self, message: str | None) -> None:
self._logger.debug("Got message empty message. Start sleeping...")
time.sleep(1)
except Exception as error:
self._logger.info("An error occurred while consuming events", exc_info=error)
self._logger.debug("An error occurred while consuming events", exc_info=error)
finally:
self._commit_message(message)
self._logger.debug("Message %s is committed.")

def _handle_message(self, message: str) -> None:
channel, payload, headers = self._parse_message(message)
Expand All @@ -83,3 +86,4 @@ def _commit_message(self, message: str | None) -> None:
if message is not None:
self._position += len(message)
self._fp.seek(self._position)
self._logger.debug("Message %s is committed.", message)
6 changes: 3 additions & 3 deletions src/message_flow/app/_simple_messaging/simple_producer.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
@final
@internal
class SimpleMessageProducer(MessageProducer):
def __init__(self, file_path: str = "/tmp/message-flow-queue.txt") -> None:
self._logger = logging.getLogger(__name__)
def __init__(self, logger: logging.Logger, file_path: str = "/tmp/message-flow-queue.txt") -> None:
self._logger = logger

self.closed = False

self._file_path = file_path

def send(self, channel: str, payload: bytes, headers: dict[str, str] | None = None) -> None:
self._logger.info(f"Send message to {channel}")
self._logger.debug(f"Send message to {channel}")
with open(self._file_path, "a+") as fp:
fp.write(f"{channel}\t{payload.decode()}\t{json.dumps(headers)}\n")

Expand Down
36 changes: 31 additions & 5 deletions src/message_flow/app/message_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from ..channel import Channel
from ..message import Message
from ..utils import external
from ..utils import external, logger
from ._internal import Channels, Info, MessageFlowSchema
from ._message_management import Dispatcher, Producer
from ._simple_messaging import SimpleMessageConsumer, SimpleMessageProducer
Expand Down Expand Up @@ -127,8 +127,27 @@ def __init__(
"""
),
] = "0.1.0",
logger: Annotated[
logging.Logger,
Doc(
"""
The custom logger for the application.
**Example**
```python
import logging
from message_flow import MessageFlow
custom_logger = logging.getLogger("custom_logger")
app = MessageFlow(logger=custom_logger)
```
"""
),
] = logger,
) -> None:
self._logger = logging.getLogger(__name__)
self._logger = logger

self.asyncapi_version: Annotated[
str,
Expand Down Expand Up @@ -160,8 +179,8 @@ def __init__(
self.version = version

self._channels = Channels(channels=channels)
self._message_producer = message_producer or SimpleMessageProducer()
self._message_consumer = message_consumer or SimpleMessageConsumer()
self._message_producer = message_producer or SimpleMessageProducer(self._logger)
self._message_consumer = message_consumer or SimpleMessageConsumer(self._logger)

@property
def producer(self) -> Producer:
Expand All @@ -172,7 +191,7 @@ def producer(self) -> Producer:
@property
def dispatcher(self) -> Dispatcher:
if not hasattr(self, "_dispatcher"):
self._dispatcher = Dispatcher(self._channels, self._message_consumer, self.producer)
self._dispatcher = Dispatcher(self._channels, self._message_consumer, self.producer, self._logger)
return self._dispatcher

def add_channel(self, channel: Annotated[Channel, Doc("The channel to add.")]) -> None:
Expand Down Expand Up @@ -379,6 +398,7 @@ def dispatch(self) -> None:
"""
try:
self.dispatcher.initialize()
self._logger.info("Message Flow app starting...")
self._message_consumer.start_consuming()
except Exception as error:
self._logger.error("An error occurred while dispatching events", exc_info=error)
Expand All @@ -403,3 +423,9 @@ def make_async_api_schema(self) -> str:
)

return json.dumps(schema)

def set_logging_level(self, level: int) -> None:
"""
Set logging level for the app logger.
"""
self._logger.setLevel(level=level)
40 changes: 28 additions & 12 deletions src/message_flow/cli/cli_app.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
import logging
from collections import defaultdict
from importlib.util import module_from_spec, spec_from_file_location
from pathlib import Path
from typing import Any
from typing import DefaultDict

import typer

from ..app import MessageFlow
from ..utils import internal
from .logging_level import LoggingLevel


@internal
class CLIApp:
def __init__(self, app_path: str, reload: bool = False) -> None:
LOGGING_LEVELS: DefaultDict[str, int] = defaultdict(
lambda: logging.INFO,
**{
LoggingLevel.CRITICAL: logging.CRITICAL,
LoggingLevel.ERROR: logging.ERROR,
LoggingLevel.WARNING: logging.WARNING,
LoggingLevel.INFO: logging.INFO,
LoggingLevel.DEBUG: logging.DEBUG,
},
)

def __init__(self, app_path: str, log_level: LoggingLevel) -> None:
self.app_path = app_path

self.reload = reload
self.instance.set_logging_level(self.LOGGING_LEVELS[log_level])

@property
def app_path(self) -> str:
Expand Down Expand Up @@ -49,19 +64,20 @@ def app_name(self) -> str:
return self._app_name

@property
def instance(self) -> Any:
try:
app_object = self._import()
except FileNotFoundError as e:
typer.echo(e, err=True)
raise typer.BadParameter("Please, input module like [python_module:message_flow_app_name]") from e
else:
return app_object # type: ignore
def instance(self) -> MessageFlow:
if not hasattr(self, "_instance"):
try:
self._instance = self._import()
except FileNotFoundError as e:
typer.echo(e, err=True)
raise typer.BadParameter("Please, input module like [python_module:message_flow_app_name]") from e

return self._instance

def dispatch(self) -> None:
self.instance.dispatch()

def _import(self) -> Any:
def _import(self) -> MessageFlow:
spec = spec_from_file_location(
"mode",
f"{self.module_path}.py",
Expand Down
12 changes: 12 additions & 0 deletions src/message_flow/cli/logging_level.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from enum import Enum

from ..utils import internal


@internal
class LoggingLevel(str, Enum):
CRITICAL = "critical"
ERROR = "error"
WARNING = "warning"
INFO = "info"
DEBUG = "debug"
13 changes: 7 additions & 6 deletions src/message_flow/cli/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import typer

from .cli_app import CLIApp
from .logging_level import LoggingLevel

__all__ = ["cli"]

Expand All @@ -20,16 +21,16 @@ def dispatch(
...,
help="[python_module:MessageFlow] - path to your application",
),
reload: bool = typer.Option(
False,
"--reload",
is_flag=True,
help="Restart app at directory files changes",
log_level: LoggingLevel = typer.Option(
LoggingLevel.INFO,
case_sensitive=False,
show_default=False,
help="[INFO] default",
),
):
"""
Shoot the portal gun
"""
cli_app = CLIApp(app, reload)
cli_app = CLIApp(app, log_level)

cli_app.dispatch()
3 changes: 2 additions & 1 deletion src/message_flow/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .log import *
from .visibility import *

__all__ = visibility.__all__
__all__ = visibility.__all__ + log.__all__
Loading

0 comments on commit b001e98

Please sign in to comment.