You can install it to the corporate artifactory and use as package I added needed configs to gradle file. ARTIFACTORY_URL = url to your artifactory
Just add it as dependency to your build.gradle (or build.gradle.kts) old gradle version
Add dependency
(for old gradle)
compile kz.progger.starter:spring-boot-starter-logger:0.0.3(for new gradle)
implementation kz.progger.starter:spring-boot-starter-logger:0.0.3from artifactory.progger.kz to your build.gradle file.
@Logger - logs path info, execution time, authorized username and passed arguments to the method
Add @Logger annotation on the top of your class, interface (including annotation type) declaration.
<pre>
...
spring:
autoconfigure:
exclude: org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration</pre>
<p>Without this config app will respond 401 "Unauthorized" error</p>
When multiple service hops are required to process a request or when multi-threading is implemented.
MDC data is passed to thread children, it doesnt work when threads are reused in a thread pool.
That is why instead of ThreadPoolExecutor use MdcThreadPoolExecutor which will add context to the child threads.
#####3) Rabbit and Akka When sending messages between servers, you have to manually set current requestId, because it will lost
RabbitMQConfig Example:
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate();
rabbitTemplate.setMessageConverter(jsonMessageConverter());
rabbitTemplate.setConnectionFactory(connectionFactory);
rabbitTemplate.setBeforePublishPostProcessors((MessagePostProcessor) message -> {
<b><i>message.getMessageProperties().setHeader("reqId", codaRequestId.get());</i></b>
return message;
});
return rabbitTemplate;
}
@Bean
public SimpleRabbitListenerContainerFactory jsaFactory(ConnectionFactory connectionFactory,
SimpleRabbitListenerContainerFactoryConfigurer configurer) {
SimpleRabbitListenerContainerFactory factory =
new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
factory.setMessageConverter(jsonMessageConverter());
factory.setConcurrentConsumers(30);
factory.setMaxConcurrentConsumers(30);
factory.setAdviceChain(org.springframework.amqp.rabbit.config.RetryInterceptorBuilder
.stateless()
.maxAttempts(10)
.backOffOptions(10_000, 2.0, 3600_000)
.build(),
(MethodInterceptor) invocation -> {
Message message = (Message) invocation.getArguments()[1];
codaRequestId.set(message.getMessageProperties().getHeaders().get("reqId")
.toString());
return invocation.proceed();
});
return factory;
}
(v2.0 - updates)
@Logger
| argValue | About | Default Value |
|---|---|---|
| logArgValue | Logging passed arguments to the method | true |
@ExcludeLogger - not log info on annotated method. It will help to avoid confidential information about customer or
some configuration values.
Useful link about what we should not log.
In version 0.0.3 you can regulate the size of arguments passed and responded from server
| argValue | About | Default Value |
|---|---|---|
| reqLogArgValLength | Length of request arg to log | -1 |
| resLogArgValLength | Length of response arg to log | -1 |
###Example
package kz.progger.example.HelloController;
...
import Logger;
...
@Controller
@RequestMapping("/customer")
@Logger
public class CustomerController {
@GetMapping
public String hello(@RequestParam String name) {
return "Hello" + name;
}
@GetMapping("/log-arg-size")
@Logger(reqLogArgValLength = 3, resLogArgValLength=3)
public String hello(@RequestParam String name) {
return "Hello" + name;
}
@GetMapping("/v2")
@ExcludeLogger
public String helloWithoutLog(@RequestParam String name) {
return "Hello" + name;
}
@PostMapping("/signin")
@Logger(logArgValue = false)
public ResponseEntity authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
...
return ResponseEntity.ok(new JwtAuthenticationResponse(jwt,tokenProvider.getAuthorities(authentication)));
}
}
And when you call this hello method you will see following info log details on your console:
2019-12-12 12:43:45,143 INFO [kz.progger.example.CustomerController] (http-nio-8080-exec-1) invoke [CustomerController.hello] requestId: 20191212_124345_008_W45 as anonymousUser with args: [{name}]
2019-12-12 12:43:45,609 INFO [[kz.progger.example.CustomerController] (http-nio-8080-exec-1) invoke [CustomerController.hello] requestId: 20191212_124345_008_W45 ok in [5 ms] as anonymousUser with result: [{Hello name}]
2019-12-12 12:43:45,143 INFO [kz.progger.example.CustomerController] (http-nio-8080-exec-1) invoke [CustomerController.hello] requestId: 20191212_124345_008_W45 as anonymousUser with args: [{na}]
2019-12-12 12:43:45,609 INFO [[kz.progger.example.CustomerController] (http-nio-8080-exec-1) invoke [CustomerController.hello] requestId: 20191212_124345_008_W45 ok in [5 ms] as anonymousUser with result: [{H}]
2019-12-12 12:43:48,143 INFO [kz.progger.example.CustomerController] (http-nio-8080-exec-1) invoke [CustomerController.authenticateUser] requestId: 20191212_124345_008_W45 as anonymousUser
2019-12-12 12:43:49,609 INFO [[kz.progger.example.CustomerController] (http-nio-8080-exec-1) invoke [CustomerController.authenticateUser] requestId: 20191212_124345_008_W45 ok in [5 ms] as anonymousUser
It will help you to control:
- Log when method is called and ended
- The incoming and outgoing arguments of this method
- How much time it was longed
To do this we used AOP. You can read detailed here
One of the benefit of the starter it has RequestListener which will generate X-Request-Id (unique Id for every request) on every request.Why its useful?
In our systems we need to deal with multiple clients simultaneously. On such system we can have different clients on multithreads. This requestId will help to developer increase their management overhead.Now developer will not take care and waisting time writing logger on every method