Generalize OTEL API and add memcache tracing support
CI / build (push) Successful in 6m22s

- Rename RedisSpan -> SpanHandle for generic span handling
- Generalize TelemetryController methods: startSpan/endSpan with dbSystem param
- Rename RedisOtelSpan -> OtelSpanHandle in rbcs-server-otel
- Update Redis cache handler to use new generic API
- Add OpenTelemetry tracing for memcache GET and SET commands
- Add channel property to MemcacheRequestController for server address attribution
- Add uses TelemetryController directive in memcache module-info

Memcache spans follow the same pattern as Redis:
db.system=memcache, db.operation=GET|SET, server.address, server.port
This commit is contained in:
opencode
2026-05-21 11:16:48 +00:00
committed by Walter Oggioni
parent f154bbd33c
commit 9a7a2566fa
10 changed files with 170 additions and 82 deletions
@@ -2,13 +2,14 @@ package net.woggioni.rbcs.server.otel
import io.netty.channel.ChannelHandler
import io.opentelemetry.api.GlobalOpenTelemetry
import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.api.trace.SpanKind
import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender
import io.opentelemetry.instrumentation.netty.v4_1.NettyServerTelemetry
import io.opentelemetry.instrumentation.runtimetelemetry.RuntimeTelemetry
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk
import net.woggioni.rbcs.api.RedisSpan
import net.woggioni.rbcs.api.SpanHandle
import net.woggioni.rbcs.api.TelemetryController
import net.woggioni.rbcs.common.createLogger
import net.woggioni.rbcs.common.info
@@ -44,21 +45,19 @@ class OtelController : TelemetryController {
return NettyServerTelemetry.create(GlobalOpenTelemetry.get()).createCombinedHandler()
}
override fun startRedisSpan(command: String, key: String): RedisSpan? {
val span = tracer.spanBuilder(command)
override fun startSpan(name: String): SpanHandle {
val span = tracer.spanBuilder(name)
.setSpanKind(SpanKind.CLIENT)
.setAttribute("db.system", "redis")
.setAttribute("db.operation", command)
.startSpan()
return RedisOtelSpan(span)
return OtelSpanHandle(span)
}
override fun endRedisSpan(span: RedisSpan?) {
(span as? RedisOtelSpan)?.delegate?.end()
override fun endSpan(span: SpanHandle?) {
(span as? OtelSpanHandle)?.delegate?.end()
}
override fun endRedisSpan(span: RedisSpan?, error: Throwable) {
val s = (span as? RedisOtelSpan)?.delegate ?: return
override fun endSpan(span: SpanHandle?, error: Throwable) {
val s = (span as? OtelSpanHandle)?.delegate ?: return
s.recordException(error)
s.setStatus(StatusCode.ERROR)
s.end()
@@ -1,11 +1,11 @@
package net.woggioni.rbcs.server.otel
import io.opentelemetry.api.trace.Span
import net.woggioni.rbcs.api.RedisSpan
import net.woggioni.rbcs.api.SpanHandle
internal class RedisOtelSpan(
internal class OtelSpanHandle(
val delegate: Span,
) : RedisSpan {
) : SpanHandle {
override fun setAttribute(key: String, value: String) {
delegate.setAttribute(key, value)
@@ -14,4 +14,8 @@ internal class RedisOtelSpan(
override fun setAttribute(key: String, value: Long) {
delegate.setAttribute(key, value)
}
override fun setAttribute(key: String, value: Boolean) {
delegate.setAttribute(key, value)
}
}