Skip to content
This repository was archived by the owner on Oct 3, 2023. It is now read-only.

Latest commit

 

History

History
1931 lines (1587 loc) · 69.7 KB

File metadata and controls

1931 lines (1587 loc) · 69.7 KB
title Metrics
date 2018-07-16 14:29:27 -0700
draft false
class shadowed-image lightbox

In this quickstart, we’ll glean insights from code segments and learn how to:

  1. Collect metrics using OpenCensus Metrics and Tags
  2. Register and enable an exporter for a backend of our choice
  3. View the metrics on the backend of our choice

Requirements

{{% notice tip %}} For assistance setting up Apache Maven, Click here for instructions. {{% /notice %}}

  • Prometheus as our choice of metrics backend: we are picking it beause it is free, open source and easy to setup

{{% notice tip %}} For assistance setting up Prometheus, Click here for a guided codelab.

You can swap out any other exporter from the list of Java exporters {{% /notice %}}

Installation

We will first create our project directory, add our pom.xml, and our source code.

mkdir repl-app
cd repl-app

touch pom.xml

mkdir -p src/main/java/io/opencensus/metrics/quickstart
touch src/main/java/io/opencensus/metrics/quickstart/Repl.java

Put this in your newly generated pom.xml file:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>io.opencensus.metrics.quickstart</groupId>
    <artifactId>quickstart</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>quickstart</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <opencensus.version>0.17.0</opencensus.version> <!-- The OpenCensus version to use -->
    </properties>

    <build>
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.5.0.Final</version>
            </extension>
        </extensions>

        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.7.0</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>

                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>appassembler-maven-plugin</artifactId>
                    <version>1.10</version>
                    <configuration>
                        <programs>
                            <program>
                                <id>Repl</id>
                                <mainClass>io.opencensus.metrics.quickstart.Repl</mainClass>
                            </program>
                        </programs>
                    </configuration>
                </plugin>
            </plugins>

        </pluginManagement>

    </build>
</project>

Put this in src/main/java/io/opencensus/metrics/quickstart/Repl.java:

package io.opencensus.metrics.quickstart;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Repl {
    public static void main(String ...args) {
        BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

        while (true) {
            try {
                readEvaluateProcessLine(stdin);
            } catch (IOException e) {
                System.err.println("Exception "+ e);
            }
        }
    }

    private static String processLine(String line) {
        return line.toUpperCase();
    }

    private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
        System.out.print("> ");
        System.out.flush();
        String line = in.readLine();
        String processed = processLine(line);
        System.out.println("< " + processed + "\n");
    }
}

To install required dependencies, run this from your project's root directory:

# Make sure to be in your project's root directory
mvn install

Brief Overview

By the end of this tutorial, we will do these four things to obtain metrics using OpenCensus:

  1. Create quantitative metrics that we will record
  2. Create tags that we will associate with our metrics
  3. Organize our metrics, similar to writing a report, in to a View
  4. Export our views to a backend (Prometheus in this case)

Getting Started

The Repl application takes input from users, converts any lower-case letters into upper-case letters, and echoes the result back to the user, for example:

> foo
< FOO

We will instrument this application to collect metrics, such as:

  • Latency per processing loop
  • Number of lines read
  • Number of errors
  • Line lengths

Let's first run the application and see what we have.

mvn exec:java -Dexec.mainClass=io.opencensus.metrics.quickstart.Repl

You will be given a text prompt. Try typing in a lowercase word and hit enter to receive the uppercase equivalent.

You should see something like this after a few tries: java image 1

To exit out of the application, hit ctrl + c on your keyboard.

From here on out, we will be rewriting sections of src/main/java/io/opencensus/metrics/quickstart/Repl.java and pom.xml.

You can recompile and run the application after editing it by running this command:

mvn install

Enable Metrics

Import Packages

To enable metrics, we’ll declare the dependencies in your pom.xml file. Add the following snippet of code after the <properties>...</properties> node.

{{}} {{}} io.opencensus opencensus-api ${opencensus.version}

io.opencensus opencensus-impl ${opencensus.version} runtime {{}}

{{}} 4.0.0 io.opencensus.metrics.quickstart quickstart jar 1.0-SNAPSHOT quickstart http://maven.apache.org

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <opencensus.version>0.17.0</opencensus.version> <!-- The OpenCensus version to use -->
</properties>

<dependencies>
    <dependency>
        <groupId>io.opencensus</groupId>
        <artifactId>opencensus-api</artifactId>
        <version>${opencensus.version}</version>
    </dependency>

    <dependency>
        <groupId>io.opencensus</groupId>
        <artifactId>opencensus-impl</artifactId>
        <version>${opencensus.version}</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>

<build>
    <extensions>
        <extension>
            <groupId>kr.motd.maven</groupId>
            <artifactId>os-maven-plugin</artifactId>
            <version>1.5.0.Final</version>
        </extension>
    </extensions>

    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>appassembler-maven-plugin</artifactId>
                <version>1.10</version>
                <configuration>
                    <programs>
                        <program>
                            <id>Repl</id>
                            <mainClass>io.opencensus.metrics.quickstart.Repl</mainClass>
                        </program>
                    </programs>
                </configuration>
            </plugin>
        </plugins>

    </pluginManagement>

</build>
{{}} {{}}

We will now be importing modules into src/main/java/io/opencensus/metrics/quickstart/Repl.java. Append the following snippet after the existing import statements:

{{}} import io.opencensus.common.Scope; import io.opencensus.stats.Stats; import io.opencensus.stats.Measure; import io.opencensus.stats.Measure.MeasureLong; import io.opencensus.stats.Measure.MeasureDouble; import io.opencensus.stats.Stats; import io.opencensus.stats.StatsRecorder; import io.opencensus.stats.View; import io.opencensus.tags.Tags; import io.opencensus.tags.Tagger; import io.opencensus.tags.TagContext; import io.opencensus.tags.TagContextBuilder; import io.opencensus.tags.TagKey; import io.opencensus.tags.TagValue; {{}}

Create Measures for Metrics

First, we will create the variables needed to later record our metrics. Place the following snippet on the line after public class Repl {:

{{}} {{}} // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms");

// Counts the number of lines read in from standard input. private static final MeasureLong M_LINES_IN = MeasureLong.create("repl/lines_in", "The number of lines read in", "1");

// Counts the number of non EOF(end-of-file) errors. private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1");

// Counts/groups the lengths of lines read in. private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By");

private static final Tagger tagger = Tags.getTagger(); private static final StatsRecorder statsRecorder = Stats.getStatsRecorder();

private static void recordStat(MeasureLong ml, Long n) { statsRecorder.newMeasureMap().put(ml, n); } {{}}

{{}} package io.opencensus.metrics.quickstart;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader;

import io.opencensus.common.Scope; import io.opencensus.stats.Stats; import io.opencensus.stats.Measure; import io.opencensus.stats.Measure.MeasureLong; import io.opencensus.stats.Measure.MeasureDouble; import io.opencensus.stats.Stats; import io.opencensus.stats.StatsRecorder; import io.opencensus.stats.View; import io.opencensus.tags.Tags; import io.opencensus.tags.Tagger; import io.opencensus.tags.TagContext; import io.opencensus.tags.TagContextBuilder; import io.opencensus.tags.TagKey; import io.opencensus.tags.TagValue;

public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms");

// Counts the number of lines read in from standard input.
private static final MeasureLong M_LINES_IN = MeasureLong.create("repl/lines_in", "The number of lines read in", "1");

// Counts the number of non EOF(end-of-file) errors.
private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1");

// Counts/groups the lengths of lines read in.
private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By");

private static final Tagger tagger = Tags.getTagger();
private static final StatsRecorder statsRecorder = Stats.getStatsRecorder();

public static void main(String ...args) {
    BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

    while (true) {
        try {
            readEvaluateProcessLine(stdin);
        } catch (IOException e) {
            System.err.println("Exception "+ e);
        }
    }
}

private static void recordStat(MeasureLong ml, Long n) {
    statsRecorder.newMeasureMap().put(ml, n);
}

private static String processLine(String line) {
    return line.toUpperCase();
}

private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
    System.out.print("> ");
    System.out.flush();
    String line = in.readLine();
    String processed = processLine(line);
    System.out.println("< " + processed + "\n");
}

} {{}} {{}}

Create Tags

Now we will create the variable later needed to record extra text meta-data.

Insert the following snippet on the line before private static final Tagger tagger = Tags.getTagger();:

{{}} {{}} // The tag "method" private static final TagKey KEY_METHOD = TagKey.create("method"); {{}}

{{}} package io.opencensus.metrics.quickstart;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader;

import io.opencensus.common.Scope; import io.opencensus.stats.Stats; import io.opencensus.stats.Measure; import io.opencensus.stats.Measure.MeasureLong; import io.opencensus.stats.Measure.MeasureDouble; import io.opencensus.stats.Stats; import io.opencensus.stats.StatsRecorder; import io.opencensus.stats.View; import io.opencensus.tags.Tags; import io.opencensus.tags.Tagger; import io.opencensus.tags.TagContext; import io.opencensus.tags.TagContextBuilder; import io.opencensus.tags.TagKey; import io.opencensus.tags.TagValue;

public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms");

// Counts the number of lines read in from standard input.
private static final MeasureLong M_LINES_IN = MeasureLong.create("repl/lines_in", "The number of lines read in", "1");

// Counts the number of non EOF(end-of-file) errors.
private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1");

// Counts/groups the lengths of lines read in.
private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By");

// The tag "method"
private static final TagKey KEY_METHOD = TagKey.create("method");

private static final Tagger tagger = Tags.getTagger();
private static final StatsRecorder statsRecorder = Stats.getStatsRecorder();

public static void main(String ...args) {
    BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

    while (true) {
        try {
            readEvaluateProcessLine(stdin);
        } catch (IOException e) {
            System.err.println("Exception "+ e);
        }
    }
}

private static void recordStat(MeasureLong ml, Long n) {
    statsRecorder.newMeasureMap().put(ml, n);
}

private static String processLine(String line) {
    return line.toUpperCase();
}

private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
    System.out.print("> ");
    System.out.flush();
    String line = in.readLine();
    String processed = processLine(line);
    System.out.println("< " + processed + "\n");
}

} {{}} {{}}

We will later use this tag, called KEY_METHOD, to record what method is being invoked. In our scenario, we will only use it to record that "repl" is calling our data.

{{% notice note %}}

Example

The value passed to TagKey.create() is arbitrary and purely up the user. For example, if we wanted to track what operating system a user is using, we could do so like this:

private static final TagKey OS_Key = TagKey.create("operating_system");

Later, if we used OS_Key, we will be given an opportunity to enter values such as "windows" or "mac".

Note: OS_Key is not used in this quickstart. It is only used as an example in this text block. {{% /notice %}}

We will now create helper functions to assist us with recording Tagged Stats. One will record a Long, and the other will record a Double.

Insert the following snippet after private static void recordStat:

{{}} {{}} private static void recordTaggedStat(TagKey key, String value, MeasureLong ml, Long n) { TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build(); try (Scope ss = tagger.withTagContext(tctx)) { statsRecorder.newMeasureMap().put(ml, n).record(); } }

private static void recordTaggedStat(TagKey key, String value, MeasureDouble md, Double d) { TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build(); try (Scope ss = tagger.withTagContext(tctx)) { statsRecorder.newMeasureMap().put(md, d).record(); } } {{}}

{{}} package io.opencensus.metrics.quickstart;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader;

import io.opencensus.common.Scope; import io.opencensus.stats.Stats; import io.opencensus.stats.Measure; import io.opencensus.stats.Measure.MeasureLong; import io.opencensus.stats.Measure.MeasureDouble; import io.opencensus.stats.Stats; import io.opencensus.stats.StatsRecorder; import io.opencensus.stats.View; import io.opencensus.tags.Tags; import io.opencensus.tags.Tagger; import io.opencensus.tags.TagContext; import io.opencensus.tags.TagContextBuilder; import io.opencensus.tags.TagKey; import io.opencensus.tags.TagValue;

public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms");

// Counts the number of lines read in from standard input.
private static final MeasureLong M_LINES_IN = MeasureLong.create("repl/lines_in", "The number of lines read in", "1");

// Counts the number of non EOF(end-of-file) errors.
private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1");

// Counts/groups the lengths of lines read in.
private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By");

// The tag "method"
private static final TagKey KEY_METHOD = TagKey.create("method");

private static final Tagger tagger = Tags.getTagger();
private static final StatsRecorder statsRecorder = Stats.getStatsRecorder();

public static void main(String ...args) {
    BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

    while (true) {
        try {
            readEvaluateProcessLine(stdin);
        } catch (IOException e) {
            System.err.println("Exception "+ e);
        }
    }
}

private static void recordStat(MeasureLong ml, Long n) {
    statsRecorder.newMeasureMap().put(ml, n);
}

private static void recordTaggedStat(TagKey key, String value, MeasureLong ml, Long n) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(ml, n).record();
    }
}

private static void recordTaggedStat(TagKey key, String value, MeasureDouble md, Double d) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(md, d).record();
    }
}

private static String processLine(String line) {
    return line.toUpperCase();
}

private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
    System.out.print("> ");
    System.out.flush();
    String line = in.readLine();
    String processed = processLine(line);
    System.out.println("< " + processed + "\n");
}

} {{}} {{}}

Recording Metrics

Finally, we'll hook our stat recorders in to main, processLine, and readEvaluateProcessLine:

{{}} {{}} public static void main(String ...args) { BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

while (true) {
    try {
        readEvaluateProcessLine(stdin);
    } catch (IOException e) {
        System.err.println("EOF bye "+ e);
        return;
    } catch (Exception e) {
        recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1));
    }
}

}

private static String processLine(String line) { long startTimeNs = System.nanoTime();

try {
    return line.toUpperCase();
} finally {
    long totalTimeNs = System.nanoTime() - startTimeNs;
    double timespentMs = (new Double(totalTimeNs))/1e6;
    recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs);
}

}

private static void readEvaluateProcessLine(BufferedReader in) throws IOException { System.out.print("> "); System.out.flush();

try {
    String line = in.readLine();
    String processed = processLine(line);
    System.out.println("< " + processed + "\n");
    recordStat(M_LINES_IN, new Long(1));
    recordStat(M_LINE_LENGTHS, new Long(line.length()));
} catch(Exception e) {
    recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1));
}

} {{}}

{{}} package io.opencensus.metrics.quickstart;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader;

import io.opencensus.common.Scope; import io.opencensus.stats.Stats; import io.opencensus.stats.Measure; import io.opencensus.stats.Measure.MeasureLong; import io.opencensus.stats.Measure.MeasureDouble; import io.opencensus.stats.Stats; import io.opencensus.stats.StatsRecorder; import io.opencensus.stats.View; import io.opencensus.tags.Tags; import io.opencensus.tags.Tagger; import io.opencensus.tags.TagContext; import io.opencensus.tags.TagContextBuilder; import io.opencensus.tags.TagKey; import io.opencensus.tags.TagValue;

public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms");

// Counts the number of lines read in from standard input.
private static final MeasureLong M_LINES_IN = MeasureLong.create("repl/lines_in", "The number of lines read in", "1");

// Counts the number of non EOF(end-of-file) errors.
private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1");

// Counts/groups the lengths of lines read in.
private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By");

// The tag "method"
private static final TagKey KEY_METHOD = TagKey.create("method");

private static final Tagger tagger = Tags.getTagger();
private static final StatsRecorder statsRecorder = Stats.getStatsRecorder();

public static void main(String ...args) {
    BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

    while (true) {
        try {
            readEvaluateProcessLine(stdin);
        } catch (IOException e) {
            System.err.println("EOF bye "+ e);
            return;
        } catch (Exception e) {
            recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1));
        }
    }
}

private static void recordStat(MeasureLong ml, Long n) {
    statsRecorder.newMeasureMap().put(ml, n);
}

private static void recordTaggedStat(TagKey key, String value, MeasureLong ml, Long n) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(ml, n).record();
    }
}

private static void recordTaggedStat(TagKey key, String value, MeasureDouble md, Double d) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(md, d).record();
    }
}

private static String processLine(String line) {
    long startTimeNs = System.nanoTime();

    try {
        return line.toUpperCase();
    } finally {
        long totalTimeNs = System.nanoTime() - startTimeNs;
        double timespentMs = (new Double(totalTimeNs))/1e6;
        recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs);
    }
}

private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
    System.out.print("> ");
    System.out.flush();

    try {
        String line = in.readLine();
        String processed = processLine(line);
        System.out.println("< " + processed + "\n");
        recordStat(M_LINES_IN, new Long(1));
        recordStat(M_LINE_LENGTHS, new Long(line.length()));
    } catch(Exception e) {
        recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1));
    }
}

} {{}} {{}}

Enable Views

In order to analyze these stats, we’ll need to aggregate our data with Views.

Import Packages

{{}} {{}} import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List;

import io.opencensus.stats.Aggregation; import io.opencensus.stats.Aggregation.Distribution; import io.opencensus.stats.BucketBoundaries; import io.opencensus.stats.View.Name; import io.opencensus.stats.ViewManager; import io.opencensus.stats.View.AggregationWindow.Cumulative; {{}}

{{}} package io.opencensus.metrics.quickstart;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List;

import io.opencensus.common.Scope; import io.opencensus.stats.Stats; import io.opencensus.stats.Measure; import io.opencensus.stats.Measure.MeasureLong; import io.opencensus.stats.Measure.MeasureDouble; import io.opencensus.stats.Stats; import io.opencensus.stats.StatsRecorder; import io.opencensus.tags.Tags; import io.opencensus.tags.Tagger; import io.opencensus.tags.TagContext; import io.opencensus.tags.TagContextBuilder; import io.opencensus.tags.TagKey; import io.opencensus.tags.TagValue; import io.opencensus.stats.Aggregation; import io.opencensus.stats.Aggregation.Distribution; import io.opencensus.stats.BucketBoundaries; import io.opencensus.stats.View; import io.opencensus.stats.View.Name; import io.opencensus.stats.ViewManager; import io.opencensus.stats.View.AggregationWindow.Cumulative;

public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms");

// Counts the number of lines read in from standard input.
private static final MeasureLong M_LINES_IN = MeasureLong.create("repl/lines_in", "The number of lines read in", "1");

// Counts the number of non EOF(end-of-file) errors.
private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1");

// Counts/groups the lengths of lines read in.
private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By");

// The tag "method"
private static final TagKey KEY_METHOD = TagKey.create("method");

private static final Tagger tagger = Tags.getTagger();
private static final StatsRecorder statsRecorder = Stats.getStatsRecorder();

public static void main(String ...args) {
    BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

    while (true) {
        try {
            readEvaluateProcessLine(stdin);
        } catch (IOException e) {
            System.err.println("Exception "+ e);
        }
    }
}

private static void recordStat(MeasureLong ml, Long n) {
    statsRecorder.newMeasureMap().put(ml, n);
}

private static void recordTaggedStat(TagKey key, String value, MeasureLong ml, Long n) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(ml, n).record();
    }
}

private static void recordTaggedStat(TagKey key, String value, MeasureDouble md, Double d) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(md, d).record();
    }
}

private static String processLine(String line) {
    long startTimeNs = System.nanoTime();

    try {
        return line.toUpperCase();
    } finally {
        long totalTimeNs = System.nanoTime() - startTimeNs;
        double timespentMs = (new Double(totalTimeNs))/1e6;
        recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs);
    }
}

private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
    System.out.print("> ");
    System.out.flush();

    try {
        String line = in.readLine();
        String processed = processLine(line);
        System.out.println("< " + processed + "\n");
        recordStat(M_LINES_IN, new Long(1));
        recordStat(M_LINE_LENGTHS, new Long(line.length()));
    } catch(Exception e) {
        recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1));
    }
}

} {{}} {{}}

Create Views

Append this code snippet as our last function inside of public class Repl:

{{}} {{}} private static void registerAllViews() { // Defining the distribution aggregations Aggregation latencyDistribution = Distribution.create(BucketBoundaries.create( Arrays.asList( // [>=0ms, >=25ms, >=50ms, >=75ms, >=100ms, >=200ms, >=400ms, >=600ms, >=800ms, >=1s, >=2s, >=4s, >=6s] 0.0, 25.0, 50.0, 75.0, 100.0, 200.0, 400.0, 600.0, 800.0, 1000.0, 2000.0, 4000.0, 6000.0) ));

Aggregation lengthsDistribution = Distribution.create(BucketBoundaries.create(
        Arrays.asList(
            // [>=0B, >=5B, >=10B, >=20B, >=40B, >=60B, >=80B, >=100B, >=200B, >=400B, >=600B, >=800B, >=1000B]
            0.0, 5.0, 10.0, 20.0, 40.0, 60.0, 80.0, 100.0, 200.0, 400.0, 600.0, 800.0, 1000.0)
        ));

// Define the count aggregation
Aggregation countAggregation = Aggregation.Count.create();

// So tagKeys
List<TagKey> noKeys = new ArrayList<TagKey>();

// Define the views
View[] views = new View[]{
    View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.singletonList(KEY_METHOD)),
    View.create(Name.create("ocjavametrics/lines_in"), "The number of lines read in from standard input", M_LINES_IN, countAggregation, noKeys),
    View.create(Name.create("ocjavametrics/errors"), "The number of errors encountered", M_ERRORS, countAggregation, noKeys),
    View.create(Name.create("ocjavametrics/line_length"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys)
};

// Create the view manager
ViewManager vmgr = Stats.getViewManager();

// Then finally register the views
for (View view : views) {
    vmgr.registerView(view);
}

} {{}}

{{}} package io.opencensus.metrics.quickstart;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List;

import io.opencensus.common.Scope; import io.opencensus.stats.Stats; import io.opencensus.stats.Measure; import io.opencensus.stats.Measure.MeasureLong; import io.opencensus.stats.Measure.MeasureDouble; import io.opencensus.stats.Stats; import io.opencensus.stats.StatsRecorder; import io.opencensus.tags.Tags; import io.opencensus.tags.Tagger; import io.opencensus.tags.TagContext; import io.opencensus.tags.TagContextBuilder; import io.opencensus.tags.TagKey; import io.opencensus.tags.TagValue; import io.opencensus.stats.Aggregation; import io.opencensus.stats.Aggregation.Distribution; import io.opencensus.stats.BucketBoundaries; import io.opencensus.stats.View; import io.opencensus.stats.View.Name; import io.opencensus.stats.ViewManager; import io.opencensus.stats.View.AggregationWindow.Cumulative;

public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms");

// Counts the number of lines read in from standard input.
private static final MeasureLong M_LINES_IN = MeasureLong.create("repl/lines_in", "The number of lines read in", "1");

// Counts the number of non EOF(end-of-file) errors.
private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1");

// Counts/groups the lengths of lines read in.
private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By");

// The tag "method"
private static final TagKey KEY_METHOD = TagKey.create("method");

private static final Tagger tagger = Tags.getTagger();
private static final StatsRecorder statsRecorder = Stats.getStatsRecorder();

public static void main(String ...args) {
    BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

    while (true) {
        try {
            readEvaluateProcessLine(stdin);
        } catch (IOException e) {
            System.err.println("EOF bye "+ e);
            return;
        } catch (Exception e) {
            recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1));
        }
    }
}

private static void recordStat(MeasureLong ml, Long n) {
    statsRecorder.newMeasureMap().put(ml, n);
}

private static void recordTaggedStat(TagKey key, String value, MeasureLong ml, Long n) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(ml, n).record();
    }
}

private static void recordTaggedStat(TagKey key, String value, MeasureDouble md, Double d) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(md, d).record();
    }
}

private static String processLine(String line) {
    long startTimeNs = System.nanoTime();

    try {
        return line.toUpperCase();
    } finally {
        long totalTimeNs = System.nanoTime() - startTimeNs;
        double timespentMs = (new Double(totalTimeNs))/1e6;
        recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs);
    }
}

private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
    System.out.print("> ");
    System.out.flush();

    try {
        String line = in.readLine();
        String processed = processLine(line);
        System.out.println("< " + processed + "\n");
        recordStat(M_LINES_IN, new Long(1));
        recordStat(M_LINE_LENGTHS, new Long(line.length()));
    } catch(Exception e) {
        recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1));
    }
}

private static void registerAllViews() {
    // Defining the distribution aggregations
    Aggregation latencyDistribution = Distribution.create(BucketBoundaries.create(
            Arrays.asList(
                // [>=0ms, >=25ms, >=50ms, >=75ms, >=100ms, >=200ms, >=400ms, >=600ms, >=800ms, >=1s, >=2s, >=4s, >=6s]
                0.0, 25.0, 50.0, 75.0, 100.0, 200.0, 400.0, 600.0, 800.0, 1000.0, 2000.0, 4000.0, 6000.0)
            ));

    Aggregation lengthsDistribution = Distribution.create(BucketBoundaries.create(
            Arrays.asList(
                // [>=0B, >=5B, >=10B, >=20B, >=40B, >=60B, >=80B, >=100B, >=200B, >=400B, >=600B, >=800B, >=1000B]
                0.0, 5.0, 10.0, 20.0, 40.0, 60.0, 80.0, 100.0, 200.0, 400.0, 600.0, 800.0, 1000.0)
            ));

    // Define the count aggregation
    Aggregation countAggregation = Aggregation.Count.create();

    // So tagKeys
    List<TagKey> noKeys = new ArrayList<TagKey>();

    // Define the views
    View[] views = new View[]{
        View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.singletonList(KEY_METHOD)),
        View.create(Name.create("ocjavametrics/lines_in"), "The number of lines read in from standard input", M_LINES_IN, countAggregation, noKeys),
        View.create(Name.create("ocjavametrics/errors"), "The number of errors encountered", M_ERRORS, countAggregation, noKeys),
        View.create(Name.create("ocjavametrics/line_length"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys)
    };

    // Create the view manager
    ViewManager vmgr = Stats.getViewManager();

    // Then finally register the views
    for (View view : views)
        vmgr.registerView(view);
}

} {{}} {{}}

Register Views

We will create a function called setupOpenCensusAndPrometheusExporter and call it from our main function:

{{}} {{}} public static void main(String ...args) { // Step 1. Enable OpenCensus Metrics. try { setupOpenCensusAndPrometheusExporter(); } catch (IOException e) { System.err.println("Failed to create and register OpenCensus Prometheus Stats exporter "+ e); return; }

BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

while (true) {
    try {
        readEvaluateProcessLine(stdin);
    } catch (IOException e) {
        System.err.println("EOF bye "+ e);
        return;
    } catch (Exception e) {
        recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1));
    }
}

}

private static void setupOpenCensusAndPrometheusExporter() throws IOException { // Firstly register the views registerAllViews(); } {{}}

{{}} package io.opencensus.metrics.quickstart;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List;

import io.opencensus.common.Scope; import io.opencensus.stats.Stats; import io.opencensus.stats.Measure; import io.opencensus.stats.Measure.MeasureLong; import io.opencensus.stats.Measure.MeasureDouble; import io.opencensus.stats.Stats; import io.opencensus.stats.StatsRecorder; import io.opencensus.tags.Tags; import io.opencensus.tags.Tagger; import io.opencensus.tags.TagContext; import io.opencensus.tags.TagContextBuilder; import io.opencensus.tags.TagKey; import io.opencensus.tags.TagValue; import io.opencensus.stats.Aggregation; import io.opencensus.stats.Aggregation.Distribution; import io.opencensus.stats.BucketBoundaries; import io.opencensus.stats.View; import io.opencensus.stats.View.Name; import io.opencensus.stats.ViewManager; import io.opencensus.stats.View.AggregationWindow.Cumulative;

public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms");

// Counts the number of lines read in from standard input.
private static final MeasureLong M_LINES_IN= MeasureLong.create("repl/lines_in", "The number of lines read in", "1");

// Counts the number of non EOF(end-of-file) errors.
private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1");

// Counts/groups the lengths of lines read in.
private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By");

// The tag "method"
private static final TagKey KEY_METHOD = TagKey.create("method");

private static final Tagger tagger = Tags.getTagger();
private static final StatsRecorder statsRecorder = Stats.getStatsRecorder();

public static void main(String ...args) {
    // Step 1. Enable OpenCensus Metrics.
    try {
        setupOpenCensusAndPrometheusExporter();
    } catch (IOException e) {
        System.err.println("Failed to create and register OpenCensus Prometheus Stats exporter "+ e);
        return;
    }

    BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

    while (true) {
        try {
            readEvaluateProcessLine(stdin);
        } catch (IOException e) {
            System.err.println("EOF bye "+ e);
            return;
        } catch (Exception e) {
            recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1));
        }
    }
}

private static void recordStat(MeasureLong ml, Long n) {
    statsRecorder.newMeasureMap().put(ml, n);
}

private static void recordTaggedStat(TagKey key, String value, MeasureLong ml, Long n) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(ml, n).record();
    }
}

private static void recordTaggedStat(TagKey key, String value, MeasureDouble md, Double d) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(md, d).record();
    }
}

private static String processLine(String line) {
    long startTimeNs = System.nanoTime();

    try {
        return line.toUpperCase();
    } finally {
        long totalTimeNs = System.nanoTime() - startTimeNs;
        double timespentMs = (new Double(totalTimeNs))/1e6;
        recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs);
    }
}

private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
    System.out.print("> ");
    System.out.flush();

    try {
        String line = in.readLine();
        String processed = processLine(line);
        System.out.println("< " + processed + "\n");
        recordStat(M_LINES_IN, new Long(1));
        recordStat(M_LINE_LENGTHS, new Long(line.length()));
    } catch(Exception e) {
        recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1));
    }
}

private static void registerAllViews() {
    // Defining the distribution aggregations
    Aggregation latencyDistribution = Distribution.create(BucketBoundaries.create(
            Arrays.asList(
                // [>=0ms, >=25ms, >=50ms, >=75ms, >=100ms, >=200ms, >=400ms, >=600ms, >=800ms, >=1s, >=2s, >=4s, >=6s]
                0.0, 25.0, 50.0, 75.0, 100.0, 200.0, 400.0, 600.0, 800.0, 1000.0, 2000.0, 4000.0, 6000.0)
            ));

    Aggregation lengthsDistribution = Distribution.create(BucketBoundaries.create(
            Arrays.asList(
                // [>=0B, >=5B, >=10B, >=20B, >=40B, >=60B, >=80B, >=100B, >=200B, >=400B, >=600B, >=800B, >=1000B]
                0.0, 5.0, 10.0, 20.0, 40.0, 60.0, 80.0, 100.0, 200.0, 400.0, 600.0, 800.0, 1000.0)
            ));

    // Define the count aggregation
    Aggregation countAggregation = Aggregation.Count.create();

    // So tagKeys
    List<TagKey> noKeys = new ArrayList<TagKey>();

    // Define the views
    View[] views = new View[]{
        View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.singletonList(KEY_METHOD)),
        View.create(Name.create("ocjavametrics/lines_in"), "The number of lines read in from standard input", M_LINES_IN, countAggregation, noKeys),
        View.create(Name.create("ocjavametrics/errors"), "The number of errors encountered", M_ERRORS, countAggregation, noKeys),
        View.create(Name.create("ocjavametrics/line_length"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys)
    };

    // Create the view manager
    ViewManager vmgr = Stats.getViewManager();

    // Then finally register the views
    for (View view : views)
        vmgr.registerView(view);
}

private static void setupOpenCensusAndPrometheusExporter() throws IOException {
    // Firstly register the views
    registerAllViews();

    // Start the Prometheus exporter here...
}

} {{}} {{}}

Exporting stats

Import Packages

Add the following code snippet to your <dependencies>...</dependencies> node in pom.xml: {{}} {{}} io.opencensus opencensus-exporter-stats-prometheus ${opencensus.version}

io.prometheus simpleclient_httpserver 0.4.0 {{}}

{{}} 4.0.0 io.opencensus.metrics.quickstart quickstart jar 1.0-SNAPSHOT quickstart http://maven.apache.org

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <opencensus.version>0.17.0</opencensus.version> <!-- The OpenCensus version to use -->
</properties>

<dependencies>
    <dependency>
        <groupId>io.opencensus</groupId>
        <artifactId>opencensus-api</artifactId>
        <version>${opencensus.version}</version>
    </dependency>

    <dependency>
        <groupId>io.opencensus</groupId>
        <artifactId>opencensus-impl</artifactId>
        <version>${opencensus.version}</version>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>io.opencensus</groupId>
        <artifactId>opencensus-exporter-stats-prometheus</artifactId>
        <version>${opencensus.version}</version>
    </dependency>

    <dependency>
        <groupId>io.prometheus</groupId>
        <artifactId>simpleclient_httpserver</artifactId>
        <version>0.4.0</version>
    </dependency>
</dependencies>

<build>
    <extensions>
        <extension>
            <groupId>kr.motd.maven</groupId>
            <artifactId>os-maven-plugin</artifactId>
            <version>1.5.0.Final</version>
        </extension>
    </extensions>

    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>appassembler-maven-plugin</artifactId>
                <version>1.10</version>
                <configuration>
                    <programs>
                        <program>
                            <id>Repl</id>
                            <mainClass>io.opencensus.metrics.quickstart.Repl</mainClass>
                        </program>
                    </programs>
                </configuration>
            </plugin>
        </plugins>

    </pluginManagement>

</build>
{{}} {{}}

We also need to expose the Prometheus endpoint say on address "localhost:8889" in order for Prometheus to scrape our application. Please add the following to our Java code

Add the following code snippet to src/main/java/io/opencensus/metrics/quickstart/Repl.java: {{}} {{}} import io.opencensus.exporter.stats.prometheus.PrometheusStatsCollector; import io.prometheus.client.exporter.HTTPServer; {{}}

{{}} package io.opencensus.metrics.quickstart;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.io.IOException;

import io.opencensus.exporter.stats.prometheus.PrometheusStatsCollector; import io.prometheus.client.exporter.HTTPServer;

import io.opencensus.common.Scope; import io.opencensus.stats.Stats; import io.opencensus.stats.Measure; import io.opencensus.stats.Measure.MeasureLong; import io.opencensus.stats.Measure.MeasureDouble; import io.opencensus.stats.Stats; import io.opencensus.stats.StatsRecorder; import io.opencensus.tags.Tags; import io.opencensus.tags.Tagger; import io.opencensus.tags.TagContext; import io.opencensus.tags.TagContextBuilder; import io.opencensus.tags.TagKey; import io.opencensus.tags.TagValue; import io.opencensus.stats.Aggregation; import io.opencensus.stats.Aggregation.Distribution; import io.opencensus.stats.BucketBoundaries; import io.opencensus.stats.View; import io.opencensus.stats.View.Name; import io.opencensus.stats.ViewManager; import io.opencensus.stats.View.AggregationWindow.Cumulative;

public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms");

// Counts the number of lines read in from standard input.
private static final MeasureLong M_LINES_IN = MeasureLong.create("repl/lines_in", "The number of lines read in", "1");

// Counts the number of non EOF(end-of-file) errors.
private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1");

// Counts/groups the lengths of lines read in.
private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By");

// The tag "method"
private static final TagKey KEY_METHOD = TagKey.create("method");

private static final Tagger tagger = Tags.getTagger();
private static final StatsRecorder statsRecorder = Stats.getStatsRecorder();

public static void main(String ...args) {
    // Step 1. Enable OpenCensus Metrics.
    try {
        setupOpenCensusAndPrometheusExporter();
    } catch (IOException e) {
        System.err.println("Failed to create and register OpenCensus Prometheus Stats exporter "+ e);
        return;
    }

    BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

    while (true) {
        try {
            readEvaluateProcessLine(stdin);
        } catch (IOException e) {
            System.err.println("EOF bye "+ e);
            return;
        } catch (Exception e) {
            recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1));
        }
    }
}

private static void recordStat(MeasureLong ml, Long n) {
    statsRecorder.newMeasureMap().put(ml, n);
}

private static void recordTaggedStat(TagKey key, String value, MeasureLong ml, Long n) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(ml, n).record();
    }
}

private static void recordTaggedStat(TagKey key, String value, MeasureDouble md, Double d) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(md, d).record();
    }
}

private static String processLine(String line) {
    long startTimeNs = System.nanoTime();

    try {
        return line.toUpperCase();
    } finally {
        long totalTimeNs = System.nanoTime() - startTimeNs;
        double timespentMs = (new Double(totalTimeNs))/1e6;
        recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs);
    }
}

private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
    System.out.print("> ");
    System.out.flush();

    try {
        String line = in.readLine();
        String processed = processLine(line);
        System.out.println("< " + processed + "\n");
        recordStat(M_LINES_IN, new Long(1));
        recordStat(M_LINE_LENGTHS, new Long(line.length()));
    } catch(Exception e) {
        recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1));
    }
}

private static void registerAllViews() {
    // Defining the distribution aggregations
    Aggregation latencyDistribution = Distribution.create(BucketBoundaries.create(
            Arrays.asList(
                // [>=0ms, >=25ms, >=50ms, >=75ms, >=100ms, >=200ms, >=400ms, >=600ms, >=800ms, >=1s, >=2s, >=4s, >=6s]
                0.0, 25.0, 50.0, 75.0, 100.0, 200.0, 400.0, 600.0, 800.0, 1000.0, 2000.0, 4000.0, 6000.0)
            ));

    Aggregation lengthsDistribution = Distribution.create(BucketBoundaries.create(
            Arrays.asList(
                // [>=0B, >=5B, >=10B, >=20B, >=40B, >=60B, >=80B, >=100B, >=200B, >=400B, >=600B, >=800B, >=1000B]
                0.0, 5.0, 10.0, 20.0, 40.0, 60.0, 80.0, 100.0, 200.0, 400.0, 600.0, 800.0, 1000.0)
            ));

    // Define the count aggregation
    Aggregation countAggregation = Aggregation.Count.create();

    // So tagKeys
    List<TagKey> noKeys = new ArrayList<TagKey>();

    // Define the views
    View[] views = new View[]{
        View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.singletonList(KEY_METHOD)),
        View.create(Name.create("ocjavametrics/lines_in"), "The number of lines read in from standard input", M_LINES_IN, countAggregation, noKeys),
        View.create(Name.create("ocjavametrics/errors"), "The number of errors encountered", M_ERRORS, countAggregation, noKeys),
        View.create(Name.create("ocjavametrics/line_length"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys)
    };

    // Create the view manager
    ViewManager vmgr = Stats.getViewManager();

    // Then finally register the views
    for (View view : views)
        vmgr.registerView(view);
}

private static void setupOpenCensusAndPrometheusExporter() throws IOException {
    // Firstly register the views
    registerAllViews();
}

} {{}} {{}}

Export Views

We will further expand upon setupOpenCensusAndPrometheusExporter:

private static void setupOpenCensusAndPrometheusExporter() throws IOException {
    // Firstly register the views
    registerAllViews();

    // Create and register the Prometheus exporter
    PrometheusStatsCollector.createAndRegister();

    // Run the server as a daemon on address "localhost:8889"
    HTTPServer server = new HTTPServer("localhost", 8889, true);
}

Here is the final state of the code: {{}} {{}} package io.opencensus.metrics.quickstart;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List;

import io.opencensus.exporter.stats.prometheus.PrometheusStatsCollector; import io.prometheus.client.exporter.HTTPServer;

import io.opencensus.common.Scope; import io.opencensus.stats.Aggregation; import io.opencensus.stats.Aggregation.Distribution; import io.opencensus.stats.BucketBoundaries; import io.opencensus.stats.Stats; import io.opencensus.stats.Measure; import io.opencensus.stats.Measure.MeasureLong; import io.opencensus.stats.Measure.MeasureDouble; import io.opencensus.stats.Stats; import io.opencensus.stats.StatsRecorder; import io.opencensus.stats.View; import io.opencensus.tags.Tags; import io.opencensus.tags.Tagger; import io.opencensus.tags.TagContext; import io.opencensus.tags.TagContextBuilder; import io.opencensus.tags.TagKey; import io.opencensus.tags.TagValue; import io.opencensus.stats.View; import io.opencensus.stats.View.Name; import io.opencensus.stats.ViewManager; import io.opencensus.stats.View.AggregationWindow.Cumulative;

public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms");

// Counts the number of lines read in from standard input.
private static final MeasureLong M_LINES_IN = MeasureLong.create("repl/lines_in", "The number of lines read in", "1");

// Counts the number of non EOF(end-of-file) errors.
private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1");

// Counts/groups the lengths of lines read in.
private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By");

// The tag "method"
private static final TagKey KEY_METHOD = TagKey.create("method");

private static final Tagger tagger = Tags.getTagger();
private static final StatsRecorder statsRecorder = Stats.getStatsRecorder();

public static void main(String ...args) {
    // Step 1. Enable OpenCensus Metrics.
    try {
        setupOpenCensusAndPrometheusExporter();
    } catch (IOException e) {
        System.err.println("Failed to create and register OpenCensus Prometheus Stats exporter "+ e);
        return;
    }

    BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

    while (true) {
        try {
            readEvaluateProcessLine(stdin);
        } catch (IOException e) {
            System.err.println("EOF bye "+ e);
            return;
        } catch (Exception e) {
            recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1));
            return;
        }
    }
}

private static void recordStat(MeasureLong ml, Long n) {
    TagContext tctx = tagger.emptyBuilder().build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(ml, n).record();
    }
}

private static void recordTaggedStat(TagKey key, String value, MeasureLong ml, Long n) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(ml, n).record();
    }
}

private static void recordTaggedStat(TagKey key, String value, MeasureDouble md, Double d) {
    TagContext tctx = tagger.emptyBuilder().put(key, TagValue.create(value)).build();
    try (Scope ss = tagger.withTagContext(tctx)) {
        statsRecorder.newMeasureMap().put(md, d).record();
    }
}

private static String processLine(String line) {
    long startTimeNs = System.nanoTime();

    try {
        return line.toUpperCase();
    } catch (Exception e) {
        recordTaggedStat(KEY_METHOD, "processLine", M_ERRORS, new Long(1));
        return "";
    } finally {
        long totalTimeNs = System.nanoTime() - startTimeNs;
        double timespentMs = (new Double(totalTimeNs))/1e6;
        recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs);
    }
}

private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
    System.out.print("> ");
    System.out.flush();

    String line = in.readLine();
    String processed = processLine(line);
    System.out.println("< " + processed + "\n");
    if (line != null && line.length() > 0) {
        recordStat(M_LINES_IN, new Long(1));
        recordStat(M_LINE_LENGTHS, new Long(line.length()));
    }
}

private static void registerAllViews() {
    // Defining the distribution aggregations
    Aggregation latencyDistribution = Distribution.create(BucketBoundaries.create(
            Arrays.asList(
                // [>=0ms, >=25ms, >=50ms, >=75ms, >=100ms, >=200ms, >=400ms, >=600ms, >=800ms, >=1s, >=2s, >=4s, >=6s]
                0.0, 25.0, 50.0, 75.0, 100.0, 200.0, 400.0, 600.0, 800.0, 1000.0, 2000.0, 4000.0, 6000.0)
            ));

    Aggregation lengthsDistribution = Distribution.create(BucketBoundaries.create(
            Arrays.asList(
                // [>=0B, >=5B, >=10B, >=20B, >=40B, >=60B, >=80B, >=100B, >=200B, >=400B, >=600B, >=800B, >=1000B]
                0.0, 5.0, 10.0, 20.0, 40.0, 60.0, 80.0, 100.0, 200.0, 400.0, 600.0, 800.0, 1000.0)
            ));

    // Define the count aggregation
    Aggregation countAggregation = Aggregation.Count.create();

    // So tagKeys
    List<TagKey> noKeys = new ArrayList<TagKey>();

    // Define the views
    View[] views = new View[]{
        View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.singletonList(KEY_METHOD)),
        View.create(Name.create("ocjavametrics/lines_in"), "The number of lines read in from standard input", M_LINES_IN, countAggregation, noKeys),
        View.create(Name.create("ocjavametrics/errors"), "The number of errors encountered", M_ERRORS, countAggregation, Collections.singletonList(KEY_METHOD)),
        View.create(Name.create("ocjavametrics/line_lengths"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys)
    };

    // Create the view manager
    ViewManager vmgr = Stats.getViewManager();

    // Then finally register the views
    for (View view : views)
        vmgr.registerView(view);
}

private static void setupOpenCensusAndPrometheusExporter() throws IOException {
    // Firstly register the views
    registerAllViews();

    // Create and register the Prometheus exporter
    PrometheusStatsCollector.createAndRegister();

    // Run the server as a daemon on address "localhost:8889"
    HTTPServer server = new HTTPServer("localhost", 8889, true);
}

} {{}}

{{}} 4.0.0 io.opencensus.metrics.quickstart quickstart jar 1.0-SNAPSHOT quickstart http://maven.apache.org

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <opencensus.version>0.17.0</opencensus.version> <!-- The OpenCensus version to use -->
</properties>

<dependencies>
    <dependency>
        <groupId>io.opencensus</groupId>
        <artifactId>opencensus-api</artifactId>
        <version>${opencensus.version}</version>
    </dependency>

    <dependency>
        <groupId>io.opencensus</groupId>
        <artifactId>opencensus-impl</artifactId>
        <version>${opencensus.version}</version>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>io.opencensus</groupId>
        <artifactId>opencensus-exporter-stats-prometheus</artifactId>
        <version>${opencensus.version}</version>
    </dependency>

    <dependency>
        <groupId>io.prometheus</groupId>
        <artifactId>simpleclient_httpserver</artifactId>
        <version>0.4.0</version>
    </dependency>
</dependencies>

<build>
    <extensions>
        <extension>
            <groupId>kr.motd.maven</groupId>
            <artifactId>os-maven-plugin</artifactId>
            <version>1.5.0.Final</version>
        </extension>
    </extensions>

    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>appassembler-maven-plugin</artifactId>
                <version>1.10</version>
                <configuration>
                    <programs>
                        <program>
                            <id>Repl</id>
                            <mainClass>io.opencensus.metrics.quickstart.Repl</mainClass>
                        </program>
                    </programs>
                </configuration>
            </plugin>
        </plugins>

    </pluginManagement>

</build>
{{}} {{}}

Running the tutorial

This step involves running the tutorial application in one terminal and then Prometheus itself in another terminal.

Having properly installed Java and Maven, in one terminal, please run

mvn install
mvn exec:java -Dexec.mainClass=io.opencensus.metrics.quickstart.Repl

Prometheus configuration file

To allow Prometheus to scrape from our application, we have to point it towards the tutorial application whose server is running on "localhost:8889".

To do this, we firstly need to create a YAML file with the configuration e.g. promconfig.yaml whose contents are:

scrape_configs:
  - job_name: 'ocjavametricstutorial'

    scrape_interval: 10s

    static_configs:
      - targets: ['localhost:8889']

Running Prometheus

With that file saved as promconfig.yaml we should now be able to run Prometheus like this

prometheus --config.file=promconfig.yaml

and then return to the terminal that's running the Java metrics quickstart and generate some work by typing inside it and it will look something like:

Viewing your metrics

With the above you should now be able to navigate to the Prometheus UI at http://localhost:9090

which should show:

  • Available metrics

  • Lines-in counts

  • Latency distributions

  • Line lengths distributions

References

Resource URL
Prometheus project https://prometheus.io/
Setting up Prometheus Prometheus Codelab
Prometheus Java exporter https://www.javadoc.io/doc/io.opencensus/opencensus-exporter-stats-prometheus
Java exporters Java exporters
OpenCensus Java Stats package https://www.javadoc.io/doc/io.opencensus/opencensus-api/