Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

For the most part Java developers don’t need to be concerned with NewRelic. The server integration comes with the ability to handle Spring MVC services automatically. This is great, but what about other stuff?

I had a case where we had Spring Scheduler via Quartz firing off jobs based upon a cron schedule. These were not tracked by NewRelic, so we had to manually add them.

Maven Dependency

To add the NewRelic Java API to your project, include the following snippet.

 <dependency>
     <groupId>com.newrelic.agent.java</groupId>
     <artifactId>newrelic-api</artifactId>
     <version>3.36.0</version>
 </dependency>

Instrumenting methods

Instrumenting a call stack is very easy. Add the com.newrelic.api.agent.Trace annotation to the top of the method that you want to monitor and away you go.

@Trace(dispatcher = true)
@scheduled
public void doSomethingOnASchedule() {
    // ...
}

Error Flagging

NewRelic counts errors by counting exceptions that rise up through the instrumented methods. This works, unless your code handles the exceptions and continues on. For cases like this, you need to manually notify NewRelic that an error happened. This is handled by using the com.newrelic.api.agent.NewRelic class.

try {
    // ...
} catch (ConfigClientException ce) {
    logger.error("logging this error to the logs", e);
    NewRelic.noticeError(ce);
    // handle error without throwing
} 

The NewRelic.noticeError method has signatures that take the following data

  • Throwable
  • Throwable, Map
  • String
  • String, Map

Excluding from NewRelic instrumentation

We noticed for some applications that we had some very fast transactions that happened very regularly and the volume scaled perfectly with our servers. It turned out to be our health check system. We provide a URL to the monitoring servers that indicates if the target service is running. We did not want those to be instrumented and skew the results. This isn’t as simple as it could be, but here it goes. You need to make an annotation with a very specific name. The package doesn’t matter. I have no idea why they don’t provide this in the NewRelic API.

package com.javaninja.newrelic;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NewRelicIgnoreTransaction {

}

Once you have created your NewRelicIgnoreTransaction annotation, you can use it to indicate that certain timings should be excluded. An example is below:

    @NewRelicIgnoreTransaction
    @RequestMapping("/healthcheck")
    public String getInternal() {
        return "true";
    }

July 14th, 2017

Posted In: NewRelic

Leave a Comment

Spring Boot

Spring Boot is changing the world of Java development with Spring. It is taking away much of the pain that was involved with configuring applications. This is great when you are trying to create what they do by default. They create executable jars by default. What do you have to do if you need to create a WAR file to run on a Tomcat by someone else.

POM file

Let’s start with our project’s pom.xml file. Here we need to define the standard Spring Boot parent starter and also include include the Spring Boot Web starter. The Spring Boot Web starter also includes the Spring Boot Tomcat starter. In our case, we do not want it packaged inside our war because our war file will be deployed on a Tomcat server directly. We don’t have to roll our own. To change this behavior, we include the Spring Boot tomcat starter explicitly and set it’s scope to provided. We also must specify the packaging of our project to be a war.

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.javaninja.springboot</groupId>
    <artifactId>springboot-web</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

Java Config

Normally the Java Configuration contains a main method because that is how the program will be launched. In this case, we do not need a main method and instead we need to provide a configure method to go along with the SpringBootServletInitializer that we extend.

package com.javaninja.springboot.web;


import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;


@SpringBootApplication
public class WebApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(WebApplication.class);
    }
}

Example Controller

That is all of the configuration that we need to make this work as a normal Spring MVC controller. To test our functionality, we need a very simple controller, such as the following,.

package com.javaninja.springboot.web;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class ExampleController {

    private Logger log = LoggerFactory.getLogger(getClass());

    @GetMapping("/example/boolean")
    public Boolean exampleBoolean() {
        log.info("Eureka!");
        return true;
    }
}

Test the controller

Let’s create a very simple test using the Spring Boot Test starter. This brings in Junit and MockMvc among other useful APIs.

package com.javaninja.springboot.web;


import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.assertj.core.api.Assertions.fail;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


/**
 * @author norris.shelton
 */
@RunWith(SpringRunner.class)
@WebMvcTest(ExampleController.class)
public class TestExampleController {

    @Autowired
    private MockMvc mvc;

    @Test
    public void testExampleBoolean() {
        try {
            mvc.perform(get("/example/boolean")
                            .accept(MediaType.APPLICATION_JSON))
               .andExpect(status().isOk())
               .andExpect(content().string("true"));
        } catch (Exception e) {
            fail(e.toString());
        }
    }
}

The test run perfectly and produces the following logging and a nice pretty green bar.

2017-07-10 18:36:06.218  INFO 7499 --- [           main] c.j.springboot.web.ExampleController     : Eureka!

July 11th, 2017

Posted In: Maven, MockMVC, Spring, Spring Boot, Spring MVC, Test Driven Development, Unit Tests

Tags: , ,

Leave a Comment

LinkedIn Auto Publish Powered By : XYZScripts.com