• EnglishEspañol日本語한국어Português
  • Log inStart now

OpenTelemetry tutorials: Instrument a sample Java app

Try out these Java tutorials to see what the New Relic platform can do with your OTLP data. We have three tutorials you can choose from, each one using the same demo Spring app. The app will calculate the nth number in the Fibonacci sequence and generate traces, metrics, and logs.

By working through these tutorials, you can learn skills to help you set up your own app with OpenTelemetry and New Relic.

After you finish any of these tutorials, you can view JVM metrics in charts like these.

Requirements

To get started, make sure you have the following:

Tutorials

Although each tutorial uses the same demo app, they have different approaches to help you become acquainted with OpenTelemetry and New Relic.

Click on the tab below for the tutorial you want to complete.

Tip

When using OpenTelemetry, you'll have two choices for exporting data from your application to New Relic via OTLP:

  • Directly from your app to New Relic
  • Your app sends data to an OpenTelemetry Collector where it is then exported to New Relic

These tutorials cover the first option. If you want to export your data via a collector, check out this collector documentation for details.

Run the pre-instrumented demo app

This is a great option if you want us to do the instrumentation so you can quickly see what it's like to send data to New Relic and view it in our UI.

  1. In your terminal, run the following to clone the demo app and navigate to the Getting Started Guides' java directory.

    bash
    $
    git clone https://github.com/newrelic/newrelic-opentelemetry-examples.git
    $
    cd newrelic-opentelemetry-examples/getting-started-guides/java
  2. Set these two environment variables to send data to your New Relic account:

    • Make sure to use your .

    • If your New Relic data center region is EU and not US, set the endpoint to: https://otlp.eu01.nr-data.net

      • OTEL_EXPORTER_OTLP_HEADERS=api-key=INSERT_YOUR_NEW_RELIC_LICENSE_KEY
      • OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net
      • OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
  3. Set the first environment variable below to name the service, then set the second for the service instance ID, which activates certain platform features. Finally, enable logs since logging is off by default:

    • OTEL_SERVICE_NAME=getting-started-java
    • OTEL_RESOURCE_ATTRIBUTES=service.instance.id=INSERT_YOUR_ID_HERE
      • Replace INSERT_YOUR_OWN_ID_HERE with a unique instance id. For example, you could use 1234.
    • OTEL_LOGS_EXPORTER=otlp
  4. In the same getting-started-guides/java directory, build and run the application:

    • macOS:

      bash
      $
      ./gradlew bootRun
    • PowerShell:

      bash
      $
      .\gradlew.bat build
  5. Open a new terminal tab, switch to the getting-started-guides/java/Instrumented directory, and run the following command to generate some traffic to the application:

    • macOS:

      bash
      $
      ./load-generator.sh
    • PowerShell:

      bash
      $
      .\load-generator.ps1

    Tip

    Alternatively, you can reach the endpoint in the browser at this URL: http://localhost:8080/fibonacci?n=INSERT_A_VALUE. Replace INSERT_A_VALUE with a value from 1 to 90. To generate an error, insert an integer outside the valid range.

  6. Go to one.newrelic.com > All capabilities > APM & services.

  7. Click your new entity (service) called getting-started-java and explore the UI. For more tips about what to look for in the UI, see View your data in New Relic.

  8. When you're finished looking at your data in the UI, shut down the application by pressing CONTROL+C in both terminal sessions.

Monitor the demo app with the OpenTelemetry Java agent

Here's a different tutorial that also uses the same demo app. In this case, you'll use the OpenTelemetry Java agent to automatically monitor the demo app. You don't need to modify the Java source code. By using the agent, you can quickly start exporting sample data to New Relic.

The auto-instrumentation agent is a JAR file that dynamically injects bytecode to capture telemetry from popular libraries and frameworks. You can also use it to capture data such as inbound requests, outbound HTTP calls, and database calls. It can be attached to any Java 8+ application.

Tip

See the official Java agent documentation for additional configuration options.

To monitor our demo app with the OpenTelemetry Java agent:

  1. Download the agent JAR file, which contains the agent and instrumentation libraries. Place it in your preferred directory and note the path, which you will use later.

  2. If you haven't already done so, download the demo application repository and switch to the following directory:

    bash
    $
    git clone https://github.com/newrelic/newrelic-opentelemetry-examples.git
    $
    cd newrelic-opentelemetry-examples/getting-started-guides/java
  3. Build the demo app with this command:

    • macOS:
      bash
      $
      ./gradlew build
    • PowerShell:
      bash
      $
      .\gradlew.bat build

      Tip

      After a successful build, you will find the resulting application JAR file in Uninstrumented/build/libs, called uninstrumented.jar.

  4. Go to our environment variables reference section below to see which variables you need to export and then return to these steps.

  5. Continue in getting-started-guides/java/Uninstrumented to launch the agent with the app:

    Important

    Replace path/to with the location of the JAR file you downloaded earlier.

    bash
    $
    java -javaagent:path/to/opentelemetry-javaagent.jar \
    >
    -jar ./build/libs/uninstrumented.jar
  6. Generate traffic to the application by opening a new terminal in the getting-started-guides/java/Uninstrumented directory and running the load generator:

    • macOS:

      bash
      $
      ./load-generator.sh
    • PowerShell:

      bash
      $
      .\load-generator.ps1

    Tip

    Alternatively, you can reach the endpoint in the browser at this URL: http://localhost:8080/fibonacci?n=INSERT_A_VALUE. Replace INSERT_A_VALUE with a value from 1 to 90. To generate an error, insert an integer outside the valid range.

  7. Now that you've sent some data to New Relic, see our instructions on viewing the data in the UI.

  8. When you're finished looking at your data in the UI, shut down the application by pressing CONTROL+C in both terminal sessions.

Set up the demo app manually

The previous tutorial helped you explore automatic instrumentation with the OpenTelemetry Java agent. This tutorial will show you how to use custom instrumentation to have more control over the telemetry you gather. You'll manually insert instrumentation into our demo app to capture telemetry, and then you'll configure the SDK to export that data to New Relic.

Tip

While you can manually configure the SDK, we will show you how to configure the SDK using the autoconfigure option, which simplifies the the process by using environment variables and system properties.

Download the demo application

If you haven't already downloaded our demo app, run the following:

bash
$
git clone https://github.com/newrelic/newrelic-opentelemetry-examples.git

Install dependencies

To add dependencies:

  1. Go to the application directory.

    bash
    $
    cd newrelic-opentelemetry-examples/getting-started-guides/java/uninstrumented
  2. Open build.gradle.

  3. Add the following highlighted items to the dependencies block (you may need to scroll down inside the code block):

    plugins {
    id 'org.springframework.boot' version '2.7.5'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
    }
    java {
    toolchain {
    languageVersion = JavaLanguageVersion.of(17)
    }
    }
    repositories {
    mavenCentral()
    }
    bootRun {
    mainClass.set 'com.example.demo.Application'
    }
    configurations.all {
    exclude module: 'spring-boot-starter-logging'
    }
    dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-log4j2'
    // OpenTelemetry core
    implementation platform('io.opentelemetry:opentelemetry-bom:1.22.0')
    implementation platform('io.opentelemetry:opentelemetry-bom-alpha:1.22.0-alpha')
    implementation 'io.opentelemetry:opentelemetry-api'
    implementation 'io.opentelemetry:opentelemetry-sdk'
    implementation 'io.opentelemetry:opentelemetry-exporter-otlp'
    implementation 'io.opentelemetry:opentelemetry-exporter-otlp-logs'
    implementation 'io.opentelemetry:opentelemetry-sdk-extension-autoconfigure'
    // OpenTelemetry instrumentation
    implementation platform('io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:1.22.1-alpha')
    implementation 'io.opentelemetry.instrumentation:opentelemetry-runtime-metrics'
    implementation 'io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17'
    implementation 'io.opentelemetry.instrumentation:opentelemetry-spring-webmvc-6.0'
    }

Notes:

  • The bom (bill of materials) dependencies are used to synchronize versions of dependencies for a particular ecosystem. Since OpenTelemetry publishes a lot of Java components, these help ensure that all the versions are synchronized, whether you use just a few or a lot of them.
  • The remaining dependencies provide access to the SDK, API, OTLP exporter, and instrumentation libraries.
  • There is an additional configuration to exclude the spring-boot-starter-logging module. This prevents a build error message relating to log4j-slf4j-impl cannot be present with log4j-to-slf4j.

Configure the SDK with the autoconfigure extension

While you can configure the SDK manually, we recommend you use the autoconfigure extension since it streamlines the process.

  1. Go to the app's source code directory:

    bash
    $
    cd newrelic-opentelemetry-examples/getting-started-guides/java/uninstrumented/src/main/java/com/example/demo
  2. Open Application.java.

  3. Insert the highlighted lines:

    @SpringBootApplication
    public class Application {
    private static volatile OpenTelemetry openTelemetry = OpenTelemetry.noop();
    public static void main(String[] args) {
    // Build the SDK auto-configuration extension module
    OpenTelemetrySdk openTelemetrySdk = AutoConfiguredOpenTelemetrySdk.builder()
    .setResultAsGlobal(false)
    .build()
    .getOpenTelemetrySdk();
    Application.openTelemetry = openTelemetrySdk;
    SpringApplication.run(Application.class, args);
    }
    @Bean
    public OpenTelemetry openTelemetry() {
    return openTelemetry;
    }
    }
  4. Go to our environment variables reference section below to see which variables you need to export and then return to these steps.

Add instrumentation libraries: traces

In Application.java, add the highlighted instrumentation for Spring Web MVC by registering a tracing filter:

@SpringBootApplication
public class Application {
private static volatile OpenTelemetry openTelemetry = OpenTelemetry.noop();
public static void main(String[] args) {
// Build the SDK auto-configuration extension module
OpenTelemetrySdk openTelemetrySdk = AutoConfiguredOpenTelemetrySdk.builder()
.setResultAsGlobal(false)
.build()
.getOpenTelemetrySdk();
Application.openTelemetry = openTelemetrySdk;
SpringApplication.run(Application.class, args);
}
@Bean
public OpenTelemetry openTelemetry() {
return openTelemetry;
}
// Add Spring WebMVC instrumentation by registering a tracing filter
@Bean
public Filter webMvcTracingFilter(OpenTelemetry openTelemetry) {
return SpringWebMvcTelemetry.create(openTelemetry).createServletFilter();
}
}

Add instrumentation libraries: metrics

Generate and collect metrics about your Java runtime by registering the following in the Application.java file. Insert the highlighted lines below:

@SpringBootApplication
public class Application {
private static volatile OpenTelemetry openTelemetry = OpenTelemetry.noop();
public static void main(String[] args) {
// Build the SDK auto-configuration extension module
OpenTelemetrySdk openTelemetrySdk = AutoConfiguredOpenTelemetrySdk.builder()
.setResultAsGlobal(false)
.build()
.getOpenTelemetrySdk();
Application.openTelemetry = openTelemetrySdk;
// Register runtime metrics instrumentation
BufferPools.registerObservers(openTelemetrySdk);
Classes.registerObservers(openTelemetrySdk);
Cpu.registerObservers(openTelemetrySdk);
GarbageCollector.registerObservers(openTelemetrySdk);
MemoryPools.registerObservers(openTelemetrySdk);
Threads.registerObservers(openTelemetrySdk);
SpringApplication.run(Application.class, args);
}
@Bean
public OpenTelemetry openTelemetry() {
return openTelemetry;
}
// Add Spring WebMVC instrumentation by registering a tracing filter
@Bean
public Filter webMvcTracingFilter(OpenTelemetry openTelemetry) {
return SpringWebMvcTelemetry.create(openTelemetry).createServletFilter();
}
}

Add instrumentation libraries: logs

This demo application is configured to use the OpenTelemetryAppender (via log4j.xml), which uses GlobalLoggerProvider. Setting GlobalLoggerProvider wires up the OpenTelemetryAppender to the Log SDK that is configured using autoconfigure here:

  1. Open Application.java.

  2. Insert the following highlighted lines.

    @SpringBootApplication
    public class Application {
    private static volatile OpenTelemetry openTelemetry = OpenTelemetry.noop();
    public static void main(String[] args) {
    // Build the SDK auto-configuration extension module
    OpenTelemetrySdk openTelemetrySdk = AutoConfiguredOpenTelemetrySdk.builder()
    .setResultAsGlobal(false)
    .build()
    .getOpenTelemetrySdk();
    Application.openTelemetry = openTelemetrySdk;
    // Set GlobalLoggerProvider, which is used by Log4j2 appender
    GlobalLoggerProvider.set(openTelemetrySdk.getSdkLoggerProvider());
    // Register runtime metrics instrumentation
    BufferPools.registerObservers(openTelemetrySdk);
    Classes.registerObservers(openTelemetrySdk);
    Cpu.registerObservers(openTelemetrySdk);
    GarbageCollector.registerObservers(openTelemetrySdk);
    MemoryPools.registerObservers(openTelemetrySdk);
    Threads.registerObservers(openTelemetrySdk);
    SpringApplication.run(Application.class, args);
    }
    @Bean
    public OpenTelemetry openTelemetry() {
    return openTelemetry;
    }
    // Add Spring WebMVC instrumentation by registering a tracing filter
    @Bean
    public Filter webMvcTracingFilter(OpenTelemetry openTelemetry) {
    return SpringWebMvcTelemetry.create(openTelemetry).createServletFilter();
    }
    }
  3. Create a directory called resources in Uninstrumented/src/main.

  4. In this new directory, create a file called log4j2.xml with the following contents:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="WARN" packages="io.opentelemetry.instrumentation.log4j.appender.v2_17">
    <Appenders>
    <Console name="ConsoleAppender" target="SYSTEM_OUT" follow="true">
    <PatternLayout pattern="%d{yyyy-mm-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <OpenTelemetry name="OpenTelemetryAppender" />
    </Appenders>
    <Loggers>
    <Root level="info">
    <AppenderRef ref="OpenTelemetryAppender" />
    <AppenderRef ref="ConsoleAppender" />
    </Root>
    </Loggers>
    </Configuration>

    Tip

    The packages=... section of this line allows Log4J to find and configure the OpenTelemetryAppender. The source code is in the OpenTelemetry repository and was added as a dependency via io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17)

Custom trace instrumentation: Create span attribute constants

Each trace is made up of spans, which represent a logical unit of work or an operation within a particular request. The code below demonstrates:

  • Static constants to hold attribute keys that can be used to provide request-level insights in your spans
  • How to initialize a Tracer, which creates spans

Insert the following highlighted lines into Controller.java:

@RestController
public class Controller {
// Attribute constants
private static final AttributeKey<Long> ATTR_N = AttributeKey.longKey("fibonacci.n");
private static final AttributeKey<Long> ATTR_RESULT = AttributeKey.longKey("fibonacci.result");
private final Tracer tracer;
@Autowired
Controller(OpenTelemetry openTelemetry) {
// Initialize tracer
tracer = openTelemetry.getTracer(Controller.class.getName());
}
@GetMapping(value = "/fibonacci")
. . .
}

Custom trace instrumentation: Create a custom span

You can create whatever spans you want, and it is up to you to annotate your spans with attributes on specific operations. The attributes you set will provide additional context about the specific operation you are tracking, such as results or operation properties.

  1. In Controller.java, insert these highlighted lines to start a new span called fibonacci that does the following:

    • Captures data about the execution of this method
    • Sets an attribute that stores the value of n from the user's request
    private long fibonacci(long n) {
    // Start a new span and set your first attribute
    var span = tracer.spanBuilder("fibonacci").setAttribute(ATTR_N, n).startSpan();
    . . .
    }
  2. Add granular detail into your code by adding an attribute to your span for storing information about successful requests:

    private long fibonacci(long n) {
    // Start a new span and set your first attribute
    var span = tracer.spanBuilder("fibonacci").setAttribute(ATTR_N, n).startSpan();
    try {
    if (n < 1 || n > 90) {
    throw new IllegalArgumentException("n must be 1 <= n <= 90.");
    }
    long result = 1;
    if (n > 2) {
    long a = 0;
    long b = 1;
    for (long i = 1; i < n; i++) {
    result = a + b;
    a = b;
    b = result;
    }
    // Set a span attribute to capture information about successful requests
    span.setAttribute(ATTR_RESULT, last);
    return last;
    } catch (IllegalArgumentException e) {
    throw e;
    }
    }

Custom trace instrumentation: Record an exception

You may want to record exceptions as they happen. We recommend you do this in conjunction with setting the span status. First, set your span as the current span, set the status code to error in the event of an exception, and then end the span:

private long fibonacci(long n) {
// Start a new span and set your first attribute
var span = tracer.spanBuilder("fibonacci").setAttribute(ATTR_N, n).startSpan();
// Set the span as the current span
try (var scope = span.makeCurrent()) {
if (n < 1 || n > 90) {
throw new IllegalArgumentException("n must be 1 <= n <= 90.");
}
long result = 1;
if (n > 2) {
long a = 0;
long b = 1;
for (long i = 1; i < n; i++) {
result = a + b;
a = b;
b = result;
}
}
// Set a span attribute to capture information about successful requests
span.setAttribute(ATTR_RESULT, result);
return result;
} catch (IllegalArgumentException e) {
// Record the exception and set the span status
span.recordException(e).setStatus(StatusCode.ERROR, e.getMessage());
throw e;
} finally {
// End the span
span.end();
}
}

This method throws an IllegalArgumentException if a user provides invalid input. When this happens, the exception is recorded as an event on the span and the span's status will be set to ERROR. The exception message is captured as the status description. The exception will be recorded as an event on the span where it occurs.

Finally, in handleException() in the ErrorHandler class, set the status for the span to ERROR with these highlighted lines:

@ControllerAdvice
private static class ErrorHandler {
@ExceptionHandler({
IllegalArgumentException.class,
MissingServletRequestParameterException.class,
HttpRequestMethodNotSupportedException.class
})
public ResponseEntity<Object> handleException(Exception e) {
// Set the span status and description
Span.current().setStatus(StatusCode.ERROR, e.getMessage());
return new ResponseEntity<>(Map.of("message", e.getMessage()), HttpStatus.BAD_REQUEST);
}
}

As in the previous step, this sets the span's status code if the user inputs an invalid number. However, because this happens in the exception handler, rather than in fibonacci(), the current span is the parent span for the request. This parent span comes from the Spring Web MVC instrumentation added via the filter in the Application class. Now, when your application endpoint raises an exception, both the parent span and child span will have a span status of ERROR.

Custom metric instrumentation: Add a custom metric counter

Metrics are a telemetry data type that are really helpful because they combine individual measurements into aggregations, and produce data that is constant as a function of system load. You can use this data in conjunction with spans to help spot trends and provide application runtime telemetry. You can also annotate any metric with attributes to help describe what subdivision of the measurements the metric represents.

The OpenTelemetry metrics API defines a number of instruments, which record measurements that are aggregated by the metrics SDK and exported out of process. There are two types of instruments:

  • Synchronous: These instruments record measurements as they occur
  • Asynchronous: These instruments register a callback, which is invoked only once per collection and do not have associated context

Tip

If you have any questions about the status of metric in the OpenTelemetry project, see the signal statuses.

Complete the following to add a custom counter:

  1. Instantiate a boolean attribute for your custom metric and initialize a metrics instrument.

    Tip

    In this case, we are using a LongCounter, which records only positive values and is useful for counting things, such as the number of bytes sent over a network. By default, counter measurements are aggregated to monotonic (always increasing) sums.

    @RestController
    public class Controller {
    // Attribute constants
    private static final AttributeKey<Long> ATTR_N = AttributeKey.longKey("fibonacci.n");
    private static final AttributeKey<Long> ATTR_RESULT = AttributeKey.longKey("fibonacci.result");
    private static final AttributeKey<Boolean> ATTR_VALID_N = AttributeKey.booleanKey("fibonacci.valid.n");
    private final Tracer tracer;
    private final LongCounter fibonacciInvocations;
    @Autowired
    Controller(OpenTelemetry openTelemetry) {
    // Initialize tracer
    tracer = openTelemetry.getTracer(Controller.class.getName());
    // Initialize instrument
    Meter meter = openTelemetry.getMeter(Controller.class.getName());
    fibonacciInvocations = meter
    .counterBuilder("fibonacci.invocations")
    .setDescription("Measures the number of times the fibonacci method is invoked.")
    .build();
    }
    . . .
    }
  2. Insert the following highlighed lines so your custom counter can capture valid and invalid inputs, as well as the number of times each occurs.

    private long fibonacci(long n) {
    // Start a new span and set your first attribute
    var span = tracer.spanBuilder("fibonacci").setAttribute(ATTR_N, n).startSpan();
    // Set the span as the current span
    try (var scope = span.makeCurrent()) {
    if (n < 1 || n > 90) {
    throw new IllegalArgumentException("n must be 1 <= n <= 90.");
    }
    long result = 1;
    if (n > 2) {
    long a = 0;
    long b = 1;
    for (long i = 1; i < n; i++) {
    result = a + b;
    a = b;
    b = result;
    }
    }
    // Set a span attribute to capture information about successful requests
    span.setAttribute(ATTR_RESULT, result);
    // Counter to increment the number of times a valid input is recorded
    fibonacciInvocations.add(1, Attributes.of(ATTR_VALID_N, true));
    return result;
    } catch (IllegalArgumentException e) {
    // Record the exception and set the span status
    span.recordException(e).setStatus(StatusCode.ERROR, e.getMessage());
    // Counter to increment the number of times an invalid input is recorded
    fibonacciInvocations.add(1, Attributes.of(ATTR_VALID_N, false));
    throw e;
    } finally {
    // End the span
    span.end();
    }
    }

Custom log instrumentation

The status of the logs signal in OpenTelemetry Java is currently experimental. Log messages are managed by the root handler in your app, which will send logs of INFO level and higher to the console by default. However, you can modify the logger behavior by changing the logging level, including for specific classes, or installing a custom handler or filter.

Initialize the logger

As previously stated, this is from the java.util.logging library. The Logger is not an OpenTelemetry component, but the application has been configured to send Log4j logs to the OpenTelemetry Log SDK:

@RestController
public class Controller {
// Logger (note that this is not an OTel component)
private static final Logger LOGGER = LogManager.getLogger(Controller.class);
// Attribute constants
private static final AttributeKey<Long> ATTR_N = AttributeKey.longKey("fibonacci.n");
private static final AttributeKey<Long> ATTR_RESULT = AttributeKey.longKey("fibonacci.result");
private static final AttributeKey<Boolean> ATTR_VALID_N = AttributeKey.booleanKey("fibonacci.valid.n");
. . .
}
Add custom log messages

Once you've initialized the logger, you can use the logger to record:

  • The result of a valid input, along with the value of that result
  • When no output was recorded

Insert the following highlighted lines:

private long fibonacci(long n) {
// Start a new span and set your first attribute
var span = tracer.spanBuilder("fibonacci").setAttribute(ATTR_N, n).startSpan();
// Set the span as the current span
try (var scope = span.makeCurrent()) {
if (n < 1 || n > 90) {
throw new IllegalArgumentException("n must be 1 <= n <= 90.");
}
long result = 1;
if (n > 2) {
long a = 0;
long b = 1;
for (long i = 1; i < n; i++) {
result = a + b;
a = b;
b = result;
}
}
// Set a span attribute to capture information about successful requests
span.setAttribute(ATTR_RESULT, result);
// Counter to increment the number of times a valid input is recorded
fibonacciInvocations.add(1, Attributes.of(ATTR_VALID_N, true));
// Log the result of a valid input
LOGGER.info("Compute fibonacci(" + n + ") = " + result);
return result;
} catch (IllegalArgumentException e) {
// Record the exception and set the span status
span.recordException(e).setStatus(StatusCode.ERROR, e.getMessage());
// Counter to increment the number of times an invalid input is recorded
fibonacciInvocations.add(1, Attributes.of(ATTR_VALID_N, false));
// Log when no output was recorded
LOGGER.info("Failed to compute fibonacci(" + n + ")");
throw e;
} finally {
// End the span
span.end();
}
}

Exercise the app to generate some traffic

You're ready to send some data to New Relic!

  1. Go to the directory getting-started-guides/java, and build and run the app with this command:

    • macOS:

      bash
      $
      ./gradlew bootRun
    • PowerShell:

      bash
      $
      .\gradlew.bat build

      Tip

      If your terminal displays the Spring ASCII, it means your app has successfully built and is running:

  2. Generate traffic from the application by opening a new terminal in the getting-started-guides/java/Uninstrumented directory and running the load generator:

    • macOS:

      bash
      $
      ./load-generator.sh
    • PowerShell:

      bash
      $
      .\load-generator.ps1

    Tip

    Alternatively, you can reach the endpoint in the browser at this URL: http://localhost:8080/fibonacci?n=INSERT_A_VALUE. Replace INSERT_A_VALUE with a value from 1 to 90. To generate an error, insert an integer outside the valid range.

  3. Now that you've sent some data to New Relic, see our instructions on viewing the data in the UI.

View your demo data in New Relic

No matter which tutorial you completed, you can follow the tips below for finding your data in the New Relic UI.

  1. Go to one.newrelic.com > All capabilities > APM & services.
  2. Click your new entity (service) called getting-started-java (or whatever name you provided).
  3. Check out the details in the sections for each data type.

Tip

If you are using Windows and do not see data in your New Relic account, check that you have allowed traffic through the firewall.

Traces

Once you've reached the getting-started-java entity in New Relic:

  1. In the left pane's Monitor section, click Distributed tracing, and then click the Fibonacci trace group.
  2. From there, find a trace with an error and click to open it.

    Tip

    With the OpenTelemetry Java agent, you might see different result than you'd see with the New Relic APM Java agent. This is because there's a difference in error handling between the two agent types. For more information, see Handling error rate in OpenTelemetry and New Relic.
  3. Once you have the trace open, click Show in-process spans, and then click on the resulting span, which will open up a details panel to the right. To see the exception you recorded when a user input is invalid, click on View span events:

If you completed the manual instrumentation tutorial, here's how the exception you recorded as a span will look in New Relic:

To view additional details that you set, such as the span attribute, span name, and status code, click on the Attributes tab. This pane is also where you can view additional metadata that is automatically collected by the instrumentation libraries you used in this guide, as well as metadata that is attached by New Relic:

For more details about viewing your data, see OpenTelemetry in the New Relic UI

Metrics

Once you've reached the getting-started-java entity in New Relic, you can see a list of all collected metrics, such as runtime metrics (JVMs) and your custom counter attributes.

Metrics explorer

This is a tool that allows you to see a list of your metrics.

  1. In the left pane, select Data > Metrics explorer, and then select fibonacci.invocations.

  2. Under Dimensions, view the attributes you collected along with your custom metric, and then click on fibonacci.valid.n.

Learn more in our documentation about the metrics explorer view.

JVMs

You can also view visualizations of your Java runtime metrics, including throughput, memory usage, and garbage collection time per minute, by heading to the JVM page:

You can view the metrics for a single instance, or select multiple instances to compare them:

Here is what you will see after selecting your instances and clicking Compare, where each instance is color coded for easy identification:

To learn more, see our documentation about the JVMs view.

Logs

Here is where to access your logs:

You will also see logs in your terminal:

Back in your logs view, select a log, and you will see a pane open up with the log message and additional attributes that were collected, such as the associated span and trace ids, as well as metadata injected by New Relic:

You can navigate to the correlated distributed trace by clicking this little blue icon:

This will open a pane that displays the correlated trace, where you can view more details about the trace. For more about this page, see OpenTelemetry in the UI: Distributed tracing page and Understand and use the distributed tracing UI:

You can also find the correlated log from the distributed traces view. When you select a trace that has a corresponding log, you will see that indicated as a tab, and you can view the log directly from the trace without having to switch views:

Learn more about the logs view here.

Reference: Environment variables

This is a list of the environment variables you should export if you're doing tutorial 2 or 3. After you finish exporting the variables, return to the tutorials using the links that follow the variable list:

After you've created the environment variables listed in the collapser above, return to the tutorial and complete the setup:

What's next?

Now that you've experimented with OpenTelemetry instrumentation and SDK configuration, you can apply what you've learned to set up your own app or service with OpenTelemetry and New Relic. For more, see Set up your own app or service with OpenTelemetry.

Copyright © 2024 New Relic Inc.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.