-
Notifications
You must be signed in to change notification settings - Fork 594
MdcLoggingDirectives (withMdcLogging, withMdcEntry, withMdcEntries, extractMarkerLog) #3974
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
Open
alexklibisz
wants to merge
10
commits into
akka:main
Choose a base branch
from
alexklibisz:mdc-logging-directives
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 5 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
65eb272
First pass at MdcLoggingDirectives (Scala only)
alexklibisz 629938f
Rearrange methods to get rid of .asInstanceOf
alexklibisz 6f6c4e0
Move .tool-versions to .git/info/exclude
alexklibisz d434e00
Use withMdcLogging & extractDiagnosticMarkerLog where possible
alexklibisz 776f4ef
Every directive call creates a new adapter to avoid race conditions
alexklibisz c652021
Merge remote-tracking branch 'origin/main' into mdc-logging-directives
alexklibisz d0ac46e
Add a case for converting an instance of BusLogging to DiagnosticMark…
alexklibisz efb56e0
Merge remote-tracking branch 'origin/main' into mdc-logging-directives
alexklibisz e2f0da6
Get tests to compile on 2.12
alexklibisz 17c6540
Use custom EventFilter class with @volatile buffer to fix test race c…
alexklibisz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,3 +10,4 @@ target | |
| .*.swp | ||
| *.vim | ||
| .ensime* | ||
| .bsp | ||
91 changes: 91 additions & 0 deletions
91
...-tests/src/test/scala/akka/http/scaladsl/server/directives/MdcLoggingDirectivesSpec.scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| package akka.http.scaladsl.server.directives | ||
|
|
||
| import akka.event._ | ||
| import akka.http.scaladsl.server.RoutingSpec | ||
| import akka.testkit.EventFilter | ||
|
|
||
| import scala.collection.mutable.ListBuffer | ||
|
|
||
| class MdcLoggingDirectivesSpec extends RoutingSpec { | ||
alexklibisz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| "The `withMarkerLoggingAdapter` directive" should { | ||
| "set a DiagnosticMarkerBusLoggingAdapter on the request context and provide the same adapter to the caller" in { | ||
| Get() ~> withMarkerLoggingAdapter { provided: MarkerLoggingAdapter => | ||
| extractLog { extracted: LoggingAdapter => | ||
| extracted shouldEqual provided | ||
| completeOk | ||
| } | ||
| } ~> check { | ||
| response shouldEqual Ok | ||
| } | ||
| } | ||
| "provides a new DiagnosticMarkerBusLoggingAdapter for each invocation" in { | ||
| Get() ~> withMarkerLoggingAdapter { _ => | ||
| extractLog { log1 => | ||
| withMarkerLoggingAdapter { _ => | ||
| extractLog { log2 => | ||
| log1 should not equal log2 | ||
| completeOk | ||
| } | ||
| } | ||
| } | ||
| } ~> check { | ||
| response shouldEqual Ok | ||
| } | ||
| } | ||
| } | ||
|
|
||
| "The `withMdcEntries` and `withMdcEntry` directives" should { | ||
| "incrementally append entries to the LoggingAdapter MDC maps" in { | ||
| Get() ~> extractLog { log1 => | ||
| withMdcEntry("foo", "foo entry 1") { | ||
| extractLog { log2 => | ||
| withMdcEntries("foo" -> "foo entry 2", "bar" -> "bar entry 1") { | ||
| extractLog { log3 => | ||
| log1.mdc shouldBe Map.empty | ||
| log2.mdc shouldBe Map("foo" -> "foo entry 1") | ||
| log3.mdc shouldBe Map("foo" -> "foo entry 2", "bar" -> "bar entry 1") | ||
| completeOk | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } ~> check { | ||
| response shouldEqual Ok | ||
| } | ||
| } | ||
| "include the entries in the LoggingEvents" in { | ||
| val buf = ListBuffer.empty[Logging.Info2] | ||
| val filter = EventFilter.custom { | ||
| case e: Logging.Info2 => buf.append(e).nonEmpty | ||
|
|
||
| } | ||
| filter.intercept { | ||
| Get() ~> withMdcEntries("user_id" -> "1234", "request_id" -> "abcd") { | ||
| extractLog { log1 => | ||
| log1.info("test 1") | ||
| withMdcEntry("status", "200") { | ||
| extractLog { log2 => | ||
| log1.info("test 2") | ||
| log2.info("test 3") | ||
| completeOk | ||
| } | ||
| } | ||
| } | ||
| } ~> check { | ||
| response shouldEqual Ok | ||
| buf.size shouldBe 3 | ||
| val l1 = buf(0) | ||
| val l2 = buf(1) | ||
| val l3 = buf(2) | ||
| l1.message shouldBe "test 1" | ||
| l1.mdc shouldBe Map("user_id" -> "1234", "request_id" -> "abcd") | ||
| l2.message shouldBe "test 2" | ||
| l2.mdc shouldBe Map("user_id" -> "1234", "request_id" -> "abcd") | ||
| l3.message shouldBe "test 3" | ||
| l3.mdc shouldBe Map("user_id" -> "1234", "request_id" -> "abcd", "status" -> "200") | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
akka-http/src/main/scala/akka/http/scaladsl/server/directives/MdcLoggingDirectives.scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| package akka.http.scaladsl.server.directives | ||
|
|
||
| import akka.event._ | ||
| import akka.http.scaladsl.server.Directives._ | ||
| import akka.http.scaladsl.server._ | ||
|
|
||
| /** | ||
| * @groupname mdc Mdc logging directives | ||
| * @groupprio mdc 240 | ||
| */ | ||
| trait MdcLoggingDirectives { | ||
|
|
||
| import MdcLoggingDirectives.createDiagnosticMarkerLoggingAdapter | ||
|
|
||
| def withMarkerLoggingAdapter: Directive1[MarkerLoggingAdapter] = { | ||
| createDiagnosticMarkerLoggingAdapter(Map.empty) | ||
| .flatMap { dmbla: DiagnosticMarkerBusLoggingAdapter => | ||
| mapRequestContext { ctx => | ||
| ctx.withLog(dmbla) | ||
| } & provide { | ||
| dmbla: MarkerLoggingAdapter | ||
| } | ||
| } | ||
| } | ||
|
|
||
| def withMdcEntries(mdc: (String, Any)*): Directive0 = | ||
johanandren marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| createDiagnosticMarkerLoggingAdapter(mdc.toMap) | ||
| .flatMap { dmbla: DiagnosticMarkerBusLoggingAdapter => | ||
| mapRequestContext { ctx => | ||
| ctx.withLog(dmbla) | ||
| } | ||
| } | ||
|
|
||
| def withMdcEntry(key: String, value: Any): Directive0 = | ||
| withMdcEntries((key, value)) | ||
| } | ||
|
|
||
| object MdcLoggingDirectives extends MdcLoggingDirectives { | ||
| private def createDiagnosticMarkerLoggingAdapter(entries: Map[String, Any]): Directive1[DiagnosticMarkerBusLoggingAdapter] = | ||
| extractActorSystem | ||
| .flatMap { sys => | ||
| extractRequestContext | ||
| .flatMap { ctx => | ||
| provide { | ||
| ctx.log match { | ||
| // In order to avoid race conditions from using a shared LoggingAdapter, even if the existing adapter | ||
| // is a DiagnosticMarkerBusLoggingAdapter, we still create a new one and merge the two entries. | ||
| case existingAdapter: DiagnosticMarkerBusLoggingAdapter => | ||
| import existingAdapter._ | ||
| val newAdapter = new DiagnosticMarkerBusLoggingAdapter(bus, logSource, logClass, loggingFilterWithMarker) | ||
| newAdapter.mdc(existingAdapter.mdc ++ entries) | ||
alexklibisz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| newAdapter | ||
| // If the logger is not already a DiagnosticLoggingAdapter, we create a new one with the given entries. | ||
| case _ => | ||
| val (str, cls) = LogSource.fromAnyRef(sys, sys) | ||
| val filter = new DefaultLoggingFilter(sys.settings, sys.eventStream) | ||
| val newAdapter = new DiagnosticMarkerBusLoggingAdapter(sys.eventStream, str, cls, filter) | ||
johanandren marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| newAdapter.mdc(entries) | ||
| newAdapter | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
docs/src/main/paradox/routing-dsl/directives/mdc-logging-directives/index.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| # MdcLoggingDirectives | ||
|
|
||
| Directives for request-level mapped diagnostic context logging using the @apidoc[MarkerLoggingAdapter]. | ||
|
|
||
| These directives provide an API to instantiate a new MDC-compatible logger for every request and append (key, value) MDC entries to be included in any logs emitted from the request. | ||
|
|
||
| For example, one might extract a request ID from a header at the beginning of the request and append it as a (key, value) MDC entry. | ||
| Any subsequent logs emitted by this request would include the request ID as an entry. | ||
|
|
||
| @@toc { depth=1 } | ||
|
|
||
| @@@ index | ||
|
|
||
| * [withMarkerLoggingAdapter](withMarkerLoggingAdapter.md) | ||
| * [withMdcEntries](withMdcEntries.md) | ||
| * [withMdcEntry](withMdcEntry.md) | ||
|
|
||
| @@@ | ||
|
|
||
| ## Structured JSON MDC Logging | ||
|
|
||
| In order to get structured (i.e., JSON) MDC logging, some additional dependencies and configurations are necessary. | ||
|
|
||
| One possible configuration is as follows: | ||
|
|
||
| 1. Add akka-slf4j, logback-classic, and logstash-logback-encoder as dependencies. | ||
| 2. Add the configuration `akka.loggers = ["akka.event.slf4j.Slf4jLogger"]` to application.conf. | ||
| 3. Create a `logback.xml` file with an appender that uses the LogstashEncoder: | ||
|
|
||
| ```xml | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <configuration> | ||
| <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> | ||
| <encoder class="net.logstash.logback.encoder.LogstashEncoder"/> | ||
| </appender> | ||
| <root level="INFO"> | ||
| <appender-ref ref="CONSOLE" /> | ||
| </root> | ||
| </configuration> | ||
| ``` |
18 changes: 18 additions & 0 deletions
18
...radox/routing-dsl/directives/mdc-logging-directives/withMarkerLoggingAdapter.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # withMarkerLoggingAdapter | ||
|
|
||
| @@@ div { .group-scala } | ||
|
|
||
| ## Signature | ||
|
|
||
| @@signature [MdcLoggingDirectives.scala](/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MdcLoggingDirectives.scala) { #withMarkerLoggingAdapter } | ||
|
|
||
| @@@ | ||
|
|
||
| ## Description | ||
|
|
||
| Replaces the @apidoc[RequestContext]'s existing @apidoc[LoggingAdapter] with a new instance of @apidoc[MarkerLoggingAdapter] and provides the same @apidoc[MarkerLoggingAdapter] to the caller. If the existing @apidoc[LoggingAdapter] already has an MDC map, the directive will copy its entries into the new @apidoc[MarkerLoggingAdapter]. | ||
|
|
||
| ## Example | ||
|
|
||
| Scala | ||
| : @@snip [MdcLoggingDirectivesExamplesSpec.scala](/docs/src/test/scala/docs/http/scaladsl/server/directives/MdcLoggingDirectivesExamplesSpec.scala) { #withMarkerLoggingAdapter } |
20 changes: 20 additions & 0 deletions
20
...rc/main/paradox/routing-dsl/directives/mdc-logging-directives/withMdcEntries.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # withMdcEntries | ||
|
|
||
| @@@ div { .group-scala } | ||
|
|
||
| ## Signature | ||
|
|
||
| @@signature [MdcLoggingDirectives.scala](/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MdcLoggingDirectives.scala) { #withMdcEntries } | ||
|
|
||
| @@@ | ||
|
|
||
| ## Description | ||
|
|
||
| Adds one or more (key, value) entries to the current MDC logging context. | ||
|
|
||
| Nested calls will accumulate entries. | ||
|
|
||
| ## Example | ||
|
|
||
| Scala | ||
| : @@snip [MdcLoggingDirectivesExamplesSpec.scala](/docs/src/test/scala/docs/http/scaladsl/server/directives/MdcLoggingDirectivesExamplesSpec.scala) { #withMdcEntries } |
20 changes: 20 additions & 0 deletions
20
.../src/main/paradox/routing-dsl/directives/mdc-logging-directives/withMdcEntry.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # withMdcEntry | ||
|
|
||
| @@@ div { .group-scala } | ||
|
|
||
| ## Signature | ||
|
|
||
| @@signature [MdcLoggingDirectives.scala](/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MdcLoggingDirectives.scala) { #withMdcEntry } | ||
|
|
||
| @@@ | ||
|
|
||
| ## Description | ||
|
|
||
| Adds a single (key, value) entry to the current MDC logging context. | ||
|
|
||
| Nested calls will accumulate entries. | ||
|
|
||
| ## Example | ||
|
|
||
| Scala | ||
| : @@snip [MdcLoggingDirectivesExamplesSpec.scala](/docs/src/test/scala/docs/http/scaladsl/server/directives/MdcLoggingDirectivesExamplesSpec.scala) { #withMdcEntry } |
49 changes: 49 additions & 0 deletions
49
...rc/test/scala/docs/http/scaladsl/server/directives/MdcLoggingDirectivesExamplesSpec.scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| package docs.http.scaladsl.server.directives | ||
|
|
||
| import akka.event._ | ||
| import akka.http.scaladsl.model.StatusCodes | ||
| import akka.http.scaladsl.server.RoutingSpec | ||
| import docs.CompileOnlySpec | ||
|
|
||
| class MdcLoggingDirectivesExamplesSpec extends RoutingSpec with CompileOnlySpec { | ||
|
|
||
| "withMarkerLoggingAdapter" in { | ||
| //#withMarkerLoggingAdapter | ||
| withMarkerLoggingAdapter { m: MarkerLoggingAdapter => | ||
| // This log.info includes entries for "user_id" and "request_id", | ||
| // but subsequent logging calls will not include them. | ||
| val marker = LogMarker("", Map("user_id" -> "1234", "request_id" -> "abcd")) | ||
| m.info(marker, "completing request") | ||
| complete(StatusCodes.OK) | ||
| } | ||
| //#withMarkerLoggingAdapter | ||
| } | ||
|
|
||
| "withMdcEntries" in { | ||
| //#withMdcEntries | ||
| withMdcEntries(("user_id", "1234"), ("request_id", "abcd")) { | ||
| extractLog { log => | ||
| // This log.info includes entries for "user_id" and "request_id", | ||
| // and subsequent calls will also include them. | ||
| log.info("completing request") | ||
| complete(StatusCodes.OK) | ||
| } | ||
| } | ||
| //#withMdcEntries | ||
| } | ||
|
|
||
| "withMdcEntry" in { | ||
| //#withMdcEntry | ||
| withMdcEntry("user_id", "1234") { | ||
| withMdcEntry("request_id", "abcd") { | ||
| extractLog { log => | ||
| // This log.info includes entries for "user_id" and "request_id", | ||
| // and subsequent calls will also include them. | ||
| log.info("completing request") | ||
| complete(StatusCodes.OK) | ||
| } | ||
| } | ||
| } | ||
| //#withMdcEntry | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.