From 8ba37945d690d0b7179b4aaf21a54fb300f574b0 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 1 May 2012 14:13:00 -0700 Subject: [PATCH] python: Implement "vlog/reopen" unixctl command in Python vlog. Signed-off-by: Ben Pfaff --- python/ovs/vlog.py | 33 +++++++++++++++++-- tests/test-unixctl.py | 6 ++++ tests/unixctl-py.at | 2 ++ tests/vlog.at | 77 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 3 deletions(-) diff --git a/python/ovs/vlog.py b/python/ovs/vlog.py index b585591b..b3a8b813 100644 --- a/python/ovs/vlog.py +++ b/python/ovs/vlog.py @@ -1,5 +1,5 @@ -# Copyright (c) 2011 Nicira, Inc. +# Copyright (c) 2011, 2012 Nicira, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import socket import sys import ovs.dirs +import ovs.unixctl import ovs.util FACILITIES = {"console": "info", "file": "info", "syslog": "info"} @@ -41,6 +42,8 @@ class Vlog: __inited = False __msg_num = 0 __mfl = {} # Module -> facility -> level + __log_file = None + __file_handler = None def __init__(self, name): """Creates a new Vlog object representing a module called 'name'. The @@ -99,6 +102,7 @@ class Vlog: Vlog.__inited = True logging.raiseExceptions = False + Vlog.__log_file = log_file for f in FACILITIES: logger = logging.getLogger(f) logger.setLevel(logging.DEBUG) @@ -110,11 +114,15 @@ class Vlog: logger.addHandler(logging.handlers.SysLogHandler( address="/dev/log", facility=logging.handlers.SysLogHandler.LOG_DAEMON)) - elif f == "file" and log_file: - logger.addHandler(logging.FileHandler(log_file)) + elif f == "file" and Vlog.__log_file: + Vlog.__file_handler = logging.FileHandler(Vlog.__log_file) + logger.addHandler(Vlog.__file_handler) except (IOError, socket.error): logger.setLevel(logging.CRITICAL) + ovs.unixctl.command_register("vlog/reopen", "", 0, 0, + Vlog._unixctl_vlog_reopen, None) + @staticmethod def set_level(module, facility, level): """ Sets the log level of the 'module'-'facility' tuple to 'level'. @@ -149,6 +157,25 @@ class Vlog: for f in facilities: Vlog.__mfl[m][f] = level + @staticmethod + def reopen_log_file(): + """Closes and then attempts to re-open the current log file. (This is + useful just after log rotation, to ensure that the new log file starts + being used.)""" + + if Vlog.__log_file: + logger = logging.getLogger("file") + logger.removeHandler(Vlog.__file_handler) + Vlog.__file_handler = logging.FileHandler(Vlog.__log_file) + logger.addHandler(Vlog.__file_handler) + + @staticmethod + def _unixctl_vlog_reopen(conn, unused_argv, unused_aux): + if Vlog.__log_file: + Vlog.reopen_log_file() + conn.reply(None) + else: + conn.reply("Logging to file not configured") def add_args(parser): """Adds vlog related options to 'parser', an ArgumentParser object. The diff --git a/tests/test-unixctl.py b/tests/test-unixctl.py index 3d86db17..ab03479b 100644 --- a/tests/test-unixctl.py +++ b/tests/test-unixctl.py @@ -40,6 +40,11 @@ def unixctl_echo_error(conn, argv, aux): conn.reply_error(str(argv)) +def unixctl_log(conn, argv, unused_aux): + vlog.info(str(argv[0])) + conn.reply(None) + + def unixctl_block(conn, unused_argv, unused_aux): pass @@ -64,6 +69,7 @@ def main(): ovs.unixctl.command_register("exit", "", 0, 0, unixctl_exit, "aux_exit") ovs.unixctl.command_register("echo", "[arg ...]", 1, 2, unixctl_echo, "aux_echo") + ovs.unixctl.command_register("log", "[arg ...]", 1, 2, unixctl_log, None) ovs.unixctl.command_register("echo_error", "[arg ...]", 1, 2, unixctl_echo_error, "aux_echo_error") ovs.unixctl.command_register("block", "", 0, 0, unixctl_block, None) diff --git a/tests/unixctl-py.at b/tests/unixctl-py.at index f9caa60f..37070c91 100644 --- a/tests/unixctl-py.at +++ b/tests/unixctl-py.at @@ -104,7 +104,9 @@ The available commands are: echo_error [[arg ...]] exit help + log [[arg ...]] version + vlog/reopen ]) mv stdout expout AT_CHECK([PYAPPCTL -t test-unixctl.py help], [0], [expout]) diff --git a/tests/vlog.at b/tests/vlog.at index 597c27ac..a1afb10f 100644 --- a/tests/vlog.at +++ b/tests/vlog.at @@ -103,3 +103,80 @@ AssertionError ]) AT_CLEANUP + +AT_SETUP([vlog - vlog/reopen - Python]) +AT_SKIP_IF([test $HAVE_PYTHON = no]) +OVS_RUNDIR=`pwd`; export OVS_RUNDIR +OVS_LOGDIR=`pwd`; export OVS_LOGDIR +OVS_SYSCONFDIR=`pwd`; export OVS_SYSCONFDIR +trap 'kill `cat test-unixctl.py.pid`' 0 + +AT_CAPTURE_FILE([log]) +AT_CAPTURE_FILE([log.old]) +AT_CHECK([$PYTHON $srcdir/test-unixctl.py --log-file=`pwd`/log --pidfile --detach]) + +AT_CHECK([APPCTL -t test-unixctl.py log message]) +mv log log.old +AT_CHECK([APPCTL -t test-unixctl.py log message2]) +AT_CHECK([APPCTL -t test-unixctl.py vlog/reopen]) +AT_CHECK([APPCTL -t test-unixctl.py log message3]) +AT_CHECK([APPCTL -t test-unixctl.py exit]) +trap '' 0 + +AT_CHECK([sed 's/.*|//' log.old], [0], [dnl +Entering run loop. +message +message2 +]) +AT_CHECK([sed 's/.*|//' log], [0], [dnl +message3 +]) +AT_CLEANUP + +AT_SETUP([vlog - vlog/reopen without log file - Python]) +AT_SKIP_IF([test $HAVE_PYTHON = no]) +OVS_RUNDIR=`pwd`; export OVS_RUNDIR +OVS_LOGDIR=`pwd`; export OVS_LOGDIR +OVS_SYSCONFDIR=`pwd`; export OVS_SYSCONFDIR +trap 'kill `cat test-unixctl.py.pid`' 0 + +AT_CHECK([$PYTHON $srcdir/test-unixctl.py --pidfile --detach]) + +AT_CHECK([APPCTL -t test-unixctl.py vlog/reopen], [0], + [Logging to file not configured +]) +AT_CLEANUP + +dnl This checks that if vlog/reopen can't reopen the log file, +dnl nothing particularly bad (e.g. Python throws an exception and +dnl aborts the program) happens. +AT_SETUP([vlog - vlog/reopen can't reopen log file - Python]) +AT_SKIP_IF([test $HAVE_PYTHON = no]) + +# Verify that /dev/full is a character device that fails writes. +AT_SKIP_IF([test ! -c /dev/full]) +AT_SKIP_IF([echo > /dev/full]) + +OVS_RUNDIR=`pwd`; export OVS_RUNDIR +OVS_LOGDIR=`pwd`; export OVS_LOGDIR +OVS_SYSCONFDIR=`pwd`; export OVS_SYSCONFDIR +trap 'kill `cat test-unixctl.py.pid`' 0 + +AT_CHECK([$PYTHON $srcdir/test-unixctl.py --log-file=`pwd`/log --pidfile --detach]) +AT_CHECK([APPCTL -t test-unixctl.py log message]) +mv log log.old +ln -s /dev/full log +AT_CHECK([APPCTL -t test-unixctl.py vlog/reopen]) +AT_CHECK([APPCTL -t test-unixctl.py log message2]) +rm log +AT_CHECK([APPCTL -t test-unixctl.py vlog/reopen]) +AT_CHECK([APPCTL -t test-unixctl.py log message3]) +AT_CHECK([APPCTL -t test-unixctl.py exit]) +AT_CHECK([sed 's/.*|//' log.old], [0], [dnl +Entering run loop. +message +]) +AT_CHECK([sed 's/.*|//' log], [0], [dnl +message3 +]) +AT_CLEANUP -- 2.30.2