support custom metadata
this patch allows us to define metadata rather than blindly capturing entire payload. Change-Id: Id445f7f6d1231f8fdfddb43389783142190db662
This commit is contained in:
parent
e8929f3e18
commit
d836f8f54a
|
@ -76,6 +76,13 @@ class MeterDefinition(object):
|
||||||
continue
|
continue
|
||||||
elif isinstance(field, six.integer_types):
|
elif isinstance(field, six.integer_types):
|
||||||
self._field_getter[name] = field
|
self._field_getter[name] = field
|
||||||
|
elif isinstance(field, dict) and name == 'metadata':
|
||||||
|
meta = {}
|
||||||
|
for key, val in field.items():
|
||||||
|
parts = self.parse_jsonpath(val)
|
||||||
|
meta[key] = functools.partial(self._parse_jsonpath_field,
|
||||||
|
parts)
|
||||||
|
self._field_getter['metadata'] = meta
|
||||||
else:
|
else:
|
||||||
parts = self.parse_jsonpath(field)
|
parts = self.parse_jsonpath(field)
|
||||||
self._field_getter[name] = functools.partial(
|
self._field_getter[name] = functools.partial(
|
||||||
|
@ -100,6 +107,11 @@ class MeterDefinition(object):
|
||||||
getter = self._field_getter.get(field)
|
getter = self._field_getter.get(field)
|
||||||
if not getter:
|
if not getter:
|
||||||
return
|
return
|
||||||
|
elif isinstance(getter, dict):
|
||||||
|
dict_val = {}
|
||||||
|
for key, val in getter.items():
|
||||||
|
dict_val[key] = val(message, all_values)
|
||||||
|
return dict_val
|
||||||
elif callable(getter):
|
elif callable(getter):
|
||||||
return getter(message, all_values)
|
return getter(message, all_values)
|
||||||
else:
|
else:
|
||||||
|
@ -232,6 +244,7 @@ class ProcessMeterNotifications(plugin_base.NotificationBase):
|
||||||
projectid = self.get_project_id(d, notification_body)
|
projectid = self.get_project_id(d, notification_body)
|
||||||
resourceid = d.parse_fields('resource_id', notification_body)
|
resourceid = d.parse_fields('resource_id', notification_body)
|
||||||
ts = d.parse_fields('timestamp', notification_body)
|
ts = d.parse_fields('timestamp', notification_body)
|
||||||
|
metadata = d.parse_fields('metadata', notification_body)
|
||||||
if d.cfg.get('lookup'):
|
if d.cfg.get('lookup'):
|
||||||
meters = d.parse_fields('name', notification_body, True)
|
meters = d.parse_fields('name', notification_body, True)
|
||||||
if not meters: # skip if no meters in payload
|
if not meters: # skip if no meters in payload
|
||||||
|
@ -265,7 +278,8 @@ class ProcessMeterNotifications(plugin_base.NotificationBase):
|
||||||
yield sample.Sample.from_notification(
|
yield sample.Sample.from_notification(
|
||||||
name=m, type=t, unit=unit, volume=v,
|
name=m, type=t, unit=unit, volume=v,
|
||||||
resource_id=r, user_id=user, project_id=p,
|
resource_id=r, user_id=user, project_id=p,
|
||||||
message=notification_body, timestamp=ts)
|
message=notification_body, timestamp=ts,
|
||||||
|
metadata=metadata)
|
||||||
else:
|
else:
|
||||||
yield sample.Sample.from_notification(
|
yield sample.Sample.from_notification(
|
||||||
name=d.cfg['name'],
|
name=d.cfg['name'],
|
||||||
|
@ -276,7 +290,7 @@ class ProcessMeterNotifications(plugin_base.NotificationBase):
|
||||||
user_id=userid,
|
user_id=userid,
|
||||||
project_id=projectid,
|
project_id=projectid,
|
||||||
message=notification_body,
|
message=notification_body,
|
||||||
timestamp=ts)
|
timestamp=ts, metadata=metadata)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_user_id(d, notification_body):
|
def get_user_id(d, notification_body):
|
||||||
|
|
|
@ -82,11 +82,12 @@ class Sample(object):
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_notification(cls, name, type, volume, unit,
|
def from_notification(cls, name, type, volume, unit,
|
||||||
user_id, project_id, resource_id,
|
user_id, project_id, resource_id,
|
||||||
message, timestamp=None, source=None):
|
message, timestamp=None, metadata=None, source=None):
|
||||||
metadata = (copy.copy(message['payload'])
|
if not metadata:
|
||||||
if isinstance(message['payload'], dict) else {})
|
metadata = (copy.copy(message['payload'])
|
||||||
metadata['event_type'] = message['event_type']
|
if isinstance(message['payload'], dict) else {})
|
||||||
metadata['host'] = message['publisher_id']
|
metadata['event_type'] = message['event_type']
|
||||||
|
metadata['host'] = message['publisher_id']
|
||||||
ts = timestamp if timestamp else message['timestamp']
|
ts = timestamp if timestamp else message['timestamp']
|
||||||
return cls(name=name,
|
return cls(name=name,
|
||||||
type=type,
|
type=type,
|
||||||
|
|
|
@ -349,13 +349,13 @@ class TestMeterProcessing(test.BaseTestCase):
|
||||||
event = copy.deepcopy(MIDDLEWARE_EVENT)
|
event = copy.deepcopy(MIDDLEWARE_EVENT)
|
||||||
del event['payload']['measurements'][1]
|
del event['payload']['measurements'][1]
|
||||||
cfg = yaml.dump(
|
cfg = yaml.dump(
|
||||||
{'metric': [dict(name="payload.measurements.[*].metric.[*].name",
|
{'metric': [dict(name="$.payload.measurements.[*].metric.[*].name",
|
||||||
event_type="objectstore.http.request",
|
event_type="objectstore.http.request",
|
||||||
type="delta",
|
type="delta",
|
||||||
unit="payload.measurements.[*].metric.[*].unit",
|
unit="$.payload.measurements.[*].metric.[*].unit",
|
||||||
volume="payload.measurements.[*].result",
|
volume="$.payload.measurements.[*].result",
|
||||||
resource_id="payload.target_id",
|
resource_id="$.payload.target_id",
|
||||||
project_id="payload.initiator.project_id",
|
project_id="$.payload.initiator.project_id",
|
||||||
multi="name")]})
|
multi="name")]})
|
||||||
self.handler.definitions = notifications.load_definitions(
|
self.handler.definitions = notifications.load_definitions(
|
||||||
self.__setup_meter_def_file(cfg))
|
self.__setup_meter_def_file(cfg))
|
||||||
|
@ -368,15 +368,15 @@ class TestMeterProcessing(test.BaseTestCase):
|
||||||
event = copy.deepcopy(MIDDLEWARE_EVENT)
|
event = copy.deepcopy(MIDDLEWARE_EVENT)
|
||||||
del event['payload']['measurements'][1]
|
del event['payload']['measurements'][1]
|
||||||
cfg = yaml.dump(
|
cfg = yaml.dump(
|
||||||
{'metric': [dict(name="payload.measurements.[*].metric.[*].name",
|
{'metric': [dict(name="$.payload.measurements.[*].metric.[*].name",
|
||||||
event_type="objectstore.http.request",
|
event_type="objectstore.http.request",
|
||||||
type="delta",
|
type="delta",
|
||||||
unit="payload.measurements.[*].metric.[*].unit",
|
unit="$.payload.measurements.[*].metric.[*].unit",
|
||||||
volume="payload.measurements.[*].result",
|
volume="$.payload.measurements.[*].result",
|
||||||
resource_id="payload.target_id",
|
resource_id="$.payload.target_id",
|
||||||
project_id="payload.initiator.project_id",
|
project_id="$.payload.initiator.project_id",
|
||||||
multi="name",
|
multi="name",
|
||||||
timestamp='payload.eventTime')]})
|
timestamp='$.payload.eventTime')]})
|
||||||
self.handler.definitions = notifications.load_definitions(
|
self.handler.definitions = notifications.load_definitions(
|
||||||
self.__setup_meter_def_file(cfg))
|
self.__setup_meter_def_file(cfg))
|
||||||
c = list(self.handler.process_notification(event))
|
c = list(self.handler.process_notification(event))
|
||||||
|
@ -385,6 +385,45 @@ class TestMeterProcessing(test.BaseTestCase):
|
||||||
self.assertEqual(MIDDLEWARE_EVENT['payload']['eventTime'],
|
self.assertEqual(MIDDLEWARE_EVENT['payload']['eventTime'],
|
||||||
s1['timestamp'])
|
s1['timestamp'])
|
||||||
|
|
||||||
|
def test_default_metadata(self):
|
||||||
|
cfg = yaml.dump(
|
||||||
|
{'metric': [dict(name="test1",
|
||||||
|
event_type="test.*",
|
||||||
|
type="delta",
|
||||||
|
unit="B",
|
||||||
|
volume="$.payload.volume",
|
||||||
|
resource_id="$.payload.resource_id",
|
||||||
|
project_id="$.payload.project_id")]})
|
||||||
|
self.handler.definitions = notifications.load_definitions(
|
||||||
|
self.__setup_meter_def_file(cfg))
|
||||||
|
c = list(self.handler.process_notification(NOTIFICATION))
|
||||||
|
self.assertEqual(1, len(c))
|
||||||
|
s1 = c[0].as_dict()
|
||||||
|
meta = NOTIFICATION['payload'].copy()
|
||||||
|
meta['host'] = NOTIFICATION['publisher_id']
|
||||||
|
meta['event_type'] = NOTIFICATION['event_type']
|
||||||
|
self.assertEqual(meta, s1['resource_metadata'])
|
||||||
|
|
||||||
|
def test_custom_metadata(self):
|
||||||
|
cfg = yaml.dump(
|
||||||
|
{'metric': [dict(name="test1",
|
||||||
|
event_type="test.*",
|
||||||
|
type="delta",
|
||||||
|
unit="B",
|
||||||
|
volume="$.payload.volume",
|
||||||
|
resource_id="$.payload.resource_id",
|
||||||
|
project_id="$.payload.project_id",
|
||||||
|
metadata={'proj': '$.payload.project_id',
|
||||||
|
'dict': '$.payload.resource_metadata'})]})
|
||||||
|
self.handler.definitions = notifications.load_definitions(
|
||||||
|
self.__setup_meter_def_file(cfg))
|
||||||
|
c = list(self.handler.process_notification(NOTIFICATION))
|
||||||
|
self.assertEqual(1, len(c))
|
||||||
|
s1 = c[0].as_dict()
|
||||||
|
meta = {'proj': s1['project_id'],
|
||||||
|
'dict': NOTIFICATION['payload']['resource_metadata']}
|
||||||
|
self.assertEqual(meta, s1['resource_metadata'])
|
||||||
|
|
||||||
def test_multi_match_event_meter(self):
|
def test_multi_match_event_meter(self):
|
||||||
cfg = yaml.dump(
|
cfg = yaml.dump(
|
||||||
{'metric': [dict(name="test1",
|
{'metric': [dict(name="test1",
|
||||||
|
|
Loading…
Reference in New Issue