Skip to content

Log Formatter #190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/cloudformation_cli_python_lib/hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,17 @@ def wrapper(self: Any, event: MutableMapping[str, Any], context: Any) -> Any:

class Hook:
def __init__(
self, type_name: str, type_configuration_model_cls: Type[BaseModel]
self,
type_name: str,
type_configuration_model_cls: Type[BaseModel],
log_format: Optional[logging.Formatter] = None,
) -> None:
self.type_name = type_name
self._type_configuration_model_cls: Type[
BaseModel
] = type_configuration_model_cls
self._handlers: MutableMapping[HookInvocationPoint, HandlerSignature] = {}
self.log_format = log_format

def handler(
self, invocation_point: HookInvocationPoint
Expand Down Expand Up @@ -247,7 +251,7 @@ def print_or_log(message: str) -> None:

metrics = MetricsPublisherProxy()
if event.requestData.providerLogGroupName and provider_sess:
HookProviderLogHandler.setup(event, provider_sess)
HookProviderLogHandler.setup(event, provider_sess, self.log_format)
logs_setup = True
metrics.add_hook_metrics_publisher(
provider_sess, event.hookTypeName, event.awsAccountId
Expand Down
20 changes: 18 additions & 2 deletions src/cloudformation_cli_python_lib/log_delivery.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ def _get_existing_logger(cls) -> Optional["ProviderLogHandler"]:

@classmethod
def setup(
cls, request: HandlerRequest, provider_sess: Optional[SessionProxy]
cls,
request: HandlerRequest,
provider_sess: Optional[SessionProxy],
log_format: Optional[logging.Formatter] = None,
) -> None:
log_group = request.requestData.providerLogGroupName
if request.stackId and request.requestData.logicalResourceId:
Expand All @@ -50,11 +53,16 @@ def setup(
# we just refresh the client with new creds
log_handler.client = provider_sess.client("logs")
return

# filter provider messages from platform
provider = request.resourceType.replace("::", "_").lower()
log_handler = cls(
group=log_group, stream=stream_name, session=provider_sess
)

if log_format:
log_handler.setFormatter(log_format)

# add log handler to root, so that provider gets plugin logs too
logging.getLogger().addHandler(log_handler)
logging.getLogger().handlers[0].addFilter(ProviderFilter(provider))
Expand Down Expand Up @@ -114,7 +122,10 @@ def _get_existing_logger(cls) -> Optional["HookProviderLogHandler"]:

@classmethod
def setup( # type: ignore
cls, request: HookInvocationRequest, provider_sess: Optional[SessionProxy]
cls,
request: HookInvocationRequest,
provider_sess: Optional[SessionProxy],
log_format: Optional[logging.Formatter] = None,
) -> None:
log_group = request.requestData.providerLogGroupName
if request.stackId and request.requestData.targetLogicalId:
Expand All @@ -129,11 +140,16 @@ def setup( # type: ignore
# we just refresh the client with new creds
log_handler.client = provider_sess.client("logs")
return

# filter provider messages from platform
provider = request.hookTypeName.replace("::", "_").lower()
logging.getLogger().handlers[0].addFilter(ProviderFilter(provider))
log_handler = cls(
group=log_group, stream=stream_name, session=provider_sess
)

if log_format:
log_handler.setFormatter(log_format)

# add log handler to root, so that provider gets plugin logs too
logging.getLogger().addHandler(log_handler)
4 changes: 3 additions & 1 deletion src/cloudformation_cli_python_lib/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,15 @@ def __init__(
type_name: str,
resouce_model_cls: Type[BaseModel],
type_configuration_model_cls: Optional[Type[BaseModel]] = None,
log_format: Optional[logging.Formatter] = None,
) -> None:
self.type_name = type_name
self._model_cls: Type[BaseModel] = resouce_model_cls
self._type_configuration_model_cls: Optional[
Type[BaseModel]
] = type_configuration_model_cls
self._handlers: MutableMapping[Action, HandlerSignature] = {}
self.log_format = log_format

def handler(self, action: Action) -> Callable[[HandlerSignature], HandlerSignature]:
def _add_handler(f: HandlerSignature) -> HandlerSignature:
Expand Down Expand Up @@ -200,7 +202,7 @@ def print_or_log(message: str) -> None:

metrics = MetricsPublisherProxy()
if event.requestData.providerLogGroupName and provider_sess:
ProviderLogHandler.setup(event, provider_sess)
ProviderLogHandler.setup(event, provider_sess, self.log_format)
logs_setup = True
metrics.add_metrics_publisher(provider_sess, event.resourceType)

Expand Down
2 changes: 1 addition & 1 deletion src/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

setup(
name="cloudformation-cli-python-lib",
version="2.1.12",
version="2.1.13a1",
description=__doc__,
author="Amazon Web Services",
author_email="[email protected]",
Expand Down
41 changes: 41 additions & 0 deletions tests/lib/log_delivery_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ def setup_patches(mock_logger):
)


@pytest.fixture
def mock_handler_set_formatter():
patch__set_handler_formatter = patch.object(ProviderLogHandler, "setFormatter")
patch__set_hook_handler_formatter = patch.object(
HookProviderLogHandler, "setFormatter"
)
return patch__set_handler_formatter, patch__set_hook_handler_formatter


@pytest.fixture
def mock_provider_handler():
plh = ProviderLogHandler(
Expand Down Expand Up @@ -197,6 +206,21 @@ def test_setup_existing_logger(setup_patches, mock_session):
mock_log.return_value.addHandler.assert_not_called()


def test_setup_with_formatter(setup_patches, mock_session, mock_handler_set_formatter):
payload, _hook_payload, p_logger, p__get_logger, _p__get_hook_logger = setup_patches
(
p__set_handler_formatter,
_p__set_hook_handler_formatter,
) = mock_handler_set_formatter
formatter = logging.Formatter()
with p_logger as mock_log, p__get_logger as mock_get, p__set_handler_formatter as mock_set_formatter: # pylint: disable=C0301 # noqa: B950
mock_get.return_value = None
ProviderLogHandler.setup(payload, mock_session, formatter)
mock_session.client.assert_called_once_with("logs")
mock_log.return_value.addHandler.assert_called_once()
mock_set_formatter.assert_called_once_with(formatter)


def test_setup_without_log_group_should_not_set_up(mock_logger, mock_session):
patch_logger = patch(
"cloudformation_cli_python_lib.log_delivery.logging.getLogger",
Expand Down Expand Up @@ -387,6 +411,23 @@ def test_setup_existing_hook_logger(setup_patches, mock_session):
mock_log.return_value.addHandler.assert_not_called()


def test_setup_with_hook_formatter(
setup_patches, mock_session, mock_handler_set_formatter
):
_payload, hook_payload, p_logger, p__get_logger, _p__get_hook_logger = setup_patches
(
_p__set_handler_formatter,
p__set_hook_handler_formatter,
) = mock_handler_set_formatter
formatter = logging.Formatter()
with p_logger as mock_log, p__get_logger as mock_get, p__set_hook_handler_formatter as mock_set_formatter: # pylint: disable=C0301 # noqa: B950
mock_get.return_value = None
HookProviderLogHandler.setup(hook_payload, mock_session, formatter)
mock_session.client.assert_called_once_with("logs")
mock_log.return_value.addHandler.assert_called_once()
mock_set_formatter.assert_called_once_with(formatter)


def test_setup_without_hook_log_group_should_not_set_up(mock_logger, mock_session):
patch_logger = patch(
"cloudformation_cli_python_lib.log_delivery.logging.getLogger",
Expand Down