PageRenderTime 39ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/metrics/src/main/java/org/springside/modules/metrics/reporter/GraphiteReporter.java

http://github.com/springside/springside4
Java | 219 lines | 172 code | 38 blank | 9 comment | 25 complexity | b50e48c6e37f7e2f44dd2565822a8573 MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright (c) 2005, 2014 springside.github.io
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. *******************************************************************************/
  6. package org.springside.modules.metrics.reporter;
  7. import java.io.BufferedWriter;
  8. import java.io.IOException;
  9. import java.io.OutputStreamWriter;
  10. import java.io.Writer;
  11. import java.net.InetSocketAddress;
  12. import java.net.Socket;
  13. import java.nio.charset.Charset;
  14. import java.util.Locale;
  15. import java.util.Map;
  16. import java.util.Map.Entry;
  17. import java.util.regex.Pattern;
  18. import javax.net.SocketFactory;
  19. import org.slf4j.Logger;
  20. import org.slf4j.LoggerFactory;
  21. import org.springside.modules.metrics.MetricRegistry;
  22. import org.springside.modules.metrics.Reporter;
  23. import org.springside.modules.metrics.metric.Counter;
  24. import org.springside.modules.metrics.metric.CounterMetric;
  25. import org.springside.modules.metrics.metric.Gauge;
  26. import org.springside.modules.metrics.metric.Histogram;
  27. import org.springside.modules.metrics.metric.HistogramMetric;
  28. import org.springside.modules.metrics.metric.Timer;
  29. import org.springside.modules.metrics.metric.TimerMetric;
  30. /**
  31. * 输出到Graphite.
  32. */
  33. public class GraphiteReporter implements Reporter {
  34. public static final String DEFAULT_PREFIX = "metrics";
  35. private static final Pattern WHITESPACE = Pattern.compile("[\\s]+");
  36. private static final Charset UTF_8 = Charset.forName("UTF-8");
  37. private static Logger logger = LoggerFactory.getLogger(GraphiteReporter.class);
  38. private String prefix;
  39. private InetSocketAddress address;
  40. private SocketFactory socketFactory;
  41. private Socket socket;
  42. private Writer writer;
  43. // use to only print connection error message once.
  44. private GraphiteConnStatus graphiteConnStatus = GraphiteConnStatus.CONN_OK;
  45. public GraphiteReporter(InetSocketAddress address) {
  46. this(address, DEFAULT_PREFIX);
  47. }
  48. public GraphiteReporter(InetSocketAddress address, String prefix) {
  49. this.prefix = prefix;
  50. this.address = address;
  51. this.socketFactory = SocketFactory.getDefault();
  52. }
  53. @Override
  54. public void report(Map<String, Gauge> gauges, Map<String, Counter> counters, Map<String, Histogram> histograms,
  55. Map<String, Timer> timers) {
  56. try {
  57. connect();
  58. long timestamp = System.currentTimeMillis() / 1000;
  59. for (Map.Entry<String, Gauge> entry : gauges.entrySet()) {
  60. reportGauge(entry.getKey(), entry.getValue().latestMetric, timestamp);
  61. }
  62. for (Map.Entry<String, Counter> entry : counters.entrySet()) {
  63. reportCounter(entry.getKey(), entry.getValue().latestMetric, timestamp);
  64. }
  65. for (Map.Entry<String, Histogram> entry : histograms.entrySet()) {
  66. reportHistogram(entry.getKey(), entry.getValue().latestMetric, timestamp);
  67. }
  68. for (Map.Entry<String, Timer> entry : timers.entrySet()) {
  69. reportTimer(entry.getKey(), entry.getValue().latestMetric, timestamp);
  70. }
  71. flush();
  72. onConnSuccess();
  73. } catch (IOException e) {
  74. onConnFail(e);
  75. } finally {
  76. try {
  77. close();
  78. } catch (IOException e) {
  79. logger.warn("Error disconnecting from Graphite", e);
  80. }
  81. }
  82. }
  83. private void reportGauge(String name, Number gauge, long timestamp) throws IOException {
  84. send(MetricRegistry.name(prefix, name, "gauge"), format(gauge), timestamp);
  85. }
  86. private void reportCounter(String name, CounterMetric counter, long timestamp) throws IOException {
  87. send(MetricRegistry.name(prefix, name, "count"), format(counter.latestCount), timestamp);
  88. }
  89. private void reportHistogram(String name, HistogramMetric histogram, long timestamp) throws IOException {
  90. send(MetricRegistry.name(prefix, name, "min"), format(histogram.min), timestamp);
  91. send(MetricRegistry.name(prefix, name, "max"), format(histogram.max), timestamp);
  92. send(MetricRegistry.name(prefix, name, "avg"), format(histogram.avg), timestamp);
  93. for (Entry<Double, Long> pct : histogram.pcts.entrySet()) {
  94. send(MetricRegistry.name(prefix, name, format(pct.getKey()).replace('.', '_')), format(pct.getValue()),
  95. timestamp);
  96. }
  97. }
  98. private void reportTimer(String name, TimerMetric timer, long timestamp) throws IOException {
  99. send(MetricRegistry.name(prefix, name, "count"), format(timer.counterMetric.latestCount), timestamp);
  100. send(MetricRegistry.name(prefix, name, "min"), format(timer.histogramMetric.min), timestamp);
  101. send(MetricRegistry.name(prefix, name, "max"), format(timer.histogramMetric.max), timestamp);
  102. send(MetricRegistry.name(prefix, name, "avg"), format(timer.histogramMetric.avg), timestamp);
  103. for (Entry<Double, Long> pct : timer.histogramMetric.pcts.entrySet()) {
  104. send(MetricRegistry.name(prefix, name, format(pct.getKey()).replace('.', '_')), format(pct.getValue()),
  105. timestamp);
  106. }
  107. }
  108. private void connect() throws IllegalStateException, IOException {
  109. if (socket != null) {
  110. throw new IllegalStateException("Already connected");
  111. }
  112. this.socket = socketFactory.createSocket(address.getAddress(), address.getPort());
  113. this.writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), UTF_8));
  114. }
  115. private void send(String name, String value, long timestamp) throws IOException {
  116. try {
  117. writer.write(sanitize(name));
  118. writer.write(' ');
  119. writer.write(sanitize(value));
  120. writer.write(' ');
  121. writer.write(format(timestamp));
  122. writer.write('\n');
  123. } catch (IOException e) {
  124. throw e;
  125. }
  126. }
  127. private void flush() throws IOException {
  128. writer.flush();
  129. }
  130. private void close() throws IOException {
  131. if (writer != null) {
  132. writer.flush();
  133. }
  134. if (socket != null) {
  135. socket.close();
  136. }
  137. this.socket = null;
  138. this.writer = null;
  139. }
  140. private String format(long n) {
  141. return Long.toString(n);
  142. }
  143. private String format(double v) {
  144. return String.format(Locale.US, "%2.2f", v);
  145. }
  146. private String format(Number o) {
  147. if (o instanceof Float) {
  148. return format(((Float) o).doubleValue());
  149. } else if (o instanceof Double) {
  150. return format(((Double) o).doubleValue());
  151. } else if (o instanceof Short) {
  152. return format(((Short) o).longValue());
  153. } else if (o instanceof Integer) {
  154. return format(((Integer) o).longValue());
  155. } else if (o instanceof Long) {
  156. return format(((Long) o).longValue());
  157. }
  158. return null;
  159. }
  160. private String sanitize(String s) {
  161. return WHITESPACE.matcher(s).replaceAll("-");
  162. }
  163. private void onConnFail(Exception exception) {
  164. if (graphiteConnStatus != GraphiteConnStatus.CONN_NOK) {
  165. logger.warn("Unable to report to Graphite", exception);
  166. graphiteConnStatus = GraphiteConnStatus.CONN_NOK;
  167. }
  168. }
  169. private void onConnSuccess() {
  170. if (graphiteConnStatus != GraphiteConnStatus.CONN_OK) {
  171. logger.info("Graphite connection is recovered.");
  172. graphiteConnStatus = GraphiteConnStatus.CONN_OK;
  173. }
  174. }
  175. private enum GraphiteConnStatus {
  176. CONN_OK, CONN_NOK
  177. }
  178. public void setPrefix(String prefix) {
  179. this.prefix = prefix;
  180. }
  181. }