Merge ~blake-rouse/maas:fix-1801389 into maas:master

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: 4e15fb66122a591d6dea99e42adfaad52917fdc7
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~blake-rouse/maas:fix-1801389
Merge into: maas:master
Diff against target: 128 lines (+79/-2)
3 files modified
src/provisioningserver/logger/__init__.py (+5/-1)
src/provisioningserver/logger/_logging.py (+1/-1)
src/provisioningserver/logger/_maaslog.py (+73/-0)
Reviewer Review Type Date Requested Status
Mike Pontillo (community) Approve
Review via email: mp+358935@code.launchpad.net

Commit message

Fixes LP: #1801389 - Queue messages to syslog until the logging handler can actually connect.

Description of the change

I spent too much time trying to unit test this handler. Upstream python tests it against a running syslog if available, but this would dirty the system running the unit tests so I didn't like that approach.

I could setup a syslog just to test this one test, but that just seems way overkill for something as simple as queue messages.

I have tested this running and it works correctly, no more stack trace and the messages get queued and wrote to the socket.

To post a comment you must log in.
Revision history for this message
Mike Pontillo (mpontillo) wrote :

Code looks good; good comments. Just a few grammar nits below.

review: Approve
~blake-rouse/maas:fix-1801389 updated
4e15fb6... by Blake Rouse

Fix comments.

Revision history for this message
Blake Rouse (blake-rouse) wrote :

Fixed the comments, thanks for the review.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/provisioningserver/logger/__init__.py b/src/provisioningserver/logger/__init__.py
index ceeaf19..2c109e2 100644
--- a/src/provisioningserver/logger/__init__.py
+++ b/src/provisioningserver/logger/__init__.py
@@ -54,6 +54,7 @@ __all__ = [
54 "get_maas_logger",54 "get_maas_logger",
55 "LegacyLogger",55 "LegacyLogger",
56 "LoggingMode",56 "LoggingMode",
57 "MAASSysLogHandler",
57 "set_verbosity",58 "set_verbosity",
58 "VerbosityOptions",59 "VerbosityOptions",
59]60]
@@ -68,7 +69,10 @@ from provisioningserver.logger._logging import (
68 configure_standard_logging,69 configure_standard_logging,
69 set_standard_verbosity,70 set_standard_verbosity,
70)71)
71from provisioningserver.logger._maaslog import get_maas_logger72from provisioningserver.logger._maaslog import (
73 get_maas_logger,
74 MAASSysLogHandler,
75)
72from provisioningserver.logger._tftp import configure_tftp_logging76from provisioningserver.logger._tftp import configure_tftp_logging
73from provisioningserver.logger._twisted import (77from provisioningserver.logger._twisted import (
74 configure_twisted_logging,78 configure_twisted_logging,
diff --git a/src/provisioningserver/logger/_logging.py b/src/provisioningserver/logger/_logging.py
index 96bca1e..b134650 100644
--- a/src/provisioningserver/logger/_logging.py
+++ b/src/provisioningserver/logger/_logging.py
@@ -110,7 +110,7 @@ def get_logging_config(verbosity: int):
110 'formatter': 'stdout',110 'formatter': 'stdout',
111 },111 },
112 'syslog': {112 'syslog': {
113 'class': 'logging.handlers.SysLogHandler',113 'class': 'provisioningserver.logger.MAASSysLogHandler',
114 'facility': logging.handlers.SysLogHandler.LOG_DAEMON,114 'facility': logging.handlers.SysLogHandler.LOG_DAEMON,
115 'address': get_syslog_address_path(),115 'address': get_syslog_address_path(),
116 'formatter': 'syslog',116 'formatter': 'syslog',
diff --git a/src/provisioningserver/logger/_maaslog.py b/src/provisioningserver/logger/_maaslog.py
index 5630ae5..89dd064 100644
--- a/src/provisioningserver/logger/_maaslog.py
+++ b/src/provisioningserver/logger/_maaslog.py
@@ -7,7 +7,10 @@ __all__ = [
7 "get_maas_logger",7 "get_maas_logger",
8 ]8 ]
99
10from collections import deque
10import logging11import logging
12import logging.handlers
13import socket
1114
1215
13class MAASLogger(logging.getLoggerClass()):16class MAASLogger(logging.getLoggerClass()):
@@ -19,6 +22,76 @@ class MAASLogger(logging.getLoggerClass()):
19 "Django logger instead")22 "Django logger instead")
2023
2124
25class MAASSysLogHandler(logging.handlers.SysLogHandler):
26 """A syslog handler that queuess messages when connection to the socket
27 cannot be performed.
28
29 Once the connection is made the queue is flushed to the socket.
30 """
31
32 def __init__(self, *args, **kwargs):
33 # `queue` must be set before `super().__init__`, because
34 # `_connect_unixsocket` is called inside.
35 self.queue = deque()
36 super().__init__(*args, **kwargs)
37
38 def _connect_unixsocket(self, address):
39 super()._connect_unixsocket(address)
40 # Successfully connected to the socket. Write any queued messages.
41 while len(self.queue) > 0:
42 msg = self.queue.popleft()
43 try:
44 self.socket.send(msg)
45 except OSError:
46 self.queue.appendleft(msg)
47 raise
48
49 def emit(self, record):
50 """
51 Emit a record.
52
53 The record is formatted, and then sent to the syslog server. If
54 exception information is present, it is NOT sent to the server.
55
56 Note: This is copied directly from the python3 source code, only the
57 modification of appending to the queue was added.
58 """
59 try:
60 msg = self.format(record)
61 if self.ident:
62 msg = self.ident + msg
63 if self.append_nul:
64 msg += '\000'
65
66 # We need to convert record level to lowercase, maybe this will
67 # change in the future.
68 prio = '<%d>' % self.encodePriority(
69 self.facility, self.mapPriority(record.levelname))
70 prio = prio.encode('utf-8')
71 # Message is a string. Convert to bytes as required by RFC 5424
72 msg = msg.encode('utf-8')
73 msg = prio + msg
74 if self.unixsocket:
75 try:
76 self.socket.send(msg)
77 except OSError:
78 self.socket.close()
79 try:
80 self._connect_unixsocket(self.address)
81 except OSError:
82 # Queue the message to send when the connection
83 # is finally made to the socket.
84 self.queue.append(msg)
85 return
86 self.socket.send(msg)
87 elif self.socktype == socket.SOCK_DGRAM:
88 self.socket.sendto(msg, self.address)
89 else:
90 self.socket.sendall(msg)
91 except Exception:
92 self.handleError(record)
93
94
22def get_maas_logger(syslog_tag=None):95def get_maas_logger(syslog_tag=None):
23 """Return a MAAS logger that will log to syslog.96 """Return a MAAS logger that will log to syslog.
2497

Subscribers

People subscribed via source and target branches