public void AddMetric(StatsdMetric metric) { string key = metric.Type + "_" + metric.Name; lock (_lock) { StatsdMetric oldMetric; if (_metrics.TryGetValue(key, out oldMetric)) { //merge double val = metric.Value; oldMetric.AddValue(val); } else { _metrics[key] = metric; } } }
/* * StatsD metric collection protocol * - metrics are separated by newlines * - each line ar generally of the form: * <metric name>:<value>|<type> * ** Gauges : <metric name>:<value>|g * ** Counters : <metric name>:<value>|c[|@<sample rate>] * ** Timers : <metric name>:<value>|ms * ** Sets : <metric name>:<value>|s */ public static StatsdMetric ParseLine(string line) { const string pattern = @"^(?<name>.*):(?<value>.*)\|(?<type>.*)(\|\@(?<rate>.*))?$"; var regex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.RightToLeft); Match match = regex.Match(line); if (!match.Success) { Logger.Debug("Parser: Invalid statsd format [{0}]", line); return (null); } GroupCollection groups = match.Groups; string name = groups["name"].Value; string valstr = groups["value"].Value; string typestr = groups["type"].Value; string ratestr = groups["rate"].Value; if (String.IsNullOrEmpty(name) || String.IsNullOrEmpty(valstr) || String.IsNullOrEmpty(typestr)) { Logger.Debug("Parser: name/value/type are not optional [{0}]", line); return (null); } StatsdMetric.StatsdType type; if (String.Compare(typestr, "g", StringComparison.OrdinalIgnoreCase) == 0) type = StatsdMetric.StatsdType.StatsdGauge; else if (String.Compare(typestr, "c", StringComparison.OrdinalIgnoreCase) == 0) type = StatsdMetric.StatsdType.StatsdCounter; else if (String.Compare(typestr, "s", StringComparison.OrdinalIgnoreCase) == 0) type = StatsdMetric.StatsdType.StatsdSet; else if (String.Compare(typestr, "ms", StringComparison.OrdinalIgnoreCase) == 0) type = StatsdMetric.StatsdType.StatsdTimer; else { Logger.Debug("Parser: invalid type [{0}]", line); return (null); } double value; try { value = Convert.ToDouble(valstr); } catch (Exception) { Logger.Debug("Parser: invalid value [{0}]", line); return (null); } double rate = 0; try { if (!String.IsNullOrEmpty(ratestr)) rate = Convert.ToDouble(ratestr); } catch (Exception) { Logger.Debug("Parser: invalid rate [{0}]", line); return (null); } if (!string.IsNullOrEmpty(ratestr) && (rate <= 0 || rate > 1)) { Logger.Debug("Parser: invalid rate range [{0}]", line); return (null); } if (!string.IsNullOrEmpty(ratestr) && type != StatsdMetric.StatsdType.StatsdCounter) { Logger.Debug("Parser: rate is supported only for Counters [{0}]", line); return (null); } if (!string.IsNullOrEmpty(ratestr)) { value = value/rate; } var metric = new StatsdMetric(name, type, value); return (metric); }
public IList <MetricValue> Read() { lock (_lock) { var res = new List <MetricValue>(); var removeList = new List <string>(); foreach (var pair in _metrics) { StatsdMetric metric = pair.Value; if (metric.NumUpdates <= 0 && ((_delCounter && metric.Type == StatsdMetric.StatsdType.StatsdCounter) || (_delTimer && metric.Type == StatsdMetric.StatsdType.StatsdTimer) || (_delGauge && metric.Type == StatsdMetric.StatsdType.StatsdGauge) || (_delSet && metric.Type == StatsdMetric.StatsdType.StatsdSet))) { removeList.Add(pair.Key); continue; } var metricVal = new MetricValue { HostName = _hostName, PluginName = "statsd", PluginInstanceName = "", TypeInstanceName = metric.Name, Values = new[] { metric.GetMetric() } }; switch (metric.Type) { case StatsdMetric.StatsdType.StatsdGauge: metricVal.TypeName = "gauge"; break; case StatsdMetric.StatsdType.StatsdTimer: metricVal.TypeName = "latency"; metricVal.TypeInstanceName += "-average"; break; case StatsdMetric.StatsdType.StatsdSet: metricVal.TypeName = "objects"; break; default: metricVal.TypeName = "derive"; break; } TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1); double epoch = t.TotalMilliseconds / 1000; metricVal.Epoch = Math.Round(epoch, 3); res.Add(metricVal); if (metric.Type == StatsdMetric.StatsdType.StatsdTimer) { if (_timerLower) { MetricValue lowerValue = metricVal.DeepCopy(); lowerValue.TypeInstanceName = metric.Name + "-lower"; lowerValue.Values[0] = metric.Lat.Min; res.Add(lowerValue); } if (_timerUpper) { MetricValue upperValue = metricVal.DeepCopy(); upperValue.TypeInstanceName = metric.Name + "-upper"; upperValue.Values[0] = metric.Lat.Max; res.Add(upperValue); } if (_timerSum) { MetricValue upperSum = metricVal.DeepCopy(); upperSum.TypeInstanceName = metric.Name + "-Sum"; upperSum.Values[0] = metric.Lat.Sum; res.Add(upperSum); } if (_timerCount) { MetricValue upperCount = metricVal.DeepCopy(); upperCount.TypeInstanceName = metric.Name + "-count"; upperCount.Values[0] = metric.Lat.Num; res.Add(upperCount); } Histogram histogram = metric.Lat.Histogram; if (_percentiles != null && _percentiles.Length > 0 && histogram != null) { foreach (float percentile in _percentiles) { double val = histogram.GetPercentile(percentile); MetricValue mv = metricVal.DeepCopy(); mv.TypeInstanceName = metric.Name + "-percentile-" + percentile; mv.Values[0] = val; res.Add(mv); } } } metric.Reset(); } Logger.Debug("Removing entries that were not updated:{0}", removeList.Count); foreach (string key in removeList) { _metrics.Remove(key); } return(res); } }
/* * StatsD metric collection protocol * - metrics are separated by newlines * - each line ar generally of the form: * <metric name>:<value>|<type> * ** Gauges : <metric name>:<value>|g * ** Counters : <metric name>:<value>|c[|@<sample rate>] * ** Timers : <metric name>:<value>|ms * ** Sets : <metric name>:<value>|s */ public static StatsdMetric ParseLine(string line) { const string pattern = @"^(?<name>.*):(?<value>.*)\|(?<type>.*)(\|\@(?<rate>.*))?$"; var regex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.RightToLeft); Match match = regex.Match(line); if (!match.Success) { Logger.Debug("Parser: Invalid statsd format [{0}]", line); return(null); } GroupCollection groups = match.Groups; string name = groups["name"].Value; string valstr = groups["value"].Value; string typestr = groups["type"].Value; string ratestr = groups["rate"].Value; if (String.IsNullOrEmpty(name) || String.IsNullOrEmpty(valstr) || String.IsNullOrEmpty(typestr)) { Logger.Debug("Parser: name/value/type are not optional [{0}]", line); return(null); } StatsdMetric.StatsdType type; if (String.Compare(typestr, "g", StringComparison.OrdinalIgnoreCase) == 0) { type = StatsdMetric.StatsdType.StatsdGauge; } else if (String.Compare(typestr, "c", StringComparison.OrdinalIgnoreCase) == 0) { type = StatsdMetric.StatsdType.StatsdCounter; } else if (String.Compare(typestr, "s", StringComparison.OrdinalIgnoreCase) == 0) { type = StatsdMetric.StatsdType.StatsdSet; } else if (String.Compare(typestr, "ms", StringComparison.OrdinalIgnoreCase) == 0) { type = StatsdMetric.StatsdType.StatsdTimer; } else { Logger.Debug("Parser: invalid type [{0}]", line); return(null); } double value; try { value = Convert.ToDouble(valstr); } catch (Exception) { Logger.Debug("Parser: invalid value [{0}]", line); return(null); } double rate = 0; try { if (!String.IsNullOrEmpty(ratestr)) { rate = Convert.ToDouble(ratestr); } } catch (Exception) { Logger.Debug("Parser: invalid rate [{0}]", line); return(null); } if (!string.IsNullOrEmpty(ratestr) && (rate <= 0 || rate > 1)) { Logger.Debug("Parser: invalid rate range [{0}]", line); return(null); } if (!string.IsNullOrEmpty(ratestr) && type != StatsdMetric.StatsdType.StatsdCounter) { Logger.Debug("Parser: rate is supported only for Counters [{0}]", line); return(null); } if (!string.IsNullOrEmpty(ratestr)) { value = value / rate; } var metric = new StatsdMetric(name, type, value); return(metric); }