Use six.wraps() for Metrics so decorated methods can be inspected

Previously it was using functools.wraps() to create the decorators.
The problem is that we can't use the
oslo_utils.reflection.get_signature() function to get the correct
signature.

Change it to use six.wraps() which will add the '__wrapped__'
attribute which will be used when calling get_signature() and return
the signature of the decorated function.

Added unit tests to show we are able to see the signature of a wrapped
function.

Closes-Bug: #1746730
Change-Id: I75428e948b64b3b6758d31678a80d158a11c6beb
This commit is contained in:
John L. Villalovos 2018-02-01 08:38:26 -08:00
parent 6eeaf10691
commit cdea1086d6
2 changed files with 49 additions and 4 deletions

View File

@ -14,7 +14,6 @@
# under the License.
import abc
import functools
import random
import time
@ -55,7 +54,7 @@ class Timer(object):
self._start = None
def __call__(self, f):
@functools.wraps(f)
@six.wraps(f)
def wrapped(*args, **kwargs):
start = _time()
result = f(*args, **kwargs)
@ -117,7 +116,7 @@ class Counter(object):
self.sample_rate = sample_rate
def __call__(self, f):
@functools.wraps(f)
@six.wraps(f)
def wrapped(*args, **kwargs):
self.metrics.send_counter(
self.metrics.get_metric_name(self.name),
@ -164,7 +163,7 @@ class Gauge(object):
self.name = name
def __call__(self, f):
@functools.wraps(f)
@six.wraps(f)
def wrapped(*args, **kwargs):
result = f(*args, **kwargs)
self.metrics.send_gauge(self.metrics.get_metric_name(self.name),

View File

@ -16,17 +16,63 @@
import types
import mock
from oslo_utils import reflection
from ironic_lib import metrics as metricslib
from ironic_lib import metrics_utils
from ironic_lib.tests import base
METRICS = metrics_utils.get_metrics_logger(prefix='foo', backend='noop')
@METRICS.timer('testing1')
def timer_check(run, timer=None):
pass
@METRICS.counter('testing2')
def counter_check(run, counter=None):
pass
@METRICS.gauge('testing2')
def gauge_check(run, gauge=None):
pass
class MockedMetricLogger(metricslib.MetricLogger):
_gauge = mock.Mock(spec_set=types.FunctionType)
_counter = mock.Mock(spec_set=types.FunctionType)
_timer = mock.Mock(spec_set=types.FunctionType)
class TestMetricReflection(base.IronicLibTestCase):
def test_timer_reflection(self):
# Ensure our decorator is done correctly (six.wraps) and we can get the
# arguments of our decorated function.
expected = ['run', 'timer']
signature = reflection.get_signature(timer_check)
parameters = list(signature.parameters)
self.assertEqual(expected, parameters)
def test_counter_reflection(self):
# Ensure our decorator is done correctly (six.wraps) and we can get the
# arguments of our decorated function.
expected = ['run', 'counter']
signature = reflection.get_signature(counter_check)
parameters = list(signature.parameters)
self.assertEqual(expected, parameters)
def test_gauge_reflection(self):
# Ensure our decorator is done correctly (six.wraps) and we can get the
# arguments of our decorated function.
expected = ['run', 'gauge']
signature = reflection.get_signature(gauge_check)
parameters = list(signature.parameters)
self.assertEqual(expected, parameters)
class TestMetricLogger(base.IronicLibTestCase):
def setUp(self):
super(TestMetricLogger, self).setUp()