1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

lvmdbusd: Add debug circular buffer

When the daemon isn't started with --debug we will keep a circular
buffer of the past N number of debug messages which we will output
when we encounter an issue.
This commit is contained in:
Tony Asleson 2022-08-17 17:24:08 -05:00
parent f65f7da760
commit b0c7220dbb
7 changed files with 47 additions and 4 deletions

View File

@ -97,6 +97,9 @@ flightrecorder = None
# RequestEntry ctor
create_request_entry = None
# Circular debug log
debug = None
def exit_daemon():
"""

View File

@ -88,6 +88,7 @@ class LvmFlightRecorder(object):
for c in reversed(self.queue):
log_error(str(c))
log_error("LVM dbus flight recorder END")
self.queue.clear()
cfg.flightrecorder = LvmFlightRecorder()
@ -176,6 +177,7 @@ def call_lvm(command, debug=False, line_cb=None,
return -errno.EINTR, "", "operation interrupted"
# The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell
_t_call = call_lvm

View File

@ -195,6 +195,7 @@ class StateUpdate(object):
except Exception as e:
st = traceback.format_exc()
log_error("update_thread exception: \n%s" % st)
cfg.debug.dump()
cfg.flightrecorder.dump()
exception_count += 1
if exception_count >= 5:

View File

@ -25,7 +25,7 @@ from .manager import Manager
import traceback
import queue
from . import udevwatch
from .utils import log_debug, log_error, log_msg
from .utils import log_debug, log_error, log_msg, DebugMessages
import argparse
import os
import sys
@ -147,6 +147,9 @@ def main():
# cmdhandler is for when we are running other code with a different main.
cfg.flightrecorder = LvmFlightRecorder(cfg.args.fr_size)
# Create a circular buffer for debug logs
cfg.debug = DebugMessages()
log_debug("Using lvm binary: %s" % cfg.LVM_CMD)
# We will dynamically add interfaces which support vdo if it

View File

@ -137,6 +137,7 @@ class Manager(AutomatedProperties):
"""
Dump the flight recorder to syslog
"""
cfg.debug.dump()
cfg.flightrecorder.dump()
@staticmethod

View File

@ -76,6 +76,7 @@ class RequestEntry(object):
# have gotten a job by the time we hit an error
# Lets get the stacktrace and set that to the error message
st = traceback.format_exc()
cfg.debug.dump()
cfg.flightrecorder.dump()
log_error("Exception returned to client: \n%s" % st)
self.register_error(-1, str(e), e)

View File

@ -10,6 +10,7 @@
import xml.etree.ElementTree as Et
import sys
import inspect
import collections
import ctypes
import errno
import fcntl
@ -282,8 +283,28 @@ def parse_tags(tags):
return dbus.Array([], signature='s')
def _common_log(msg, *attributes):
cfg.stdout_lock.acquire()
class DebugMessages(object):
def __init__(self, size=5000):
self.queue = collections.deque(maxlen=size)
self.lock = threading.RLock()
def add(self, message):
with self.lock:
self.queue.append(message)
def dump(self):
if cfg.args and not cfg.args.debug:
with self.lock:
if len(self.queue):
log_error("LVM dbus debug messages START last (%d max) messages" % self.queue.maxlen)
for m in self.queue:
print(m)
log_error("LVM dbus debug messages END")
self.queue.clear()
def _format_log_entry(msg):
tid = ctypes.CDLL('libc.so.6').syscall(186)
if STDOUT_TTY:
@ -293,6 +314,12 @@ def _common_log(msg, *attributes):
else:
msg = "%d:%d - %s" % (os.getpid(), tid, msg)
return msg
def _common_log(msg, *attributes):
cfg.stdout_lock.acquire()
msg = _format_log_entry(msg)
if STDOUT_TTY and attributes:
print(color(msg, *attributes))
@ -309,6 +336,9 @@ def _common_log(msg, *attributes):
def log_debug(msg, *attributes):
if cfg.args and cfg.args.debug:
_common_log(msg, *attributes)
else:
if cfg.debug:
cfg.debug.add(_format_log_entry(msg))
def log_error(msg, *attributes):
@ -348,13 +378,15 @@ def handler(signum):
try:
# signal 10
if signum == signal.SIGUSR1:
cfg.debug.dump()
dump_threads_stackframe()
# signal 12
elif signum == signal.SIGUSR2:
cfg.debug.dump()
cfg.flightrecorder.dump()
else:
cfg.run.value = 0
log_debug('Exiting daemon with signal %d' % signum)
log_error('Exiting daemon with signal %d' % signum)
if cfg.loop is not None:
cfg.loop.quit()
except: