Skip to content

Commit 932022c

Browse files
authored
🔧 Open up logging (#237)
* 🔧 Open up logging Create methods on logger for add/remove handlers and get all handlers. Expose these in global methods as well on the global instance of LOG. Open up the get methods for file and stream handlers Remove the file logger since it now can be added afterward instead of by default. * ✅ MyPy correction to silent 'silent' apparently should be without quotes. A warning is thrown on lint. * ✅Add tests for logs
1 parent 95e122b commit 932022c

File tree

3 files changed

+109
-22
lines changed

3 files changed

+109
-22
lines changed

mypy.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ warn_return_any = True
66
warn_unused_configs = True
77
disallow_untyped_defs = True
88
ignore_missing_imports = True
9-
follow_imports = "silent"
9+
follow_imports = silent
1010
show_column_numbers = True
1111
mypy_path = "src:stubs"
1212

src/electionguard/logs.py

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import logging
33
import os.path
44
import sys
5-
from typing import Any, Tuple
5+
from typing import Any, List, Tuple
66
from logging.handlers import RotatingFileHandler
77

88
from .singleton import Singleton
@@ -21,8 +21,7 @@ def __init__(self) -> None:
2121
super(ElectionGuardLog, self).__init__()
2222

2323
self.__logger = logging.getLogger("electionguard")
24-
self.__logger.addHandler(self._get_file_handler())
25-
self.__logger.addHandler(self._get_stream_handler())
24+
self.__logger.addHandler(get_stream_handler())
2625

2726
@staticmethod
2827
def __get_call_info() -> Tuple[str, str, int]:
@@ -45,30 +44,23 @@ def __formatted_message(self, message: str) -> str:
4544
message = f"{os.path.basename(filename)}.{funcname}:#L{line}: {message}"
4645
return message
4746

48-
def _get_stream_handler(self) -> logging.StreamHandler:
47+
def add_handler(self, handler: logging.Handler) -> None:
4948
"""
50-
Get a Stream Handler, sends only warnings and errors to stdout.
49+
Adds a logger handler
5150
"""
52-
stream_handler = logging.StreamHandler(sys.stdout)
53-
stream_handler.setLevel(logging.WARNING)
54-
stream_handler.setFormatter(logging.Formatter(FORMAT))
55-
return stream_handler
51+
self.__logger.addHandler(handler)
5652

57-
def _get_file_handler(self) -> logging.FileHandler:
53+
def remove_handler(self, handler: logging.Handler) -> None:
5854
"""
59-
Get a File System Handler, sends verbose logging to a file, `electionguard.log`.
60-
When that file gets too large, the logs will rotate, creating files with names
61-
like `electionguard.log.1`.
55+
Removes a logger handler
6256
"""
57+
self.__logger.removeHandler(handler)
6358

64-
# TODO: add file compression, save a bunch of space.
65-
# https://medium.com/@rahulraghu94/overriding-pythons-timedrotatingfilehandler-to-compress-your-log-files-iot-c766a4ace240
66-
file_handler = RotatingFileHandler(
67-
"electionguard.log", "a", maxBytes=10_000_000, backupCount=10
68-
)
69-
file_handler.setLevel(logging.DEBUG)
70-
file_handler.setFormatter(logging.Formatter(FORMAT))
71-
return file_handler
59+
def handlers(self) -> List[logging.Handler]:
60+
"""
61+
Returns all logging handlers
62+
"""
63+
return self.__logger.handlers
7264

7365
def debug(self, message: str, *args: Any, **kwargs: Any) -> None:
7466
"""
@@ -101,9 +93,57 @@ def critical(self, message: str, *args: Any, **kwargs: Any) -> None:
10193
self.__logger.critical(self.__formatted_message(message), *args, **kwargs)
10294

10395

96+
def get_stream_handler() -> logging.StreamHandler:
97+
"""
98+
Get a Stream Handler, sends only warnings and errors to stdout.
99+
"""
100+
stream_handler = logging.StreamHandler(sys.stdout)
101+
stream_handler.setLevel(logging.WARNING)
102+
stream_handler.setFormatter(logging.Formatter(FORMAT))
103+
return stream_handler
104+
105+
106+
def get_file_handler() -> logging.FileHandler:
107+
"""
108+
Get a File System Handler, sends verbose logging to a file, `electionguard.log`.
109+
When that file gets too large, the logs will rotate, creating files with names
110+
like `electionguard.log.1`.
111+
"""
112+
113+
# TODO: add file compression, save a bunch of space.
114+
# https://medium.com/@rahulraghu94/overriding-pythons-timedrotatingfilehandler-to-compress-your-log-files-iot-c766a4ace240
115+
file_handler = RotatingFileHandler(
116+
"electionguard.log", "a", maxBytes=10_000_000, backupCount=10
117+
)
118+
file_handler.setLevel(logging.DEBUG)
119+
file_handler.setFormatter(logging.Formatter(FORMAT))
120+
return file_handler
121+
122+
104123
LOG = ElectionGuardLog()
105124

106125

126+
def log_add_handler(handler: logging.Handler) -> None:
127+
"""
128+
Adds a handler to the logger
129+
"""
130+
LOG.add_handler(handler)
131+
132+
133+
def log_remove_handler(handler: logging.Handler) -> None:
134+
"""
135+
Removes a handler from the logger
136+
"""
137+
LOG.remove_handler(handler)
138+
139+
140+
def log_handlers() -> List[logging.Handler]:
141+
"""
142+
Returns all logger handlers
143+
"""
144+
return LOG.handlers()
145+
146+
107147
def log_debug(msg: str, *args: Any, **kwargs: Any) -> None:
108148
"""
109149
Logs a debug message to the console and the file log.

tests/test_logs.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from unittest import TestCase
2+
3+
from electionguard.logs import (
4+
get_stream_handler,
5+
log_add_handler,
6+
log_remove_handler,
7+
log_handlers,
8+
log_debug,
9+
log_error,
10+
log_info,
11+
log_warning,
12+
)
13+
14+
15+
class TestLogs(TestCase):
16+
def test_log_methods(self):
17+
# Arrange
18+
message = "test log message"
19+
20+
# Act
21+
log_debug(message)
22+
log_error(message)
23+
log_info(message)
24+
log_warning(message)
25+
26+
def test_log_handlers(self):
27+
# Arrange
28+
29+
# Act
30+
handlers = log_handlers()
31+
32+
# Assert
33+
self.assertEqual(len(handlers), 1)
34+
35+
# Act
36+
log_remove_handler(handlers[0])
37+
empty_handlers = log_handlers()
38+
39+
# Assert
40+
self.assertEqual(len(empty_handlers), 0)
41+
42+
# Act
43+
log_add_handler(get_stream_handler())
44+
added_handlers = log_handlers()
45+
46+
# Assert
47+
self.assertEqual(len(added_handlers), 1)

0 commit comments

Comments
 (0)