Merge "timedelta plugin for meter definition process"
This commit is contained in:
commit
ec4848b9f0
@ -17,6 +17,7 @@ import abc
|
||||
|
||||
from debtcollector import moves
|
||||
from oslo_log import log
|
||||
from oslo_utils import timeutils
|
||||
import six
|
||||
|
||||
from ceilometer.i18n import _LW
|
||||
@ -188,3 +189,42 @@ class BitfieldTraitPlugin(TraitPluginBase):
|
||||
else:
|
||||
bitfield |= bit
|
||||
return [bitfield]
|
||||
|
||||
|
||||
class TimedeltaPluginMissedFields(Exception):
|
||||
def __init__(self):
|
||||
msg = ('It is required to use two timestamp field with Timedelta '
|
||||
'plugin.')
|
||||
super(TimedeltaPluginMissedFields, self).__init__(msg)
|
||||
|
||||
|
||||
class TimedeltaPlugin(TraitPluginBase):
|
||||
"""Setup timedelta meter volume of two timestamps fields.
|
||||
|
||||
Example::
|
||||
|
||||
trait's fields definition: ['payload.created_at',
|
||||
'payload.launched_at']
|
||||
value is been created as total seconds between 'launched_at' and
|
||||
'created_at' timestamps.
|
||||
"""
|
||||
# TODO(idegtiarov): refactor code to have meter_plugins separate from
|
||||
# trait_plugins
|
||||
|
||||
def trait_value(self, match_list):
|
||||
if len(match_list) != 2:
|
||||
LOG.warning(_LW('Timedelta plugin is required two timestamp fields'
|
||||
' to create timedelta value.'))
|
||||
return
|
||||
start, end = match_list
|
||||
try:
|
||||
start_time = timeutils.parse_isotime(start[1])
|
||||
end_time = timeutils.parse_isotime(end[1])
|
||||
except Exception as err:
|
||||
LOG.warning(_LW('Failed to parse date from set fields, both '
|
||||
'fields %(start)s and %(end)s must be datetime: '
|
||||
'%(err)s') %
|
||||
dict(start=start[0], end=end[0], err=err)
|
||||
)
|
||||
return
|
||||
return abs((end_time - start_time).total_seconds())
|
||||
|
@ -107,6 +107,16 @@ metric:
|
||||
project_id: $.payload.tenant_id
|
||||
resource_id: $.payload.instance_id
|
||||
|
||||
- name: 'compute.instance.booting.time'
|
||||
event_type: 'compute.instance.create.end'
|
||||
type: 'gauge'
|
||||
unit: 'sec'
|
||||
volume:
|
||||
fields: [$.payload.created_at, $.payload.launched_at]
|
||||
plugin: 'timedelta'
|
||||
project_id: $.payload.tenant_id
|
||||
resource_id: $.payload.instance_id
|
||||
|
||||
- name: 'disk.root.size'
|
||||
event_type: 'compute.instance.*'
|
||||
type: 'gauge'
|
||||
|
71
ceilometer/tests/unit/meter/test_meter_plugins.py
Normal file
71
ceilometer/tests/unit/meter/test_meter_plugins.py
Normal file
@ -0,0 +1,71 @@
|
||||
#
|
||||
# Copyright 2016 Mirantis Inc.
|
||||
#
|
||||
# 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 mock
|
||||
from oslotest import base
|
||||
|
||||
from ceilometer.event import trait_plugins
|
||||
|
||||
|
||||
class TestTimedeltaPlugin(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestTimedeltaPlugin, self).setUp()
|
||||
self.plugin = trait_plugins.TimedeltaPlugin()
|
||||
|
||||
def test_timedelta_transformation(self):
|
||||
match_list = [('test.timestamp1', '2016-03-02T15:04:32'),
|
||||
('test.timestamp2', '2016-03-02T16:04:32')]
|
||||
value = self.plugin.trait_value(match_list)
|
||||
self.assertEqual(3600, value)
|
||||
|
||||
def test_timedelta_missing_field(self):
|
||||
match_list = [('test.timestamp1', '2016-03-02T15:04:32')]
|
||||
with mock.patch('%s.LOG' % self.plugin.trait_value.__module__) as log:
|
||||
self.assertIsNone(self.plugin.trait_value(match_list))
|
||||
log.warning.assert_called_once_with(
|
||||
'Timedelta plugin is required two timestamp fields to create '
|
||||
'timedelta value.')
|
||||
|
||||
def test_timedelta_exceed_field(self):
|
||||
match_list = [('test.timestamp1', '2016-03-02T15:04:32'),
|
||||
('test.timestamp2', '2016-03-02T16:04:32'),
|
||||
('test.timestamp3', '2016-03-02T16:10:32')]
|
||||
with mock.patch('%s.LOG' % self.plugin.trait_value.__module__) as log:
|
||||
self.assertIsNone(self.plugin.trait_value(match_list))
|
||||
log.warning.assert_called_once_with(
|
||||
'Timedelta plugin is required two timestamp fields to create '
|
||||
'timedelta value.')
|
||||
|
||||
def test_timedelta_invalid_timestamp(self):
|
||||
match_list = [('test.timestamp1', '2016-03-02T15:04:32'),
|
||||
('test.timestamp2', '2016-03-02T15:004:32')]
|
||||
with mock.patch('%s.LOG' % self.plugin.trait_value.__module__) as log:
|
||||
self.assertIsNone(self.plugin.trait_value(match_list))
|
||||
msg = log.warning._mock_call_args[0][0]
|
||||
self.assertTrue(msg.startswith('Failed to parse date from set '
|
||||
'fields, both fields ')
|
||||
)
|
||||
|
||||
def test_timedelta_reverse_timestamp_order(self):
|
||||
match_list = [('test.timestamp1', '2016-03-02T15:15:32'),
|
||||
('test.timestamp2', '2016-03-02T15:10:32')]
|
||||
value = self.plugin.trait_value(match_list)
|
||||
self.assertEqual(300, value)
|
||||
|
||||
def test_timedelta_precise_difference(self):
|
||||
match_list = [('test.timestamp1', '2016-03-02T15:10:32.786893'),
|
||||
('test.timestamp2', '2016-03-02T15:10:32.786899')]
|
||||
value = self.plugin.trait_value(match_list)
|
||||
self.assertEqual(0.000006, value)
|
@ -33,7 +33,9 @@ NOTIFICATION = {
|
||||
'timestamp': u'2015-06-1909: 19: 35.786893',
|
||||
'payload': {u'user_id': u'e1d870e51c7340cb9d555b15cbfcaec2',
|
||||
u'resource_id': u'bea70e51c7340cb9d555b15cbfcaec23',
|
||||
u'timestamp': u'2015-06-19T09: 19: 35.785330',
|
||||
u'timestamp': u'2015-06-19T09:19:35.785330',
|
||||
u'created_at': u'2015-06-19T09:25:35.785330',
|
||||
u'launched_at': u'2015-06-19T09:25:40.785330',
|
||||
u'message_signature': u'fake_signature1',
|
||||
u'resource_metadata': {u'foo': u'bar'},
|
||||
u'source': u'30be1fc9a03c4e94ab05c403a8a377f2: openstack',
|
||||
@ -455,6 +457,23 @@ class TestMeterProcessing(test.BaseTestCase):
|
||||
meta['event_type'] = NOTIFICATION['event_type']
|
||||
self.assertEqual(meta, s1['resource_metadata'])
|
||||
|
||||
def test_datetime_plugin(self):
|
||||
cfg = yaml.dump(
|
||||
{'metric': [dict(name="test1",
|
||||
event_type="test.*",
|
||||
type="gauge",
|
||||
unit="sec",
|
||||
volume={"fields": ["$.payload.created_at",
|
||||
"$.payload.launched_at"],
|
||||
"plugin": "timedelta"},
|
||||
resource_id="$.payload.resource_id",
|
||||
project_id="$.payload.project_id")]})
|
||||
self._load_meter_def_file(cfg)
|
||||
c = list(self.handler.process_notification(NOTIFICATION))
|
||||
self.assertEqual(1, len(c))
|
||||
s1 = c[0].as_dict()
|
||||
self.assertEqual(5.0, s1['volume'])
|
||||
|
||||
def test_custom_metadata(self):
|
||||
cfg = yaml.dump(
|
||||
{'metric': [dict(name="test1",
|
||||
|
@ -237,6 +237,8 @@ ceilometer.event.publisher =
|
||||
ceilometer.event.trait_plugin =
|
||||
split = ceilometer.event.trait_plugins:SplitterTraitPlugin
|
||||
bitfield = ceilometer.event.trait_plugins:BitfieldTraitPlugin
|
||||
timedelta = ceilometer.event.trait_plugins:TimedeltaPlugin
|
||||
|
||||
|
||||
console_scripts =
|
||||
ceilometer-api = ceilometer.cmd.api:main
|
||||
|
Loading…
Reference in New Issue
Block a user