Skip to content

Commit 6920c0f

Browse files
authored
Merge pull request #982 from cmu-delphi/main
Deploy runner-based logging fixes to production
2 parents c678a7f + 3f15ac6 commit 6920c0f

File tree

9 files changed

+38
-22
lines changed

9 files changed

+38
-22
lines changed

_delphi_utils_python/delphi_utils/logger.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,12 @@ def get_structured_logger(name=__name__,
4040
is a good choice.
4141
filename: An (optional) file to write log output.
4242
"""
43-
# Configure the underlying logging configuration
44-
handlers = [logging.StreamHandler()]
45-
if filename:
46-
handlers.append(logging.FileHandler(filename))
47-
43+
# Configure the basic underlying logging configuration
4844
logging.basicConfig(
4945
format="%(message)s",
5046
level=logging.INFO,
51-
handlers=handlers
52-
)
47+
handlers=[logging.StreamHandler()]
48+
)
5349

5450
# Configure structlog. This uses many of the standard suggestions from
5551
# the structlog documentation.
@@ -84,7 +80,12 @@ def get_structured_logger(name=__name__,
8480
cache_logger_on_first_use=True,
8581
)
8682

87-
logger = structlog.get_logger(name)
83+
# Create the underlying python logger and wrap it with structlog
84+
system_logger = logging.getLogger(name)
85+
if filename:
86+
system_logger.addHandler(logging.FileHandler(filename))
87+
system_logger.setLevel(logging.INFO)
88+
logger = structlog.wrap_logger(system_logger)
8889

8990
if log_exceptions:
9091
handle_exceptions(logger)

_delphi_utils_python/delphi_utils/runner.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import importlib
44
from typing import Any, Callable, Dict, Optional
55
from .archive import ArchiveDiffer, archiver_from_params
6+
from .logger import get_structured_logger
67
from .utils import read_params
78
from .validator.validate import Validator
89
from .validator.run import validator_from_params
@@ -40,6 +41,7 @@ def run_indicator_pipeline(indicator_fn: Callable[[Params], None],
4041
archiver = archiver_fn(params)
4142
if validator:
4243
validation_report = validator.validate()
44+
validation_report.log(get_structured_logger(params["common"].get("log_filename", None)))
4345
if archiver and (not validator or validation_report.success()):
4446
archiver.archive()
4547

_delphi_utils_python/delphi_utils/validator/report.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
from ..logger import get_structured_logger
55
from .errors import ValidationFailure
66

7-
logger = get_structured_logger(__name__)
8-
97
class ValidationReport:
108
"""Class for reporting the results of validation."""
119

@@ -83,14 +81,17 @@ def summary(self):
8381
out_str += f"{len(self.raised_warnings)} warnings\n"
8482
return out_str
8583

86-
def log(self):
84+
def log(self, logger=None):
8785
"""Log errors and warnings."""
86+
if logger is None:
87+
logger = get_structured_logger(__name__)
88+
8889
for error in self.unsuppressed_errors:
8990
logger.critical(str(error))
9091
for warning in self.raised_warnings:
9192
logger.warning(str(warning))
9293

93-
def print_and_exit(self, die_on_failures=True):
94+
def print_and_exit(self, logger=None, die_on_failures=True):
9495
"""Print results and exit.
9596
9697
Arguments
@@ -99,7 +100,7 @@ def print_and_exit(self, die_on_failures=True):
99100
Whether to return non-zero status if any failures were encountered.
100101
"""
101102
print(self.summary())
102-
self.log()
103+
self.log(logger)
103104
if self.success():
104105
sys.exit(0)
105106
elif die_on_failures:

_delphi_utils_python/delphi_utils/validator/run.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
when the module is run with `python -m delphi_utils.validator`.
66
"""
77
import argparse as ap
8-
from .. import read_params
8+
from .. import read_params, get_structured_logger
99
from .validate import Validator
1010

1111

@@ -15,8 +15,12 @@ def run_module():
1515
parser.add_argument("--dry_run", action="store_true", help="When provided, return zero exit"
1616
" status irrespective of the number of failures")
1717
args = parser.parse_args()
18-
validator = Validator(read_params())
19-
validator.validate().print_and_exit(not args.dry_run)
18+
params = read_params()
19+
validator = Validator(params)
20+
validator.validate().print_and_exit(
21+
get_structured_logger(__name__,
22+
params["common"].get("log_filename", None),
23+
not args.dry_run))
2024

2125

2226
def validator_from_params(params):

_delphi_utils_python/tests/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class TestRunIndicator:
3535
"""Fixture for running indicators."""
3636
# arbitrary params to pass to function generators
3737
PARAMS = {
38+
"common": {},
3839
"indicator": {"a": 1},
3940
"validation": {"b": 2},
4041
"archive": {"c": 3}

_delphi_utils_python/tests/validator/test_report.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ def test_str(self):
4444
assert report.summary() ==\
4545
"3 checks run\n1 checks failed\n1 checks suppressed\n2 warnings\n"
4646

47-
@mock.patch("delphi_utils.validator.report.logger")
48-
def test_log(self, mock_logger):
47+
def test_log(self):
4948
"""Test that the logs contain all failures and warnings."""
49+
mock_logger = mock.Mock()
5050
report = ValidationReport([self.ERROR_1])
5151
report.increment_total_checks()
5252
report.increment_total_checks()
@@ -56,7 +56,7 @@ def test_log(self, mock_logger):
5656
report.add_raised_error(self.ERROR_1)
5757
report.add_raised_error(self.ERROR_2)
5858

59-
report.log()
59+
report.log(mock_logger)
6060
mock_logger.critical.assert_called_once_with(
6161
"bad failed for sig2 at resolution county on 2020-11-07: msg 2")
6262
mock_logger.warning.assert_has_calls([mock.call("wrong import"), mock.call("right import")])

ansible/templates/google_symptoms-params-prod.json.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
},
66
"indicator": {
77
"export_start_date": "2020-02-20",
8-
"num_export_days": 14,
8+
"num_export_days": null,
99
"bigquery_credentials": {
1010
"type": "{{ google_symptoms_account_type }}",
1111
"project_id": "{{ google_symptoms_project_id }}",

google_symptoms/delphi_google_symptoms/run.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import time
88
from datetime import datetime, date
99
from itertools import product
10+
import covidcast
1011

1112
import numpy as np
1213
from delphi_utils import (
@@ -52,7 +53,13 @@ def run_module(params):
5253
), "%Y-%m-%d")
5354

5455
export_dir = params["common"]["export_dir"]
55-
num_export_days = params["indicator"].get("num_export_days", "all")
56+
num_export_days = params["indicator"]["num_export_days"]
57+
58+
if num_export_days is None:
59+
# Get number of days based on what's missing from the API.
60+
metadata = covidcast.metadata()
61+
gs_metadata = metadata[(metadata.data_source == "google-symptoms")]
62+
num_export_days = max(gs_metadata.min_lag)
5663

5764
logger = get_structured_logger(
5865
__name__, filename=params["common"].get("log_filename"),

google_symptoms/params.json.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
},
66
"indicator": {
77
"export_start_date": "2020-02-20",
8-
"num_export_days": 14,
8+
"num_export_days": null,
99
"bigquery_credentials": {}
1010
},
1111
"validation": {

0 commit comments

Comments
 (0)