Spring Boot Logger Aspects - java

I'm having problems getting my logging aspect to log information when methods from classes of a particular package are accessed. In other words, "no" logging occurs. I even got desperate and added System.out.println statements, with no luck.
All of my classes are located under the org.my.package package, i.e. org.my.package.controller, org.my.package.model, etc.
Here is my Application class:
package org.my.package;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#ComponentScan(basePackages = {"org.my.package.config"})
#EnableAutoConfiguration
#EnableAspectJAutoProxy
public class FirstWebAppApplication {
public static void main(String[] args) {
SpringApplication.run(FirstWebAppApplication.class, args);
}
}
This is my configuration class:
package org.my.package.config;
import org.deloitte.javatraining.daythree.utilities.MyLogger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#EnableAspectJAutoProxy
#ComponentScan(basePackages = {"org.my.package.utilities"})
public class AssetConfig {
//-----------------------------------------------------------------------------------------------------------------------
#Bean
public MyLogger myLogger(){
return new MyLogger();
}
}
This is my Aspect class:
package org.my.package.utilities;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class MyLogger {
/** Handle to the log file */
private final Log log = LogFactory.getLog(getClass());
public MyLogger () {}
#AfterReturning("execution(* org.my.package.*.*(..))")
public void logMethodAccessAfter(JoinPoint joinPoint) {
log.info("***** Completed: " + joinPoint.getSignature().getName() + " *****");
System.out.println("***** Completed: " + joinPoint.getSignature().getName() + " *****");
}
#Before("execution(* org.my.package.*.*(..))")
public void logMethodAccessBefore(JoinPoint joinPoint) {
log.info("***** Starting: " + joinPoint.getSignature().getName() + " *****");
System.out.println("***** Starting: " + joinPoint.getSignature().getName() + " *****");
}
}
These are my Gradle build dependencies:
dependencies {
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-web")
compile('com.h2database:h2:1.3.156')
compile('javax.servlet:jstl:1.2')
compile('org.springframework.boot:spring-boot-starter-aop')
providedRuntime("org.apache.tomcat.embed:tomcat-embed-jasper")
testCompile("org.springframework.boot:spring-boot-starter-test")
}
Am I missing something or otherwise mis-configuring my Aspect class? I can't find anything wrong, after verifying with other, similar Stack Overflow questions and online tutorials.
Please advise.

Your point cut, execution( * org.my.package.*.*(..)), is only matching the execution of methods on classes in the org.my.packagepackage not sub packages.
What you probably want is execution( * org.my.package..*.*(..)) notice the .. instead of ..

Related

spring cloud stream - gcp pubsub binder maxFetchSize?

try to use spring cloud gcp binder library polling messages from GCP pubsub topic.
ref from streaming-vs-polled-input. use spring.cloud.stream.gcp.pubsub.default.consumer.maxFetchSize poll get N message (maxFetchSize's value) at a time, but even i set up the property and set maxFetchSize to 2 or others. i alwasy got 1 message from topic, even the topic has other messages. Does anyone here has other idea?
spring cloud version: 2021.0.3
google spring-cloud-gcp-dependencies version: 3.3.0
java: openjdk 11
# application.properties
spring.cloud.gcp.pubsub.project-id=
spring.cloud.gcp.credentials.location=
spring.cloud.stream.default-binder=pubsub
spring.cloud.stream.bindings.input.destination=iamatopic
spring.cloud.stream.bindings.input.content-type=text/plain;charset=UTF-8
spring.cloud.stream.gcp.pubsub.default.consumer.maxFetchSize=3
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.cloud.stream.binder.PollableMessageSource;
public interface PollableSink {
#Input("input")
PollableMessageSource input();
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.binder.PollableMessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.scheduling.annotation.Scheduled;
import com.google.cloud.spring.pubsub.support.AcknowledgeablePubsubMessage;
import com.google.cloud.spring.pubsub.support.GcpPubSubHeaders;
import lombok.extern.slf4j.Slf4j;
#Configuration
#EnableBinding(PollableSink.class)
#Slf4j
public class PollConfiguration {
#Autowired
PollableMessageSource destIn;
PolledMessageHandler messageHandler = new PolledMessageHandler();
#Scheduled(fixedRate = 5000)
public void poller() {
log.info("start polling ");
destIn.poll(this.messageHandler, ParameterizedTypeReference.forType(String.class));
log.info("end polling ");
}
static class PolledMessageHandler implements MessageHandler {
#Override
public void handleMessage(Message<?> message) {
AcknowledgeablePubsubMessage ackableMessage = (AcknowledgeablePubsubMessage) message.getHeaders()
.get(GcpPubSubHeaders.ORIGINAL_MESSAGE);
ackableMessage.ack();
System.out.println("get payload : " + message.getPayload());
}
}
}
Try setting spring.cloud.stream.poller.maxMessagesPerPoll value -- it's 1 by default in Spring Cloud Stream.
Reference: https://docs.spring.io/spring-cloud-stream/docs/current/reference/html/spring-cloud-stream.html#_polling_configuration_properties

Why my Spring Boot #Pointcut not triggering with #Around advise and ProceedingJoinPoint?

I am trying to log some info during api call in console in my Spring Boot application. I have used Spring Aop and trying to use #Around advise with #Pointcut by using ProceedingJoinPoint. The program is compiling successfully & runs quite well. But logging is not happening in console. I think my Pointcut is not triggering. My code is given bellow. Please help.
package org.mycomp.mat.aspect;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.mycomp.mycompmat.user.profile.service.UserProfile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
#Aspect
#Component
public class LoggingAspect {
Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
#Pointcut("execution(public * org.mycomp.mat.repository..*(..))")
public void requestPointcut() {
}
#Around("requestPointcut()")
public Object requestLogger(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
ObjectMapper objectMapper = new ObjectMapper();
String methodName = proceedingJoinPoint.getSignature().getName();
String className = proceedingJoinPoint.getTarget().getClass().toString();
Object[] inputArguments = proceedingJoinPoint.getArgs();
logger.info(
"Operation " + methodName +
" Of " + className +
" On " + LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME) +
" With Input Parameters :-> " + objectMapper.writeValueAsString(inputArguments)
);
Object object = proceedingJoinPoint.proceed();
logger.info(objectMapper.writeValueAsString(object));
return object;
}
}
the issue is with the pointcut expression missing * for the class name part
like org.mycomp.mat.repository.myClass.myMethod({arguments})
change from #Pointcut("execution(public * org.mycomp.mat.repository..*(..))") to #Pointcut("execution(public * org.mycomp.mat.repository.*.*(..))")

#JmsListener - hitting the destined queue continuously

I have a spring boot application with JMS messaging included. The receiver and the connection Factory is as below,The problem I am having is the listener always looks the queue and prints in logs, Logs attached for reference. It should trigger the process() when there is a message in the queue.
Any help appreciated
package uk.gov.hmrc.cds.dmscaseemulator.receiver;
import javax.jms.JMSException;
import javax.jms.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import uk.gov.hmrc.cds.dmscaseemulator.bo.DMSMessageProcessBO;
#Service
#Slf4j
public class DMSQReceiver {
#Value("${queue.DMS_Q}")
private String listeningQ;
#Autowired DMSMessageProcessBO processBo;
#JmsListener(destination="${queue.DMS_Q}", containerFactory = "myFactory")
public void recv(Message message) throws JMSException{
try{
log.info("Listening to : {} ", listeningQ);
processBo.process(message);
}catch(JMSException ex){
log.error("ERROR IN DMS Case Emulator while receiving " + listeningQ +". ERROR IS : ", ex);
throw ex;
}
}
}
package uk.gov.hmrc.cds.dmscaseemulator.config;
import javax.jms.ConnectionFactory;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;
#Configuration
#EnableJms
public class JMSConfig {
#Bean
public JmsListenerContainerFactory<?> myFactory(
ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
configurer.configure(factory, connectionFactory);
return factory;
}
}
20:23:37.281 [DefaultMessageListenerContainer-1] INFO u.g.h.c.d.receiver.DMSQReceiver - Listening to : DMS.QA.CTRL_MGMT_EXPORT
20:23:37.282 [DefaultMessageListenerContainer-1] DEBUG u.g.h.c.d.b.c.ControlTypeResolver - Found control type
20:23:37.282 [DefaultMessageListenerContainer-1] DEBUG u.g.h.c.d.b.c.ControlTypeResolver - Returning control type value : 3
20:23:37.283 [DefaultMessageListenerContainer-1] INFO u.g.h.c.d.bo.DMSMessageProcessBO - Control Type is: 3
20:23:37.290 [DefaultMessageListenerContainer-1] INFO u.g.h.c.d.receiver.DMSQReceiver - Listening to : DMS.QA.CTRL_MGMT_EXPORT
20:23:37.291 [DefaultMessageListenerContainer-1] DEBUG u.g.h.c.d.b.c.ControlTypeResolver - Found control type
20:23:37.291 [DefaultMessageListenerContainer-1] DEBUG u.g.h.c.d.b.c.ControlTypeResolver - Returning control type value : 3
20:23:37.292 [DefaultMessageListenerContainer-1] INFO u.g.h.c.d.bo.DMSMessageProcessBO - Control Type is: 3

Problem with cutomizing ErrorAttributeOptions in Spring Reactive

In my handler function I have this method
public Mono<ServerResponse> itemsEx(ServerRequest serverRequest) {
throw new RuntimeException("RuntimeException Occured");
}
Now, I want to handle this exception, so I override AbstractErrorWebExceptionHandler and create this class.
package com.learnreactivespring.learnreactivespring.exception;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.*;
import reactor.core.publisher.Mono;
import java.util.Map;
#Component
#Slf4j
public class FunctionalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
public FunctionalErrorWebExceptionHandler(ErrorAttributes errorAttributes,
ApplicationContext applicationContext,
ServerCodecConfigurer serverCodecConfigurer) {
super(errorAttributes, new ResourceProperties(), applicationContext);
super.setMessageWriters(serverCodecConfigurer.getWriters());
super.setMessageReaders(serverCodecConfigurer.getReaders());
}
#Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
private Mono<ServerResponse> renderErrorResponse(ServerRequest serverRequest) {
ErrorAttributeOptions errorAttributes = ErrorAttributeOptions.of(ErrorAttributeOptions.Include.MESSAGE);
Map<String, Object> errorAttributesMap = getErrorAttributes(serverRequest, errorAttributes);
log.info("errorAttributesMap : " + errorAttributesMap);
return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(errorAttributesMap.get("message")));
}
The problem is, that I have still a Stacktrace in my terminal... but I explicitly defined ErrorAttributeOptions only with message.
My current version of Spring Boot is 2.3.1.RELEASE. In previous version (2.1.1) I didn't have this problem because I used to this
package com.learnreactivespring.exception;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.*;
import reactor.core.publisher.Mono;
import java.util.Map;
#Component
#Slf4j
public class FunctionalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
public FunctionalErrorWebExceptionHandler(ErrorAttributes errorAttributes,
ApplicationContext applicationContext,
ServerCodecConfigurer serverCodecConfigurer) {
super(errorAttributes, new ResourceProperties(), applicationContext);
super.setMessageWriters(serverCodecConfigurer.getWriters());
super.setMessageReaders(serverCodecConfigurer.getReaders());
}
#Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
private Mono<ServerResponse> renderErrorResponse(ServerRequest serverRequest) {
Map<String, Object> errorAttributesMap = getErrorAttributes(serverRequest, false);
log.info("errorAttributesMap : " + errorAttributesMap);
return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(errorAttributesMap.get("message")));
}
}
Now, after bumped version of Spring Boot this issue occured.
You should use ErrorAttributeOptions.defaults(). But note that by default message is always empty (and stacktrace is not present).
So you probably want to use something like this:
ErrorAttributeOptions options = ErrorAttributeOptions
.defaults()
.including(ErrorAttributeOptions.Include.MESSAGE)
;
And use .excluding(.) if you want to exclude something.

#Value returning null in unit test

I have a spring boot app with an Endpoint Test Configuration class and a unit test to test my http client. I am trying to get my server address and port from my application.properties which is located in my src/test.(All the classes are in my src/test.)
Here is my config class code :
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import javax.xml.bind.JAXBException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import com.nulogix.billing.service.PredictionEngineService;
import com.nulogix.billing.ws.endpoint.AnalyzeEndPoint;
import com.nulogix.billing.ws.endpoint.GetVersionEndPoint;
#Configuration
public class EndPointTestConfiguration {
#Value("${billing.engine.address}")
private String mockAddress;
#Value("${billing.engine.port}")
private String mockPort;
#Bean
public String getAddress() {
String serverAddress = "http://" + mockAddress + ":" + mockPort;
return serverAddress;
}
#Bean
public GetVersionEndPoint getVersionEndPoint() {
return new GetVersionEndPoint();
}
I annotated the values from my .properties with #value and then created a method that I instantiated with a bean to to return my server address string.
I then use that string value here in my HttpClientTest class:
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.Map;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ConfigurableApplicationContext;
import com.google.gson.Gson;
import com.nulogix.billing.configuration.EndPointTestConfiguration;
import com.nulogix.billing.mockserver.MockServerApp;
#SpringBootTest(classes = EndPointTestConfiguration.class)
public class HttpClientTest {
#Autowired
EndPointTestConfiguration endpoint;
public static final String request_bad = "ncs|56-2629193|1972-03-28|20190218|77067|6208|3209440|self|";
public static final String request_good = "ncs|56-2629193|1972-03-28|20190218|77067|6208|3209440|self|-123|-123|-123|0.0|0.0|0.0|0.0|0.0|0.0|0.0";
//gets application context
static ConfigurableApplicationContext context;
//call mock server before class
#BeforeClass
static public void setup(){
SpringApplication springApplication = new SpringApplicationBuilder()
.sources(MockServerApp.class)
.build();
context = springApplication.run();
}
//shutdown mock server after class
#AfterClass
static public void tearDown(){
SpringApplication.exit(context);
}
#Test
public void test_bad() throws ClientProtocolException, IOException {
// missing parameter
String result = Request.Post(endpoint.getAddress())
.connectTimeout(2000)
.socketTimeout(2000)
.bodyString(request_bad, ContentType.TEXT_PLAIN)
.execute().returnContent().asString();
Map<?, ?> resultJsonObj = new Gson().fromJson(result, Map.class);
// ensure the key exists
assertEquals(resultJsonObj.containsKey("status"), true);
assertEquals(resultJsonObj.containsKey("errorMessage"), true);
// validate values
Boolean status = (Boolean) resultJsonObj.get("status");
assertEquals(status, false);
String errorMessage = (String) resultJsonObj.get("errorMessage");
assertEquals(errorMessage.contains("Payload has incorrect amount of parts"), true);
}
#Test
public void test_good() throws ClientProtocolException, IOException {
String result = Request.Post(endpoint.getAddress())
.connectTimeout(2000)
.socketTimeout(2000)
.bodyString(request_good, ContentType.TEXT_PLAIN)
.execute().returnContent().asString();
Map<?, ?> resultJsonObj = new Gson().fromJson(result, Map.class);
// ensure the key exists
assertEquals(resultJsonObj.containsKey("status"), true);
assertEquals(resultJsonObj.containsKey("errorMessage"), false);
assertEquals(resultJsonObj.containsKey("HasCopay"), true);
assertEquals(resultJsonObj.containsKey("CopayAmount"), true);
assertEquals(resultJsonObj.containsKey("HasCoinsurance"), true);
assertEquals(resultJsonObj.containsKey("CoinsuranceAmount"), true);
assertEquals(resultJsonObj.containsKey("version"), true);
// validate values
Boolean status = (Boolean) resultJsonObj.get("status");
assertEquals(status, true);
String version = (String) resultJsonObj.get("version");
assertEquals(version, "0.97");
}
}
I use it in the request.post, I didn't want to hardcode in my IP address and port number.
When I run the test it says
[ERROR] HttpClientTest.test_bad:63 NullPointer
[ERROR] HttpClientTest.test_good:86 NullPointer
But I am not sure why it is null? I am pretty sure I have everything instantiated and the string is clearly populated..
My package structure for my config is com.billing.mockserver and my package structure for my unit test is com.billing.ws.endpoint.
Here is my application.properties
server.port=9119
server.ssl.enabled=false
logging.config=classpath:logback-spring.xml
logging.file=messages
logging.file.max-size=50MB
logging.level.com.nulogix=DEBUG
billing.engine.address=127.0.0.1
billing.engine.port=9119
billing.engine.api.version=0.97
billing.engine.core.name=Patient_Responsibility
You are missing springboot basic understanding. #Configuration class is to initialize other spring beans and other things and are the first classes which get initialized. You should not #Autowire #configuration class.
In your Configuration class you can either create Spring bean for username and password and autowire that in your test class or directly use #Value in your Test class.
Example: in your configuration class you are creating bean of GetVersionEndPoint and you can autowire that in your Test class.
Update 2:
For test classes, you need to add application.properties file in src\test\resource

Categories

Resources