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

Feature: micrometer.io metrics integration #352

Open
magicprinc opened this issue Nov 28, 2022 · 4 comments
Open

Feature: micrometer.io metrics integration #352

magicprinc opened this issue Nov 28, 2022 · 4 comments

Comments

@jhalterman
Copy link
Member

The approach Failsafe takes is to expose event listeners which could be used to record metrics, which avoids adding any external dependencies. Are there any particular metrics/event listeners that you'd like to see?

@magicprinc
Copy link
Author

Metrics are my colleges' responsibility, so I don't have a concrete answer yet :-)

But usually people like if somebody smarter than they—"an expert in the field" have already made decisions.

I know that Hystrix has a lot of metrics, even with HttpServlet to publish them as JSON feed.

Here are your competitors as a source of inspiration:
https://resilience4j.readme.io/docs/micrometer

https://github.com/findinpath/spring-retry-metrics

@magicprinc
Copy link
Author

magicprinc commented Nov 29, 2022

Core library without dependencies is a good thing!
It could be an additional (optional) artifact.

And people who use let's say Prometheus directly could clone the project and make a "Prometheus metrics for FailSafe"

@cykl
Copy link

cykl commented Sep 24, 2024

@jhalterman Are you aware of anyone having implemented a good instrumentation for failsafe? (using Prometheus, OpenTelemetry, Micrometer or anything else).

I'm trying to instrument some code using failsafe with Micrometer. I expect to end up with something close to what is available in resilience4j. Contrary to what I expected, it doesn't seem to be that simple.

The idiomatic way to instrument something using Micrometer is to provide a MeterBinder.

Let's start with something simple and say we want to instrument a circuit breaker. It would look like this:

public class FailsafeCircuitBreakerMetrics implements MeterBinder {

    private final CircuitBreaker<?> circuitBreaker;
    private final String name;
    private final Iterable<Tag> tags;

    public FailsafeCircuitBreakerMetrics( CircuitBreaker<?> circuitBreaker, String name ) {
        this( circuitBreaker, name, Tags.empty( ) );
    }

    public FailsafeCircuitBreakerMetrics( CircuitBreaker<?> circuitBreaker, String name, Iterable<Tag> tags ) {
        this.circuitBreaker = circuitBreaker;
        this.name = name;
        this.tags = Tags.of( tags ).and( "name", name );
    }

    @Override
    public void bindTo( MeterRegistry registry ) {
        FunctionCounter.builder( "failsafe.circuit-breaker.execution.total", circuitBreaker,
                        CircuitBreaker::getSuccessCount )
                .baseUnit( BaseUnits.OPERATIONS )
                .tags( tags )
                .tag( "outcome", "success" )
                .register( registry );

        FunctionCounter.builder( "failsafe.circuit-breaker.execution.total", circuitBreaker,
                        CircuitBreaker::getSuccessCount )
                .baseUnit( BaseUnits.OPERATIONS )
                .tags( tags )
                .tag( "outcome", "failure" )
                .register( registry );

        Gauge.builder( "failsafe.circuit-breaker.state", circuitBreaker, ( CircuitBreaker<?> cb ) -> {
                    if( cb.isClosed( ) ) {
                        return 0;
                    } else if( cb.isHalfOpen( ) ) {
                        return 1;
                    } else if( cb.isOpen( ) ) {
                        return 2;
                    } else {
                        return -1;
                    }
                } )
                .tags( tags )
                .register( registry );
    }
}

So far, no problem, everything is available and it's just defining some meter integrating metrics exposed by the monitored object.

No let's say I have a FailsafeExecutor with bulkhead and timeout policies. It would expect to be able to invoke something like new FailsafeExecutorMetrics(failsafeExecutor, "my-executor").bindTo(Metrics.globalRegistry()) and relevant metrics would be automatically created.

My issues are:

  1. Unlike CircuitBreaker, Timeout & Bulkhead policies expose nothing. From the policy, I cannot observe the number of executions currently running, the number of timeout that have occurred or whatever relevant to the policy.
  2. FailsafeExecutor has listeners that might be helpful to implement instrumentation. However, only one listener is supported (calling onXxx() will override the current listener) and it's not possible to access the current listener. Client code may have already have registered a listener and instrumentation should not override it.
  3. Adding a listener which is invoked on completion is unlikely be enough to observe something like running operation in a bulkhead.

How would you approach the problem?

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

3 participants