All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cvent.retrofit.metrics.TimedCallAdapterFactory Maven / Gradle / Ivy

Go to download

Library to support dropwizard metrics with retrofit clients using Timed annotation

There is a newer version: 2.0.2
Show newest version
package com.cvent.retrofit.metrics;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.codahale.metrics.annotation.Timed;
import okhttp3.Request;
import retrofit2.Call;
import retrofit2.CallAdapter;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Objects;

/**
 * A Retrofit call adapter which produces timer metrics on client methods annotated with
 * {@link com.codahale.metrics.annotation.Timed}. The {@link com.codahale.metrics.annotation.Timed} annotation requires
 * a value for the name field.
 */
public class TimedCallAdapterFactory extends CallAdapter.Factory {

    private final MetricRegistry metrics;

    public TimedCallAdapterFactory(MetricRegistry metrics) {
        Objects.requireNonNull(metrics);
        this.metrics = metrics;
    }

    @Override
    public CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        Timed timed = getTimedAnnotation(annotations);
        if (timed == null) {
            return null;
        }

        String name = timed.name();
        if (name.isEmpty()) {
            // Unfortunately retrofit does not provide the Method for the annotation therefore require a name
            throw new IllegalArgumentException("Timer annotation requires a non-empty name");
        }

        CallAdapter nextCallAdapter = retrofit.nextCallAdapter(this, returnType, annotations);
        return new TimedCallAdapter(metrics.timer(name), nextCallAdapter);
    }

    private Timed getTimedAnnotation(Annotation[] annotations) {
        for (Annotation annotation : annotations) {
            if (annotation instanceof Timed) {
                return (Timed) annotation;
            }
        }
        return null;
    }

    /**
     * Creates wrapped TimedCall objects.
     * @param 
     */
    private static final class TimedCallAdapter implements CallAdapter {
        private final Timer timer;
        private final CallAdapter nextCallAdapter;

        private TimedCallAdapter(Timer timer, CallAdapter nextCallAdapter) {
            this.timer = timer;
            this.nextCallAdapter = nextCallAdapter;
        }

        @Override
        public Type responseType() {
            return nextCallAdapter.responseType();
        }

        @Override
        public  T adapt(Call call) {
            return (T) nextCallAdapter.adapt(new TimedCall(call, timer));
        }
    }

    /**
     * Wraps Call request/response methods in a timer.
     * @param 
     */
    private static final class TimedCall implements Call {
        private final Timer timer;
        private final Call wrappedCall;

        private TimedCall(Call call, Timer timer) {
            this.wrappedCall = call;
            this.timer = timer;
        }

        @Override
        public Response execute() throws IOException {
            try (Timer.Context ctx = timer.time()) {
                return wrappedCall.execute();
            }
        }

        @Override
        public void enqueue(Callback callback) {
            Timer.Context ctx = timer.time();

            wrappedCall.enqueue(new Callback() {
                @Override
                public void onResponse(Call call, Response response) {
                    ctx.stop();
                    callback.onResponse(call, response);
                }

                @Override
                public void onFailure(Call call, Throwable t) {
                    ctx.stop();
                    callback.onFailure(call, t);
                }
            });
        }

        @Override
        public boolean isExecuted() {
            return wrappedCall.isExecuted();
        }

        @Override
        public void cancel() {
            wrappedCall.cancel();
        }

        @Override
        public boolean isCanceled() {
            return wrappedCall.isCanceled();
        }

        @Override
        public Call clone() {
            return new TimedCall(wrappedCall.clone(), timer);
        }

        @Override
        public Request request() {
            return wrappedCall.request();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy