Skip to content

Commit

Permalink
feat(utils): add multiline log formatter (reanahub#468)
Browse files Browse the repository at this point in the history
  • Loading branch information
jlemesh committed Sep 19, 2024
1 parent 891aeab commit 264b078
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 2 deletions.
8 changes: 7 additions & 1 deletion reana_job_controller/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from reana_job_controller import config
from reana_job_controller.spec import build_openapi_spec
from reana_job_controller.utils import MultilineFormatter


@event.listens_for(db_engine, "checkin")
Expand Down Expand Up @@ -55,7 +56,12 @@ def shutdown_session(response_or_exc):

def create_app(config_mapping=None):
"""Create REANA-Job-Controller application."""
logging.basicConfig(level=REANA_LOG_LEVEL, format=REANA_LOG_FORMAT)
handler = logging.StreamHandler()
handler.setFormatter(MultilineFormatter(REANA_LOG_FORMAT))
logging.basicConfig(
level=REANA_LOG_LEVEL, format=REANA_LOG_FORMAT, handlers=[handler]
)

app = Flask(__name__)
app.secret_key = "mega secret key"
app.session = Session
Expand Down
28 changes: 27 additions & 1 deletion reana_job_controller/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# This file is part of REANA.
# Copyright (C) 2017, 2018, 2019, 2020, 2022, 2023 CERN.
# Copyright (C) 2017, 2018, 2019, 2020, 2022, 2023, 2024 CERN.
#
# REANA is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
Expand All @@ -13,11 +13,37 @@
import socket
import subprocess
import sys
from logging import Formatter, LogRecord

from reana_db.database import Session
from reana_db.models import Workflow


class MultilineFormatter(Formatter):
"""Logging formatter for multiline logs."""

def format(self, record: LogRecord):
"""Format multiline log message.
:param record: LogRecord object.
:type record: logging.LogRecord
:return: Formatted log message.
:rtype: str
"""
save_msg = str(record.msg)
output = ""
lines = save_msg.splitlines()
for line in lines:
record.msg = line
output += super().format(record) + "\n"
output = output.strip()
record.msg = save_msg
record.message = output

return output


def singleton(cls):
"""Singelton decorator."""
instances = {}
Expand Down
62 changes: 62 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
#
# This file is part of REANA.
# Copyright (C) 2024 CERN.
#
# REANA is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

import logging
import pytest

from reana_job_controller.utils import MultilineFormatter

"""REANA-Job-Controller utils tests."""


@pytest.mark.parametrize(
"message,expected_output",
[
(
"test",
"name | INFO | test",
),
(
"test\n",
"name | INFO | test",
),
(
"test\ntest",
"name | INFO | test\nname | INFO | test",
),
(
"test\ntest\n\n\n",
"name | INFO | test\nname | INFO | test\nname | INFO | \nname | INFO |",
),
(
" test\ntest ",
"name | INFO | test\nname | INFO | test",
),
(
" t e s\tt\n t e s t ",
"name | INFO | t e s\tt\nname | INFO | t e s t",
),
],
)
def test_multiline_formatter_format(message, expected_output):
"""Test MultilineFormatter formatting."""
formatter = MultilineFormatter("%(name)s | " "%(levelname)s | %(message)s")
assert (
formatter.format(
logging.LogRecord(
"name",
logging.INFO,
"pathname",
1,
message,
None,
None,
),
)
== expected_output
)

0 comments on commit 264b078

Please sign in to comment.