I'm developing an app against a cloud application that has hard api rate limits in place. In order to have my team get a feeling for how close we are in regards to those limits I want to count all API calls made from our app in a meaningful way.
We use Feign as access layer, and I was hoping to be able to use the RequestInterceptor
to count the different API endpoints we call:
RequestInterceptor ri = rq -> addStatistics(rq.url());
Now this does not work, as the resulting URLs almost always count "1" afterwards, as they already contain all resolved path variables, so I get counts for
1 - /something/id1valueverycryptic/get
1 - /something/anothercrypticidkey/get
and so on.
I was hoping to somehow get access to either the @ResuqestLine
mapping value (GET /something/{id}/get
) or at least the uri template pre-resolve (/somethine/{id}/get
)
Is there a way to do this?
Thanks!
Maybe you could try using custom feign InvocationHandlerFactory.
I've managed to log RequestInterceptor using code like this:
change EnableFeignClients and add defaultConfiguration
@EnableFeignClients(defaultConfiguration = FeignConfig.class)
add default feign config
@Configuration
public class FeignConfig {
@Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() {
return Retryer.NEVER_RETRY;
}
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public Feign.Builder feignBuilder(Retryer retryer) {
return Feign.builder()
.retryer(retryer)
.invocationHandlerFactory((target, dispatch) -> new CountingFeignInvocationHandler(target, dispatch));
}
}
create your invocation handler (code based on feign.ReflectiveFeign.FeignInvocationHandler)
public class CountingFeignInvocationHandler implements InvocationHandler {
private final Target target;
private final Map<Method, MethodHandler> dispatch;
public CountingFeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("equals".equals(method.getName())) {
try {
Object otherHandler =
args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return equals(otherHandler);
} catch (IllegalArgumentException e) {
return false;
}
} else if ("hashCode".equals(method.getName())) {
return hashCode();
} else if ("toString".equals(method.getName())) {
return toString();
}
RequestLine requestLine = method.getAnnotation(RequestLine.class);
addStatistics(requestLine.value());
return dispatch.get(method).invoke(args);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof CountingFeignInvocationHandler) {
CountingFeignInvocationHandler other = (CountingFeignInvocationHandler) obj;
return target.equals(other.target);
}
return false;
}
@Override
public int hashCode() {
return target.hashCode();
}
@Override
public String toString() {
return target.toString();
}
}
Be careful and check if you feign configuration wasn't more complex and in that case extend classes as needed.