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

Micrometer Timer to Micrometer Observation conversion #1

Open
marcingrzejszczak opened this issue Aug 14, 2023 · 2 comments
Open

Micrometer Timer to Micrometer Observation conversion #1

marcingrzejszczak opened this issue Aug 14, 2023 · 2 comments
Labels

Comments

@marcingrzejszczak
Copy link

marcingrzejszczak commented Aug 14, 2023

What problem are you trying to solve?

Convert Micrometer Timer to a Micrometer Observation (cc @shakuzen @jonatan-ivanov).

NOTE: This feature request is temporarily set in rewrite-spring but since it's related to Micrometer it has nothing to do with Spring.

What precondition(s) should be checked before applying this recipe?

Java projects.

Describe the situation before applying the recipe

.Example using Timer Builder

class Example2 {

        private final MeterRegistry registry;

        Example2(MeterRegistry registry) {
            this.registry = registry;
        }

        void run() {
            Timer.builder("foo")
                    .tag("lowTag", "lowTagValue")
                    .register(registry)
                    .record(() -> System.out.println("Hello"));
        }

    }

.Example using Sample

    class Example3 {

        private final MeterRegistry registry;

        Example3(MeterRegistry registry) {
            this.registry = registry;
        }

        void run() {
            Timer.Sample sample = Timer.start(registry);
            System.out.println("Hello");
            sample.stop(Timer.builder("foo")
                    .tag("lowTag", "lowTagValue")
                    .register(registry));
        }

    }

.Example using Wrap + Run

    class Example4 {

        private final MeterRegistry registry;

        Example4(MeterRegistry registry) {
            this.registry = registry;
        }

        void run() {
            Timer.builder("foo")
                    .tag("lowTag", "lowTagValue")
                    .register(registry)
                    .wrap(() -> System.out.println("Hello"))
                    .run();
        }

    }

.Example for different timers in the same class

    static class ExampleWithDifferentMeters {

        private final MeterRegistry registry;

        ExampleWithDifferentMeters(MeterRegistry registry) {
            this.registry = registry;
        }

        void run() {
            DistributionSummary summary = DistributionSummary.builder("summary")
                    .register(registry);

            Counter counter = Counter.builder("counter outside of timer").register(registry);

            Timer.builder("foo")
                    .tag("lowTag", "lowTagValue")
                    .register(registry)
                    .record(() -> {
                        Counter counter2 = Counter.builder("counter inside of timer").register(registry);
                        counter2.increment();
                        System.out.println("Hello");
                    });

            counter.increment(10);

            summary.record(100);
        }

    }

Describe the situation after applying the recipe

. Solution for Example2, Example3, Example4

class Example {

    private final ObservationRegistry registry;

    Example(ObservationRegistry registry) {
        this.registry = registry;
    }

    void run() {
        Observation.createNotStarted("foo", registry)
                .lowCardinalityKeyValue("lowTag", "lowTagValue")
                .observe(() -> System.out.println("Hello"));
    }

}

. Solution for ExampleWithDifferentMeters

class ExampleWithDifferentMetersWithObservation {

        private final ObservationRegistry observationRegistry;

        private final MeterRegistry registry;

        ExampleWithDifferentMetersWithObservation(ObservationRegistry observationRegistry, MeterRegistry registry) {
            this.observationRegistry = observationRegistry;
            this.registry = registry;
        }

        void run() {
            DistributionSummary summary = DistributionSummary.builder("summary")
                    .register(registry);

            Counter counter = Counter.builder("counter outside of timer").register(registry);

            Observation observation = Observation.createNotStarted("foo", observationRegistry)
                    .lowCardinalityKeyValue("lowTag", "lowTagValue");

            observation.observe(() -> {
                observation.event(() -> "counter inside of timer");
                System.out.println("Hello");
            });

            counter.increment(10);

            summary.record(100);
        }

    }

Have you considered any alternatives or workarounds?

No workarounds at this point that I'm aware of.

Any additional context

If we're scanning users' business code then most likely all timers are related to business operations that should be within an actual tracing scope. That means that conversion from a timer to an observation with having e.g. Micrometer Tracing on the classpath will result in creation of a child span and that's a great outcome.

The problem we can face is if there are any timers in infrastructure part of the code. Those might maybe be kept as timers (e.g. time required to start the application - we don't want that to become a span). I doubt however that we are able to get this information from scanning the code.

This recipe should be applicable only if micrometer-core JAR is on the classpath (that contains the Timer class). If we want to migrate to Micrometer Observation then micrometer-observation JAR must be present on the classpath.

Check the Micrometer Docs for more information about Micrometer Observation.

Are you interested in contributing this recipe to OpenRewrite?

We can definitely help with guidance on how to do this feature.

@timtebeek
Copy link
Contributor

Discussed internally just now: we'll indeed move this item and any related non-spring-specific recipes into a separate rewrite-micrometer module.

@timtebeek timtebeek transferred this issue from openrewrite/rewrite-spring Aug 15, 2023
@timtebeek timtebeek self-assigned this Aug 15, 2023
@timtebeek
Copy link
Contributor

Quick note to say I'm reading up, and have started to define the scenarios (not) to convert in #2; welcome to follow along and chime in there with further cases to cover.

@timtebeek timtebeek removed their assignment Mar 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Backlog
Development

No branches or pull requests

2 participants