Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make metrics pluggable #26

Open
OlegDokuka opened this issue Jan 7, 2019 · 1 comment
Open

Make metrics pluggable #26

OlegDokuka opened this issue Jan 7, 2019 · 1 comment

Comments

@OlegDokuka
Copy link
Member

User Story

As an RSocket-RPC-Java user, I want to have metrics pluggable

Actual Behavior

In the current implementation, metrics are built-in, so it is hardly manageable to eliminate it from the generated code.

Expected Behavior

The current implementation provides proper abstraction and code generation that does not require a user to live with opentracing and micrometer dependencies as an built-in code. In turn, it would be much easier to have an addon to current plugin that can generate adapters for metrics and tracing that could be plugged in as in the following sample:

new TracingAwareMetricsSnapshotHandlerServerAdapter(
	new MeterAwareMetricsSnapshotHandlerServerAdapter(
    	new MetricsSnapshotHandlerServer(...),
    	meterRegistry
	)
)

in that case server/client, impl will be metrics-free code which does the same and adapters code will look like the following (example of generate server adapter):

public class MeterAwareGreeter extends AbstractRSocketService {

    private final AbstractRSocketService delegate;

    private final Function<? super Publisher<Void>, ? extends Publisher<Void>> streamGreet6MeterFunction;
    private final Function<? super Publisher<Payload>, ? extends Publisher<Payload>> streamGreet1MeterFunction;
    private final Function<? super Publisher<Payload>, ? extends Publisher<Payload>> streamGreet4MeterFunction;
    private final Function<? super Publisher<Payload>, ? extends Publisher<Payload>> streamGreet2MeterFunction;
    private final Function<? super Publisher<Payload>, ? extends Publisher<Payload>> streamGreet3MeterFunction;
    private final Function<? super Publisher<Payload>, ? extends Publisher<Payload>> streamGreet5MeterFunction;


    public MeterAwareGreeter(AbstractRSocketService delegate, MeterRegistry registry) {
        this.delegate = delegate;
        this.streamGreet6MeterFunction = Metrics.timed(registry, "rsocket.server", "service", Greeter.SERVICE, "method", Greeter.METHOD_STREAM_GREET6);
        this.streamGreet1MeterFunction = Metrics.timed(registry, "rsocket.server", "service", Greeter.SERVICE, "method", Greeter.METHOD_STREAM_GREET1);
        this.streamGreet4MeterFunction = Metrics.timed(registry, "rsocket.server", "service", Greeter.SERVICE, "method", Greeter.METHOD_STREAM_GREET4);
        this.streamGreet2MeterFunction = Metrics.timed(registry, "rsocket.server", "service", Greeter.SERVICE, "method", Greeter.METHOD_STREAM_GREET2);
        this.streamGreet3MeterFunction = Metrics.timed(registry, "rsocket.server", "service", Greeter.SERVICE, "method", Greeter.METHOD_STREAM_GREET3);
        this.streamGreet5MeterFunction = Metrics.timed(registry, "rsocket.server", "service", Greeter.SERVICE, "method", Greeter.METHOD_STREAM_GREET5);
    }

    @Override
    public Class<?> getServiceClass() {
        return delegate.getServiceClass();
    }

    @Override
    public String getService() {
        return delegate.getService();
    }


    @Override
    public Mono<Void> fireAndForget(Payload payload) {
        String methodName;

        try {
            ByteBuf metadata = payload.sliceMetadata();
            methodName = Metadata.getMethod(metadata);
        } catch (Throwable t) {
            payload.release();
            return Mono.error(t);
        }

        switch(methodName) {
            case "streamGreet6":
                return delegate.fireAndForget(payload)
                               .transform(streamGreet6MeterFunction);
            default: {
                payload.release();
                return Mono.error(new UnsupportedOperationException());
            }
        }
    }




    @Override
    public Mono<Payload> requestResponse(Payload payload) {
        String methodName;

        try {
            ByteBuf metadata = payload.sliceMetadata();
            methodName = Metadata.getMethod(metadata);
        } catch (Throwable t) {
            payload.release();
            return Mono.error(t);
        }

        switch(methodName) {
            case "streamGreet1":
                return delegate.requestResponse(payload)
                               .transform(streamGreet1MeterFunction);
            case "streamGreet4":
                return delegate.requestResponse(payload)
                               .transform(streamGreet4MeterFunction);
            default: {
                payload.release();
                return Mono.error(new UnsupportedOperationException());
            }
        }
    }
....
}
@bsideup
Copy link
Member

bsideup commented Jan 8, 2019

I think this approach is much cleaner and scales better.

It will also allow having different tracing implementations (Zipkin, OpenTracing, etc...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants