public void Aggregate(ref MetricValue metricValue)
{
// If rates are not stored then there is nothing to aggregate
if (!_storeRates)
{
return;
}
IList <DataSource> dsl = DataSetCollection.Instance.GetDataSource(metricValue.TypeName);
if (dsl == null || metricValue.Values.Length != dsl.Count)
{
return;
}
double now = Util.GetNow();
lock (_cacheLock)
{
CacheEntry cEntry;
string key = metricValue.Key();
if (!(_cache.TryGetValue(key, out cEntry)))
{
cEntry = new CacheEntry(metricValue.DeepCopy());
for (int i = 0; i < metricValue.Values.Length; i++)
{
if (dsl[i].Type == DsType.Derive ||
dsl[i].Type == DsType.Absolute ||
dsl[i].Type == DsType.Counter)
{
metricValue.Values[i] = double.NaN;
cEntry.MetricRate.Values[i] = double.NaN;
}
}
cEntry.MetricRate.Epoch = now;
_cache[key] = cEntry;
return;
}
for (int i = 0; i < metricValue.Values.Length; i++)
{
double rawValNew = metricValue.Values[i];
double rawValOld = cEntry.RawValues[i];
double rawValDiff = rawValNew - rawValOld;
double timeDiff = cEntry.MetricRate.Epoch - now;
double rateNew = rawValDiff / timeDiff;
switch (dsl[i].Type)
{
case DsType.Gauge:
// no rates calculations are done, values are stored as-is for gauge
cEntry.RawValues[i] = rawValNew;
cEntry.MetricRate.Values[i] = rawValNew;
break;
case DsType.Absolute:
// similar to gauge, except value will be divided by time diff
cEntry.MetricRate.Values[i] = metricValue.Values[i] / timeDiff;
cEntry.RawValues[i] = rawValNew;
metricValue.Values[i] = cEntry.MetricRate.Values[i];
break;
case DsType.Derive:
cEntry.RawValues[i] = rawValNew;
cEntry.MetricRate.Values[i] = rateNew;
metricValue.Values[i] = rateNew;
break;
case DsType.Counter:
// Counters are very simlar to derive except when counter wraps around
if (rawValNew < rawValOld)
{
// counter has wrapped around
cEntry.MetricRate.Values[i] = metricValue.Values[i] / timeDiff;
cEntry.RawValues[i] = rawValNew;
metricValue.Values[i] = cEntry.MetricRate.Values[i];
}
else
{
cEntry.MetricRate.Values[i] = rateNew;
cEntry.RawValues[i] = rawValNew;
metricValue.Values[i] = rateNew;
}
break;
}
// range checks
if (metricValue.Values[i] < dsl[i].Min)
{
metricValue.Values[i] = dsl[i].Min;
cEntry.RawValues[i] = metricValue.Values[i];
}
if (metricValue.Values[i] > dsl[i].Max)
{
metricValue.Values[i] = dsl[i].Max;
cEntry.RawValues[i] = metricValue.Values[i];
}
cEntry.MetricRate.Epoch = now;
_cache[key] = cEntry;
}
}
}