MDC log with Reactor using logOnNext

413 views Asked by At

I need to show context values in logs of the whole application. I tried to do it in this method: "searchStudents" but I got not success. It seems when do step ".doOnComplete()" the subscriberContext is lost and I need and alternative. Have somebody some solution to propose me??

Controller

@GetMapping(value = "{userId}/searchStudents")
public Flux<Student> searchStudents(
        @ModelAttribute(USER_CONTEXT_REQUEST_ATTRIBUTE) Context userContext,
        @PathVariable String userId, 
        @RequestParam String lang, 
        @RequestParam String studentName) {
    return coursesProvider.searchStudents(userId, lang, studentName).subscriberContext(userContext);

logUtils

public class LogUtils {
    public static <T> Consumer<Signal<T>> logOnNext(Consumer<T> logStatement) {
        return signal -> {
            if (!signal.isOnNext()) 
                return;
        
        Optional<String> teacherIdMaybe = signal.getContext().getOrEmpty("TEACHER_ID");
            
        if (teacherIdMaybe.isPresent()) {
            try (MDC.MDCCloseable teacherIdMdcCloseable = MDC.putCloseable("TEACHER_ID", teacherIdMaybe.get())) {
                logStatement.accept(signal.get());
            }
        } else {
            logStatement.accept(signal.get());
        };
    };
}

}

Service

    @Override
    public Flux<Student> searchStudents(String userId, String lang, String studentName) {
        AtomicInteger counter = new AtomicInteger(); 
        return Mono.just(String.format(">>> Searching student named: %s. <<<", studentName))
                .doOnEach(logOnNext(LOGGER::info))   // well logged
                .thenMany(webClient.get()
                        .uri(uriBuilder -> uriBuilder
                                .path("/v1/users/{userId}/courses/searchStudents/{lang}/{studentName}")
                                .build(userId, lang, studentName))
                        .accept(APPLICATION_JSON)
                        .retrieve()
                        .bodyToFlux(Student.class)
                        .filter(Student::isEligible)
                        .doOnNext(p -> counter.incrementAndGet())
                        
                        // this is the ligne that I need to change
                        .doOnComplete(() -> LOGGER.info("{} students found", counter.get())) 
                );
    }

My tries:

  1. Return a Flux of String

.then( Mono.just(String.format("%s students found", counter.get())) .doOnEach(logOnNext(LOGGER::info)))

  1. No log
.doOnComplete(() -> Mono.just(String.format("%s students found", counter.get()))
.doOnEach(logOnNext(LOGGER::info))
.then() // no log
.subscribe() // log without MDC
)
  1. Every count is logged and I want final count
.doOnEach(logOnNext( x -> LOGGER.info("{} students found", counter.get()))
0

There are 0 answers