lib/sync-metrics.js
function(metric, records) {
  var returnValue = {message: 'no stats available', name: metric.displayName};
  if (records && records.length > 0) {
    returnValue = _.chain(records).map(function(recordStr) {
      return JSON.parse(recordStr);
    }).groupBy(function(record) {
      return record.tags[metric.groupByTag];
    }).reduce(function(reduced, groupRecords, groupKey) {
      groupRecords = _.sortBy(groupRecords, 'ts');
      var processedData = _.reduce(groupRecords, function(memo, groupRecord) {
        var value = groupRecord.fields[metric.valueField];
        memo.current = value;
        memo.numberOfRecords++;
        memo.total += value;
        memo.max = Math.max(value, memo.max);
        memo.min = Math.min(value, memo.min);
        memo.from = Math.min(groupRecord.ts, memo.from);
        memo.end = Math.max(groupRecord.ts, memo.end);
        return memo;
      }, {max: 0, min: MAX_NUMBER, current: 0, numberOfRecords: 0, total: 0, from: MAX_NUMBER, end: 0});
      reduced[groupKey] = {
        current: metric.dataFormatter(processedData.current),
        max: metric.dataFormatter(processedData.max),
        min: metric.dataFormatter(processedData.min),
        average: metric.dataFormatter(processedData.total / processedData.numberOfRecords),
        numberOfRecords: processedData.numberOfRecords,
        from: new Date(processedData.from).toISOString(),
        end: new Date(processedData.end).toISOString()
      };
      return reduced;
    }, {}).value();
  }
  return returnValue;
}
function(metric, records) {
  var returnValue = {message: 'no stats available', name: metric.displayName};
  if (records && records.length > 0) {
    returnValue = _.chain(records).map(function(recordStr) {
      return JSON.parse(recordStr);
    }).groupBy(function(record) {
      return record.tags[metric.groupByTag];
    }).reduce(function(reduced, groupRecords, groupKey) {
      groupRecords = _.sortBy(groupRecords, 'ts');
      var processedData = _.reduce(groupRecords, function(memo, groupRecord) {
        var value = groupRecord.fields[metric.valueField];
        memo.current = value;
        memo.numberOfRecords++;
        memo.total += value;
        memo.max = Math.max(value, memo.max);
        memo.min = Math.min(value, memo.min);
        memo.from = Math.min(groupRecord.ts, memo.from);
        memo.end = Math.max(groupRecord.ts, memo.end);
        return memo;
      }, {max: 0, min: MAX_NUMBER, current: 0, numberOfRecords: 0, total: 0, from: MAX_NUMBER, end: 0});
      reduced[groupKey] = {
        current: metric.dataFormatter(processedData.current),
        max: metric.dataFormatter(processedData.max),
        min: metric.dataFormatter(processedData.min),
        average: metric.dataFormatter(processedData.total / processedData.numberOfRecords),
        numberOfRecords: processedData.numberOfRecords,
        from: new Date(processedData.from).toISOString(),
        end: new Date(processedData.end).toISOString()
      };
      return reduced;
    }, {}).value();
  }
  return returnValue;
}
Compute the max, min, current, average values from the records
@param {Object} metric some meta data about the metric
@param {Array} records