Skip to content

Commit 5acf9f7

Browse files
committed
refactor(zio-opentelemetry): improve logging layer and update error handling in tracing
1 parent 4f0781e commit 5acf9f7

3 files changed

Lines changed: 18 additions & 16 deletions

File tree

observability/zio-opentelemetry/src/main/scala/sttp/tapir/server/ziopentelemetry/ZIOpenTelemetryApp.scala

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -96,23 +96,22 @@ trait ZIOpenTelemetryApp extends ZIOApp {
9696
tracer <- tracerProvider
9797
} yield OtelProviders(tracer, meter, logger))
9898

99-
/** The console log layer, provide a console logger to the ZIO application.
99+
/** The base log layer.
100100
*
101101
* Default implementation does nothing, hence uses the default ZIO console logger, which logs to stdout.
102102
*
103-
* You should override this to use a different logger:
103+
* You should override this to use a different logger.
104+
* Exmples include:
105+
*. - To bridge SLF4J to ZIO logging, you can use the following layer:
106+
* {{{
107+
* override def consoleLogLayer: ZLayer[Any, Nothing, Unit] = Slf4jBridge.init(...)
108+
* }}}
104109
* - No logs at all:
105-
*
106110
* {{{
107111
* override def consoleLogLayer: ZLayer[Any, Nothing, Unit] = Runtime.removeDefaultLoggers
108112
* }}}
109-
*
110-
* - SLF4J, Logback, etc. To use SLF4J, you can use the following layer:
111-
* {{{
112-
* override def consoleLogLayer: ZLayer[Any, Nothing, Unit] = Runtime.removeDefaultLoggers >>> SLF4J.slf4j
113-
* }}}
114113
*/
115-
def consoleLogLayer: ZLayer[Any, Nothing, Unit] = ZLayer.unit
114+
def baseLogLayer: ZLayer[Any, Nothing, Unit] = ZLayer.unit
116115

117116
/** The OpenTelemetry metrics layer for the ZIOpenTelemetry trait.
118117
*
@@ -154,7 +153,7 @@ trait ZIOpenTelemetryApp extends ZIOApp {
154153
)
155154

156155
def observabilityLayer: ULayer[ContextStorage & OpenTelemetrySdk & Meter & Tracing] =
157-
consoleLogLayer >>>
156+
baseLogLayer >>>
158157
OpenTelemetry.contextZIO >+> (otelProviders >>>
159158
openTelemetryLive) >+> (otel4zLogging ++ zioMetrics ++ otel4zMetrics(resourceName) ++ otel4zTracing(resourceName))
160159
}

observability/zio-opentelemetry/src/main/scala/sttp/tapir/server/ziopentelemetry/ZIOpenTelemetryTracing.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ class ZIOpenTelemetryTracing(
8282
)
8383
.flatMap { case (span, finalize) =>
8484
handleRequest(span, finalize, request, endpoints)
85+
.tapError { e =>
86+
spanError(span, finalize)(Right(e))
87+
}
8588
}
8689

8790
/** Handle the request, setting span attributes and status based on the result.
@@ -136,7 +139,7 @@ class ZIOpenTelemetryTracing(
136139
}
137140
ZIO.succeed(response.copy(body = Some(Right(ZioStreamHttpResponseBody(wrapped, contentLength)).asInstanceOf[B])))
138141
case _ =>
139-
ZIO.when(response.isServerError)(
142+
ZIO.when(response.isServerError || response.isClientError)(
140143
spanError(span, finalize)(Left(response.code))
141144
) *> finalize *> ZIO.succeed(response)
142145
})

observability/zio-opentelemetry/src/test/scala/sttp/tapir/server/ziopentelemetry/ZIOpenTelemetryTracingSpec.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ object ZIOpenTelemetryTracingSpec extends ZIOSpecDefault {
357357
assert(finishedSpans.get(0).getAttributes.get(ErrorAttributes.ERROR_TYPE))(equalTo("RuntimeException"))
358358
}
359359
},
360-
test("4xx client error does NOT set span error status") {
360+
test("4xx client error does set span error status") {
361361
val ep = endpoint
362362
.in("client-error")
363363
.out(stringBody)
@@ -369,7 +369,7 @@ object ZIOpenTelemetryTracingSpec extends ZIOSpecDefault {
369369
span <- runRequestSingleSpan(List(ep), request)
370370
} yield {
371371
// 4xx is not a server error, so span status should NOT be ERROR
372-
assert(span.getStatus.getStatusCode)(not(equalTo(OtelStatusCode.ERROR))) &&
372+
assert(span.getStatus.getStatusCode)(equalTo(OtelStatusCode.ERROR)) &&
373373
assert(span.getAttributes.get(HttpAttributes.HTTP_RESPONSE_STATUS_CODE))(equalTo(java.lang.Long.valueOf(400L)))
374374
}
375375
}
@@ -437,7 +437,7 @@ object ZIOpenTelemetryTracingSpec extends ZIOSpecDefault {
437437
// ─── Endpoint Matching Behavior ────────────────────────────────────────────
438438

439439
private val endpointMatchingSuite = suite("Endpoint Matching Behavior")(
440-
test("unmatched request does not set error status") {
440+
test("unmatched request does set error status") {
441441
val ep = endpoint
442442
.in("person")
443443
.out(stringBody)
@@ -450,7 +450,7 @@ object ZIOpenTelemetryTracingSpec extends ZIOSpecDefault {
450450
spans <- runRequest(List(ep), request)
451451
} yield {
452452
assertTrue(spans.size() == 1) &&
453-
assert(spans.get(0).getStatus.getStatusCode)(not(equalTo(OtelStatusCode.ERROR)))
453+
assert(spans.get(0).getStatus.getStatusCode)(equalTo(OtelStatusCode.ERROR))
454454
}
455455
},
456456
test("decode failure on matched endpoint - span is created with initial name") {
@@ -471,7 +471,7 @@ object ZIOpenTelemetryTracingSpec extends ZIOSpecDefault {
471471
// the endpoint is not confirmed, so span retains the initial request-based name.
472472
assertTrue(spans.size() >= 1) &&
473473
assertTrue(spans.get(0).getKind == SpanKind.SERVER) &&
474-
assert(spans.get(0).getStatus.getStatusCode)(not(equalTo(OtelStatusCode.ERROR)))
474+
assert(spans.get(0).getStatus.getStatusCode)(equalTo(OtelStatusCode.ERROR))
475475
}
476476
},
477477
test("security failure on matched endpoint updates span name") {

0 commit comments

Comments
 (0)