Skip to content

Commit 178f2aa

Browse files
Merge pull request #116 from MITLibraries/improve-display-run-details
Improve display of run details on the status page
2 parents c8e50f7 + 034a11c commit 178f2aa

File tree

8 files changed

+87
-57
lines changed

8 files changed

+87
-57
lines changed

lambdas.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
from apig_wsgi import make_lambda_handler
55

6-
from webapp import Config, create_app
6+
from webapp import create_app
7+
from webapp.config import Config, configure_logger, configure_sentry
78

89
logger = logging.getLogger(__name__)
910
CONFIG = Config()
@@ -21,8 +22,8 @@ def lambda_handler(event: dict, context: dict) -> dict:
2122
See https://github.com/adamchainz/apig-wsgi/tree/main.
2223
"""
2324
CONFIG.check_required_env_vars()
24-
CONFIG.configure_logger(verbose=True)
25-
CONFIG.configure_sentry()
25+
logger.info(configure_logger(verbose=True))
26+
logger.info(configure_sentry())
2627

2728
apig_wsgi_handler = make_lambda_handler(create_app())
2829

tests/conftest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
from moto.core.utils import unix_time_millis, utcnow
1313
from moto.moto_api import state_manager
1414

15-
from webapp import Config, create_app
15+
from webapp import create_app
1616
from webapp.app import User
17+
from webapp.config import Config
1718
from webapp.utils.aws import CloudWatchLogsClient, ECSClient
1819

1920
AWS_DEFAULT_REGION = "us-east-1"

tests/test_aws/test_cloudwatch.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,27 @@ def test_cloudwatchlogs_client_get_log_messages_review_run_success(
1616
cloudwatch_sapinvoices_review_run_logs,
1717
mock_cloudwatchlogs_log_stream_review_run_task,
1818
):
19-
assert (
20-
cloudwatchlogs_client.get_log_messages(task_id="abc001")
21-
== cloudwatch_sapinvoices_review_run_logs
22-
)
19+
assert cloudwatchlogs_client.get_log_messages(task_id="abc001") == [
20+
"INFO sapinvoices.cli.process_invoices(): SAP invoice process completed for a review run", # noqa: E501
21+
"3 monograph invoices retrieved and processed:",
22+
"2 SAP monograph invoices",
23+
"1 other payment monograph invoices",
24+
"2 serial invoices retrieved and processed",
25+
]
2326

2427

2528
def test_cloudwatchlogs_client_get_log_messages_final_run_success(
2629
cloudwatchlogs_client,
2730
cloudwatch_sapinvoices_final_run_logs,
2831
mock_cloudwatchlogs_log_stream_final_run_task,
2932
):
30-
assert (
31-
cloudwatchlogs_client.get_log_messages(task_id="abc002")
32-
== cloudwatch_sapinvoices_final_run_logs
33-
)
33+
assert cloudwatchlogs_client.get_log_messages(task_id="abc002") == [
34+
"INFO sapinvoices.cli.process_invoices(): SAP invoice process completed for a final run", # noqa: E501
35+
"3 monograph invoices retrieved and processed:",
36+
"2 SAP monograph invoices",
37+
"1 other payment monograph invoices",
38+
"2 serial invoices retrieved and processed",
39+
]
3440

3541

3642
def test_cloudwatchlogs_client_get_log_events_raise_error(

tests/test_config.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import pytest
44

5+
from webapp.config import configure_logger, configure_sentry
6+
57

68
def test_config_check_required_env_vars_success(config):
79
config.check_required_env_vars()
@@ -15,30 +17,32 @@ def test_config_check_required_env_vars_error(monkeypatch, config):
1517

1618
def test_configure_logger_not_verbose(config, caplog):
1719
logger = logging.getLogger(__name__)
18-
result = config.configure_logger(verbose=False)
20+
result = configure_logger(verbose=False)
1921
assert logger.getEffectiveLevel() == logging.INFO
2022
assert result == "Logger 'root' configured with level=INFO"
2123

2224

2325
def test_configure_logger_verbose(config, caplog):
2426
logger = logging.getLogger(__name__)
25-
result = config.configure_logger(verbose=True)
27+
result = configure_logger(verbose=True)
2628
assert logger.getEffectiveLevel() == logging.DEBUG
2729
assert result == "Logger 'root' configured with level=DEBUG"
2830

2931

3032
def test_configure_sentry_if_dsn_exists(config, caplog, monkeypatch):
3133
monkeypatch.setenv("SENTRY_DSN", "https://[email protected]/123456")
32-
config.configure_sentry()
34+
3335
assert (
34-
"Sentry DSN found, exceptions will be sent to Sentry with env=test" in caplog.text
36+
configure_sentry()
37+
== "Sentry DSN found, exceptions will be sent to Sentry with env=test"
3538
)
3639

3740

3841
def test_configure_sentry_if_dsn_missing(config, caplog, monkeypatch):
3942
monkeypatch.delenv("SENTRY_DSN", raising=False)
40-
config.configure_sentry()
41-
assert "No Sentry DSN found, exceptions will not be sent to Sentry" in caplog.text
43+
assert (
44+
configure_sentry() == "No Sentry DSN found, exceptions will not be sent to Sentry"
45+
)
4246

4347

4448
def test_config_env_access_success(config):

webapp/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""lambdas package."""
22

33
from webapp.app import create_app
4-
from webapp.config import Config
54

6-
__all__ = ["Config", "create_app"]
5+
__all__ = ["create_app"]

webapp/config.py

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from typing import Any
66

77
import sentry_sdk
8-
from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration
98

109
logger = logging.getLogger("__name__")
1110

@@ -62,41 +61,37 @@ def check_required_env_vars(self) -> None:
6261
message = f"Missing required environment variables: {', '.join(missing_vars)}"
6362
raise OSError(message)
6463

65-
def configure_logger(self, *, verbose: bool) -> str:
66-
logger = logging.getLogger()
67-
if verbose:
68-
logging.basicConfig(
69-
format=(
70-
"%(asctime)s %(levelname)s %(name)s.%(funcName)s() "
71-
"line %(lineno)d: "
72-
"%(message)s"
73-
)
74-
)
75-
logger.setLevel(logging.DEBUG)
76-
else:
77-
logging.basicConfig(
78-
format="%(asctime)s %(levelname)s %(name)s.%(funcName)s(): %(message)s"
79-
)
80-
logger.setLevel(logging.INFO)
8164

82-
return (
83-
f"Logger '{logger.name}' configured with level="
84-
f"{logging.getLevelName(logger.getEffectiveLevel())}"
65+
def configure_logger(*, verbose: bool) -> str:
66+
logger = logging.getLogger()
67+
if verbose:
68+
logging.basicConfig(
69+
format=(
70+
"%(asctime)s %(levelname)s %(name)s.%(funcName)s() "
71+
"line %(lineno)d: "
72+
"%(message)s"
73+
)
8574
)
75+
logger.setLevel(logging.DEBUG)
76+
else:
77+
logging.basicConfig(
78+
format="%(asctime)s %(levelname)s %(name)s.%(funcName)s(): %(message)s"
79+
)
80+
logger.setLevel(logging.INFO)
8681

87-
def configure_sentry(self) -> None:
88-
if sentry_dsn := self.SENTRY_DSN:
89-
sentry_sdk.init(
90-
dsn=sentry_dsn,
91-
environment=self.WORKSPACE,
92-
integrations=[
93-
AwsLambdaIntegration(),
94-
],
95-
traces_sample_rate=1.0,
96-
)
97-
logger.info(
98-
"Sentry DSN found, exceptions will be sent to Sentry with env=%s",
99-
self.WORKSPACE,
100-
)
101-
else:
102-
logger.info("No Sentry DSN found, exceptions will not be sent to Sentry")
82+
return (
83+
f"Logger '{logger.name}' configured with level="
84+
f"{logging.getLevelName(logger.getEffectiveLevel())}"
85+
)
86+
87+
88+
def configure_sentry() -> str:
89+
env = os.getenv("WORKSPACE")
90+
sentry_dsn = os.getenv("SENTRY_DSN")
91+
if sentry_dsn and sentry_dsn.lower() != "none":
92+
sentry_sdk.init(
93+
sentry_dsn,
94+
environment=env,
95+
)
96+
return f"Sentry DSN found, exceptions will be sent to Sentry with env={env}"
97+
return "No Sentry DSN found, exceptions will not be sent to Sentry"

webapp/static/libraries-additional.min.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
.box-content {
2+
display: inline-block;
3+
}
4+
15
.platform-name {
26
color: #fff;
37
font-size: clamp(1rem,5vw,2.8rem);

webapp/utils/aws/cloudwatch.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,29 @@ def client(self) -> "CloudWatchLogsClientType":
3939
def get_log_messages(self, task_id: str) -> list:
4040
messages: list = []
4141
if logs := self.get_log_events(task_id):
42-
messages.extend(event["message"] for event in logs)
42+
return self.get_log_summary(logs)
4343
return messages
4444

45+
def get_log_summary(self, logs: list[dict]) -> list[str]:
46+
"""Get summary of SAP invoice processing logs.
47+
48+
This function will first determine the index of the log event
49+
the marks the start of the "summary" log messages that
50+
describe the output of the SAP invoice processing run.
51+
The function will then retrieve all the messages starting from
52+
that index, effectively retrieving a summary of the run.
53+
"""
54+
summary_index: int | None = None
55+
for index, event in enumerate(logs):
56+
message = event["message"]
57+
if (
58+
"SAP invoice process completed" in message
59+
or "No invoices waiting to be sent in Alma" in message
60+
):
61+
summary_index = index
62+
return [event["message"] for event in logs[summary_index:]]
63+
return ["SAP invoice process did not complete."]
64+
4565
def get_log_events(self, task_id: str) -> list:
4666
logger.info("Retrieving CloudWatch logs for task.")
4767
log_events = []

0 commit comments

Comments
 (0)