Codebase list logbook / b070d24
Merge branch 'upstream-update_1.4.2-1' into 'master' New upstream release 1.4.2-1 See merge request debian/logbook!21 Agustin Henze 5 years ago
6 changed file(s) with 131 addition(s) and 50 deletion(s). Raw diff Collapse all Expand all
00 Logbook Changelog
11 =================
2
3 Not yet released
4
5 - Use correct record delimiters (null for UNIX, newline for network) in SyslogHandler (thanks Jonathan Kamens)
6 - Try to reconnect to SyslogHandler TCP sockets when they are disconnected (thanks Jonathan Kamens)
7 - Use RFC 5424 format for networking logging in SyslogHandler (thanks Jonathan Kamens)
28
39 Here you can see the full list of changes between each Logbook release.
410
0 logbook (1.4.2-1) UNRELEASED; urgency=medium
1
2 * New upstream version 1.4.2
3
4 -- Downstreamer <salsa-ci-team@debian.org> Thu, 20 Dec 2018 18:20:07 +0000
5
06 logbook (1.4.1-1) unstable; urgency=medium
17
28 [ Ondřej Nový ]
497497
498498 if (not suppression_count and
499499 len(self._record_limits) >= self.max_record_cache):
500 cache_items = self._record_limits.items()
501 cache_items.sort()
500 cache_items = sorted(self._record_limits.items())
502501 del cache_items[:int(self._record_limits)
503502 * self.record_cache_prune]
504503 self._record_limits = dict(cache_items)
15341533 def __init__(self, application_name=None, address=None,
15351534 facility='user', socktype=socket.SOCK_DGRAM,
15361535 level=NOTSET, format_string=None, filter=None,
1537 bubble=False):
1536 bubble=False, record_delimiter=None):
15381537 Handler.__init__(self, level, filter, bubble)
15391538 StringFormatterHandlerMixin.__init__(self, format_string)
15401539 self.application_name = application_name
15451544 else:
15461545 address = '/dev/log'
15471546
1548 self.address = address
1547 self.remote_address = self.address = address
15491548 self.facility = facility
15501549 self.socktype = socktype
15511550
15521551 if isinstance(address, string_types):
15531552 self._connect_unixsocket()
1553 self.enveloper = self.unix_envelope
1554 default_delimiter = u'\x00'
15541555 else:
15551556 self._connect_netsocket()
1557 self.enveloper = self.net_envelope
1558 default_delimiter = u'\n'
1559
1560 self.record_delimiter = default_delimiter \
1561 if record_delimiter is None else record_delimiter
1562
1563 self.connection_exception = getattr(
1564 __builtins__, 'BrokenPipeError', socket.error)
15561565
15571566 def _connect_unixsocket(self):
15581567 self.unixsocket = True
15681577 self.unixsocket = False
15691578 self.socket = socket.socket(socket.AF_INET, self.socktype)
15701579 if self.socktype == socket.SOCK_STREAM:
1571 self.socket.connect(self.address)
1580 self.socket.connect(self.remote_address)
15721581 self.address = self.socket.getsockname()
15731582
15741583 def encode_priority(self, record):
15771586 self.LOG_WARNING)
15781587 return (facility << 3) | priority
15791588
1589 def wrap_segments(self, record, before):
1590 msg = self.format(record)
1591 segments = [segment for segment in msg.split(self.record_delimiter)]
1592 return (before + segment + self.record_delimiter
1593 for segment in segments)
1594
1595 def unix_envelope(self, record):
1596 before = u'<{}>{}'.format(
1597 self.encode_priority(record),
1598 self.application_name + ':' if self.application_name else '')
1599 return self.wrap_segments(record, before)
1600
1601 def net_envelope(self, record):
1602 # Gross but effective
1603 try:
1604 format_string = self.format_string
1605 application_name = self.application_name
1606 if not application_name and record.channel and \
1607 '{record.channel}: ' in format_string:
1608 self.format_string = format_string.replace(
1609 '{record.channel}: ', '')
1610 self.application_name = record.channel
1611 # RFC 5424: <PRIVAL>version timestamp hostname app-name procid
1612 # msgid structured-data message
1613 before = u'<{}>1 {}Z {} {} {} - - '.format(
1614 self.encode_priority(record),
1615 record.time.isoformat(),
1616 socket.gethostname(),
1617 self.application_name if self.application_name else '-',
1618 record.process)
1619 return self.wrap_segments(record, before)
1620 finally:
1621 self.format_string = format_string
1622 self.application_name = application_name
1623
15801624 def emit(self, record):
1581 prefix = u('')
1582 if self.application_name is not None:
1583 prefix = self.application_name + u(':')
1584 self.send_to_socket((u('<%d>%s%s\x00') % (
1585 self.encode_priority(record),
1586 prefix,
1587 self.format(record)
1588 )).encode('utf-8'))
1625 for segment in self.enveloper(record):
1626 self.send_to_socket(segment.encode('utf-8'))
15891627
15901628 def send_to_socket(self, data):
15911629 if self.unixsocket:
15981636 # the flags are no longer optional on Python 3
15991637 self.socket.sendto(data, 0, self.address)
16001638 else:
1601 self.socket.sendall(data)
1639 try:
1640 self.socket.sendall(data)
1641 except self.connection_exception:
1642 self._connect_netsocket()
1643 self.socket.send(data)
16021644
16031645 def close(self):
16041646 self.socket.close()
3232 with redirected_logging(set_root_logger_level):
3333 logger.debug('This is from the old system')
3434 logger.info('This is from the old system')
35 logger.warn('This is from the old %s', 'system')
35 logger.warning('This is from the old %s', 'system')
3636 logger.error('This is from the old system')
3737 logger.critical('This is from the old system')
3838 logger.error('This is a %(what)s %(where)s', {'what': 'mapping', 'where': 'test'})
3939 header, data = mail.split('\n\n', 1)
4040 if 'Content-Transfer-Encoding: base64' in header:
4141 data = base64.b64decode(data).decode('utf-8')
42 assert re.search('Message type:\s+ERROR', data)
43 assert re.search('Location:.*%s' %
42 assert re.search(r'Message type:\s+ERROR', data)
43 assert re.search(r'Location:.*%s' %
4444 re.escape(__file_without_pyc__), data)
45 assert re.search('Module:\s+%s' % __name__, data)
46 assert re.search('Function:\s+test_mail_handler', data)
45 assert re.search(r'Module:\s+%s' % __name__, data)
46 assert re.search(r'Function:\s+test_mail_handler', data)
4747 body = u('Viva la Espa\xf1a')
4848 if sys.version_info < (3, 0):
4949 body = body.encode('utf-8')
7171 body, rest = pieces
7272 rest = rest.replace('\r', '')
7373
74 assert re.search('Message type:\s+ERROR', body)
75 assert re.search('Module:\s+%s' % __name__, body)
76 assert re.search('Function:\s+test_mail_handler_batching', body)
74 assert re.search(r'Message type:\s+ERROR', body)
75 assert re.search(r'Module:\s+%s' % __name__, body)
76 assert re.search(r'Function:\s+test_mail_handler_batching', body)
7777
7878 related = rest.strip().split('\n\n')
7979 assert len(related) == 2
80 assert re.search('Message type:\s+WARNING', related[0])
81 assert re.search('Message type:\s+DEBUG', related[1])
80 assert re.search(r'Message type:\s+WARNING', related[0])
81 assert re.search(r'Message type:\s+DEBUG', related[1])
8282
8383 assert 'And this triggers it again' in mail_handler.mails[1][2]
8484
100100 body, rest = pieces
101101 rest = rest.replace('\r', '')
102102
103 assert re.search('Message type:\\s+ERROR', body)
104 assert re.search('Module:\s+' + __name__, body)
105 assert re.search('Function:\s+test_group_handler_mail_combo', body)
103 assert re.search(r'Message type:\s+ERROR', body)
104 assert re.search(r'Module:\s+' + __name__, body)
105 assert re.search(r'Function:\s+test_group_handler_mail_combo', body)
106106
107107 related = rest.strip().split('\n\n')
108108 assert len(related) == 2
109 assert re.search('Message type:\s+WARNING', related[0])
110 assert re.search('Message type:\s+DEBUG', related[1])
109 assert re.search(r'Message type:\s+WARNING', related[0])
110 assert re.search(r'Message type:\s+DEBUG', related[1])
111111
112112
113113 def test_mail_handler_arguments():
00 import os
1 import re
12 import socket
23 from contextlib import closing
34
67
78 import pytest
89
10 unix_socket = "/tmp/__unixsock_logbook.test"
911
10 def test_syslog_handler(logger, activation_strategy, unix_sock_path):
11 to_test = [
12 (socket.AF_INET, ('127.0.0.1', 0)),
13 ]
14 if hasattr(socket, 'AF_UNIX'):
15 to_test.append((socket.AF_UNIX, unix_sock_path))
16 for sock_family, address in to_test:
17 with closing(socket.socket(sock_family, socket.SOCK_DGRAM)) as inc:
18 inc.bind(address)
19 inc.settimeout(1)
20 for app_name in [None, 'Testing']:
21 handler = logbook.SyslogHandler(app_name, inc.getsockname())
22 with activation_strategy(handler):
23 logger.warn('Syslog is weird')
24 try:
12 to_test = [
13 (socket.AF_INET, socket.SOCK_DGRAM, ('127.0.0.1', 0)),
14 (socket.AF_INET, socket.SOCK_STREAM, ('127.0.0.1', 0)),
15 ]
16 if hasattr(socket, 'AF_UNIX'):
17 to_test.append((socket.AF_UNIX, socket.SOCK_DGRAM, unix_socket))
18
19 @pytest.mark.usefixtures("unix_sock_path")
20 @pytest.mark.parametrize("sock_family,socktype,address", to_test)
21 def test_syslog_handler(logger, activation_strategy,
22 sock_family, socktype, address):
23 delimiter = {socket.AF_UNIX: '\x00',
24 socket.AF_INET: '\n'}[sock_family]
25 with closing(socket.socket(sock_family, socktype)) as inc:
26 inc.bind(address)
27 if socktype == socket.SOCK_STREAM:
28 inc.listen(0)
29 inc.settimeout(1)
30 for app_name in [None, 'Testing']:
31 if sock_family == socket.AF_UNIX:
32 expected = (r'^<12>%stestlogger: Syslog is weird%s$' %
33 (app_name + ':' if app_name else '',
34 delimiter))
35 else:
36 expected = (r'^<12>1 \d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?Z %s %s %d '
37 '- - %sSyslog is weird%s$' %
38 (socket.gethostname(),
39 app_name if app_name else 'testlogger',
40 os.getpid(), 'testlogger: ' if app_name else '',
41 delimiter))
42
43 handler = logbook.SyslogHandler(app_name, inc.getsockname(),
44 socktype=socktype)
45 with activation_strategy(handler):
46 logger.warn('Syslog is weird')
47 try:
48 if socktype == socket.SOCK_STREAM:
49 with closing(inc.accept()[0]) as inc2:
50 rv = inc2.recv(1024)
51 else:
2552 rv = inc.recvfrom(1024)[0]
26 except socket.error:
27 assert False, 'got timeout on socket'
28 assert rv == (
29 u('<12>%stestlogger: Syslog is weird\x00') %
30 ((app_name and (app_name + u(':'))) or u(''))).encode('utf-8')
53 except socket.error:
54 assert False, 'got timeout on socket'
55 rv = rv.decode('utf-8')
56 assert re.match(expected, rv), \
57 'expected {}, got {}'.format(expected, rv)
3158
3259
3360 @pytest.fixture
3461 def unix_sock_path(request):
35 returned = "/tmp/__unixsock_logbook.test"
62 returned = unix_socket
3663
3764 @request.addfinalizer
3865 def cleanup():