From 8780157755de98914a0abd90d5d2475227ab91e6 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Wed, 6 Jun 2012 11:02:20 +0200 Subject: [PATCH] Add and use ceilometer own log module This fixes bug #1004130 Change-Id: I143124ad411d5efefa604e831173dca87548bd7f Signed-off-by: Julien Danjou --- bin/ceilometer-agent | 4 +- bin/ceilometer-collector | 4 +- ceilometer/agent/manager.py | 7 +-- ceilometer/collector/dispatcher.py | 7 +-- ceilometer/collector/manager.py | 7 +-- ceilometer/compute/libvirt.py | 14 ++--- ceilometer/compute/network.py | 5 +- ceilometer/log.py | 98 ++++++++++++++++++++++++++++++ tests/test_log.py | 64 +++++++++++++++++++ 9 files changed, 180 insertions(+), 30 deletions(-) create mode 100644 ceilometer/log.py create mode 100644 tests/test_log.py diff --git a/bin/ceilometer-agent b/bin/ceilometer-agent index 845ce339..f59940ee 100755 --- a/bin/ceilometer-agent +++ b/bin/ceilometer-agent @@ -23,13 +23,13 @@ eventlet.monkey_patch() import sys from nova import flags -from nova import log as logging from nova import service from nova import utils +from ceilometer import log if __name__ == '__main__': flags.parse_args(sys.argv) - logging.setup() + log.setup() utils.monkey_patch() server = \ service.Service.create(binary='ceilometer-agent', diff --git a/bin/ceilometer-collector b/bin/ceilometer-collector index e674fbd4..b890171b 100755 --- a/bin/ceilometer-collector +++ b/bin/ceilometer-collector @@ -23,13 +23,13 @@ eventlet.monkey_patch() import sys from nova import flags -from nova import log as logging from nova import service from nova import utils +from ceilometer import log if __name__ == '__main__': flags.parse_args(sys.argv) - logging.setup() + log.setup() utils.monkey_patch() server = \ service.Service.create(binary='ceilometer-collector', diff --git a/ceilometer/agent/manager.py b/ceilometer/agent/manager.py index 8d3e9487..864c9fcb 100644 --- a/ceilometer/agent/manager.py +++ b/ceilometer/agent/manager.py @@ -18,18 +18,15 @@ import pkg_resources -from nova import log as logging from nova import manager from nova import rpc from ceilometer import meter from ceilometer import cfg +from ceilometer import log -# FIXME(dhellmann): We need to have the main program set up logging -# correctly so messages from modules outside of the nova package -# appear in the output. -LOG = logging.getLogger('nova.' + __name__) +LOG = log.getLogger(__name__) COMPUTE_PLUGIN_NAMESPACE = 'ceilometer.poll.compute' diff --git a/ceilometer/collector/dispatcher.py b/ceilometer/collector/dispatcher.py index 57ce1441..e8ef1f93 100644 --- a/ceilometer/collector/dispatcher.py +++ b/ceilometer/collector/dispatcher.py @@ -21,12 +21,9 @@ and publish the results. import pkg_resources -from nova import log as logging +from ceilometer import log -# FIXME(dhellmann): We need to have the main program set up logging -# correctly so messages from modules outside of the nova package -# appear in the output. -LOG = logging.getLogger('nova.' + __name__) +LOG = log.getLogger(__name__) class NotificationDispatcher(object): diff --git a/ceilometer/collector/manager.py b/ceilometer/collector/manager.py index d053440b..c753ad12 100644 --- a/ceilometer/collector/manager.py +++ b/ceilometer/collector/manager.py @@ -18,12 +18,12 @@ from nova import context from nova import flags -from nova import log as logging from nova import manager from nova import rpc as nova_rpc from nova.rpc import dispatcher as rpc_dispatcher from ceilometer import rpc +from ceilometer import log from ceilometer import meter from ceilometer import cfg from ceilometer.collector import dispatcher @@ -33,10 +33,7 @@ from ceilometer.collector import dispatcher import nova.notifier.rabbit_notifier FLAGS = flags.FLAGS -# FIXME(dhellmann): We need to have the main program set up logging -# correctly so messages from modules outside of the nova package -# appear in the output. -LOG = logging.getLogger('nova.' + __name__) +LOG = log.getLogger(__name__) COMPUTE_COLLECTOR_NAMESPACE = 'ceilometer.collector.compute' diff --git a/ceilometer/compute/libvirt.py b/ceilometer/compute/libvirt.py index b6a58964..c02c1815 100644 --- a/ceilometer/compute/libvirt.py +++ b/ceilometer/compute/libvirt.py @@ -20,19 +20,15 @@ import datetime from lxml import etree -from nova import log as logging from nova import flags import nova.virt.connection -from .. import counter -from .. import plugin +from ceilometer import log +from ceilometer import counter +from ceilometer import plugin FLAGS = flags.FLAGS -# FIXME(dhellmann): We need to have the main program set up logging -# correctly so messages from modules outside of the nova package -# appear in the output. -LOG = logging.getLogger('nova.' + __name__) MIB = 2 ** 20 # mebibytes @@ -57,7 +53,7 @@ def make_counter_from_instance(instance, type, volume): class DiskIOPollster(plugin.PollsterBase): - LOG = logging.getLogger('nova.' + __name__ + '.diskio') + LOG = log.getLogger(__name__ + '.diskio') def _get_disks(self, conn, instance): """Get disks of an instance, only used to bypass bug#998089.""" @@ -98,7 +94,7 @@ class DiskIOPollster(plugin.PollsterBase): class CPUPollster(plugin.PollsterBase): - LOG = logging.getLogger('nova.' + __name__ + '.cpu') + LOG = log.getLogger(__name__ + '.cpu') def get_counters(self, manager, context): conn = nova.virt.connection.get_connection(read_only=True) diff --git a/ceilometer/compute/network.py b/ceilometer/compute/network.py index 5907084f..2fae4167 100644 --- a/ceilometer/compute/network.py +++ b/ceilometer/compute/network.py @@ -16,16 +16,17 @@ # License for the specific language governing permissions and limitations # under the License. -from nova import log as logging from nova import exception +from ceilometer import log + from .. import counter from .. import plugin class FloatingIPPollster(plugin.PollsterBase): - LOG = logging.getLogger('nova.' + __name__ + '.floatingip') + LOG = log.getLogger(__name__ + '.floatingip') def get_counters(self, manager, context): try: diff --git a/ceilometer/log.py b/ceilometer/log.py new file mode 100644 index 00000000..0e7e1a72 --- /dev/null +++ b/ceilometer/log.py @@ -0,0 +1,98 @@ +# -*- encoding: utf-8 -*- +# +# Copyright © 2012 eNovance +# +# Author: Julien Danjou +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import os +import inspect +import logging +import logging.config +import traceback +import sys + +from ceilometer import cfg + +cfg.CONF.register_opts([ + cfg.StrOpt('log_config', + help='Log configuration file', + ), + cfg.StrOpt('log_file', + help='Log file', + ), + cfg.StrOpt('log_dir', + help='Log file directory', + ), + cfg.StrOpt('log_level', + default="debug", + help='Log level', + ), + cfg.StrOpt('logging_default_format_string', + default='%(asctime)s %(levelname)s %(name)s: %(message)s', + help='format string to use for log messages'), + ]) + + +def _get_binary_name(): + return os.path.basename(inspect.stack()[-1][1]) + + +def _get_log_file_path(binary=None): + if cfg.CONF.log_file and not cfg.CONF.log_dir: + return cfg.CONF.log_file + + if cfg.CONF.log_file and cfg.CONF.log_dir: + return os.path.join(cfg.CONF.log_file, + cfg.CONF.log_file) + + if cfg.CONF.log_dir: + binary = binary or _get_binary_name() + return '%s.log' % (os.path.join(cfg.CONF.log_dir, binary),) + + +def getLogger(name='ceilometer'): + return logging.getLogger(name) + + +def setup(): + if cfg.CONF.log_config: + try: + logging.config.fileConfig(cfg.CONF.log_config) + except Exception: + traceback.print_exc() + raise + else: + root = getLogger() + for handler in root.handlers: + root.removeHandler(handler) + logpath = _get_log_file_path() + if logpath: + filelog = logging.handlers.WatchedFileHandler(logpath) + filelog.setFormatter( + logging.Formatter(cfg.CONF.logging_default_format_string)) + root.addHandler(filelog) + + mode = int(FLAGS.logfile_mode, 8) + st = os.stat(logpath) + if st.st_mode != (stat.S_IFREG | mode): + os.chmod(logpath, mode) + else: + streamlog = logging.StreamHandler(sys.stdout) + streamlog.setFormatter( + logging.Formatter(cfg.CONF.logging_default_format_string)) + root.addHandler(streamlog) + + if cfg.CONF.log_level: + root.setLevel(logging.getLevelName(cfg.CONF.log_level.upper())) diff --git a/tests/test_log.py b/tests/test_log.py new file mode 100644 index 00000000..8114dcfd --- /dev/null +++ b/tests/test_log.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +# +# Copyright © 2012 eNovance +# +# Author: Julien Danjou +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest +import logging + +from ceilometer import log +from ceilometer import cfg + +class LoggerTestCase(unittest.TestCase): + def setUp(self): + super(LoggerTestCase, self).setUp() + self.log = log.getLogger() + + def test_log_level(self): + cfg.CONF.log_level = "info" + log.setup() + self.assertEqual(logging.INFO, self.log.getEffectiveLevel()) + + def test_child_log_level(self): + cfg.CONF.log_level = "info" + log.setup() + self.assertEqual(logging.INFO, log.getLogger('ceilometer.foobar').getEffectiveLevel()) + + +class LogfilePathTestCase(unittest.TestCase): + def test_log_path_logdir(self): + cfg.CONF.log_dir = '/some/path' + cfg.CONF.log_file = None + self.assertEquals(log._get_log_file_path(binary='foo-bar'), + '/some/path/foo-bar.log') + + def test_log_path_logfile(self): + cfg.CONF.log_file = '/some/path/foo-bar.log' + self.assertEquals(log._get_log_file_path(binary='foo-bar'), + '/some/path/foo-bar.log') + + def test_log_path_none(self): + cfg.CONF.log_dir = None + cfg.CONF.log_file = None + self.assertTrue(log._get_log_file_path(binary='foo-bar') is None) + + def test_log_path_logfile_overrides_logdir(self): + cfg.CONF.log_dir = '/some/other/path' + cfg.CONF.log_file = '/some/path/foo-bar.log' + self.assertEquals(log._get_log_file_path(binary='foo-bar'), + '/some/path/foo-bar.log') +