Remove statds from the logs module

We would like to remove any Statsd related code from logs.py.  That
requires that SwiftLogAdapter no longer provides a StatsdClient
interface by default. However, for backwards compatibility the main
utils.get_logger/get_prefixed_logger entrypoints must provide a
SwiftLogAdapter that does have a StatdsClient interface.

The new utils._patch_statsd_methods helper function is therefore used
to retrospectively patch a SwiftLogAdapter instance with the
StatsdClient interface when necessary. The _patch_statsd_helper is
used in get_logger, and again when we clone a logger in
get_prefixed_logger.

Co-Authored-By: Shreeya Deshpande <shreeyad@nvidia.com>

Change-Id: I44694b92264066ca427bb96456d6f944e09b31c0
This commit is contained in:
Alistair Coles 2024-10-04 11:55:55 +01:00
parent ffbf17e47c
commit 8699af83c9
9 changed files with 553 additions and 222 deletions

View File

@ -30,10 +30,10 @@ from swift.common.exceptions import LockTimeout
from swift.common.storage_policy import POLICIES from swift.common.storage_policy import POLICIES
from swift.common.utils import replace_partition_in_path, config_true_value, \ from swift.common.utils import replace_partition_in_path, config_true_value, \
audit_location_generator, get_logger, readconf, drop_privileges, \ audit_location_generator, get_logger, readconf, drop_privileges, \
RateLimitedIterator, distribute_evenly, \ RateLimitedIterator, distribute_evenly, get_prefixed_logger, \
non_negative_float, non_negative_int, config_auto_int_value, \ non_negative_float, non_negative_int, config_auto_int_value, \
dump_recon_cache, get_partition_from_path, get_hub dump_recon_cache, get_partition_from_path, get_hub
from swift.common.utils.logs import SwiftLogAdapter, get_prefixed_logger from swift.common.utils.logs import SwiftLogAdapter
from swift.obj import diskfile from swift.obj import diskfile
from swift.common.recon import RECON_RELINKER_FILE, DEFAULT_RECON_CACHE_PATH from swift.common.recon import RECON_RELINKER_FILE, DEFAULT_RECON_CACHE_PATH

View File

@ -87,8 +87,8 @@ from .base import ( # noqa
from swift.common.utils.logs import ( # noqa from swift.common.utils.logs import ( # noqa
SysLogHandler, # t.u.helpers.setup_servers monkey patch is sketch SysLogHandler, # t.u.helpers.setup_servers monkey patch is sketch
logging_monkey_patch, logging_monkey_patch,
get_logger, get_swift_logger,
get_prefixed_logger, get_prefixed_swift_logger,
LogLevelFilter, LogLevelFilter,
NullLogger, NullLogger,
capture_stdio, capture_stdio,
@ -157,7 +157,7 @@ from swift.common.utils.ipaddrs import ( # noqa
parse_socket_string, parse_socket_string,
whataremyips, whataremyips,
) )
from swift.common.statsd_client import StatsdClient # noqa from swift.common.statsd_client import StatsdClient, get_statsd_client
import logging import logging
EUCLEAN = getattr(errno, 'EUCLEAN', 117) # otherwise not present on osx EUCLEAN = getattr(errno, 'EUCLEAN', 117) # otherwise not present on osx
@ -205,6 +205,140 @@ DEFAULT_LOCK_TIMEOUT = 10
DEFAULT_DRAIN_LIMIT = 65536 DEFAULT_DRAIN_LIMIT = 65536
def _patch_statsd_methods(target, statsd_client_source):
"""
Note: this function is only used to create backwards compatible
legacy "hybrid" loggers that also have a StatsdClient interface.
It should not otherwise be used to patch arbitrary objects to
have a StatsdClient interface.
Patch the ``target`` object with methods that present an interface to a
``StatsdClient`` instance that is an attribute ``statsd_client`` of
``statsd_client_source``.
Note: ``statsd_client_source`` is an object that *has a* ``StatsdClient``
and not an object that *is a* ``StatsdClient`` instance, because the
actual ``StatsdClient`` instance may change. The patched target
therefore forwards its methods to whatever instance of ``StatsdClient``
the ``statsd_client_source`` currently has.
:param target: an object that will be patched to present an interface to a
``StatsdClient``.
:param statsd_client_source: an object that must have an attribute
``statsd_client`` that must be an instance of a ``StatsdClient``.
This is typically a core ``logging.Logger`` that has been patched with
a ``StatsdClient`` by ``get_logger()``.
"""
try:
if not isinstance(statsd_client_source.statsd_client, StatsdClient):
raise ValueError()
except (AttributeError, ValueError):
raise ValueError(
'statsd_client_source must have a statsd_client attribute')
def set_statsd_prefix(prefix):
"""
This method is deprecated. Callers should use the
``statsd_tail_prefix`` argument of ``get_logger`` when instantiating a
logger.
The StatsD client prefix defaults to the "name" of the logger. This
method may override that default with a specific value. Currently used
in the proxy-server to differentiate the Account, Container, and Object
controllers.
"""
warnings.warn(
'set_statsd_prefix() is deprecated; use the '
'``statsd_tail_prefix`` argument to ``get_logger`` instead.',
DeprecationWarning, stacklevel=2
)
if getattr(statsd_client_source, 'statsd_client'):
statsd_client_source.statsd_client._set_prefix(prefix)
def statsd_delegate(statsd_func_name):
"""
Factory to create methods which delegate to methods on
``statsd_client_source.statsd_client`` (an instance of StatsdClient).
The created methods conditionally delegate to a method whose name is
given in 'statsd_func_name'. The created delegate methods are a no-op
when StatsD logging is not configured.
:param statsd_func_name: the name of a method on ``StatsdClient``.
"""
func = getattr(StatsdClient, statsd_func_name)
@functools.wraps(func)
def wrapped(*a, **kw):
if getattr(statsd_client_source, 'statsd_client'):
func = getattr(statsd_client_source.statsd_client,
statsd_func_name)
return func(*a, **kw)
return wrapped
target.update_stats = statsd_delegate('update_stats')
target.increment = statsd_delegate('increment')
target.decrement = statsd_delegate('decrement')
target.timing = statsd_delegate('timing')
target.timing_since = statsd_delegate('timing_since')
target.transfer_rate = statsd_delegate('transfer_rate')
target.set_statsd_prefix = set_statsd_prefix
target.statsd_client_source = statsd_client_source
def get_logger(conf, name=None, log_to_console=False, log_route=None,
fmt="%(server)s: %(message)s", statsd_tail_prefix=None):
"""
Returns a ``SwiftLogAdapter`` that has been patched to also provide an
interface to a ``StatsdClient``.
:param conf: Configuration dict to read settings from
:param name: This value is used to populate the ``server`` field in the log
format, as the prefix for statsd messages, and as the default
value for ``log_route``; defaults to the ``log_name`` value in
``conf``, if it exists, or to 'swift'.
:param log_to_console: Add handler which writes to console on stderr.
:param log_route: Route for the logging, not emitted to the log, just used
to separate logging configurations; defaults to the value
of ``name`` or whatever ``name`` defaults to. This value
is used as the name attribute of the
``SwiftLogAdapter`` that is returned.
:param fmt: Override log format.
:param statsd_tail_prefix: tail prefix to pass to ``StatsdClient``; if None
then the tail prefix defaults to the value of ``name``.
:return: an instance of ``SwiftLogAdapter``.
"""
conf = conf or {}
swift_logger = get_swift_logger(
conf, name, log_to_console, log_route, fmt)
name = conf.get('log_name', 'swift') if name is None else name
tail_prefix = name if statsd_tail_prefix is None else statsd_tail_prefix
statsd_client = get_statsd_client(conf, tail_prefix, swift_logger.logger)
swift_logger.logger.statsd_client = statsd_client
_patch_statsd_methods(swift_logger, swift_logger.logger)
return swift_logger
def get_prefixed_logger(swift_logger, prefix):
"""
Return a clone of the given ``swift_logger`` with a new prefix string
that replaces the prefix string of the given ``swift_logger``
If the given ``swift_logger`` has been patched with an interface to a
``StatsdClient`` instance then the returned ``SwiftLogAdapter`` will also
be patched with an interface to the same ``StatsdClient`` instance.
:param swift_logger: an instance of ``SwiftLogAdapter``.
:param prefix: a string prefix.
:returns: a new instance of ``SwiftLogAdapter``.
"""
new_logger = get_prefixed_swift_logger(swift_logger, prefix=prefix)
if hasattr(swift_logger, 'statsd_client_source'):
if getattr(swift_logger.statsd_client_source, 'statsd_client'):
_patch_statsd_methods(
new_logger, swift_logger.statsd_client_source)
return new_logger
class InvalidHashPathConfigError(ValueError): class InvalidHashPathConfigError(ValueError):
def __str__(self): def __str__(self):

View File

@ -24,9 +24,7 @@ import socket
import stat import stat
import string import string
import sys import sys
import functools
import time import time
import warnings
import fcntl import fcntl
import eventlet import eventlet
import six import six
@ -35,7 +33,6 @@ import datetime
from swift.common.utils.base import md5, quote, split_path from swift.common.utils.base import md5, quote, split_path
from swift.common.utils.timestamp import UTC from swift.common.utils.timestamp import UTC
from swift.common.utils.config import config_true_value from swift.common.utils.config import config_true_value
from swift.common import statsd_client
# common.utils imports a fully qualified common.exceptions so that # common.utils imports a fully qualified common.exceptions so that
# common.exceptions can import common.utils with out a circular import error # common.exceptions can import common.utils with out a circular import error
# (if we only make reference to attributes of a module w/i our function/method # (if we only make reference to attributes of a module w/i our function/method
@ -175,13 +172,13 @@ class PipeMutex(object):
def __del__(self): def __del__(self):
# We need this so we don't leak file descriptors. Otherwise, if you # We need this so we don't leak file descriptors. Otherwise, if you
# call get_logger() and don't explicitly dispose of it by calling # call get_swift_logger() and don't explicitly dispose of it by calling
# logger.logger.handlers[0].lock.close() [1], the pipe file # logger.logger.handlers[0].lock.close() [1], the pipe file
# descriptors are leaked. # descriptors are leaked.
# #
# This only really comes up in tests. Swift processes tend to call # This only really comes up in tests. Swift processes tend to call
# get_logger() once and then hang on to it until they exit, but the # get_swift_logger() once and then hang on to it until they exit,
# test suite calls get_logger() a lot. # but the test suite calls get_swift_logger() a lot.
# #
# [1] and that's a completely ridiculous thing to expect callers to # [1] and that's a completely ridiculous thing to expect callers to
# do, so nobody does it and that's okay. # do, so nobody does it and that's okay.
@ -294,6 +291,7 @@ class SwiftLogAdapter(logging.LoggerAdapter, object):
@property @property
def name(self): def name(self):
# py3 does this for us already; add it for py2
return self.logger.name return self.logger.name
@property @property
@ -389,52 +387,6 @@ class SwiftLogAdapter(logging.LoggerAdapter, object):
call = self._exception call = self._exception
call('%s: %s' % (msg, emsg), *args, **kwargs) call('%s: %s' % (msg, emsg), *args, **kwargs)
def set_statsd_prefix(self, prefix):
"""
This method is deprecated. Callers should use the
``statsd_tail_prefix`` argument of ``get_logger`` when instantiating a
logger.
The StatsD client prefix defaults to the "name" of the logger. This
method may override that default with a specific value. Currently used
in the proxy-server to differentiate the Account, Container, and Object
controllers.
"""
warnings.warn(
'set_statsd_prefix() is deprecated; use the '
'``statsd_tail_prefix`` argument to ``get_logger`` instead.',
DeprecationWarning, stacklevel=2
)
if self.logger.statsd_client:
self.logger.statsd_client._set_prefix(prefix)
def statsd_delegate(statsd_func_name):
"""
Factory to create methods which delegate to methods on
self.logger.statsd_client (an instance of StatsdClient). The
created methods conditionally delegate to a method whose name is given
in 'statsd_func_name'. The created delegate methods are a no-op when
StatsD logging is not configured.
:param statsd_func_name: the name of a method on StatsdClient.
"""
func = getattr(statsd_client.StatsdClient, statsd_func_name)
@functools.wraps(func)
def wrapped(self, *a, **kw):
if getattr(self.logger, 'statsd_client'):
func = getattr(self.logger.statsd_client, statsd_func_name)
return func(*a, **kw)
return wrapped
update_stats = statsd_delegate('update_stats')
increment = statsd_delegate('increment')
decrement = statsd_delegate('decrement')
timing = statsd_delegate('timing')
timing_since = statsd_delegate('timing_since')
transfer_rate = statsd_delegate('transfer_rate')
class SwiftLogFormatter(logging.Formatter): class SwiftLogFormatter(logging.Formatter):
""" """
@ -588,8 +540,8 @@ class LogLevelFilter(object):
return 1 return 1
def get_logger(conf, name=None, log_to_console=False, log_route=None, def get_swift_logger(conf, name=None, log_to_console=False, log_route=None,
fmt="%(server)s: %(message)s", statsd_tail_prefix=None): fmt="%(server)s: %(message)s"):
""" """
Get the current system logger using config settings. Get the current system logger using config settings.
@ -604,10 +556,10 @@ def get_logger(conf, name=None, log_to_console=False, log_route=None,
log_address = /dev/log log_address = /dev/log
:param conf: Configuration dict to read settings from :param conf: Configuration dict to read settings from
:param name: This value is used to populate the ``server`` field in the log :param name: This value is used to populate the ``server`` field in
format, as the prefix for statsd messages, and as the default the log format, as the default value for ``log_route``;
value for ``log_route``; defaults to the ``log_name`` value in defaults to the ``log_name`` value in ``conf``, if it exists,
``conf``, if it exists, or to 'swift'. or to 'swift'.
:param log_to_console: Add handler which writes to console on stderr :param log_to_console: Add handler which writes to console on stderr
:param log_route: Route for the logging, not emitted to the log, just used :param log_route: Route for the logging, not emitted to the log, just used
to separate logging configurations; defaults to the value to separate logging configurations; defaults to the value
@ -615,13 +567,11 @@ def get_logger(conf, name=None, log_to_console=False, log_route=None,
is used as the name attribute of the is used as the name attribute of the
``logging.LogAdapter`` that is returned. ``logging.LogAdapter`` that is returned.
:param fmt: Override log format :param fmt: Override log format
:param statsd_tail_prefix: tail prefix to pass to statsd client; if None :return: an instance of ``SwiftLogAdapter``
then the tail prefix defaults to the value of ``name``.
:return: an instance of ``LogAdapter``
""" """
# note: log_name is typically specified in conf (i.e. defined by # note: log_name is typically specified in conf (i.e. defined by
# operators), whereas log_route is typically hard-coded in callers of # operators), whereas log_route is typically hard-coded in callers of
# get_logger (i.e. defined by developers) # get_swift_logger (i.e. defined by developers)
if not conf: if not conf:
conf = {} conf = {}
if name is None: if name is None:
@ -634,11 +584,11 @@ def get_logger(conf, name=None, log_to_console=False, log_route=None,
formatter = SwiftLogFormatter( formatter = SwiftLogFormatter(
fmt=fmt, max_line_length=int(conf.get('log_max_line_length', 0))) fmt=fmt, max_line_length=int(conf.get('log_max_line_length', 0)))
# get_logger will only ever add one SysLog Handler to a logger # get_swift_logger will only ever add one SysLog Handler to a logger
if not hasattr(get_logger, 'handler4logger'): if not hasattr(get_swift_logger, 'handler4logger'):
get_logger.handler4logger = {} get_swift_logger.handler4logger = {}
if logger in get_logger.handler4logger: if logger in get_swift_logger.handler4logger:
logger.removeHandler(get_logger.handler4logger[logger]) logger.removeHandler(get_swift_logger.handler4logger[logger])
# facility for this logger will be set by last call wins # facility for this logger will be set by last call wins
facility = getattr(SysLogHandler, conf.get('log_facility', 'LOG_LOCAL0'), facility = getattr(SysLogHandler, conf.get('log_facility', 'LOG_LOCAL0'),
@ -667,31 +617,26 @@ def get_logger(conf, name=None, log_to_console=False, log_route=None,
handler = ThreadSafeSysLogHandler(facility=facility) handler = ThreadSafeSysLogHandler(facility=facility)
handler.setFormatter(formatter) handler.setFormatter(formatter)
logger.addHandler(handler) logger.addHandler(handler)
get_logger.handler4logger[logger] = handler get_swift_logger.handler4logger[logger] = handler
# setup console logging # setup console logging
if log_to_console or hasattr(get_logger, 'console_handler4logger'): if log_to_console or hasattr(get_swift_logger, 'console_handler4logger'):
# remove pre-existing console handler for this logger # remove pre-existing console handler for this logger
if not hasattr(get_logger, 'console_handler4logger'): if not hasattr(get_swift_logger, 'console_handler4logger'):
get_logger.console_handler4logger = {} get_swift_logger.console_handler4logger = {}
if logger in get_logger.console_handler4logger: if logger in get_swift_logger.console_handler4logger:
logger.removeHandler(get_logger.console_handler4logger[logger]) logger.removeHandler(
get_swift_logger.console_handler4logger[logger])
console_handler = logging.StreamHandler(sys.__stderr__) console_handler = logging.StreamHandler(sys.__stderr__)
console_handler.setFormatter(formatter) console_handler.setFormatter(formatter)
logger.addHandler(console_handler) logger.addHandler(console_handler)
get_logger.console_handler4logger[logger] = console_handler get_swift_logger.console_handler4logger[logger] = console_handler
# set the level for the logger # set the level for the logger
logger.setLevel( logger.setLevel(
getattr(logging, conf.get('log_level', 'INFO').upper(), logging.INFO)) getattr(logging, conf.get('log_level', 'INFO').upper(), logging.INFO))
# Setup logger with a StatsD client if so configured
if statsd_tail_prefix is None:
statsd_tail_prefix = name
logger.statsd_client = statsd_client.get_statsd_client(
conf, statsd_tail_prefix, logger)
adapted_logger = SwiftLogAdapter(logger, name) adapted_logger = SwiftLogAdapter(logger, name)
other_handlers = conf.get('log_custom_handlers', None) other_handlers = conf.get('log_custom_handlers', None)
if other_handlers: if other_handlers:
@ -713,7 +658,15 @@ def get_logger(conf, name=None, log_to_console=False, log_route=None,
return adapted_logger return adapted_logger
def get_prefixed_logger(swift_logger, prefix): def get_prefixed_swift_logger(swift_logger, prefix):
"""
Return a clone of the given ``swift_logger`` with a new prefix string
that replaces the prefix string of the given ``swift_logger``.
:param swift_logger: an instance of ``SwiftLogAdapter``.
:param prefix: a string prefix.
:returns: a new instance of ``SwiftLogAdapter``.
"""
return SwiftLogAdapter( return SwiftLogAdapter(
swift_logger.logger, swift_logger.server, prefix=prefix) swift_logger.logger, swift_logger.server, prefix=prefix)
@ -760,7 +713,7 @@ def capture_stdio(logger, **kwargs):
# collect stdio file desc not in use for logging # collect stdio file desc not in use for logging
stdio_files = [sys.stdin, sys.stdout, sys.stderr] stdio_files = [sys.stdin, sys.stdout, sys.stderr]
console_fds = [h.stream.fileno() for _junk, h in getattr( console_fds = [h.stream.fileno() for _junk, h in getattr(
get_logger, 'console_handler4logger', {}).items()] get_swift_logger, 'console_handler4logger', {}).items()]
stdio_files = [f for f in stdio_files if f.fileno() not in console_fds] stdio_files = [f for f in stdio_files if f.fileno() not in console_fds]
with open(os.devnull, 'r+b') as nullfile: with open(os.devnull, 'r+b') as nullfile:

View File

@ -272,7 +272,9 @@ class DebugLogAdapter(utils.logs.SwiftLogAdapter):
def debug_logger(name='test'): def debug_logger(name='test'):
"""get a named adapted debug logger""" """get a named adapted debug logger"""
return DebugLogAdapter(DebugLogger(), name) adapted_logger = DebugLogAdapter(DebugLogger(), name)
utils._patch_statsd_methods(adapted_logger, adapted_logger.logger)
return adapted_logger
class ForwardingLogHandler(logging.NullHandler): class ForwardingLogHandler(logging.NullHandler):
@ -327,7 +329,7 @@ def capture_logger(conf, *args, **kwargs):
""" """
with mock.patch('swift.common.utils.logs.SwiftLogAdapter', with mock.patch('swift.common.utils.logs.SwiftLogAdapter',
CaptureLogAdapter): CaptureLogAdapter):
log_adapter = utils.logs.get_logger(conf, *args, **kwargs) log_adapter = utils.get_logger(conf, *args, **kwargs)
log_adapter.start_capture() log_adapter.start_capture()
try: try:
yield log_adapter yield log_adapter

View File

@ -23,7 +23,7 @@ from logging.handlers import SysLogHandler
import six import six
from six.moves.urllib.parse import unquote from six.moves.urllib.parse import unquote
from swift.common.utils import get_logger, split_path from swift.common.utils import get_swift_logger, split_path
from swift.common.statsd_client import StatsdClient from swift.common.statsd_client import StatsdClient
from swift.common.middleware import proxy_logging from swift.common.middleware import proxy_logging
from swift.common.registry import register_sensitive_header, \ from swift.common.registry import register_sensitive_header, \
@ -969,7 +969,7 @@ class TestProxyLogging(unittest.TestCase):
FakeApp(), FakeApp(),
{'log_headers': 'yes', {'log_headers': 'yes',
'access_log_facility': 'LOG_LOCAL7'}) 'access_log_facility': 'LOG_LOCAL7'})
handler = get_logger.handler4logger[app.access_logger.logger] handler = get_swift_logger.handler4logger[app.access_logger.logger]
self.assertEqual(SysLogHandler.LOG_LOCAL7, handler.facility) self.assertEqual(SysLogHandler.LOG_LOCAL7, handler.facility)
def test_filter(self): def test_filter(self):

View File

@ -819,39 +819,3 @@ class TestModuleFunctions(unittest.TestCase):
self.assertEqual(self.logger, client.logger) self.assertEqual(self.logger, client.logger)
warn_lines = self.logger.get_lines_for_level('warning') warn_lines = self.logger.get_lines_for_level('warning')
self.assertEqual([], warn_lines) self.assertEqual([], warn_lines)
class TestSwiftLogAdapterDelegation(unittest.TestCase):
def setUp(self):
self.logger = utils.get_logger({'log_statsd_host': 'some.host.com'},
'some-name', log_route='some-route')
self.mock_socket = MockUdpSocket()
self.logger.logger.statsd_client._open_socket = \
lambda *_: self.mock_socket
self.address = ('some.host.com', 8125)
def test_setup(self):
self.logger.increment('foo')
self.assertEqual(self.mock_socket.sent,
[(b'some-name.foo:1|c', self.address)])
def test_get_prefix_logger(self):
prefixed_logger = utils.get_prefixed_logger(self.logger, 'my-prefix')
prefixed_logger.increment('bar')
self.assertEqual(self.mock_socket.sent,
[(b'some-name.bar:1|c', self.address)])
def test_adapted_logger(self):
adapted_logger = utils.logs.SwiftLogAdapter(
self.logger.logger, 'my-adapter')
adapted_logger.increment('buz')
self.assertEqual(self.mock_socket.sent,
[(b'some-name.buz:1|c', self.address)])
def test_wrapped_adapter(self):
wrapped_adapter = utils.logs.SwiftLogAdapter(
self.logger, 'wrapped-adapter')
with self.assertRaises(AttributeError) as ctx:
wrapped_adapter.increment('baz')
self.assertIn("has no attribute 'statsd_client'", str(ctx.exception))

View File

@ -16,10 +16,11 @@
"""Tests for swift.common.utils""" """Tests for swift.common.utils"""
from __future__ import print_function from __future__ import print_function
import argparse
import hashlib import hashlib
import itertools import itertools
from test.debug_logger import debug_logger from test.debug_logger import debug_logger, FakeStatsdClient
from test.unit import temptree, make_timestamp_iter, with_tempdir, \ from test.unit import temptree, make_timestamp_iter, with_tempdir, \
mock_timestamp_now, FakeIterable mock_timestamp_now, FakeIterable
@ -7367,3 +7368,283 @@ class TestContextPool(unittest.TestCase):
self.assertEqual(pool.running(), size) self.assertEqual(pool.running(), size)
pool.close() pool.close()
self.assertEqual(pool.running(), 0) self.assertEqual(pool.running(), 0)
class TestLoggerStatsdClientDelegation(unittest.TestCase):
def setUp(self):
self.logger_name = 'server'
def tearDown(self):
# Avoid test coupling by removing any StatsdClient instance
# that may have been patched on to a Logger.
core_logger = logging.getLogger(self.logger_name)
if hasattr(core_logger, 'statsd_client'):
del core_logger.statsd_client
def test_patch_statsd_methods(self):
client = FakeStatsdClient('host.com', 1234)
source = argparse.Namespace()
source.statsd_client = client
target = argparse.Namespace()
utils._patch_statsd_methods(target, source)
target.increment('a')
target.decrement('b')
target.update_stats('c', 4)
target.timing('d', 23.4)
target.timing_since('e', 23.4)
target.transfer_rate('f', 56.7, 1234.5)
exp = {
'decrement': [(('b',), {})],
'increment': [(('a',), {})],
'timing': [(('d', 23.4), {}),
(('f', 45929.52612393682, None), {})],
'timing_since': [(('e', 23.4), {})],
'transfer_rate': [(('f', 56.7, 1234.5), {})],
'update_stats': [(('a', 1, None), {}),
(('b', -1, None), {}),
(('c', 4), {})]
}
self.assertEqual(exp, client.calls)
def test_patch_statsd_methods_source_is_none(self):
with self.assertRaises(ValueError) as cm:
utils._patch_statsd_methods(object, None)
self.assertEqual(
'statsd_client_source must have a statsd_client attribute',
str(cm.exception))
def test_patch_statsd_methods_source_no_statsd_client(self):
source = argparse.Namespace()
with self.assertRaises(ValueError) as cm:
utils._patch_statsd_methods(object, source)
self.assertEqual(
'statsd_client_source must have a statsd_client attribute',
str(cm.exception))
def test_patch_statsd_methods_source_statsd_client_is_none(self):
source = argparse.Namespace()
source.statsd_client = None
with self.assertRaises(ValueError) as cm:
utils._patch_statsd_methods(object, source)
self.assertEqual(
'statsd_client_source must have a statsd_client attribute',
str(cm.exception))
def test_patch_statsd_methods_client_deleted_from_source(self):
client = FakeStatsdClient('host.com', 1234)
source = argparse.Namespace()
source.statsd_client = client
target = argparse.Namespace()
utils._patch_statsd_methods(target, source)
target.increment('a')
exp = {
'increment': [(('a',), {})],
'update_stats': [(('a', 1, None), {})],
}
self.assertEqual(exp, client.calls)
# if the statsd_client is deleted you will blow up...
del source.statsd_client
try:
target.increment('b')
except AttributeError as err:
self.assertEqual(
str(err),
"'Namespace' object has no attribute 'statsd_client'")
def test_get_logger_provides_a_swift_log_adapter(self):
orig_get_swift_logger = utils.logs.get_swift_logger
calls = []
def fake_get_swift_logger(*args, **kwargs):
result = orig_get_swift_logger(*args, **kwargs)
calls.append((args, kwargs, result))
return result
conf = {}
fmt = 'test %(message)s'
with mock.patch(
'swift.common.utils.get_swift_logger', fake_get_swift_logger):
logger = utils.get_logger(
conf, name=self.logger_name, log_to_console=True,
log_route='test', fmt=fmt)
self.assertEqual(1, len(calls))
self.assertEqual(
((conf, self.logger_name, True, 'test', fmt), {}),
calls[0][:2])
self.assertIs(calls[0][2], logger)
def test_get_logger_provides_statsd_client(self):
with mock.patch(
'swift.common.statsd_client.StatsdClient', FakeStatsdClient):
swift_logger = utils.get_logger(None, name=self.logger_name)
self.assertTrue(hasattr(swift_logger.logger, 'statsd_client'))
self.assertIsInstance(swift_logger.logger.statsd_client,
FakeStatsdClient)
swift_logger.increment('a')
swift_logger.decrement('b')
swift_logger.update_stats('c', 4)
swift_logger.timing('d', 23.4)
swift_logger.timing_since('e', 23.4)
swift_logger.transfer_rate('f', 56.7, 1234.5)
exp = {
'decrement': [(('b',), {})],
'increment': [(('a',), {})],
'timing': [(('d', 23.4), {}),
(('f', 45929.52612393682, None), {})],
'timing_since': [(('e', 23.4), {})],
'transfer_rate': [(('f', 56.7, 1234.5), {})],
'update_stats': [(('a', 1, None), {}),
(('b', -1, None), {}),
(('c', 4), {})]
}
self.assertTrue(hasattr(swift_logger.logger, 'statsd_client'))
client = swift_logger.logger.statsd_client
self.assertEqual(exp, client.calls)
def test_get_logger_statsd_client_prefix(self):
def call_get_logger(conf, name, statsd_tail_prefix):
with mock.patch('swift.common.statsd_client.StatsdClient',
FakeStatsdClient):
swift_logger = utils.get_logger(
conf, name=name, statsd_tail_prefix=statsd_tail_prefix)
self.assertTrue(hasattr(swift_logger.logger, 'statsd_client'))
self.assertIsInstance(swift_logger.logger.statsd_client,
FakeStatsdClient)
return swift_logger.logger.statsd_client
# tail prefix defaults to swift
statsd_client = call_get_logger(None, None, None)
self.assertEqual('swift.', statsd_client._prefix)
# tail prefix defaults to conf log_name
conf = {'log_name': 'bar'}
statsd_client = call_get_logger(conf, None, None)
self.assertEqual('bar.', statsd_client._prefix)
# tail prefix defaults to name arg which overrides conf log_name
statsd_client = call_get_logger(conf, '', None)
self.assertEqual('', statsd_client._prefix)
# tail prefix defaults to name arg which overrides conf log_name
statsd_client = call_get_logger(conf, 'baz', None)
self.assertEqual('baz.', statsd_client._prefix)
# tail prefix set to statsd_tail_prefix arg which overrides name arg
statsd_client = call_get_logger(conf, 'baz', '')
self.assertEqual('', statsd_client._prefix)
# tail prefix set to statsd_tail_prefix arg which overrides name arg
statsd_client = call_get_logger(conf, 'baz', 'boo')
self.assertEqual('boo.', statsd_client._prefix)
# base prefix is configured, tail prefix defaults to swift
conf = {'log_statsd_metric_prefix': 'foo'}
statsd_client = call_get_logger(conf, None, None)
self.assertEqual('foo.swift.', statsd_client._prefix)
# base prefix is configured, tail prefix defaults to conf log_name
conf = {'log_statsd_metric_prefix': 'foo', 'log_name': 'bar'}
statsd_client = call_get_logger(conf, None, None)
self.assertEqual('foo.bar.', statsd_client._prefix)
# base prefix is configured, tail prefix defaults to name arg
statsd_client = call_get_logger(conf, 'baz', None)
self.assertEqual('foo.baz.', statsd_client._prefix)
# base prefix is configured, tail prefix set to statsd_tail_prefix arg
statsd_client = call_get_logger(conf, None, '')
self.assertEqual('foo.', statsd_client._prefix)
# base prefix is configured, tail prefix set to statsd_tail_prefix arg
statsd_client = call_get_logger(conf, 'baz', 'boo')
self.assertEqual('foo.boo.', statsd_client._prefix)
def test_get_logger_replaces_statsd_client(self):
# Each call to get_logger creates a *new* StatsdClient instance and
# sets it as an attribute of the potentially *shared* Logger instance.
# This is a questionable pattern but the test at least reminds us.
orig_logger = utils.get_logger(
{'log_statsd_port': 1234},
name=self.logger_name,
statsd_tail_prefix='orig')
self.assertTrue(hasattr(orig_logger.logger, 'statsd_client'))
orig_client = orig_logger.logger.statsd_client
self.assertEqual('orig.', orig_client._prefix)
self.assertEqual(1234, orig_client._port)
new_adapted_logger = utils.get_logger(
{'log_statsd_port': 5678},
name=self.logger_name,
statsd_tail_prefix='new')
self.assertTrue(hasattr(new_adapted_logger.logger, 'statsd_client'))
new_client = new_adapted_logger.logger.statsd_client
# same core Logger...
self.assertIs(orig_logger.logger, new_adapted_logger.logger)
# ... different StatsdClient !
self.assertIsNot(new_client, orig_client)
self.assertIs(new_client, orig_logger.logger.statsd_client)
self.assertEqual('new.', new_client._prefix)
self.assertEqual(5678, new_client._port)
def test_get_prefixed_logger_calls_get_prefixed_swift_logger(self):
orig_get_prefixed_swift_logger = utils.logs.get_prefixed_swift_logger
base_logger = utils.logs.get_swift_logger(None)
calls = []
def fake_get_prefixed_swift_logger(*args, **kwargs):
result = orig_get_prefixed_swift_logger(*args, **kwargs)
calls.append((args, kwargs, result))
return result
with mock.patch(
'swift.common.utils.get_prefixed_swift_logger',
fake_get_prefixed_swift_logger):
logger = utils.get_prefixed_logger(base_logger, 'boo')
self.assertEqual(1, len(calls))
self.assertEqual(((base_logger,), {'prefix': 'boo'}), calls[0][:2])
self.assertEqual(calls[0][2], logger)
self.assertEqual('boo', logger.prefix)
def test_get_prefixed_logger_adopts_statsd_client(self):
# verify that get_prefixed_logger installs an interface to any existing
# StatsdClient that the source logger has
with mock.patch(
'swift.common.statsd_client.StatsdClient', FakeStatsdClient):
adapted_logger = utils.get_logger(None, name=self.logger_name)
self.assertTrue(hasattr(adapted_logger.logger, 'statsd_client'))
self.assertIsInstance(adapted_logger.logger.statsd_client,
FakeStatsdClient)
prefixed_logger = utils.get_prefixed_logger(adapted_logger, 'test')
self.assertTrue(hasattr(prefixed_logger.logger, 'statsd_client'))
self.assertIs(prefixed_logger.logger.statsd_client,
adapted_logger.logger.statsd_client)
prefixed_logger.increment('foo')
prefixed_logger.decrement('boo')
exp = {
'increment': [(('foo',), {})],
'decrement': [(('boo',), {})],
'update_stats': [(('foo', 1, None), {}),
(('boo', -1, None), {})]
}
self.assertEqual(exp, prefixed_logger.logger.statsd_client.calls)
self.assertEqual(exp, adapted_logger.logger.statsd_client.calls)
def test_get_prefixed_logger_no_statsd_client(self):
# verify get_prefixed_logger can be used to mutate the prefix of a
# SwiftLogAdapter that does *not* have a StatsdClient interface
adapted_logger = utils.logs.get_swift_logger(
None, name=self.logger_name)
self.assertFalse(
hasattr(adapted_logger.logger, 'statsd_client'))
self.assertFalse(hasattr(adapted_logger, 'statsd_client_source'))
self.assertFalse(hasattr(adapted_logger, 'increment'))
prefixed_logger = utils.get_prefixed_logger(adapted_logger, 'test')
self.assertFalse(hasattr(prefixed_logger, 'statsd_client_source'))
self.assertFalse(hasattr(prefixed_logger.logger, 'statsd_client'))
self.assertFalse(hasattr(prefixed_logger, 'increment'))

View File

@ -36,8 +36,7 @@ from six.moves import http_client
from test.unit import with_tempdir from test.unit import with_tempdir
from test.unit import quiet_eventlet_exceptions from test.unit import quiet_eventlet_exceptions
from test.unit.common.test_utils import MockOs, MockSys from test.unit.common.test_utils import MockOs, MockSys
from swift.common.exceptions import Timeout, \ from swift.common.exceptions import Timeout, MessageTimeout, ConnectionTimeout
MessageTimeout, ConnectionTimeout
if six.PY2: if six.PY2:
import eventlet.green.httplib as green_http_client import eventlet.green.httplib as green_http_client
@ -48,23 +47,24 @@ from swift.common import utils
from swift.common.swob import Request, Response from swift.common.swob import Request, Response
from swift.common.utils.logs import SwiftLogFormatter, SwiftLogAdapter, \ from swift.common.utils.logs import SwiftLogFormatter, SwiftLogAdapter, \
get_prefixed_logger get_swift_logger, get_prefixed_swift_logger
def reset_loggers(): def reset_loggers():
if hasattr(utils.get_logger, 'handler4logger'): if hasattr(get_swift_logger, 'handler4logger'):
for logger, handler in utils.get_logger.handler4logger.items(): for logger, handler in get_swift_logger.handler4logger.items():
logger.removeHandler(handler) logger.removeHandler(handler)
delattr(utils.get_logger, 'handler4logger') delattr(get_swift_logger, 'handler4logger')
if hasattr(utils.get_logger, 'console_handler4logger'): if hasattr(get_swift_logger, 'console_handler4logger'):
for logger, h in utils.get_logger.console_handler4logger.items(): for logger, h in \
get_swift_logger.console_handler4logger.items():
logger.removeHandler(h) logger.removeHandler(h)
delattr(utils.get_logger, 'console_handler4logger') delattr(get_swift_logger, 'console_handler4logger')
# Reset the LogAdapter class thread local state. Use get_logger() here # Reset the LogAdapter class thread local state. Use get_swift_logger()
# to fetch a LogAdapter instance because the items from # here to fetch a LogAdapter instance because the items from
# get_logger.handler4logger above are the underlying logger instances, # get_swift_logger.handler4logger above are the underlying logger
# not the LogAdapter. # instances not the LogAdapter.
utils.get_logger(None).thread_locals = (None, None) get_swift_logger(None).thread_locals = (None, None)
def reset_logger_state(f): def reset_logger_state(f):
@ -192,22 +192,22 @@ class TestUtilsLogs(unittest.TestCase):
logger.removeHandler(handler) logger.removeHandler(handler)
def test_get_logger(self): def test_get_swift_logger(self):
sio = StringIO() sio = StringIO()
logger = logging.getLogger('server') logger = logging.getLogger('server')
logger.addHandler(logging.StreamHandler(sio)) logger.addHandler(logging.StreamHandler(sio))
logger = utils.get_logger(None, 'server', log_route='server') logger = get_swift_logger(None, 'server', log_route='server')
logger.warning('test1') logger.warning('test1')
self.assertEqual(sio.getvalue(), 'test1\n') self.assertEqual(sio.getvalue(), 'test1\n')
logger.debug('test2') logger.debug('test2')
self.assertEqual(sio.getvalue(), 'test1\n') self.assertEqual(sio.getvalue(), 'test1\n')
logger = utils.get_logger({'log_level': 'DEBUG'}, 'server', logger = get_swift_logger({'log_level': 'DEBUG'}, 'server',
log_route='server') log_route='server')
logger.debug('test3') logger.debug('test3')
self.assertEqual(sio.getvalue(), 'test1\ntest3\n') self.assertEqual(sio.getvalue(), 'test1\ntest3\n')
# Doesn't really test that the log facility is truly being used all the # Doesn't really test that the log facility is truly being used all the
# way to syslog; but exercises the code. # way to syslog; but exercises the code.
logger = utils.get_logger({'log_facility': 'LOG_LOCAL3'}, 'server', logger = get_swift_logger({'log_facility': 'LOG_LOCAL3'}, 'server',
log_route='server') log_route='server')
logger.warning('test4') logger.warning('test4')
self.assertEqual(sio.getvalue(), self.assertEqual(sio.getvalue(),
@ -221,7 +221,7 @@ class TestUtilsLogs(unittest.TestCase):
self.assertEqual(sio.getvalue(), self.assertEqual(sio.getvalue(),
'test1\ntest3\ntest4\ntest6\n') 'test1\ntest3\ntest4\ntest6\n')
def test_get_logger_name_and_route(self): def test_get_swift_logger_name_and_route(self):
@contextlib.contextmanager @contextlib.contextmanager
def add_log_handler(logger): def add_log_handler(logger):
# install a handler to capture log messages formatted as per swift # install a handler to capture log messages formatted as per swift
@ -234,7 +234,7 @@ class TestUtilsLogs(unittest.TestCase):
yield sio yield sio
logger.logger.removeHandler(handler) logger.logger.removeHandler(handler)
logger = utils.get_logger({}, name='name', log_route='route') logger = utils.get_swift_logger({}, name='name', log_route='route')
# log_route becomes the LogAdapter.name and logging.Logger.name # log_route becomes the LogAdapter.name and logging.Logger.name
self.assertEqual('route', logger.name) self.assertEqual('route', logger.name)
self.assertEqual('route', logger.logger.name) self.assertEqual('route', logger.logger.name)
@ -245,36 +245,37 @@ class TestUtilsLogs(unittest.TestCase):
logger.info('testing') logger.info('testing')
self.assertEqual('name: testing\n', sio.getvalue()) self.assertEqual('name: testing\n', sio.getvalue())
logger = utils.get_logger({'log_name': 'conf-name'}, name='name', logger = utils.get_swift_logger({'log_name': 'conf-name'},
log_route='route') name='name', log_route='route')
self.assertEqual('route', logger.name) self.assertEqual('route', logger.name)
self.assertEqual('name', logger.server) self.assertEqual('name', logger.server)
with add_log_handler(logger) as sio: with add_log_handler(logger) as sio:
logger.info('testing') logger.info('testing')
self.assertEqual('name: testing\n', sio.getvalue()) self.assertEqual('name: testing\n', sio.getvalue())
logger = utils.get_logger({'log_name': 'conf-name'}, log_route='route') logger = utils.get_swift_logger({'log_name': 'conf-name'},
log_route='route')
self.assertEqual('route', logger.name) self.assertEqual('route', logger.name)
self.assertEqual('conf-name', logger.server) self.assertEqual('conf-name', logger.server)
with add_log_handler(logger) as sio: with add_log_handler(logger) as sio:
logger.info('testing') logger.info('testing')
self.assertEqual('conf-name: testing\n', sio.getvalue()) self.assertEqual('conf-name: testing\n', sio.getvalue())
logger = utils.get_logger({'log_name': 'conf-name'}) logger = utils.get_swift_logger({'log_name': 'conf-name'})
self.assertEqual('conf-name', logger.name) self.assertEqual('conf-name', logger.name)
self.assertEqual('conf-name', logger.server) self.assertEqual('conf-name', logger.server)
with add_log_handler(logger) as sio: with add_log_handler(logger) as sio:
logger.info('testing') logger.info('testing')
self.assertEqual('conf-name: testing\n', sio.getvalue()) self.assertEqual('conf-name: testing\n', sio.getvalue())
logger = utils.get_logger({}) logger = utils.get_swift_logger({})
self.assertEqual('swift', logger.name) self.assertEqual('swift', logger.name)
self.assertEqual('swift', logger.server) self.assertEqual('swift', logger.server)
with add_log_handler(logger) as sio: with add_log_handler(logger) as sio:
logger.info('testing') logger.info('testing')
self.assertEqual('swift: testing\n', sio.getvalue()) self.assertEqual('swift: testing\n', sio.getvalue())
logger = utils.get_logger({}, log_route='route') logger = utils.get_swift_logger({}, log_route='route')
self.assertEqual('route', logger.name) self.assertEqual('route', logger.name)
self.assertEqual('swift', logger.server) self.assertEqual('swift', logger.server)
with add_log_handler(logger) as sio: with add_log_handler(logger) as sio:
@ -282,20 +283,16 @@ class TestUtilsLogs(unittest.TestCase):
self.assertEqual('swift: testing\n', sio.getvalue()) self.assertEqual('swift: testing\n', sio.getvalue())
# same log_route, different names... # same log_route, different names...
logger1 = utils.get_logger({'log_statsd_host': '1.2.3.4'}, logger1 = utils.get_swift_logger({'log_statsd_host': '1.2.3.4'},
name='name1', log_route='route') name='name1', log_route='route')
logger2 = utils.get_logger({'log_statsd_host': '1.2.3.5'}, logger2 = utils.get_swift_logger({'log_statsd_host': '1.2.3.5'},
name='name2', log_route='route') name='name2', log_route='route')
self.assertEqual('route', logger1.name) self.assertEqual('route', logger1.name)
self.assertEqual('route', logger1.logger.name) self.assertEqual('route', logger1.logger.name)
self.assertEqual('name1', logger1.server) self.assertEqual('name1', logger1.server)
# oh dear, the statsd client on the common logging.Logger instance got
# mutated when logger2 was created
self.assertEqual('name2.', logger1.logger.statsd_client._prefix)
self.assertEqual('route', logger2.name) self.assertEqual('route', logger2.name)
self.assertEqual('route', logger2.logger.name) self.assertEqual('route', logger2.logger.name)
self.assertEqual('name2', logger2.server) self.assertEqual('name2', logger2.server)
self.assertEqual('name2.', logger2.logger.statsd_client._prefix)
self.assertIs(logger2.logger, logger1.logger) self.assertIs(logger2.logger, logger1.logger)
with add_log_handler(logger1) as sio: with add_log_handler(logger1) as sio:
logger1.info('testing') logger1.info('testing')
@ -305,18 +302,16 @@ class TestUtilsLogs(unittest.TestCase):
self.assertEqual('name2: testing\n', sio.getvalue()) self.assertEqual('name2: testing\n', sio.getvalue())
# different log_route, different names... # different log_route, different names...
logger1 = utils.get_logger({'log_statsd_host': '1.2.3.4'}, logger1 = utils.get_swift_logger({'log_statsd_host': '1.2.3.4'},
name='name1', log_route='route1') name='name1', log_route='route1')
logger2 = utils.get_logger({'log_statsd_host': '1.2.3.5'}, logger2 = utils.get_swift_logger({'log_statsd_host': '1.2.3.5'},
name='name2', log_route='route2') name='name2', log_route='route2')
self.assertEqual('route1', logger1.name) self.assertEqual('route1', logger1.name)
self.assertEqual('route1', logger1.logger.name) self.assertEqual('route1', logger1.logger.name)
self.assertEqual('name1', logger1.server) self.assertEqual('name1', logger1.server)
self.assertEqual('name1.', logger1.logger.statsd_client._prefix)
self.assertEqual('route2', logger2.name) self.assertEqual('route2', logger2.name)
self.assertEqual('route2', logger2.logger.name) self.assertEqual('route2', logger2.logger.name)
self.assertEqual('name2', logger2.server) self.assertEqual('name2', logger2.server)
self.assertEqual('name2.', logger2.logger.statsd_client._prefix)
self.assertIsNot(logger2.logger, logger1.logger) self.assertIsNot(logger2.logger, logger1.logger)
with add_log_handler(logger1) as sio: with add_log_handler(logger1) as sio:
logger1.info('testing') logger1.info('testing')
@ -326,7 +321,7 @@ class TestUtilsLogs(unittest.TestCase):
self.assertEqual('name2: testing\n', sio.getvalue()) self.assertEqual('name2: testing\n', sio.getvalue())
@with_tempdir @with_tempdir
def test_get_logger_sysloghandler_plumbing(self, tempdir): def test_get_swift_logger_sysloghandler_plumbing(self, tempdir):
orig_sysloghandler = utils.logs.ThreadSafeSysLogHandler orig_sysloghandler = utils.logs.ThreadSafeSysLogHandler
syslog_handler_args = [] syslog_handler_args = []
@ -348,7 +343,7 @@ class TestUtilsLogs(unittest.TestCase):
syslog_handler_catcher), \ syslog_handler_catcher), \
mock.patch.object(socket, 'getaddrinfo', fake_getaddrinfo): mock.patch.object(socket, 'getaddrinfo', fake_getaddrinfo):
# default log_address # default log_address
utils.get_logger({ get_swift_logger({
'log_facility': 'LOG_LOCAL3', 'log_facility': 'LOG_LOCAL3',
}, 'server', log_route='server') }, 'server', log_route='server')
expected_args = [((), {'address': '/dev/log', expected_args = [((), {'address': '/dev/log',
@ -365,7 +360,7 @@ class TestUtilsLogs(unittest.TestCase):
# custom log_address - file doesn't exist: fallback to UDP # custom log_address - file doesn't exist: fallback to UDP
log_address = os.path.join(tempdir, 'foo') log_address = os.path.join(tempdir, 'foo')
syslog_handler_args = [] syslog_handler_args = []
utils.get_logger({ get_swift_logger({
'log_facility': 'LOG_LOCAL3', 'log_facility': 'LOG_LOCAL3',
'log_address': log_address, 'log_address': log_address,
}, 'server', log_route='server') }, 'server', log_route='server')
@ -378,7 +373,7 @@ class TestUtilsLogs(unittest.TestCase):
with open(log_address, 'w'): with open(log_address, 'w'):
pass pass
syslog_handler_args = [] syslog_handler_args = []
utils.get_logger({ get_swift_logger({
'log_facility': 'LOG_LOCAL3', 'log_facility': 'LOG_LOCAL3',
'log_address': log_address, 'log_address': log_address,
}, 'server', log_route='server') }, 'server', log_route='server')
@ -394,7 +389,7 @@ class TestUtilsLogs(unittest.TestCase):
sock.settimeout(5) sock.settimeout(5)
sock.bind(log_address) sock.bind(log_address)
syslog_handler_args = [] syslog_handler_args = []
utils.get_logger({ get_swift_logger({
'log_facility': 'LOG_LOCAL3', 'log_facility': 'LOG_LOCAL3',
'log_address': log_address, 'log_address': log_address,
}, 'server', log_route='server') }, 'server', log_route='server')
@ -406,7 +401,7 @@ class TestUtilsLogs(unittest.TestCase):
# Using UDP with default port # Using UDP with default port
syslog_handler_args = [] syslog_handler_args = []
utils.get_logger({ get_swift_logger({
'log_udp_host': 'syslog.funtimes.com', 'log_udp_host': 'syslog.funtimes.com',
}, 'server', log_route='server') }, 'server', log_route='server')
self.assertEqual([ self.assertEqual([
@ -417,7 +412,7 @@ class TestUtilsLogs(unittest.TestCase):
# Using UDP with non-default port # Using UDP with non-default port
syslog_handler_args = [] syslog_handler_args = []
utils.get_logger({ get_swift_logger({
'log_udp_host': 'syslog.funtimes.com', 'log_udp_host': 'syslog.funtimes.com',
'log_udp_port': '2123', 'log_udp_port': '2123',
}, 'server', log_route='server') }, 'server', log_route='server')
@ -429,13 +424,13 @@ class TestUtilsLogs(unittest.TestCase):
with mock.patch.object(utils.logs, 'ThreadSafeSysLogHandler', with mock.patch.object(utils.logs, 'ThreadSafeSysLogHandler',
side_effect=OSError(errno.EPERM, 'oops')): side_effect=OSError(errno.EPERM, 'oops')):
with self.assertRaises(OSError) as cm: with self.assertRaises(OSError) as cm:
utils.get_logger({ get_swift_logger({
'log_facility': 'LOG_LOCAL3', 'log_facility': 'LOG_LOCAL3',
'log_address': 'log_address', 'log_address': 'log_address',
}, 'server', log_route='server') }, 'server', log_route='server')
self.assertEqual(errno.EPERM, cm.exception.errno) self.assertEqual(errno.EPERM, cm.exception.errno)
def test_get_logger_custom_log_handlers(self): def test_get_swift_logger_custom_log_handlers(self):
def custom_log_handler(conf, name, log_to_console, log_route, fmt, def custom_log_handler(conf, name, log_to_console, log_route, fmt,
logger, adapted_logger): logger, adapted_logger):
adapted_logger.server = adapted_logger.server.upper() adapted_logger.server = adapted_logger.server.upper()
@ -449,7 +444,7 @@ class TestUtilsLogs(unittest.TestCase):
# sanity check... # sanity check...
conf = {} conf = {}
adapted_logger = utils.get_logger( adapted_logger = get_swift_logger(
conf, 'my_server', log_route='my_logger_name') conf, 'my_server', log_route='my_logger_name')
adapted_logger.warning('test') adapted_logger.warning('test')
self.assertEqual(sio.getvalue(), self.assertEqual(sio.getvalue(),
@ -461,7 +456,7 @@ class TestUtilsLogs(unittest.TestCase):
patch_target = 'test.unit.common.utils.custom_log_handler' patch_target = 'test.unit.common.utils.custom_log_handler'
conf = {'log_custom_handlers': patch_target} conf = {'log_custom_handlers': patch_target}
with mock.patch(patch_target, custom_log_handler, create=True): with mock.patch(patch_target, custom_log_handler, create=True):
adapted_logger = utils.get_logger( adapted_logger = get_swift_logger(
conf, 'my_server', log_route='my_logger_name') conf, 'my_server', log_route='my_logger_name')
adapted_logger.warning('test') adapted_logger.warning('test')
self.assertEqual(sio.getvalue(), self.assertEqual(sio.getvalue(),
@ -471,7 +466,7 @@ class TestUtilsLogs(unittest.TestCase):
def test_clean_logger_exception(self): def test_clean_logger_exception(self):
# setup stream logging # setup stream logging
sio = StringIO() sio = StringIO()
logger = utils.get_logger(None) logger = get_swift_logger(None)
handler = logging.StreamHandler(sio) handler = logging.StreamHandler(sio)
logger.logger.addHandler(handler) logger.logger.addHandler(handler)
@ -610,7 +605,7 @@ class TestUtilsLogs(unittest.TestCase):
def test_swift_log_formatter_max_line_length(self): def test_swift_log_formatter_max_line_length(self):
# setup stream logging # setup stream logging
sio = StringIO() sio = StringIO()
logger = utils.get_logger(None) logger = get_swift_logger(None)
handler = logging.StreamHandler(sio) handler = logging.StreamHandler(sio)
formatter = utils.SwiftLogFormatter(max_line_length=10) formatter = utils.SwiftLogFormatter(max_line_length=10)
handler.setFormatter(formatter) handler.setFormatter(formatter)
@ -666,7 +661,7 @@ class TestUtilsLogs(unittest.TestCase):
def test_swift_log_formatter(self): def test_swift_log_formatter(self):
# setup stream logging # setup stream logging
sio = StringIO() sio = StringIO()
logger = utils.get_logger(None) logger = get_swift_logger(None)
handler = logging.StreamHandler(sio) handler = logging.StreamHandler(sio)
handler.setFormatter(utils.SwiftLogFormatter()) handler.setFormatter(utils.SwiftLogFormatter())
logger.logger.addHandler(handler) logger.logger.addHandler(handler)
@ -728,13 +723,13 @@ class TestUtilsLogs(unittest.TestCase):
logger.logger.removeHandler(handler) logger.logger.removeHandler(handler)
@reset_logger_state @reset_logger_state
def test_get_prefixed_logger(self): def test_get_prefixed_swift_logger(self):
# setup stream logging # setup stream logging
sio = StringIO() sio = StringIO()
base_logger = utils.get_logger(None) base_logger = get_swift_logger(None)
handler = logging.StreamHandler(sio) handler = logging.StreamHandler(sio)
base_logger.logger.addHandler(handler) base_logger.logger.addHandler(handler)
logger = get_prefixed_logger(base_logger, 'some prefix: ') logger = get_prefixed_swift_logger(base_logger, 'some prefix: ')
def strip_value(sio): def strip_value(sio):
sio.seek(0) sio.seek(0)
@ -759,13 +754,13 @@ class TestUtilsLogs(unittest.TestCase):
base_logger.logger.removeHandler(handler) base_logger.logger.removeHandler(handler)
@reset_logger_state @reset_logger_state
def test_get_prefixed_logger_exception_method(self): def test_get_prefixed_swift_logger_exception_method(self):
# setup stream logging # setup stream logging
sio = StringIO() sio = StringIO()
base_logger = utils.get_logger(None) base_logger = get_swift_logger(None)
handler = logging.StreamHandler(sio) handler = logging.StreamHandler(sio)
base_logger.logger.addHandler(handler) base_logger.logger.addHandler(handler)
logger = get_prefixed_logger(base_logger, 'some prefix: ') logger = get_prefixed_swift_logger(base_logger, 'some prefix: ')
def strip_value(sio): def strip_value(sio):
sio.seek(0) sio.seek(0)
@ -816,13 +811,13 @@ class TestUtilsLogs(unittest.TestCase):
base_logger.logger.removeHandler(handler) base_logger.logger.removeHandler(handler)
@reset_logger_state @reset_logger_state
def test_get_prefixed_logger_non_string_values(self): def test_get_prefixed_swift_logger_non_string_values(self):
# setup stream logging # setup stream logging
sio = StringIO() sio = StringIO()
base_logger = utils.get_logger(None) base_logger = get_swift_logger(None)
handler = logging.StreamHandler(sio) handler = logging.StreamHandler(sio)
base_logger.logger.addHandler(handler) base_logger.logger.addHandler(handler)
logger = get_prefixed_logger(base_logger, 'some prefix: ') logger = get_prefixed_swift_logger(base_logger, 'some prefix: ')
exc = Exception('blah') exc = Exception('blah')
def strip_value(sio): def strip_value(sio):
@ -832,21 +827,21 @@ class TestUtilsLogs(unittest.TestCase):
return v return v
try: try:
logger = get_prefixed_logger(logger, 'abc') logger = get_prefixed_swift_logger(logger, 'abc')
self.assertEqual('abc', logger.prefix) self.assertEqual('abc', logger.prefix)
logger.info('test') logger.info('test')
self.assertEqual(strip_value(sio), 'abctest\n') self.assertEqual(strip_value(sio), 'abctest\n')
logger.info(exc) logger.info(exc)
self.assertEqual(strip_value(sio), 'abcblah\n') self.assertEqual(strip_value(sio), 'abcblah\n')
logger = get_prefixed_logger(logger, '') logger = get_prefixed_swift_logger(logger, '')
self.assertEqual('', logger.prefix) self.assertEqual('', logger.prefix)
logger.info('test') logger.info('test')
self.assertEqual(strip_value(sio), 'test\n') self.assertEqual(strip_value(sio), 'test\n')
logger.info(exc) logger.info(exc)
self.assertEqual(strip_value(sio), 'blah\n') self.assertEqual(strip_value(sio), 'blah\n')
logger = get_prefixed_logger(logger, 0) logger = get_prefixed_swift_logger(logger, 0)
self.assertEqual(0, logger.prefix) self.assertEqual(0, logger.prefix)
logger.info('test') logger.info('test')
self.assertEqual(strip_value(sio), '0test\n') self.assertEqual(strip_value(sio), '0test\n')
@ -856,14 +851,14 @@ class TestUtilsLogs(unittest.TestCase):
logger.logger.removeHandler(handler) logger.logger.removeHandler(handler)
@reset_logger_state @reset_logger_state
def test_get_prefixed_logger_replaces_prefix(self): def test_get_prefixed_swift_logger_replaces_prefix(self):
# setup stream logging # setup stream logging
sio = StringIO() sio = StringIO()
base_logger = utils.get_logger(None) base_logger = get_swift_logger(None)
handler = logging.StreamHandler(sio) handler = logging.StreamHandler(sio)
base_logger.logger.addHandler(handler) base_logger.logger.addHandler(handler)
logger1 = get_prefixed_logger(base_logger, 'one: ') logger1 = get_prefixed_swift_logger(base_logger, 'one: ')
logger2 = get_prefixed_logger(logger1, 'two: ') logger2 = get_prefixed_swift_logger(logger1, 'two: ')
def strip_value(sio): def strip_value(sio):
sio.seek(0) sio.seek(0)
@ -886,17 +881,17 @@ class TestUtilsLogs(unittest.TestCase):
finally: finally:
base_logger.logger.removeHandler(handler) base_logger.logger.removeHandler(handler)
def test_get_prefixed_logger_isolation(self): def test_get_prefixed_swift_logger_isolation(self):
# verify that the new instance's attributes are copied by value # verify that the new instance's attributes are copied by value
# from the old (except prefix), but the thread_locals are still shared # from the old (except prefix), but the thread_locals are still shared
adapted_logger = utils.get_logger(None, name='server') adapted_logger = get_swift_logger(None, name='server')
adapted_logger.thread_locals = ('id', 'ip') adapted_logger.thread_locals = ('id', 'ip')
adapted_logger = get_prefixed_logger(adapted_logger, 'foo') adapted_logger = get_prefixed_swift_logger(adapted_logger, 'foo')
self.assertEqual(adapted_logger.server, 'server') self.assertEqual(adapted_logger.server, 'server')
self.assertEqual(adapted_logger.thread_locals, ('id', 'ip')) self.assertEqual(adapted_logger.thread_locals, ('id', 'ip'))
self.assertEqual(adapted_logger.prefix, 'foo') self.assertEqual(adapted_logger.prefix, 'foo')
cloned_adapted_logger = get_prefixed_logger( cloned_adapted_logger = get_prefixed_swift_logger(
adapted_logger, 'boo') adapted_logger, 'boo')
self.assertEqual(cloned_adapted_logger.server, 'server') self.assertEqual(cloned_adapted_logger.server, 'server')
self.assertEqual(cloned_adapted_logger.thread_locals, ('id', 'ip')) self.assertEqual(cloned_adapted_logger.thread_locals, ('id', 'ip'))
@ -907,7 +902,7 @@ class TestUtilsLogs(unittest.TestCase):
self.assertEqual(adapted_logger.prefix, 'foo') self.assertEqual(adapted_logger.prefix, 'foo')
self.assertIs(adapted_logger.logger, cloned_adapted_logger.logger) self.assertIs(adapted_logger.logger, cloned_adapted_logger.logger)
cloned_adapted_logger = get_prefixed_logger( cloned_adapted_logger = get_prefixed_swift_logger(
adapted_logger, adapted_logger.prefix + 'bar') adapted_logger, adapted_logger.prefix + 'bar')
adapted_logger.server = 'waiter' adapted_logger.server = 'waiter'
self.assertEqual(adapted_logger.server, 'waiter') self.assertEqual(adapted_logger.server, 'waiter')
@ -923,7 +918,7 @@ class TestUtilsLogs(unittest.TestCase):
@reset_logger_state @reset_logger_state
def test_capture_stdio(self): def test_capture_stdio(self):
# stubs # stubs
logger = utils.logs.get_logger(None, 'dummy') logger = get_swift_logger(None, 'dummy')
# mock utils system modules # mock utils system modules
mock_os = MockOs() mock_os = MockOs()
@ -958,7 +953,7 @@ class TestUtilsLogs(unittest.TestCase):
mock_sys = MockSys() mock_sys = MockSys()
with mock.patch.object(utils.logs, 'os', mock_os), \ with mock.patch.object(utils.logs, 'os', mock_os), \
mock.patch.object(utils.logs, 'sys', mock_sys): mock.patch.object(utils.logs, 'sys', mock_sys):
logger = utils.get_logger(None, log_to_console=True) logger = get_swift_logger(None, log_to_console=True)
# test console log # test console log
utils.logs.capture_stdio(logger, capture_stdout=False, utils.logs.capture_stdio(logger, capture_stdout=False,
@ -976,19 +971,19 @@ class TestUtilsLogs(unittest.TestCase):
utils.logs.LoggerFileObject)) utils.logs.LoggerFileObject))
@reset_logger_state @reset_logger_state
def test_get_logger_console(self): def test_get_swift_logger_console(self):
logger = utils.get_logger(None) logger = get_swift_logger(None)
console_handlers = [h for h in logger.logger.handlers if console_handlers = [h for h in logger.logger.handlers if
isinstance(h, logging.StreamHandler)] isinstance(h, logging.StreamHandler)]
self.assertFalse(console_handlers) self.assertFalse(console_handlers)
logger = utils.get_logger(None, log_to_console=True) logger = get_swift_logger(None, log_to_console=True)
console_handlers = [h for h in logger.logger.handlers if console_handlers = [h for h in logger.logger.handlers if
isinstance(h, logging.StreamHandler)] isinstance(h, logging.StreamHandler)]
self.assertTrue(console_handlers) self.assertTrue(console_handlers)
# make sure you can't have two console handlers # make sure you can't have two console handlers
self.assertEqual(len(console_handlers), 1) self.assertEqual(len(console_handlers), 1)
old_handler = console_handlers[0] old_handler = console_handlers[0]
logger = utils.get_logger(None, log_to_console=True) logger = get_swift_logger(None, log_to_console=True)
console_handlers = [h for h in logger.logger.handlers if console_handlers = [h for h in logger.logger.handlers if
isinstance(h, logging.StreamHandler)] isinstance(h, logging.StreamHandler)]
self.assertEqual(len(console_handlers), 1) self.assertEqual(len(console_handlers), 1)

View File

@ -53,7 +53,7 @@ from six.moves import range
from six.moves.urllib.parse import quote, parse_qsl from six.moves.urllib.parse import quote, parse_qsl
from test import listen_zero from test import listen_zero
from test.debug_logger import debug_logger from test.debug_logger import debug_logger, FakeStatsdClient
from test.unit import ( from test.unit import (
connect_tcp, readuntil2crlfs, fake_http_connect, FakeRing, connect_tcp, readuntil2crlfs, fake_http_connect, FakeRing,
FakeMemcache, patch_policies, write_fake_ring, mocked_http_conn, FakeMemcache, patch_policies, write_fake_ring, mocked_http_conn,
@ -2295,16 +2295,17 @@ class TestProxyServerConfigLoading(unittest.TestCase):
use = egg:swift#proxy use = egg:swift#proxy
""" % self.tempdir """ % self.tempdir
conf_path = self._write_conf(dedent(conf_sections)) conf_path = self._write_conf(dedent(conf_sections))
with mock.patch('swift.common.statsd_client.StatsdClient') \ with mock.patch('swift.common.statsd_client.StatsdClient',
as mock_statsd: FakeStatsdClient):
app = loadapp(conf_path, allow_modify_pipeline=False) app = loadapp(conf_path, allow_modify_pipeline=False)
# logger name is hard-wired 'proxy-server' # logger name is hard-wired 'proxy-server'
self.assertEqual('proxy-server', app.logger.name) self.assertEqual('proxy-server', app.logger.name)
self.assertEqual('swift', app.logger.server) self.assertEqual('swift', app.logger.server)
mock_statsd.assert_called_once_with( self.assertIsInstance(app.logger.logger.statsd_client, StatsdClient)
'example.com', 8125, base_prefix='', tail_prefix='proxy-server', self.assertEqual(app.logger.logger.statsd_client._host, 'example.com')
default_sample_rate=1.0, sample_rate_factor=1.0, self.assertEqual(app.logger.logger.statsd_client._port, 8125)
logger=app.logger.logger) self.assertEqual(app.logger.logger.statsd_client._prefix,
'proxy-server.')
conf_sections = """ conf_sections = """
[DEFAULT] [DEFAULT]
@ -2320,18 +2321,19 @@ class TestProxyServerConfigLoading(unittest.TestCase):
""" % self.tempdir """ % self.tempdir
conf_path = self._write_conf(dedent(conf_sections)) conf_path = self._write_conf(dedent(conf_sections))
with mock.patch('swift.common.statsd_client.StatsdClient') \ with mock.patch('swift.common.statsd_client.StatsdClient',
as mock_statsd: FakeStatsdClient):
app = loadapp(conf_path, allow_modify_pipeline=False) app = loadapp(conf_path, allow_modify_pipeline=False)
# logger name is hard-wired 'proxy-server' # logger name is hard-wired 'proxy-server'
self.assertEqual('proxy-server', app.logger.name) self.assertEqual('proxy-server', app.logger.name)
# server is defined by log_name option # server is defined by log_name option
self.assertEqual('test-name', app.logger.server) self.assertEqual('test-name', app.logger.server)
# statsd tail prefix is hard-wired 'proxy-server' # statsd tail prefix is hard-wired 'proxy-server'
mock_statsd.assert_called_once_with( self.assertIsInstance(app.logger.logger.statsd_client, StatsdClient)
'example.com', 8125, base_prefix='', tail_prefix='proxy-server', self.assertEqual(app.logger.logger.statsd_client._host, 'example.com')
default_sample_rate=1.0, sample_rate_factor=1.0, self.assertEqual(app.logger.logger.statsd_client._port, 8125)
logger=app.logger.logger) self.assertEqual(app.logger.logger.statsd_client._prefix,
'proxy-server.')
class TestProxyServerConfigStringLoading(TestProxyServerConfigLoading): class TestProxyServerConfigStringLoading(TestProxyServerConfigLoading):