Merge "Remove implementation for watch_log_file"
This commit is contained in:
commit
014047bfd0
@ -1,12 +0,0 @@
|
|||||||
==================
|
|
||||||
oslo_log.watchers
|
|
||||||
==================
|
|
||||||
|
|
||||||
.. automodule:: oslo_log.watchers
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
.. seealso::
|
|
||||||
|
|
||||||
:ref:`using`
|
|
@ -377,10 +377,9 @@ def _setup_logging_from_conf(conf, project, version):
|
|||||||
logpath = _get_log_file_path(conf)
|
logpath = _get_log_file_path(conf)
|
||||||
if logpath:
|
if logpath:
|
||||||
# On Windows, in-use files cannot be moved or deleted.
|
# On Windows, in-use files cannot be moved or deleted.
|
||||||
if conf.watch_log_file and platform.system() == 'Linux':
|
if conf.watch_log_file:
|
||||||
from oslo_log import watchers
|
raise RuntimeError('watch_log_file feature was removed because '
|
||||||
file_handler = watchers.FastWatchedFileHandler
|
'it has been broken for multiple releases.')
|
||||||
filelog = file_handler(logpath)
|
|
||||||
elif conf.log_rotation_type.lower() == "interval":
|
elif conf.log_rotation_type.lower() == "interval":
|
||||||
file_handler = logging.handlers.TimedRotatingFileHandler
|
file_handler = logging.handlers.TimedRotatingFileHandler
|
||||||
when = conf.log_rotate_interval_type.lower()
|
when = conf.log_rotate_interval_type.lower()
|
||||||
|
@ -22,7 +22,6 @@ import datetime
|
|||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import platform
|
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
try:
|
try:
|
||||||
@ -154,24 +153,6 @@ class CommonLoggerTestsMixIn(object):
|
|||||||
mock_logger = loggers_mock.return_value.logger
|
mock_logger = loggers_mock.return_value.logger
|
||||||
mock_logger.addHandler.assert_any_call(handler_mock.return_value)
|
mock_logger.addHandler.assert_any_call(handler_mock.return_value)
|
||||||
|
|
||||||
@mock.patch('oslo_log.watchers.FastWatchedFileHandler')
|
|
||||||
@mock.patch('oslo_log.log._get_log_file_path', return_value='test.conf')
|
|
||||||
@mock.patch('platform.system', return_value='Linux')
|
|
||||||
def test_watchlog_on_linux(self, platfotm_mock, path_mock, handler_mock):
|
|
||||||
self.config(watch_log_file=True)
|
|
||||||
log._setup_logging_from_conf(self.CONF, 'test', 'test')
|
|
||||||
handler_mock.assert_called_once_with(path_mock.return_value)
|
|
||||||
self.assertEqual(self.log_handlers[0], handler_mock.return_value)
|
|
||||||
|
|
||||||
@mock.patch('logging.handlers.WatchedFileHandler')
|
|
||||||
@mock.patch('oslo_log.log._get_log_file_path', return_value='test.conf')
|
|
||||||
@mock.patch('platform.system', return_value='Windows')
|
|
||||||
def test_watchlog_on_windows(self, platform_mock, path_mock, handler_mock):
|
|
||||||
self.config(watch_log_file=True)
|
|
||||||
log._setup_logging_from_conf(self.CONF, 'test', 'test')
|
|
||||||
handler_mock.assert_called_once_with(path_mock.return_value)
|
|
||||||
self.assertEqual(self.log_handlers[0], handler_mock.return_value)
|
|
||||||
|
|
||||||
@mock.patch('logging.handlers.TimedRotatingFileHandler')
|
@mock.patch('logging.handlers.TimedRotatingFileHandler')
|
||||||
@mock.patch('oslo_log.log._get_log_file_path', return_value='test.conf')
|
@mock.patch('oslo_log.log._get_log_file_path', return_value='test.conf')
|
||||||
def test_timed_rotate_log(self, path_mock, handler_mock):
|
def test_timed_rotate_log(self, path_mock, handler_mock):
|
||||||
@ -1363,54 +1344,6 @@ class SetDefaultsTestCase(BaseTestCase):
|
|||||||
self.assertIsNone(self.conf.log_file)
|
self.assertIsNone(self.conf.log_file)
|
||||||
|
|
||||||
|
|
||||||
@testtools.skipIf(platform.system() != 'Linux',
|
|
||||||
'pyinotify library works on Linux platform only.')
|
|
||||||
class FastWatchedFileHandlerTestCase(BaseTestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(FastWatchedFileHandlerTestCase, self).setUp()
|
|
||||||
|
|
||||||
def _config(self):
|
|
||||||
os_level, log_path = tempfile.mkstemp()
|
|
||||||
log_dir_path = os.path.dirname(log_path)
|
|
||||||
log_file_path = os.path.basename(log_path)
|
|
||||||
self.CONF(['--log-dir', log_dir_path, '--log-file', log_file_path])
|
|
||||||
self.config(use_stderr=False)
|
|
||||||
self.config(watch_log_file=True)
|
|
||||||
log.setup(self.CONF, 'test', 'test')
|
|
||||||
return log_path
|
|
||||||
|
|
||||||
def test_instantiate(self):
|
|
||||||
self._config()
|
|
||||||
logger = log._loggers[None].logger
|
|
||||||
self.assertEqual(1, len(logger.handlers))
|
|
||||||
from oslo_log import watchers
|
|
||||||
self.assertIsInstance(logger.handlers[0],
|
|
||||||
watchers.FastWatchedFileHandler)
|
|
||||||
|
|
||||||
def test_log(self):
|
|
||||||
log_path = self._config()
|
|
||||||
logger = log._loggers[None].logger
|
|
||||||
text = 'Hello World!'
|
|
||||||
logger.info(text)
|
|
||||||
with open(log_path, 'r') as f:
|
|
||||||
file_content = f.read()
|
|
||||||
self.assertIn(text, file_content)
|
|
||||||
|
|
||||||
def test_move(self):
|
|
||||||
log_path = self._config()
|
|
||||||
os_level_dst, log_path_dst = tempfile.mkstemp()
|
|
||||||
os.rename(log_path, log_path_dst)
|
|
||||||
time.sleep(6)
|
|
||||||
self.assertTrue(os.path.exists(log_path))
|
|
||||||
|
|
||||||
def test_remove(self):
|
|
||||||
log_path = self._config()
|
|
||||||
os.remove(log_path)
|
|
||||||
time.sleep(6)
|
|
||||||
self.assertTrue(os.path.exists(log_path))
|
|
||||||
|
|
||||||
|
|
||||||
class MutateTestCase(BaseTestCase):
|
class MutateTestCase(BaseTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(MutateTestCase, self).setUp()
|
super(MutateTestCase, self).setUp()
|
||||||
|
@ -1,111 +0,0 @@
|
|||||||
# 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 errno
|
|
||||||
import logging
|
|
||||||
import logging.config
|
|
||||||
import logging.handlers
|
|
||||||
import os
|
|
||||||
import pyinotify
|
|
||||||
import stat
|
|
||||||
import time
|
|
||||||
try:
|
|
||||||
import syslog
|
|
||||||
except ImportError:
|
|
||||||
syslog = None
|
|
||||||
|
|
||||||
"""Linux specific pyinotify based logging handlers"""
|
|
||||||
|
|
||||||
|
|
||||||
class _FileKeeper(pyinotify.ProcessEvent):
|
|
||||||
def my_init(self, watched_handler, watched_file):
|
|
||||||
self._watched_handler = watched_handler
|
|
||||||
self._watched_file = watched_file
|
|
||||||
|
|
||||||
def process_default(self, event):
|
|
||||||
if event.name == self._watched_file:
|
|
||||||
self._watched_handler.reopen_file()
|
|
||||||
|
|
||||||
|
|
||||||
class _EventletThreadedNotifier(pyinotify.ThreadedNotifier):
|
|
||||||
|
|
||||||
def loop(self):
|
|
||||||
"""Eventlet friendly ThreadedNotifier
|
|
||||||
|
|
||||||
EventletFriendlyThreadedNotifier contains additional time.sleep()
|
|
||||||
call insude loop to allow switching to other thread when eventlet
|
|
||||||
is used.
|
|
||||||
It can be used with eventlet and native threads as well.
|
|
||||||
"""
|
|
||||||
|
|
||||||
while not self._stop_event.is_set():
|
|
||||||
self.process_events()
|
|
||||||
time.sleep(0)
|
|
||||||
ref_time = time.time()
|
|
||||||
if self.check_events():
|
|
||||||
self._sleep(ref_time)
|
|
||||||
self.read_events()
|
|
||||||
|
|
||||||
|
|
||||||
class FastWatchedFileHandler(logging.handlers.WatchedFileHandler, object):
|
|
||||||
"""Frequency of reading events.
|
|
||||||
|
|
||||||
Watching thread sleeps max(0, READ_FREQ - (TIMEOUT / 1000)) seconds.
|
|
||||||
"""
|
|
||||||
READ_FREQ = 5
|
|
||||||
|
|
||||||
"""Poll timeout in milliseconds.
|
|
||||||
|
|
||||||
See https://docs.python.org/2/library/select.html#select.poll.poll"""
|
|
||||||
TIMEOUT = 5
|
|
||||||
|
|
||||||
def __init__(self, logpath, *args, **kwargs):
|
|
||||||
self._log_file = os.path.basename(logpath)
|
|
||||||
self._log_dir = os.path.dirname(logpath)
|
|
||||||
super(FastWatchedFileHandler, self).__init__(logpath, *args, **kwargs)
|
|
||||||
self._watch_file()
|
|
||||||
|
|
||||||
def _watch_file(self):
|
|
||||||
mask = pyinotify.IN_MOVED_FROM | pyinotify.IN_DELETE
|
|
||||||
watch_manager = pyinotify.WatchManager()
|
|
||||||
handler = _FileKeeper(watched_handler=self,
|
|
||||||
watched_file=self._log_file)
|
|
||||||
notifier = _EventletThreadedNotifier(
|
|
||||||
watch_manager,
|
|
||||||
default_proc_fun=handler,
|
|
||||||
read_freq=FastWatchedFileHandler.READ_FREQ,
|
|
||||||
timeout=FastWatchedFileHandler.TIMEOUT)
|
|
||||||
notifier.daemon = True
|
|
||||||
watch_manager.add_watch(self._log_dir, mask)
|
|
||||||
notifier.start()
|
|
||||||
|
|
||||||
def reopen_file(self):
|
|
||||||
try:
|
|
||||||
# stat the file by path, checking for existence
|
|
||||||
sres = os.stat(self.baseFilename)
|
|
||||||
except OSError as err:
|
|
||||||
if err.errno == errno.ENOENT:
|
|
||||||
sres = None
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
# compare file system stat with that of our stream file handle
|
|
||||||
if (not sres or
|
|
||||||
sres[stat.ST_DEV] != self.dev or
|
|
||||||
sres[stat.ST_INO] != self.ino):
|
|
||||||
if self.stream is not None:
|
|
||||||
# we have an open file handle, clean it up
|
|
||||||
self.stream.flush()
|
|
||||||
self.stream.close()
|
|
||||||
self.stream = None
|
|
||||||
# open a new file handle and get new stat info from that fd
|
|
||||||
self.stream = self._open()
|
|
||||||
self._statstream()
|
|
@ -3,3 +3,9 @@ deprecations:
|
|||||||
- |
|
- |
|
||||||
The ``watch_log_file`` option has been deprecated and will be removed in
|
The ``watch_log_file`` option has been deprecated and will be removed in
|
||||||
a future release.
|
a future release.
|
||||||
|
|
||||||
|
upgrade:
|
||||||
|
- |
|
||||||
|
Setting ``[DEFAULT] watch_log_file = True`` now raises RuntimeError while
|
||||||
|
configuring logger. The feature has been broken for multiple cycles and
|
||||||
|
depends on pyinotify library which is not maintained now.
|
||||||
|
Loading…
Reference in New Issue
Block a user