Documentation request: rollbar-reactive-streams-reactor example
Please add some recommendations and a working example of a rollbar-reactive-streams-reactor to the list of java examples on your docs page. Questions that comes to mind are what happens if you combine the rollbar-reactive-streams-reactor with log appenders such as rollbar-logback or rollbar-log4j2? What happens if you omit the rollbar-reactive-streams-reactor entirely and revert use vanilla Log4J or Logback in the reactive code path, etc?
Can you please also share a more involved example then the one provided in the com.rollbar.reactivestreams.reactor.example.Application which I find somewhat rudimentary.
@matsev Sure thing. We have some examples, but we'll need to clean them up. If nothing urgent comes up, we'll update the examples by the end of next week.
One question that has surfaced is if log statements need to be duplicated? For example, if we use ReactorRollbar for error logs, will the error message also be forwarded to standard logging libraries (e.g. Java Util Logging, Commons Logging, Log4J, or SLF4J depending on application)? Maybe it is configurable?
Reason for asking is that without this option, either developer experience will suffer (as each log statement need to be written twice) or operations experience will suffer (if ops need to go back and forth between Rollbar logs and application logs to get the full picture when troubleshooting application errors).
@matsev I had an internal discussion about your requests. I want to share some updates and ask you to specify specific questions.
Please add some recommendations and a working example of a rollbar-reactive-streams-reactor to the list of java examples on your docs page. Can you please also share a more involved example then the one provided in the com.rollbar.reactivestreams.reactor.example.Application which I find somewhat rudimentary.
Can you elaborate on what you consider a more involved example? We're happy to update the reactor example you mentioned, but we need more hints on what you missed.
Questions that comes to mind are what happens if you combine the
rollbar-reactive-streams-reactorwith log appenders such asrollbar-logbackorrollbar-log4j2?
You can use both, but the log appender must be configured separately, and rollbar-reactive-streams-reactor will not forward any errors to the logger. If you intend to send errors to Rollbar and also write them to the log files, rollbar-log4j2 or rollbar-logback are the best options. Also, it's a good idea to use the async wrappers provided by Log4J or Logback, to ensure logging actions don't block the reactive operators.
What happens if you omit the
rollbar-reactive-streams-reactorentirely and revert use vanilla Log4J or Logback in the reactive code path, etc?
This can work. Use the rollbar-logback or rollbar-log4j2 packages, but wrap them in an async appended so they won't block your application. This will not send the full stack trace, but probably the last frame only. Logging in a reactive environment is a fairly complex thing. You might want to check the Debug Mode section in the Reactor Tools documentation for more details.
It is unclear to me if you recommend that I use an (async) log appender or the ReactorRollbar or both. We will use standard (async) logback appender for our application logs. Given this premise, what value does ReactorRollbar add? Observing that the sample application decorates a failing mono by using onErrorResume(). How is this different from the code below:
public class Application {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Application.class);
// ...
Mono<HttpClientResponse> request = HttpClient.create()
.get()
.uri(url)
.response()
.onErrorResume(t -> {
log.error("bad stuff happened", t);
return Mono.error(t);
});
}
I locked in Rollbar's documentation for configuration examples for an async log appender configuration. Maybe I was looking in the wrong place, because I have not found any async log appender example? I found the logback.xml in the reference docs and a corresponding logback.xml in the example repository, but they are both synchronous.
Can you elaborate on what you consider a more involved example?
- From the looks of it, the logMonoError only permits logging of the raw
Throwable. How can one provide a log statement with some additional context (without wrapping the throwable in another throwable)? - What would a Spring example look like for the reactive stack (with and without
ReactiveRollbar), c.f. Rollbar Spring
- The logging API is not reactive, so you can’t use
ReactorRollbarin a log appender in a way that would benefit the application. We cannot get the logging action to become part of the reactive stream as thelog.errorcall does not return a Mono or Flux. - In this context, maybe using the Rollbar appender, wrapped in an async proxy, and not
ReactorRollbar, might be the best choice.
As for the async wrapper, it will depend on the underlying logging implementation. If you’re using logback, here’s an example of how to configure it: https://sorenpoulsen.com/set-up-slf4j-with-logbacks-asyncappender
As for the tradeoff, it’s the usual tradeoff in non-blocking, callback-based concurrency vs thread-based concurrency.
Sending occurrences via ReactorRollbar means its HTTP requests will be non-blocking, just like the rest of the user’s reactive workflow. With this approach, the number of in-flight requests is not limited to the number of OS threads that are running, and this applies to the reporting of occurrences to Rollbar as well as any other function in the application.
On the other hand, the async appender offloads the log action to a different thread dedicated to logging. With only 1 thread, there can only be 1 in-flight request to report an occurrence, and it will be blocking (the thread won’t progress until the request is completed.)
Though I wouldn’t call this a tradeoff situation, I think ReactorRollbar will work better in a reactive application, and I can’t think of any significant drawbacks. But it’s impossible to use ReactorRollbar if you want occurrences to be reported via the slf4j API, as that API is not reactive.