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 # RequestEntry ctor
create_request_entry = None create_request_entry = None
# Circular debug log
debug = None
def exit_daemon(): def exit_daemon():
""" """

View File

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

View File

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

View File

@ -25,7 +25,7 @@ from .manager import Manager
import traceback import traceback
import queue import queue
from . import udevwatch 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 argparse
import os import os
import sys import sys
@ -147,6 +147,9 @@ def main():
# cmdhandler is for when we are running other code with a different main. # cmdhandler is for when we are running other code with a different main.
cfg.flightrecorder = LvmFlightRecorder(cfg.args.fr_size) 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) log_debug("Using lvm binary: %s" % cfg.LVM_CMD)
# We will dynamically add interfaces which support vdo if it # 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 Dump the flight recorder to syslog
""" """
cfg.debug.dump()
cfg.flightrecorder.dump() cfg.flightrecorder.dump()
@staticmethod @staticmethod

View File

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

View File

@ -10,6 +10,7 @@
import xml.etree.ElementTree as Et import xml.etree.ElementTree as Et
import sys import sys
import inspect import inspect
import collections
import ctypes import ctypes
import errno import errno
import fcntl import fcntl
@ -282,8 +283,28 @@ def parse_tags(tags):
return dbus.Array([], signature='s') return dbus.Array([], signature='s')
def _common_log(msg, *attributes): class DebugMessages(object):
cfg.stdout_lock.acquire()
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) tid = ctypes.CDLL('libc.so.6').syscall(186)
if STDOUT_TTY: if STDOUT_TTY:
@ -293,6 +314,12 @@ def _common_log(msg, *attributes):
else: else:
msg = "%d:%d - %s" % (os.getpid(), tid, msg) 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: if STDOUT_TTY and attributes:
print(color(msg, *attributes)) print(color(msg, *attributes))
@ -309,6 +336,9 @@ def _common_log(msg, *attributes):
def log_debug(msg, *attributes): def log_debug(msg, *attributes):
if cfg.args and cfg.args.debug: if cfg.args and cfg.args.debug:
_common_log(msg, *attributes) _common_log(msg, *attributes)
else:
if cfg.debug:
cfg.debug.add(_format_log_entry(msg))
def log_error(msg, *attributes): def log_error(msg, *attributes):
@ -348,13 +378,15 @@ def handler(signum):
try: try:
# signal 10 # signal 10
if signum == signal.SIGUSR1: if signum == signal.SIGUSR1:
cfg.debug.dump()
dump_threads_stackframe() dump_threads_stackframe()
# signal 12 # signal 12
elif signum == signal.SIGUSR2: elif signum == signal.SIGUSR2:
cfg.debug.dump()
cfg.flightrecorder.dump() cfg.flightrecorder.dump()
else: else:
cfg.run.value = 0 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: if cfg.loop is not None:
cfg.loop.quit() cfg.loop.quit()
except: except: