monasca-agent/monasca_agent/common/metrics.py
Jui Chandwaskar c983708637 Add Apache License
Added Apache 2.0 License for missed files

Change-Id: I72217d3cf0089434a9bbe1e5dfd57224a803704e
Signed-off-by: Jui Chandwaskar <jchandwaskar@op5.com>
2018-04-14 11:50:07 +00:00

152 lines
4.8 KiB
Python

# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
# 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.
""" Metric data types
"""
import logging
log = logging.getLogger(__name__)
class Metric(object):
"""A base metric class """
def __init__(self, name, dimensions, tenant):
self.metric = {'name': name,
'dimensions': dimensions.copy()}
self.value_meta = None
self.value = None
self.timestamp = None
self.tenant = tenant
def measurement(self, value, timestamp):
measurement = self.metric.copy()
if self.value_meta:
measurement['value_meta'] = self.value_meta.copy()
else:
measurement['value_meta'] = None
measurement['value'] = value
measurement['timestamp'] = timestamp * 1000
envelope = {'measurement': measurement,
'tenant_id': self.tenant}
return envelope
def sample(self, value, sample_rate, timestamp):
"""Save a sample. """
raise NotImplementedError()
def flush(self):
if self.timestamp is None:
return []
envelope = self.measurement(self.value, self.timestamp)
self.timestamp = None
self.value = None
return [envelope]
class Gauge(Metric):
"""A metric that tracks a value at particular points in time. """
def __init__(self, name, dimensions, tenant=None):
super(Gauge, self).__init__(name, dimensions, tenant)
def sample(self, value, sample_rate, timestamp):
self.value = value
self.timestamp = timestamp
class Counter(Metric):
"""A metric that tracks a counter value. """
def __init__(self, name, dimensions, tenant=None):
super(Counter, self).__init__(name, dimensions, tenant)
def sample(self, value, sample_rate, timestamp):
try:
inc = float(value) / sample_rate
if self.timestamp is None:
self.value = inc
else:
self.value += inc
self.timestamp = timestamp
except (TypeError, ValueError):
log.exception("illegal metric {} value {} sample_rate {}".
format(self.metric['name'], value, sample_rate))
# redefine flush method to make counter an integer when sample rates <> 1.0 used
def flush(self):
if self.timestamp:
self.value = int(self.value)
return super(Counter, self).flush()
else:
return []
class Rate(Metric):
"""Track the rate of metrics over each flush interval """
def __init__(self, name, dimensions, tenant=None):
super(Rate, self).__init__(name, dimensions, tenant)
self.start_value = None
self.start_timestamp = None
def sample(self, value, sample_rate, timestamp):
# set first value if missing
if self.start_timestamp is None:
self.start_timestamp = timestamp
self.start_value = value
# set second value otherwise
else:
self.timestamp = timestamp
self.value = value
# redefine flush method to calculate rate from metrics
def flush(self):
# need at least two timestamps to determine rate
# is the second one is missing then the first is kept as start value for
# the subsequent interval
if self.start_timestamp is None or self.timestamp is None:
return []
delta_t = self.timestamp - self.start_timestamp
delta_v = self.value - self.start_value
try:
rate = delta_v / float(delta_t)
except ZeroDivisionError:
log.warning(
'Conflicting values reported for metric %s with dimensions %s at time %d: (%f, %f)',
self.metric['name'],
self.metric['dimensions'],
self.timestamp,
self.start_value,
self.value)
# skip this measurement, but keep value for next cycle
self.start_value = self.value
return []
# make it start value for next interval (even if it is None!)
self.start_value = self.value
self.start_timestamp = self.timestamp
envelope = self.measurement(rate, self.timestamp)
self.timestamp = None
self.value = None
return [envelope]