Cannot get AppInsights working under Spring Boot - azure

I followed the https://learn.microsoft.com/en-us/azure/application-insights/app-insights-java-get-started, but still without success.
I have applicationinsights-web dependency in place via maven
I added ApplicationInsights.xml to main/resources with hardcoded instrumentation key and even with <SDKLogger /> inside
I added the scan path: #ComponentScan({...., "com.microsoft.applicationinsights.web.spring"})
Results:
I see no logs about looking up the configuration file, even if I make the syntax error in in or remove it completely
in debug I see that RequestNameHandlerInterceptorAdapter is instantiated via com.microsoft.applicationinsights.web.spring.internal.InterceptorRegistry, and during calls the preHandle method is called, but calls to ThreadContext.getRequestTelemetryContext() returns always null and nothing more happens
It looks like it is something obvious, but no idea what. What part/classes are responsible for loading the configuration file?

I was a little bit confused with documentation. As mentioned by yonisha, the filter does the whole magic. The following configuration class takes care of creating and adding the filter in Spring Boot application.
import com.microsoft.applicationinsights.web.internal.WebRequestTrackingFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
#Configuration
#ComponentScan("com.microsoft.applicationinsights.web.spring")
public class ApplicationInsightsConfiguration {
#Bean
public FilterRegistrationBean someFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(appInsightsWebRequestTrackingFilter());
registration.addUrlPatterns("/*");
registration.setName("webRequestTrackingFilter");
registration.setOrder(1);
return registration;
}
#Bean(name = "appInsightsWebRequestTrackingFilter")
public Filter appInsightsWebRequestTrackingFilter() {
return new WebRequestTrackingFilter();
}
Important: It will work nicely if you set the server.context-path property to some value. If not, AI initialization will fail with error
AI: ERROR 03-04-2017 14:11, 20: WebApp name is not found, unable to register WebApp
In order to keep servlet-context empty, I had to implement wrappers for the filter and 2 other classes to override it, but it was a very dirty fix... Would be great, if the name could be passed as a parameter to the filter, but that is not yet possible (https://github.com/Microsoft/ApplicationInsights-Java/issues/359)

In spring boot , We need to configure WebRequestTrackingFilter by extending WebSecurityConfigurerAdapter and overriding configure(HttpSecurity httpSecurity)
#Bean
public WebRequestTrackingFilter applicationInsightsFilterBean() throws Exception {
WebRequestTrackingFilter webRequestTrackingFilter = new WebRequestTrackingFilter();
return webRequestTrackingFilter;
}
#Override
public void configure(HttpSecurity httpSecurity) throws Exception {
//other stuff...
httpSecurity.addFilterBefore(applicationInsightsFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
you need to have below configuration also ..
applicationinsights-web dependency in place via maven
added ApplicationInsights.xml to main/resources

Here is newer guide for Spring Boot Application Insights integration that worked well for me just now:
https://github.com/AzureCAT-GSI/DevCamp/tree/master/HOL/java/06-appinsights
The idea is basically what Tomasz has above with some minor differences.
package devCamp.WebApp.configurations;
import javax.servlet.Filter;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.microsoft.applicationinsights.TelemetryConfiguration;
import com.microsoft.applicationinsights.web.internal.WebRequestTrackingFilter;
#Configuration
public class AppInsightsConfig {
#Bean
public String telemetryConfig() {
String telemetryKey = System.getenv("APPLICATION_INSIGHTS_IKEY");
if (telemetryKey != null) {
TelemetryConfiguration.getActive().setInstrumentationKey(telemetryKey);
}
return telemetryKey;
}
#Bean
public FilterRegistrationBean aiFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new WebRequestTrackingFilter());
registration.addUrlPatterns("/**");
registration.setOrder(1);
return registration;
}
#Bean(name = "WebRequestTrackingFilter")
public Filter WebRequestTrackingFilter() {
return new WebRequestTrackingFilter();
}
}
The guide at the link above has a full set of instructions and includes client side js and a java log appender example as well. Hope this helps.

The above all method works! However you can try the whole new seamless experience using Application Insights SpringBoot Starter.
https://github.com/Microsoft/ApplicationInsights-Java/blob/master/azure-application-insights-spring-boot-starter/README.md
This is currently in BETA

Related

Spring Integration JdbcMessageStore casting error

I am trying to create service that will read some data from remote server and process them using Spring Integration.
I have class that extends ArrayList, because I need to keep pointer to other page, so I can read it in next remote call. I set up release strategy to collect all these pages, until there is no pointer for the next page.
Here is definition of class:
public class CustomList extends ArrayList<DataInfo>
{
private String nextCursor;
// Methods omitted for readability
}
Everything worked fine, until I setup JdbcMessageStore in Aggregator, so I can keep messages in case of service shutdown.
Problem on which I come across is that in my release strategy class I cast my list class to same class (because message group does not define type), this exceptions is raised:
java.lang.ClassCastException: com.example.CustomList cannot be cast to com.example.CustomList
This is my release strategy class:
#Component
public class CursorReleaseStrategy implements ReleaseStrategy
{
#Override
public boolean canRelease(MessageGroup group)
{
return group.getMessages().stream()
.anyMatch(message -> ((CustomList) message.getPayload()).getNextCursor() == null);
}
}
If I remove message store, everything works fine, but the problem is that I need message store.
I am using spring boot 2.1.6 and Spring Integration DSL for creating this flow.
From what I read, this error happens because of different class loaders, but this I do from the same application.
Is there anything more that I need to configure for this to work_
Almost certainly a class loader issue; you can find which class loader loads each component (message store, release strategy) by injecting them into a bean and calling getClass().getClassLoader().
When application has been packaged in jar, there was such error.
So to fix the problem I created two beans, depending on profile.
For example:
#Profile("!prod")
#Bean
public MessageGroupStore messageStore(DataSource dataSource)
{
JdbcMessageStore jdbcMessageStore = new JdbcMessageStore(dataSource);
jdbcMessageStore.setDeserializer(inputStream -> {
ConfigurableObjectInputStream objectInputStream = new ConfigurableObjectInputStream(inputStream, Thread.currentThread().getContextClassLoader());
try {
return (Message<?>) objectInputStream.readObject();
} catch (ClassNotFoundException var4) {
throw new NestedIOException("Failed to deserialize object type", var4);
}
});
return jdbcMessageStore;
}
#Profile("prod")
#Bean
public MessageGroupStore prodMessageStore(DataSource dataSource)
{
return new JdbcMessageStore(dataSource);
}

How can I run code in JUnit before Spring starts?

How can I run code in my #RunWith(SpringRunner.class) #SpringBootTest(classes = {...}) JUnit test before Spring starts?
This question has been asked several times (e.g. 1, 2) but was always "solved" by some configuration recommendation or other, never with a universal answer. Kindly don't question what I am about to do in that code but simply suggest a clean way to do it.
Tried so far and failed:
Extend SpringJUnit4ClassRunner to get a class whose constructor can run custom code before initializing Spring. Failed because super(testClass) must be called first thing and already does a whole lot of things that get in the way.
Extend Runner to get a class that delegates to SpringRunner instead of inheriting it. This class could run custom code in its constructor before actually instantiating the SpringRunner. However, this setup fails with obscure error messages like java.lang.NoClassDefFoundError: javax/servlet/SessionCookieConfig. "Obscure" because my test has no web config and thus shouldn't meddle with sessions and cookies.
Adding an ApplicationContextInitializer that is triggered before Spring loads its context. These things are easy to add to the actual #SpringApplication, but hard to add in Junit. They are also quite late in the process, and a lot of Spring has already started.
One way to do it is to leave out SpringRunner and use the equivalent combination of SpringClassRule and SpringMethodRule instead. Then you can wrap the SpringClassRule and do your stuff before it kicks in:
public class SomeSpringTest {
#ClassRule
public static final TestRule TestRule = new TestRule() {
private final SpringClassRule springClassRule =
new SpringClassRule();
#Override
public Statement apply(Statement statement, Description description) {
System.out.println("Before everything Spring does");
return springClassRule.apply(statement, description);
}
};
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
#Test
public void test() {
// ...
}
}
(Tested with 5.1.4.RELEASE Spring verison)
I don't think you can get more "before" than that. As for other options you could also check out #BootstrapWith and #TestExecutionListeners annotations.
Complementing jannis' comment on the question, the option to create an alternative JUnit runner and let it delegate to the SpringRunner does work:
public class AlternativeSpringRunner extends Runner {
private SpringRunner springRunner;
public AlternativeSpringRunner(Class testClass) {
doSomethingBeforeSpringStarts();
springRunner = new SpringRunner(testClass);
}
private doSomethingBeforeSpringStarts() {
// whatever
}
public Description getDescription() {
return springRunner.getDescription();
}
public void run(RunNotifier notifier) {
springRunner.run(notifier);
}
}
Being based on spring-test 4.3.9.RELEASE, I had to override spring-core and spring-tx, plus javax.servlet's servlet-api with higher versions to make this work.

How do I Mock SpringApplication.run

I have a File handler for Spring Batch that I want to test.
SpringApplication.run() is a static method for which I would like to verify the arguments passed to it.
Does this mean I need to go down the PowerMock path or is there something in the SpringFramework that will enable me to test this?
public File handleFile(File file) {
// Start the Batch Process and set the inputFile parameter
String[] args = {"--inputFile=" + file.getAbsolutePath()};
SpringApplication.run(InitialFileBatchApplication.class, args);
return null;
}
My test class has the following annotations which don't seem to be working:
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
#SpringBootTest
#PrepareForTest(SpringApplication.class)
What am I missing?
The exception getting thrown is:
java.lang.IllegalStateException: Failed to transform class with name org.springframework.boot.SpringApplication. Reason: cannot find
org.springframework.web.context.support.StandardServletEnvironment
This occurs when the #PrepareForTest(SpringApplication.class) is processed. I'm testing a Spring Batch application so there is no web environment and I've also added.
#SpringBootTest(webEnvironment=WebEnvironment.NONE)
As I share your dislike for PowerMock, the first answer is unfortunately: the method that you have written right now - yes that can only be tested using PowerMock.
So, if you want to test that method; you have to use PowerMock. Or you take the minimal risk ... and simply don't test it.
Beyond that: I recommend to put that method into some interface; you simply want to prevent that this static call gives you trouble when you start testing other methods that want to call handleFile() - then you want to be able to mock that call; to prevent that static call inside to happen.
This issue due to the exception that I was having was due to a missing entry in the pom.xml, which frustrates me a bit with the SpringFramework since I'm working only in a batch application and have no web or servlet components whatsoever in this test. The missing pom entry was.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
The other spring dependecies that I had were
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
In order to test this, I did take the approach of PowerMock with externalizing some of the methods so that I could test them and even though I'm testing with a Spring Application, I was able to exclude the SpringRunner that loads the context to simplify this test. Below is my implementation class as well as the test class that tested it.
import java.io.File;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
public class InitialFileInputFileHandler {
private Logger logger = LoggerFactory.getLogger(InitialFileInputFileHandler.class);
/**
* Handles the Initial Client files that get put into the input directory that match the pattern
* defined in initialFileListenerApplicationContext.xml
* #param file - The file
* #return
*/
public File handleFile(File file) {
logger.info("Got the Initial Client file: " + file.getAbsolutePath() + " start Batch Processing");
// Start the Batch Process and set the inputFile parameter
String[] args = buildArguments(file);
SpringApplication.run(InitialFileBatchApplication.class, args);
// Whatever we return is written to the outbound-channel-adapter.
// Returning null will not write anything out and we do not need an outbound-channel-adapter
return null;
}
protected String[] buildArguments(File file) {
String[] args = {"--inputFile=" + file.getAbsolutePath()};
return args;
}
}
And here's the test class
import static org.mockito.Mockito.*;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.MatcherAssert.*;
import java.io.File;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.boot.SpringApplication;
// This test class must test static methods. One way to do that is with PowerMock.
// Testing with static methods so we have to run with the PowerMockRunner.
#RunWith(PowerMockRunner.class)
// The static method that we want to test is in the SpringApplication class so
// by using PowerMock we have to prepare this class for testing.
#PrepareForTest({SpringApplication.class})
// If you wanted to load a SpringContext you'd have to include the SpringRunner.
// Since our Runner is PowerMockRunner, we still have to setup the spring context, so
// you setup the SpringRunner as the delegate.
//#PowerMockRunnerDelegate(SpringRunner.class)
public class InitialFileInputFileHandlerTest {
// Setup a mockFile so that I can specify what comes back from the getAbsolutiePath method
// without actually to have a file on the file system.
#Mock File mockFile;
private InitialFileInputFileHandler handler;
#Before
public void setUp() throws Exception {
handler = new InitialFileInputFileHandler();
org.mockito.Mockito.when( mockFile.getAbsolutePath() ).thenReturn("src/input/fooFile.txt");
}
#Test
public void testBuildArguments(){
String[] args = handler.buildArguments(mockFile);
assertThat( args[0], equalTo("--inputFile=src/input/fooFile.txt") );
}
#Test
public void testHandleFile() throws Exception {
// Tell PowerMockito to keep track of my static method calls in the SpringApplication class
PowerMockito.mockStatic( SpringApplication.class );
// What I expect the argument to be
String[] args = {"--inputFile=src/input/fooFile.txt"};
// Call the actual method
handler.handleFile(mockFile);
// Have to call verifyStatic since its a static method.
PowerMockito.verifyStatic();
// One of a few possibilities to test the execution of the static method.
//SpringApplication.run( InitialFileBatchApplication.class, args);
//SpringApplication.run( Mockito.any(InitialFileBatchApplication.class), eq(args[0]));
SpringApplication.run( Mockito.any(Object.class), eq(args[0]));
}
}
1.if you want to verify args in your tests, you need to return it to caller code of method handleFile(file) and currently you are doing - return null; , instead you should return args ( if method signature can be changed ).
I have assumed that handleFile method is in InitialFileBatchApplication class.
#Test
public void testHandleFile() {
File file = new File("ABC");
String[] response = new InitialFileBatchApplication().handleFile(file);
//Verify response here
}
Above will actually kick off your job.
2.If you wish to mock - SpringApplication.run as it is , PowerMock is the way to go. You should indicate in question as what error you are getting with current set up.
3.Mockito is inbuilt in Spring Test now so if you can refactor your code to have a non - static method call the static method then you can mock non - static method and that will eventually mock your static call. #MockBean annotation is part of Spring Test.
4.If Mocking SpringApplication.run in spring batch is equivalent to not running the job but simply initializing the context then purpose can be achieved by saying , spring.batch.job.enabled=false in application.properties. Only that your unit tests will have to wait for real call to - SpringApplication.run to complete but job will not kick off.
Code refactoring is always encouraged to make your code unit testable in addition to functionally being correct so don't hesitate to refactor to overcome framework limitations.
Hope it helps !!

Mockito implemetation for formhandlers in ATG

I am new to Mockito as a concept. Can you please help me understand using Mockito for formhandlers in ATG. Some examples will be appreciated.
There is a good answer (related to ATG) for other similar question: using-mockito-for-writing-atg-test-case. Please review if it includes what you need.
Many of ATG-specific components (and form handlers particularly) are known to be "less testable" (in comparison to components developed using TDD/BDD approach), b/c design of OOTB components (including reference application) doesn't always adhere to the principle of having "Low Coupling and High Cohesion"
But still the generic approach is applicable for writing unit-tests for all ATG components.
Below is a framework we've used for testing ATG FormHandlers with Mockito. Obviously you'll need to put in all the proper bits of the test but this should get you started.
public class AcmeFormHandlerTest {
#Spy #InjectMocks private AcmeFormHandler testObj;
#Mock private Validator<AcmeInterface> acmeValidatorMock;
#Mock private DynamoHttpServletRequest requestMock;
#Mock private DynamoHttpServletResponse responseMock;
private static final String ERROR1_KEY = "error1";
private static final String ERROR1_VALUE = "error1value";
#BeforeMethod(groups = { "unit" })
public void setUp() throws Exception {
testObj = new AcmeFormHandler();
initMocks(this);
}
//Test the happy path scenario
#Test(groups = { "unit" })
public void testWithValidData() throws Exception {
testObj.handleUpdate(requestMock, responseMock);
//Assume your formhandler calls a helper method, then ensure the helper method is called once. You verify the working of your helper method as you would do any Unit test
Mockito.verify(testObj).update(Matchers.refEq(requestMock), Matchers.refEq(responseMock), Mockito.anyString(), (AcmeBean) Mockito.anyObject());
}
//Test a validation exception
#Test(groups = { "unit" })
public void testWithInvalidData() throws Exception {
Map<String, String> validationMessages = new HashMap<String, String>();
validationMessages.put(ERROR1_KEY, ERROR1_VALUE);
when(acmeValidatorMock.validate((AcmeInterface) Mockito.any())).thenReturn(validationMessages);
testObj.handleUpdate(requestMock, responseMock);
assertEquals(1, testObj.getFormExceptions().size());
DropletFormException exception = (DropletFormException) testObj.getFormExceptions().get(0);
Assert.assertEquals(exception.getMessage(), ERROR1_VALUE);
}
//Test a runtime exception
#Test(groups = { "unit" })
public void testWithRunProcessException() throws Exception {
doThrow(new RunProcessException("")).when(testObj).update(Matchers.refEq(requestMock), Matchers.refEq(responseMock), Mockito.anyString(), (AcmeBean) Mockito.anyObject());
testObj.handleAddGiftCardToCart(requestMock, responseMock);
assertEquals(1, testObj.getFormExceptions().size());
DropletFormException exception = (DropletFormException) testObj.getFormExceptions().get(0);
Assert.assertEquals(exception.getMessage(), GENERAL_ERROR_KEY);
}
}
Obviously the above is just a framework that fit in nicely with the way in which we developed our FormHandlers. You can also add validation for redirects and stuff like that if you choose:
Mockito.verify(responseMock, Mockito.times(1)).sendLocalRedirect(SUCCESS_URL, requestMock);
Ultimately the caveats of testing other people's code still applies.
Here's what I do when I unit test a form handler (at least until I manage to release a major update for AtgDust). Note that I don't use wildcard imports, so I'm not sure if this causes any namespace conflicts.
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
import org.junit.*;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.*;
import atg.servlet.*;
import some.form.handler.FormHandler;
#RunWith(JUnit4.class)
public class FormHandlerTest {
#Mock DynamoHttpServletRequest request;
#Mock DynamoHttpServletResponse response;
FormHandler handler;
#Before
public void setup() {
initMocks(this);
handler = new FormHandler();
}
#Test
public void testSubmitHandlerRedirects() {
handler.handleSubmit(request, response);
verify(response).sendLocalRedirect(eq("/success.jsp"), eq(request));
assertThat(handler.getFormError(), is(false));
}
}
The basic idea is to set up custom behavior for mocks/stubs using when() on the mock object method invocation to return some test value or throw an exception, then verify() mock objects were invoked an exact number of times (in the default case, once), and do any assertions on data that's been changed in the form handler. Essentially, you'll want to use when() to emulate any sort of method calls that need to return other mock objects. When do you need to do this? The easiest way to tell is when you get NPEs or other runtime exceptions due to working with nulls, zeros, empty strings, etc.
In an integration test, ideally, you'd be able to use a sort of in-between mock/test servlet that pretends to work like a full application server that performs minimal request/session/global scope management. This is a good use for Arquillian as far as I know, but I haven't gotten around to trying that out yet.

Unable to get default constructor for Integration class ninject

I'm new on using ninject and Dependency Injection, and have a problem using it.
I try to using Ninject on my class libray, and building an integration tests.
now, I see in many example that, for using ninject is just specified the DI Module like this:
Public Class DIModule : NinjectModule
public override void Load()
{
Bind<IUSAServices>().To<USAServices>();
}
And then on my test class, I try to call my dependency is like this:
[TestClass]
public class USAIntegrationTests
{
private readonly IUSAServices _usaService;
public USAIntegrationTests(IUSAServices usaServices)
{
_usaService = usaServices;
}
[TestMethod]
public void ValidateUserTests()
{
Assert.IsTrue(_usaService.ValidateUser("username1", "password1"));
}
}
And Getting this error:
Unable to get default constructor for class USATests.IntegrationTests.USAIntegrationTests.
However I read the documentation and tried like this:
[TestClass]
public class USAIntegrationTests
{
private readonly IUSAServices _usaService;
public USAIntegrationTests()
{
using (IKernel kernel = new StandardKernel(new DIModule()))
{
_usaService = kernel.Get<IUSAServices>();
}
}
[TestMethod]
public void ValidateUserTests()
{
Assert.IsTrue(_usaService.ValidateUser("mantab", "banget"));
}
}
The test is works properly.
My question is, why I getting that error? is that some way to get around it?
Thanks in advance.
Unit test frameworks require your test classes to have a default constructor. You usually can't integrate DI containers with them. Instead of using constructor injection, you will have to call the container directly from your code, although for unit tests you should typically not have a container at all (for integration tests however, this is okay).
You can add a paramterless constructor for the class. It worked for me.

Resources