diff --git a/akka-docs/src/main/paradox/stream/stream-cookbook.md b/akka-docs/src/main/paradox/stream/stream-cookbook.md index 3adc6682af..4f551ae6a8 100644 --- a/akka-docs/src/main/paradox/stream/stream-cookbook.md +++ b/akka-docs/src/main/paradox/stream/stream-cookbook.md @@ -18,7 +18,7 @@ If you need a quick reference of the available processing stages used in the rec In this collection we show simple recipes that involve linear flows. The recipes in this section are rather general, more targeted recipes are available as separate sections (@ref:[Buffers and working with rate](stream-rate.md), @ref:[Working with streaming IO](stream-io.md)). -### Logging elements of a stream +### Logging in streams **Situation:** During development it is sometimes helpful to see what happens in a particular section of a stream. @@ -31,8 +31,8 @@ Scala Java : @@snip [RecipeLoggingElements.java]($code$/java/jdocs/stream/javadsl/cookbook/RecipeLoggingElements.java) { #println-debug } -Another approach to logging is to use `log()` operation which allows configuring logging for elements flowing through -the stream as well as completion and erroring. +Another approach to logging is to use `log()` operation. This approach gives you more fine-grained control of logging levels for +elements flowing through the stream, finish and failure of the stream. Scala : @@snip [RecipeLoggingElements.scala]($code$/scala/docs/stream/cookbook/RecipeLoggingElements.scala) { #log-custom } diff --git a/akka-docs/src/main/paradox/stream/stream-error.md b/akka-docs/src/main/paradox/stream/stream-error.md index 13f4d06f71..128d8f41f6 100644 --- a/akka-docs/src/main/paradox/stream/stream-error.md +++ b/akka-docs/src/main/paradox/stream/stream-error.md @@ -13,6 +13,28 @@ In many cases you may want to avoid complete stream failure, this can be done in In addition to these built in tools for error handling, a common pattern is to wrap the stream inside an actor, and have the actor restart the entire stream on failure. +## Logging errors + +`log()` enables logging of a stream, which is typically useful for error logging. +The below stream fails with `ArithmeticException` when the element `0` goes through the `map` stage, + +Scala +: @@snip [RecipeLoggingElements.scala]($code$/scala/docs/stream/cookbook/RecipeLoggingElements.scala) { #log-error } + +Java +: @@snip [RecipeLoggingElements.java]($code$/java/jdocs/stream/javadsl/cookbook/RecipeLoggingElements.java) { #log-error } + + +and error messages like below will be logged. + +``` +[error logging] Upstream failed. +java.lang.ArithmeticException: / by zero +``` + +If you want to control logging levels on each element, completion, and failure, you can find more details +in @ref:[Logging in streams](stream-cookbook.md#logging-in-streams). + ## Recover `recover` allows you to emit a final element and then complete the stream on an upstream failure. diff --git a/akka-docs/src/test/java/jdocs/stream/javadsl/cookbook/RecipeLoggingElements.java b/akka-docs/src/test/java/jdocs/stream/javadsl/cookbook/RecipeLoggingElements.java index 71f7ef1cd7..80a1f9a214 100644 --- a/akka-docs/src/test/java/jdocs/stream/javadsl/cookbook/RecipeLoggingElements.java +++ b/akka-docs/src/test/java/jdocs/stream/javadsl/cookbook/RecipeLoggingElements.java @@ -68,14 +68,14 @@ public class RecipeLoggingElements extends RecipeTest { { final Source mySource = Source.from(Arrays.asList("1", "2", "3")); - final int onElement = Logging.WarningLevel(); - final int onFinish = Logging.ErrorLevel(); - final int onFailure = Logging.ErrorLevel(); - //#log-custom // customise log levels mySource.log("before-map") - .withAttributes(Attributes.createLogLevels(onElement, onFinish, onFailure)) + .withAttributes(Attributes.createLogLevels( + Logging.WarningLevel(), //onElement + Logging.InfoLevel(), //onFinish + Logging.DebugLevel() //onFailure + )) .map(i -> analyse(i)); // or provide custom logging adapter @@ -94,4 +94,18 @@ public class RecipeLoggingElements extends RecipeTest { }; } + @Test + public void errorLog() throws Exception { + new TestKit(system) { + { + //#log-error + Source.from(Arrays.asList(-1, 0, 1)) + .map(x -> 1 / x) //throwing ArithmeticException: / by zero + .log("error logging") + .runWith(Sink.ignore(), mat); + //#log-error + } + }; + } + } diff --git a/akka-docs/src/test/scala/docs/stream/cookbook/RecipeLoggingElements.scala b/akka-docs/src/test/scala/docs/stream/cookbook/RecipeLoggingElements.scala index 7f262377e6..0e3058a123 100644 --- a/akka-docs/src/test/scala/docs/stream/cookbook/RecipeLoggingElements.scala +++ b/akka-docs/src/test/scala/docs/stream/cookbook/RecipeLoggingElements.scala @@ -30,7 +30,13 @@ class RecipeLoggingElements extends RecipeSpec { //#log-custom // customise log levels mySource.log("before-map") - .withAttributes(Attributes.logLevels(onElement = Logging.WarningLevel)) + .withAttributes( + Attributes.logLevels( + onElement = Logging.WarningLevel, + onFinish = Logging.InfoLevel, + onFailure = Logging.DebugLevel + ) + ) .map(analyse) // or provide custom logging adapter @@ -42,9 +48,16 @@ class RecipeLoggingElements extends RecipeSpec { EventFilter.debug(start = "[custom] Element: ").intercept { loggedSource.runWith(Sink.ignore) } - } + "use log() for error logging" in { + //#log-error + Source(-5 to 5) + .map(1 / _) //throwing ArithmeticException: / by zero + .log("error logging") + .runWith(Sink.ignore) + //#log-error + } } }