1 /* 2 * Copyright 2018, OpenCensus Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.opencensus.examples.quickstart; 18 19 import io.opencensus.common.Scope; 20 import io.opencensus.exporter.stats.prometheus.PrometheusStatsCollector; 21 import io.opencensus.stats.Aggregation; 22 import io.opencensus.stats.Aggregation.Distribution; 23 import io.opencensus.stats.BucketBoundaries; 24 import io.opencensus.stats.Measure.MeasureDouble; 25 import io.opencensus.stats.Measure.MeasureLong; 26 import io.opencensus.stats.Stats; 27 import io.opencensus.stats.StatsRecorder; 28 import io.opencensus.stats.View; 29 import io.opencensus.stats.View.Name; 30 import io.opencensus.stats.ViewManager; 31 import io.opencensus.tags.TagContext; 32 import io.opencensus.tags.TagKey; 33 import io.opencensus.tags.TagValue; 34 import io.opencensus.tags.Tagger; 35 import io.opencensus.tags.Tags; 36 import io.prometheus.client.exporter.HTTPServer; 37 import java.io.BufferedReader; 38 import java.io.IOException; 39 import java.io.InputStreamReader; 40 import java.util.ArrayList; 41 import java.util.Arrays; 42 import java.util.Collections; 43 import java.util.List; 44 45 /** Sample application that shows how to record stats and export to Prometheus. */ 46 public final class Repl { 47 48 // The latency in milliseconds 49 private static final MeasureDouble M_LATENCY_MS = 50 MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms"); 51 52 // Counts the number of lines read in from standard input. 53 private static final MeasureLong M_LINES_IN = 54 MeasureLong.create("repl/lines_in", "The number of lines read in", "1"); 55 56 // Counts the number of non EOF(end-of-file) errors. 57 private static final MeasureLong M_ERRORS = 58 MeasureLong.create("repl/errors", "The number of errors encountered", "1"); 59 60 // Counts/groups the lengths of lines read in. 61 private static final MeasureLong M_LINE_LENGTHS = 62 MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By"); 63 64 // The tag "method" 65 private static final TagKey KEY_METHOD = TagKey.create("method"); 66 67 private static final Tagger tagger = Tags.getTagger(); 68 private static final StatsRecorder statsRecorder = Stats.getStatsRecorder(); 69 70 /** Main launcher for the Repl example. */ main(String... args)71 public static void main(String... args) { 72 // Step 1. Enable OpenCensus Metrics. 73 try { 74 setupOpenCensusAndPrometheusExporter(); 75 } catch (IOException e) { 76 System.err.println("Failed to create and register OpenCensus Prometheus Stats exporter " + e); 77 return; 78 } 79 80 BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); 81 82 while (true) { 83 try { 84 readEvaluateProcessLine(stdin); 85 } catch (IOException e) { 86 System.err.println("EOF bye " + e); 87 return; 88 } catch (Exception e) { 89 recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); 90 return; 91 } 92 } 93 } 94 recordStat(MeasureLong ml, Long n)95 private static void recordStat(MeasureLong ml, Long n) { 96 TagContext tctx = tagger.emptyBuilder().build(); 97 try (Scope ss = tagger.withTagContext(tctx)) { 98 statsRecorder.newMeasureMap().put(ml, n).record(); 99 } 100 } 101 recordTaggedStat(TagKey key, String value, MeasureLong ml, Long n)102 private static void recordTaggedStat(TagKey key, String value, MeasureLong ml, Long n) { 103 TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build(); 104 try (Scope ss = tagger.withTagContext(tctx)) { 105 statsRecorder.newMeasureMap().put(ml, n).record(); 106 } 107 } 108 recordTaggedStat(TagKey key, String value, MeasureDouble md, Double d)109 private static void recordTaggedStat(TagKey key, String value, MeasureDouble md, Double d) { 110 TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build(); 111 try (Scope ss = tagger.withTagContext(tctx)) { 112 statsRecorder.newMeasureMap().put(md, d).record(); 113 } 114 } 115 processLine(String line)116 private static String processLine(String line) { 117 long startTimeNs = System.nanoTime(); 118 119 try { 120 return line.toUpperCase(); 121 } catch (Exception e) { 122 recordTaggedStat(KEY_METHOD, "processLine", M_ERRORS, new Long(1)); 123 return ""; 124 } finally { 125 long totalTimeNs = System.nanoTime() - startTimeNs; 126 double timespentMs = (new Double(totalTimeNs)) / 1e6; 127 recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs); 128 } 129 } 130 readEvaluateProcessLine(BufferedReader in)131 private static void readEvaluateProcessLine(BufferedReader in) throws IOException { 132 System.out.print("> "); 133 System.out.flush(); 134 135 String line = in.readLine(); 136 String processed = processLine(line); 137 System.out.println("< " + processed + "\n"); 138 if (line != null && line.length() > 0) { 139 recordStat(M_LINES_IN, new Long(1)); 140 recordStat(M_LINE_LENGTHS, new Long(line.length())); 141 } 142 } 143 registerAllViews()144 private static void registerAllViews() { 145 // Defining the distribution aggregations 146 Aggregation latencyDistribution = 147 Distribution.create( 148 BucketBoundaries.create( 149 Arrays.asList( 150 // [>=0ms, >=25ms, >=50ms, >=75ms, >=100ms, >=200ms, >=400ms, >=600ms, >=800ms, 151 // >=1s, >=2s, >=4s, >=6s] 152 0.0, 153 25.0, 154 50.0, 155 75.0, 156 100.0, 157 200.0, 158 400.0, 159 600.0, 160 800.0, 161 1000.0, 162 2000.0, 163 4000.0, 164 6000.0))); 165 166 Aggregation lengthsDistribution = 167 Distribution.create( 168 BucketBoundaries.create( 169 Arrays.asList( 170 // [>=0B, >=5B, >=10B, >=20B, >=40B, >=60B, >=80B, >=100B, >=200B, >=400B, 171 // >=600B, 172 // >=800B, >=1000B] 173 0.0, 174 5.0, 175 10.0, 176 20.0, 177 40.0, 178 60.0, 179 80.0, 180 100.0, 181 200.0, 182 400.0, 183 600.0, 184 800.0, 185 1000.0))); 186 187 // Define the count aggregation 188 Aggregation countAggregation = Aggregation.Count.create(); 189 190 // So tagKeys 191 List<TagKey> noKeys = new ArrayList<TagKey>(); 192 193 // Define the views 194 View[] views = 195 new View[] { 196 View.create( 197 Name.create("ocjavametrics/latency"), 198 "The distribution of latencies", 199 M_LATENCY_MS, 200 latencyDistribution, 201 Collections.singletonList(KEY_METHOD)), 202 View.create( 203 Name.create("ocjavametrics/lines_in"), 204 "The number of lines read in from standard input", 205 M_LINES_IN, 206 countAggregation, 207 noKeys), 208 View.create( 209 Name.create("ocjavametrics/errors"), 210 "The number of errors encountered", 211 M_ERRORS, 212 countAggregation, 213 Collections.singletonList(KEY_METHOD)), 214 View.create( 215 Name.create("ocjavametrics/line_lengths"), 216 "The distribution of line lengths", 217 M_LINE_LENGTHS, 218 lengthsDistribution, 219 noKeys) 220 }; 221 222 // Create the view manager 223 ViewManager vmgr = Stats.getViewManager(); 224 225 // Then finally register the views 226 for (View view : views) { 227 vmgr.registerView(view); 228 } 229 } 230 setupOpenCensusAndPrometheusExporter()231 private static void setupOpenCensusAndPrometheusExporter() throws IOException { 232 // Firstly register the views 233 registerAllViews(); 234 235 // Create and register the Prometheus exporter 236 PrometheusStatsCollector.createAndRegister(); 237 238 // Run the server as a daemon on address "localhost:8889" 239 HTTPServer server = new HTTPServer("localhost", 8889, true); 240 } 241 } 242