3

Given a Flux or a Mono from project reactor is a there a way to get the Flux or Mono to print out what the operator chain looks like. For example given the code below.

Fulx flux = Flux.just("a","b","c")
              .map( v -> v.toUpperCase())
              .log();

Is there some way to get the flux to print out a list of all the operators that are chained inside in the processing pipeline? Some nice ascii formatted text or a marble diagram?

printTheFlux(flux) should make a nice printout that show the structure of all the operators from the example above. I am not expecting to produce the code in the lambda's just a way to see what operators are chained together.

ams
  • 60,316
  • 68
  • 200
  • 288

2 Answers2

1

There is partial building blocks for doing this with the Scannable interface:

public String textRepresentation(Flux<?> flux) {
    Scannable sc = Scannable.from(flux);
    //scan the last operator in the chain and ask if it knows its parents
    List<String> names = sc.parents().map(Scannable::operatorName)
                                     .collect(Collectors.toList());
    //as it traverses the chain from bottom to top, we need to reverse the order
    Collections.reverse(names);
    //need to also add the last operator
    names.add(sc.operatorName());
    return names.toString();
}

@Test
public void textRepresentationTest() {
    Flux flux = Flux.just("a","b","c")
                    .map( v -> v.toUpperCase())
                    .log();

    System.out.println(textRepresentation(flux));
}

Prints

[map, log]

Not all operators fully support it though (as you can see, the just source doesn't for instance).

Simon Baslé
  • 27,105
  • 5
  • 69
  • 70
0

Nice suggestion!

However, waiting for it, we can just have something like :

    Disposable flux = Flux.just("a", "b", "c")
            .map(String::toUpperCase)
            .doOnNext(FluxUtil::print)
            .subscribe();

Where FluxUtil::print is just a static method that you can write with different ways.

Here is the complete code works for me:

public class FluxUtil {

    private static String s = "";

    public static void main(String[] args) {

        Disposable flux = Flux.just("a", "b", "c")
                .map(String::toUpperCase)
                .doOnNext(FluxUtil::print)
                .subscribe();
    }

    private static Object print(Object o) {

        s = !s.isEmpty() ? s.concat("->") : s;
        s = s.concat(o.toString());
        System.out.println(s);
        return o;
    }
}
  • this is more about printing the data that flows through, isn't it? OP wants to print a graphical representation of the operators. Several issues: the print `map` would be better as a `doOnNext`, this has the major drawback that there is state (`s`) potentially shared by multiple subscribers, it's probably redundant with `log()` (minus the custom formatting) – Simon Baslé Jan 24 '18 at 09:17
  • Thanks Simon for the doOnNext, I edited the post. For the (s) yes it's embarrassing! Have you please an idea to a better way that makes it like a local to a flux ? – Montassar El Béhi Jan 24 '18 at 09:27
  • could use the `Context`: put a `StringBuffer` in the context via `subscriberContext(Context.of("print", new StringBuffer())`, then use `doOnEach` (the `Signal` has a `getContext()`) rather than `doOnNext`, to accumulate and print. But again, this doesn't print the desired output. – Simon Baslé Jan 24 '18 at 09:35