How to measure service methods using spring boot 2 and micrometer - java

I started my first project on Spring Boot 2 (RC1). Thanks to the already good documentation this has not been to hard coming from Spring Boot 1.x.
However now that I want to integrate metrics I'm stumbeling. As far as I was able to find currently there is only documentation for the metrics shipped by default. But I'd like to also measure service level execution time as well as the time used in dynamodb.
EDIT
I'm looking for a solution using Micrometer, the library used in the new actuator library shipped with spring-boot 2.
Is there any guide on how this should be done? From this I read that there is no easy annotation based solution for arbitrary spring beans yet. Could s.o. give me an example / link to documentation on how a method like below could be metered?
#Service
#Timed
public class MyService {
public void doSomething() {
...;
}
}

#io.micrometer.core.annotation.Timed annotation seems to be out of order for custom calls due to reduction of scope, at it is mentioned in link in your question.
You need to manually setup an Aspect:
#Configuration
#EnableAspectJAutoProxy
public class AutoTimingConfiguration {
#Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
}
This way method like this:
#Timed("GET_CARS")
public List<Car> getCars(){
return Lists.newArrayList();
}
will result in GET_CARS metric in /actuator/metrics (default) endpoint.

Here's a little sample which should get you going. There's more variants to Timer.record() which aren't shown here. (Also: Field injection only used for brevity.)
You don't have to put the called methods name into a tag. You can also make it part of the metric name itself. Just wanted to show what you could do.
Update 2018-03-12: As of Micrometer 1.0.0 a TimedAspect has been introduced so that you can also use the #Timed annotation. For now you need to register the Bean yourself. (You need to be cautious though when you have custom #Timed annotations on your Spring-MVC or Jersey resources.) This was already mentioned by Michal Stepan in a follow-up answer.
package io.github.mweirauch.micrometered.eval;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import io.micrometer.core.annotation.Timed;
import io.micrometer.core.aop.TimedAspect;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.Timer.Sample;
#Configuration
#EnableAspectJAutoProxy
public class TimingStuff {
#Service
static class MyService {
#Autowired
private MeterRegistry registry;
public void helloManual() {
// you can keep a ref to this; ok to call multiple times, though
Timer timer = Timer.builder("myservice").tag("method", "manual").register(registry);
// manually do the timing calculation
long start = System.nanoTime();
doSomething();
timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS);
}
public void helloSupplier() {
Timer timer = Timer.builder("myservice").tag("method", "supplier").register(registry);
// execution of the method is timed internally
timer.record(() -> doSomething());
}
public void helloSample() {
Timer timer = Timer.builder("myservice").tag("method", "sample").register(registry);
// records time taken between Sample creation and registering the
// stop() with the given Timer
Sample sample = Timer.start(registry);
doSomething();
sample.stop(timer);
}
// TimedAspect adds "class" and "method" tags
#Timed(value = "myservice.aspect")
public void helloAspect() {
doSomething();
}
private void doSomething() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
//
}
}
}
#Autowired
private MyService myService;
#Bean
TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
#Scheduled(fixedRate = 1000)
public void postConstruct() {
myService.helloManual();
myService.helloSupplier();
myService.helloSample();
myService.helloAspect();
}
}
In case you go for Prometheus, you'd end up with something like that:
# HELP myservice_seconds
# TYPE myservice_seconds summary
myservice_seconds_count{application="micrometered",method="manual",} 4.0
myservice_seconds_sum{application="micrometered",method="manual",} 0.200378014
myservice_seconds_max{application="micrometered",method="manual",} 0.050115291
myservice_seconds_count{application="micrometered",method="supplier",} 4.0
myservice_seconds_sum{application="micrometered",method="supplier",} 0.200393455
myservice_seconds_max{application="micrometered",method="supplier",} 0.05011635
myservice_seconds_count{application="micrometered",method="sample",} 4.0
myservice_seconds_sum{application="micrometered",method="sample",} 0.200527005
myservice_seconds_max{application="micrometered",method="sample",} 0.050250191
# HELP myservice_aspect_seconds
# TYPE myservice_aspect_seconds summary
myservice_aspect_seconds_count{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 4.0
myservice_aspect_seconds_sum{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 0.201824272
myservice_aspect_seconds_max{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 0.051014296

Related

Not able to rollback DB changes in Aspect in Spring boot application

I have written one aspect around a service class. In the aspect, I am doing some operation in the before section, which I would like to be rolled back if some exception occurs in the enclosed service method.
The service class is as follows:
#Service
#Transactional
class ServiceA {
...
public void doSomething() {
...
}
...
}
The aspect is as follows:
#Aspect
#Order(2)
public class TcStateManagementAspect {
...
#Around(value = "applicationServicePointcut()", argNames = "joinPoint")
public Object process(ProceedingJoinPoint joinPoint)
throws Throwable {
...
*/Before section */
do some processing and persist in DB
...
Object object = joinPoint.proceed();
...
do some post-processing
}
}
I am seeing an exception in the service method is not rolling back the DB operation in the Begin Section. I tried putting #Transactional on #Around, but it did not help.
In this context, I have gone through the following posts:
Spring #Transactional in an Aspect (AOP)
Custom Spring AOP Around + #Transactional
But I am not able to get any concrete idea regarding how to achieve this. Could anyone please help here? Thanks.
Like I said in my comment, what your around advice does must be declared transactional too. You cannot do that directly, because #Transactional internally uses Spring AOP via dynamic proxies. However, Spring AOP aspects cannot be the target of other aspects. But you can simply create a new helper #Component which you delegate your advice's action to.
Let us assume that the goal is to log the arguments of the #Transactional method targeted by your aspect. Then simply do this:
package com.example.managingtransactions;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class TxLogAspect {
private final static Logger logger = LoggerFactory.getLogger(TxLogAspect.class);
#Autowired
TxLogService txLogService;
#Pointcut(
"#annotation(org.springframework.transaction.annotation.Transactional) && " +
"!within(com.example.managingtransactions.TxLogService)"
)
public void applicationServicePointcut() {}
#Around("applicationServicePointcut()")
public Object process(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info(joinPoint.toString());
// Delegate to helper component in order to be able to use #Transactional
return txLogService.logToDB(joinPoint);
}
}
package com.example.managingtransactions;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
/**
* Helper component to delegate aspect advice execution to in order to make the
* advice transactional.
* <p>
* Aspect methods themselves cannot be #Transactional, because Spring AOP aspects
* cannot be targeted by other aspects. Delegation is a simple and elegant
* workaround.
*/
#Component
public class TxLogService {
#Autowired
private JdbcTemplate jdbcTemplate;
#Transactional
public Object logToDB(ProceedingJoinPoint joinPoint) throws Throwable {
jdbcTemplate.update(
"insert into TX_LOG(MESSAGE) values (?)",
Arrays.deepToString(joinPoint.getArgs())
);
return joinPoint.proceed();
}
public List<String> findAllTxLogs() {
return jdbcTemplate.query(
"select MESSAGE from TX_LOG",
(rs, rowNum) -> rs.getString("MESSAGE")
);
}
}
See? We are passing through the joinpoint instance to the helper component's own #Transactional method, which means that the transaction is started when entering that method and committed or rolled back depending on the result of joinPoint.proceed(). I.e. what the aspect helper writes to the DB itself will also be rolled back if something goes wrong in the aspect's target method.
BTW, because I never used Spring transactions before, I simply took the example from https://spring.io/guides/gs/managing-transactions/ and added the two classes above. Before, I also added this to schema.sql:
create table TX_LOG(ID serial, MESSAGE varchar(255) NOT NULL);
Next, I added made sure that TxLogService is injected into AppRunner:
private final BookingService bookingService;
private final TxLogService txLogService;
public AppRunner(BookingService bookingService, TxLogService txLogger) {
this.bookingService = bookingService;
this.txLogService = txLogger;
}
If then at the end of AppRunner.run(String...) you add these two statements
logger.info("BOOKINGS: " + bookingService.findAllBookings().toString());
logger.info("TX_LOGS: " + txLogService.findAllTxLogs().toString());
you should see something like this at the end of the console log:
c.e.managingtransactions.AppRunner : BOOKINGS: [Alice, Bob, Carol]
c.e.managingtransactions.AppRunner : TX_LOGS: [[[Alice, Bob, Carol]]]
I.e. you see that only for the successful booking transaction a log message something was written to the DB, not for the two failed ones.

How to create JobConsumer in Sling?

According to Apache Sling official site(https://sling.apache.org/documentation/bundles/apache-sling-eventing-and-job-handling.html#job-consumers), this is the way to write JobConsumer.
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.consumer.JobConsumer;
#Component
#Service(value={JobConsumer.class})
#Property(name=JobConsumer.PROPERTY_TOPICS, value="my/special/jobtopic",)
public class MyJobConsumer implements JobConsumer {
public JobResult process(final Job job) {
// process the job and return the result
return JobResult.OK;
}
}
However #Service and #Property are both deprecated annotations.
I want to know the proper way to create JobConsumer.
Does anyone know how to write a code equivalent to the above?
The scr annotations are deprecated in AEM and it is recommended to use the official OSGi Declarative Services annotations going forward. There is a seminar by Adobe on using the OSGi R7 annotations.
The new way of writing the same would be
import org.osgi.service.component.annotations.Component;
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.consumer.JobConsumer;
#Component(
immediate = true,
service = JobConsumer.class,
property = {
JobConsumer.PROPERTY_TOPICS +"=my/special/jobtopic"
}
)
public class MyJobConsumer implements JobConsumer {
public JobResult process(final Job job) {
// process the job and return the result
return JobResult.OK;
}
}
You can refer to the below blog. I have tried to explain it here.
https://www.linkedin.com/pulse/aem-how-write-sling-jobs-aem-veena-vikraman

Why does Spring App crash when using #autowire [duplicate]

This question already has an answer here:
What is a NoSuchBeanDefinitionException and how do I fix it?
(1 answer)
Closed 3 years ago.
I am using latest version of IntelliJIDEA CE edition (11.0.4).
There is one thing that I could not find anywhere, and it is a blocker for my further improvements with Java/Spring.
Controller:
import com.example.demo.classes.SaveToFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class MainController {
#Autowired protected SaveToFile saveToFile;
//#Autowired SaveToDb saveToDb;
#RequestMapping("/start")
public String whatever(#RequestParam(value="name", defaultValue="World") String name) {
saveToFile.save(name);
return "something";
//return new SaveToFile(name);
}
}
Class:
import com.example.demo.interfaces.ISave;
public class SaveToFile implements ISave {
private String filename = "Vlad";
#Override
public void save(String name) {
System.out.println("Saving " + name + " to file.");
}
public String getFilename(){
return filename;
}
}
Class Interface:
public interface ISave {
void save(String name);
}
Nothing fancy, just to get a grasp of Spring and Java.
Inside my Controller, when I try to use
#Autowired protected SaveToFile saveToFile;
I get an error that prevents app from starting. Here is the error:
Execution failed for task ':DemoApplication.main()'.
Process 'command '/Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home/bin/java''
finished with non-zero exit value 1
If I comment that out, I can instantiate my class with "new", but thats not the point.
I have tried changing SDK's in the Project Structure menu option. but to no avail.
Maybe worth to point out, that similar project I also work on in Kotlin, has no issues at all. I tried to Mimick the "Kotlin" settings, but nothing.
Does anyone have any clue as to what is going on in here?
You should either annotate the SaveToFile class with #Component, or create a bean of that type (annotated #Bean) in any config class for the #Autowired to work.
First, make SaveToFile a Spring-managed bean:
#Component
public class SaveToFile implements ISave {
// [...]
}
Second, autowire the bean:
#RestController
public class MainController {
#Autowired protected ISave saveToFile;
// [...]
}
Spring needs to pick that one up as a component, otherwise it doesn't really know where to Autowire it from.
Try annotating it with a #Service and make the class itself is within Component Scanner's reach.

Jira/Java - injecting manager not working (setter)

I'm building a plugin for Jira. I want to add a caching-layer so I wanted to use the com.atlassian.cache.CacheManager. I have to inject this via an argument / setter.
Since I'm extending an other class I wanted to inject this via a setter, but for some reason it returns null all the time.
import com.atlassian.cache.Cache;
import com.atlassian.cache.CacheLoader;
import com.atlassian.cache.CacheManager;
import com.atlassian.cache.CacheSettingsBuilder;
public class Foo extends AbstractJiraContextProvider
{
private CacheManager cacheManager;
public void setCacheManager(CacheManager cacheManager) {
//It does not get past this function..
this.cacheManager = cacheManager;
}
#Override
public Map getContextMap(ApplicationUser user, JiraHelper jiraHelper) {
cache = this.cacheManager.getCache("bar");
}
}
I also tried this by doing the following:
public Foo(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
After that the plugin does nothing anymore. I do not get errors, but it just gives 0 output.
I used this for documentation: https://developer.atlassian.com/confdev/confluence-plugin-guide/writing-confluence-plugins/accessing-confluence-components-from-plugin-modules
And https://developer.atlassian.com/confdev/development-resources/confluence-developer-faq/how-do-i-cache-data-in-a-plugin#HowdoIcachedatainaplugin?-Instructions
Your question mentions JIRA, but the documentation links that you provide are for Confluence (and outdated).
If you're developing an add-on for a recent version of JIRA (7.2+) then injecting components is now handled by Atlassian Spring Scanner 2, so everything works with annotations.
If you follow the instructions listed here then you should be able to inject components via a constructor like so:
#Component
public class MyService {
private final IssueService issueService;
private final InternalComponent internalComponent;
#Inject
public MyService(#ComponentImport final IssueService issueService,final InternalComponent internalComponent) {
this.issueService = issueService;
this.internalComponent = internalComponent;
}
}

Using Spring Security ACL

I am trying to implement Spring Security ACL in my application. I have many classes that I want to use an ACL on.
I read in the documentation that AOP have been used with success before. Does this mean that all the services should have a common interface for doing CRUD against the objects for maximum reuse of the advise?
Or is it normal to manually insert, delete, ... in the save, update, delete methods of the service?
I can't manage to find many examples of how people use the framework.
---- Listener for Entity removal (includes cascading deletes) -----
package com.acme.model.aspects;
import javax.annotation.PostConstruct;
import javax.persistence.PreRemove;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.data.domain.Persistable;
import com.acme.PermissionService;
#Component
public class ObjectIdentityListener {
private static final Logger LOG = LoggerFactory.getLogger(ObjectIdentityListener.class);
static private PermissionService permissionService;
#Autowired(required = true)
#Qualifier("permissionService")
public void setSearchService(PermissionService _permissionService)
{
permissionService = _permissionService;
}
#PreRemove
public void preRemove(Object object) {
if(object instanceof Persistable) {
LOG.info("Deleting object identity for class {} id {} ", persistable.getClass(), persistable.getId());
permissionService.deleteObjectIdentity((Persistable) object);
}
}
#PostConstruct
public void init() {
Assert.notNull(permissionService, "'permissionService' is required");
}
}
---- Delete method for permissionService ----
public void deleteObjectIdentity(Persistable persistable) {
try{
MutableAcl acl = (MutableAcl) mutableAclService.readAclById(identity(persistable));
mutableAclService.deleteAcl(acl.getObjectIdentity(), true);
} catch (NotFoundException e){
LOG.info("Could not find ACL for target {}", persistable);
}
}
It all depends on your app. Having a centralized hierarchy of services would certainly make it simpler to implement single security checks for create/retrieve/update/delete methods. But you have an existing app with different services that don't necessarily have a common parent implementation, then you'd have to add ALC security annotation on each service method.
Another option is to put ACL security on your DAO layer, it works fine, but for some reason just doesn't feel right. IMHO DAO's shouldn't deal with things like security. I've spent a LOT of time dealing with Spring Security ACL, got a pretty good handle on it by now, ping me if you need any concrete examples.

Categories

Resources