Compare commits

..

3 Commits
dev ... dev

Author SHA1 Message Date
bfce91905f removed telemetry switch from configuration 2026-04-30 21:38:07 +08:00
ab2a06e810 refactor 2026-04-30 02:15:34 +08:00
1d938b7ea3 Add optional OpenTelemetry Netty server instrumentation
- Update lys.version to 2026.04.14

- Add optional compileOnly dependency on opentelemetry-netty-4.1 in rbcs-server

- Add runtime guard to only activate instrumentation when OTel classes are on classpath

- Insert OTel combined handler after HttpServerCodec in the Netty pipeline

- Add requires-static JPMS directives for optional module support
2026-04-29 02:59:51 +08:00
33 changed files with 270 additions and 189 deletions

View File

@@ -58,6 +58,18 @@ jobs:
tags: |
gitea.woggioni.net/woggioni/rbcs:dev-redis
target: release-redis
-
name: Build rbcs full Docker image
uses: docker/build-push-action@v5.3.0
with:
builder: "multiplatform-builder"
context: "docker/build/docker"
platforms: linux/amd64,linux/arm64
push: true
pull: true
tags: |
gitea.woggioni.net/woggioni/rbcs:dev-full
target: release-full
-
name: Build rbcs native Docker image
uses: docker/build-push-action@v5.3.0

View File

@@ -61,6 +61,19 @@ jobs:
gitea.woggioni.net/woggioni/rbcs:redis
gitea.woggioni.net/woggioni/rbcs:${{ steps.retrieve-version.outputs.VERSION }}-redis
target: release-redis
-
name: Build rbcs full Docker image
uses: docker/build-push-action@v5.3.0
with:
builder: "multiplatform-builder"
context: "docker/build/docker"
platforms: linux/amd64,linux/arm64
push: true
pull: true
tags: |
gitea.woggioni.net/woggioni/rbcs:full
gitea.woggioni.net/woggioni/rbcs:${{ steps.retrieve-version.outputs.VERSION }}-full
target: release-full
-
name: Build rbcs native Docker image
uses: docker/build-push-action@v5.3.0

5
.gitignore vendored
View File

@@ -5,3 +5,8 @@
build
rbcs-cli/native-image/*.json
# Ignore JDTLS files
.classpath
.project
.settings

View File

@@ -139,6 +139,7 @@ Configures TLS encryption.
<rbcs:server xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rbcs="urn:net.woggioni.rbcs.server"
xs:schemaLocation="urn:net.woggioni.rbcs.server jpms://net.woggioni.rbcs.server/net/woggioni/rbcs/server/schema/rbcs-server.xsd"
path="/my/custom/path"
>
<bind host="0.0.0.0" port="8080" incoming-connections-backlog-size="1024" proxy-protocol="true">
<trusted-proxies>

View File

@@ -7,7 +7,8 @@ FROM base-release AS release-vanilla
ADD rbcs-cli-envelope-*.jar rbcs.jar
ADD logback.xml /etc/rbcs/logback.xml
ENV RBCS_CONFIGURATION_DIR="/etc/rbcs"
ENTRYPOINT ["java", "-Dlogback.configurationFile=/etc/rbcs/logback.xml", "-XX:MaxRAMPercentage=70", "-XX:GCTimeRatio=24", "-XX:+UseZGC", "-jar", "/var/lib/rbcs/rbcs.jar"]
ENV JDK_JAVA_OPTIONS=-Dlogback.configurationFile=/etc/rbcs/logback.xml\ -XX:MaxRAMPercentage=70\ -XX:GCTimeRatio=24\ -XX:+UseZGC
ENTRYPOINT ["java", "-jar", "/var/lib/rbcs/rbcs.jar"]
FROM base-release AS release-memcache
ADD --chown=rbcs:rbcs rbcs-cli-envelope-*.jar rbcs.jar
@@ -16,8 +17,7 @@ WORKDIR /var/lib/rbcs/plugins
RUN --mount=type=bind,source=.,target=/build/distributions tar -xf /build/distributions/rbcs-server-memcache*.tar
WORKDIR /var/lib/rbcs
ADD logback.xml /etc/rbcs/logback.xml
ENV RBCS_CONFIGURATION_DIR="/etc/rbcs"
ENTRYPOINT ["java", "-Dlogback.configurationFile=/etc/rbcs/logback.xml", "-XX:MaxRAMPercentage=70", "-XX:GCTimeRatio=24", "-XX:+UseZGC", "-jar", "/var/lib/rbcs/rbcs.jar"]
ENTRYPOINT ["java", "-jar", "/var/lib/rbcs/rbcs.jar"]
FROM base-release AS release-redis
ADD --chown=rbcs:rbcs rbcs-cli-envelope-*.jar rbcs.jar
@@ -26,8 +26,19 @@ WORKDIR /var/lib/rbcs/plugins
RUN --mount=type=bind,source=.,target=/build/distributions tar -xf /build/distributions/rbcs-server-redis*.tar
WORKDIR /var/lib/rbcs
ADD logback.xml /etc/rbcs/logback.xml
ENV RBCS_CONFIGURATION_DIR="/etc/rbcs"
ENTRYPOINT ["java", "-Dlogback.configurationFile=/etc/rbcs/logback.xml", "-XX:MaxRAMPercentage=70", "-XX:GCTimeRatio=24", "-XX:+UseZGC", "-jar", "/var/lib/rbcs/rbcs.jar"]
ENTRYPOINT ["java", "-jar", "/var/lib/rbcs/rbcs.jar"]
FROM base-release AS release-full
ADD --chown=rbcs:rbcs rbcs-cli-envelope-*.jar rbcs.jar
RUN mkdir plugins
WORKDIR /var/lib/rbcs/plugins
RUN --mount=type=bind,source=.,target=/build/distributions tar -xf /build/distributions/rbcs-server-memcache*.tar
RUN --mount=type=bind,source=.,target=/build/distributions tar -xf /build/distributions/rbcs-server-redis*.tar
RUN --mount=type=bind,source=.,target=/build/distributions tar -xf /build/distributions/rbcs-server-otel*.tar
WORKDIR /var/lib/rbcs
ADD logback.xml /etc/rbcs/logback.xml
ENV OTEL_SDK_DISABLED="true"
ENTRYPOINT ["java", "-jar", "/var/lib/rbcs/rbcs.jar"]
FROM busybox:musl AS base-native
RUN mkdir -p /var/lib/rbcs /var/tmp/rbcs /etc/rbcs
@@ -54,5 +65,5 @@ USER rbcs
WORKDIR /var/lib/rbcs
ADD logback.xml /etc/rbcs/logback.xml
ENV RBCS_CONFIGURATION_DIR="/etc/rbcs"
ENV JAVA_OPTS=-XX:-UseJVMCICompiler\ -Dlogback.configurationFile=/etc/rbcs/logback.xml\ -XX:MaxRAMPercentage=70\ -XX:GCTimeRatio=24\ -XX:+UseZGC
ENV JDK_JAVA_OPTIONS=-XX:-UseJVMCICompiler\ -Dlogback.configurationFile=/etc/rbcs/logback.xml\ -XX:MaxRAMPercentage=70\ -XX:GCTimeRatio=24\ -XX:+UseZGC
ENTRYPOINT ["/usr/local/bin/rbcs-cli"]

View File

@@ -21,6 +21,7 @@ dependencies {
docker project(path: ':rbcs-cli', configuration: 'release')
docker project(path: ':rbcs-server-memcache', configuration: 'release')
docker project(path: ':rbcs-server-redis', configuration: 'release')
docker project(path: ':rbcs-server-otel', configuration: 'release')
}
Provider<Task> cleanTaskProvider = tasks.named(BasePlugin.CLEAN_TASK_NAME) {}

View File

@@ -4,7 +4,7 @@ org.gradle.caching=true
rbcs.version = 0.5.0
lys.version = 2026.04.28
lys.version = 2026.04.29
gitea.maven.url = https://gitea.woggioni.net/api/packages/woggioni/maven
docker.registry.url=gitea.woggioni.net

View File

@@ -11,6 +11,7 @@ dependencies {
api catalog.netty.buffer
api catalog.netty.handler
api catalog.netty.codec.http
api catalog.jetbrains.annotations
}
publishing {

View File

@@ -8,7 +8,7 @@ module net.woggioni.rbcs.api {
requires io.netty.buffer;
requires org.slf4j;
requires java.xml;
requires org.jetbrains.annotations;
exports net.woggioni.rbcs.api;
exports net.woggioni.rbcs.api.exception;

View File

@@ -16,13 +16,12 @@ import java.util.stream.Collectors;
@Value
public class Configuration {
boolean enableTelemetry;
String host;
int port;
String serverPath;
boolean proxyProtocolEnabled;
List<Cidr> trustedProxyIPs;
int incomingConnectionsBacklogSize;
String serverPath;
@NonNull
EventExecutor eventExecutor;
@NonNull
@@ -151,7 +150,6 @@ public class Configuration {
}
public static Configuration of(
boolean enableTelemetry,
String host,
int port,
boolean proxyProtocolEnabled,
@@ -168,13 +166,12 @@ public class Configuration {
Tls tls
) {
return new Configuration(
enableTelemetry,
host,
port,
serverPath != null && !serverPath.isEmpty() && !serverPath.equals("/") ? serverPath : null,
proxyProtocolEnabled,
trustedProxyIPs,
incomingConnectionsBacklogSize,
serverPath != null && !serverPath.isEmpty() && !serverPath.equals("/") ? serverPath : null,
eventExecutor,
rateLimiter,
connection,

View File

@@ -0,0 +1,9 @@
package net.woggioni.rbcs.api;
import io.netty.channel.ChannelHandler;
import org.jetbrains.annotations.NotNull;
public interface TelemetryController {
void initialize();
@NotNull ChannelHandler createHandler();
}

View File

@@ -30,7 +30,6 @@ configurations {
transitive = false
canBeConsumed = true
canBeResolved = true
visible = true
}
configureNativeImageImplementation {
@@ -51,6 +50,7 @@ dependencies {
configureNativeImageImplementation project
configureNativeImageImplementation project(':rbcs-server-memcache')
configureNativeImageImplementation project(':rbcs-server-redis')
// configureNativeImageImplementation project(':rbcs-server-otel')
implementation catalog.jwo
implementation catalog.slf4j.api
@@ -59,9 +59,7 @@ dependencies {
implementation project(':rbcs-client')
implementation project(':rbcs-server')
// runtimeOnly catalog.slf4j.jdk14
runtimeOnly catalog.logback.classic
// runtimeOnly catalog.slf4j.simple
nativeImage project(':rbcs-server-memcache')
nativeImage project(':rbcs-server-redis')
@@ -142,7 +140,12 @@ Provider<JlinkTask> jlinkTaskProvider = tasks.named(JlinkPlugin.JLINK_TASK_NAME,
'net.woggioni.rbcs.server.memcache',
'net.woggioni.rbcs.server.redis',
'ch.qos.logback.classic',
'jdk.crypto.ec'
'jdk.crypto.ec',
// 'io.opentelemetry.api',
// 'io.opentelemetry.instrumentation.netty_4_1',
// 'io.opentelemetry.sdk.autoconfigure',
// 'io.opentelemetry.instrumentation.logback_appender_1_0',
// 'io.opentelemetry.extension.trace.propagation'
]
compressionLevel = 2
stripDebug = false

View File

@@ -120,10 +120,10 @@ object GraalNativeImageConfiguration {
val serverConfiguration = Configuration(
"127.0.0.1",
serverPort,
null,
false,
emptyList(),
100,
null,
Configuration.EventExecutor(true),
Configuration.RateLimiter(
false, 0x100000, 10

View File

@@ -1,11 +1,11 @@
module net.woggioni.rbcs.cli {
requires org.slf4j;
requires net.woggioni.jwo;
requires net.woggioni.rbcs.server;
requires info.picocli;
requires net.woggioni.rbcs.common;
requires net.woggioni.rbcs.client;
requires kotlin.stdlib;
requires net.woggioni.jwo;
requires net.woggioni.rbcs.api;
exports net.woggioni.rbcs.cli.impl.converters to info.picocli;
@@ -14,4 +14,6 @@ module net.woggioni.rbcs.cli {
opens net.woggioni.rbcs.cli to info.picocli, net.woggioni.rbcs.common;
exports net.woggioni.rbcs.cli;
uses net.woggioni.rbcs.api.TelemetryController;
}

View File

@@ -1,6 +1,8 @@
package net.woggioni.rbcs.cli
import net.woggioni.jwo.Application
import net.woggioni.jwo.LoggerController
import net.woggioni.rbcs.api.TelemetryController
import net.woggioni.rbcs.cli.impl.AbstractVersionProvider
import net.woggioni.rbcs.cli.impl.RbcsCommand
import net.woggioni.rbcs.cli.impl.commands.BenchmarkCommand
@@ -14,6 +16,8 @@ import net.woggioni.rbcs.common.RbcsUrlStreamHandlerFactory
import net.woggioni.rbcs.common.createLogger
import picocli.CommandLine
import picocli.CommandLine.Model.CommandSpec
import java.util.ServiceLoader
import net.woggioni.rbcs.common.RBCS.loadService
@CommandLine.Command(
@@ -61,6 +65,10 @@ class RemoteBuildCacheServerCli : RbcsCommand() {
@JvmStatic
fun main(vararg args: String) {
loadService(TelemetryController::class.java)
.firstOrNull()
?.initialize()
LoggerController.initializeLoggers()
System.exit(createCommandLine().execute(*args))
}
}

View File

@@ -2,6 +2,7 @@ package net.woggioni.rbcs.common
import io.netty.channel.Channel
import io.netty.channel.ChannelHandlerContext
import net.woggioni.jwo.LoggerController
import java.nio.file.Files
import java.nio.file.Path
import java.util.logging.LogManager
@@ -11,8 +12,10 @@ import org.slf4j.MDC
import org.slf4j.event.Level
import org.slf4j.spi.LoggingEventBuilder
inline fun <reified T> T.contextLogger() = LoggerFactory.getLogger(T::class.java)
inline fun <reified T> createLogger() = LoggerFactory.getLogger(T::class.java)
fun <T> lazyLogger(cls: Class<T>) = LoggerController.lazyLogger(cls)
inline fun <reified T> T.contextLogger() = lazyLogger(T::class.java)
inline fun <reified T> createLogger() = lazyLogger(T::class.java)
inline fun Logger.traceParam(messageBuilder: () -> Pair<String, Array<Any>>) {
if (isTraceEnabled) {

View File

@@ -1,5 +1,7 @@
package net.woggioni.rbcs.common
import net.woggioni.jwo.JWO
import net.woggioni.jwo.Tuple2
import java.io.IOException
import java.net.InetAddress
import java.net.ServerSocket
@@ -9,18 +11,10 @@ import java.nio.file.Files
import java.nio.file.Path
import java.security.KeyStore
import java.security.MessageDigest
import java.security.cert.CertPathValidator
import java.security.cert.CertPathValidatorException
import java.security.cert.CertificateException
import java.security.cert.CertificateFactory
import java.security.cert.PKIXParameters
import java.security.cert.PKIXRevocationChecker
import java.security.cert.X509Certificate
import java.util.EnumSet
import java.security.cert.*
import java.util.*
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
import net.woggioni.jwo.JWO
import net.woggioni.jwo.Tuple2
object RBCS {
fun String.toUrl(): URL = URL.of(URI(this), null)
@@ -164,4 +158,10 @@ object RBCS {
.single() as X509TrustManager
}
}
inline fun <T, reified U> U.loadService(serviceClass : Class<T>): Sequence<T> {
return (U::class.java.module.layer?.let { layer ->
ServiceLoader.load(layer, serviceClass)
} ?: ServiceLoader.load(serviceClass)).asSequence()
}
}

View File

@@ -0,0 +1,81 @@
plugins {
id 'java-library'
id 'maven-publish'
alias catalog.plugins.kotlin.jvm
}
configurations {
bundle {
canBeResolved = false
canBeConsumed = false
transitive = true
}
filteredBundle {
canBeResolved = true
canBeConsumed = false
transitive = true
extendsFrom bundle
resolutionStrategy {
dependencies {
exclude group: 'org.slf4j', module: 'slf4j-api'
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib'
exclude group: 'org.jetbrains', module: 'annotations'
}
}
}
release {
transitive = false
canBeConsumed = true
canBeResolved = true
}
compileOnly {
extendsFrom bundle
}
}
dependencies {
compileOnly project(':rbcs-common')
compileOnly project(':rbcs-api')
compileOnly catalog.netty.transport
compileOnly catalog.slf4j.api
compileOnly catalog.kotlin.stdlib.jdk8
compileOnly catalog.logback.core
compileOnly catalog.logback.classic
bundle catalog.opentelemetry.netty.'4'.'1'
bundle catalog.opentelemetry.sdk.extension.autoconfigure
bundle catalog.opentelemetry.logback.appender.'1'.'0'
bundle catalog.opentelemetry.logback.mdc.'1'.'0'
bundle catalog.opentelemetry.extension.trace.propagators
bundle catalog.opentelemetry.exporter.otlp
bundle catalog.opentelemetry.runtime.telemetry
}
Provider<Tar> bundleTask = tasks.register("bundle", Tar) {
from(tasks.named(JavaPlugin.JAR_TASK_NAME))
from(configurations.filteredBundle)
group = BasePlugin.BUILD_GROUP
}
tasks.named(BasePlugin.ASSEMBLE_TASK_NAME) {
dependsOn(bundleTask)
}
artifacts {
release(bundleTask)
}
publishing {
publications {
maven(MavenPublication) {
artifact bundleTask
}
}
}

View File

@@ -0,0 +1,20 @@
module net.woggioni.rbcs.server.otel {
requires net.woggioni.rbcs.common;
requires kotlin.stdlib;
requires io.netty.transport;
requires io.netty.common;
requires io.netty.buffer;
requires org.slf4j;
requires ch.qos.logback.core;
requires ch.qos.logback.classic;
requires io.opentelemetry.api;
requires io.opentelemetry.sdk.autoconfigure;
requires io.opentelemetry.instrumentation.runtime_telemetry;
requires io.opentelemetry.instrumentation.netty_4_1;
requires io.opentelemetry.instrumentation.logback_appender_1_0;
requires io.opentelemetry.extension.trace.propagation;
requires net.woggioni.rbcs.api;
provides net.woggioni.rbcs.api.TelemetryController with net.woggioni.rbcs.server.otel.OtelController;
}

View File

@@ -0,0 +1,39 @@
package net.woggioni.rbcs.server.otel
import io.netty.channel.ChannelHandler
import io.opentelemetry.api.GlobalOpenTelemetry
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.TelemetryController
import net.woggioni.rbcs.common.createLogger
import net.woggioni.rbcs.common.info
class OtelController : TelemetryController {
private val log = createLogger<OtelController>()
override fun initialize() {
log.info { "Initializing OpenTelemetry SDK with auto-configuration" }
val sdk = AutoConfiguredOpenTelemetrySdk.builder()
.setResultAsGlobal()
.build()
.openTelemetrySdk
RuntimeTelemetry.create(sdk)
runCatching {
OpenTelemetryAppender.install(sdk)
log.info { "OpenTelemetry logback appender installed" }
}.onFailure { ex ->
val msg = ex.localizedMessage ?: ex.javaClass.name
log.info { "Failed to install OpenTelemetry logback appender: $msg" }
}
log.info { "OpenTelemetry SDK initialized successfully" }
}
override fun createHandler(): ChannelHandler {
return NettyServerTelemetry.create(GlobalOpenTelemetry.get()).createCombinedHandler()
}
}

View File

@@ -17,11 +17,6 @@ module net.woggioni.rbcs.server {
requires io.netty.common;
requires io.netty.codec;
requires io.netty.codec.haproxy;
requires static io.opentelemetry.api;
requires static io.opentelemetry.instrumentation.netty_4_1;
requires static io.opentelemetry.sdk.autoconfigure;
requires static io.opentelemetry.instrumentation.logback_appender_1_0;
requires static io.opentelemetry.extension.trace.propagation;
requires org.slf4j;
exports net.woggioni.rbcs.server;
@@ -31,5 +26,6 @@ module net.woggioni.rbcs.server {
uses CacheProvider;
uses net.woggioni.rbcs.api.TelemetryController;
provides CacheProvider with FileSystemCacheProvider, InMemoryCacheProvider;
}

View File

@@ -2,16 +2,8 @@ package net.woggioni.rbcs.server
import io.netty.bootstrap.ServerBootstrap
import io.netty.buffer.ByteBuf
import io.netty.channel.Channel
import io.netty.channel.ChannelFactory
import io.netty.channel.ChannelFuture
import io.netty.channel.*
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelInboundHandlerAdapter
import io.netty.channel.ChannelInitializer
import io.netty.channel.ChannelOption
import io.netty.channel.ChannelPromise
import io.netty.channel.MultiThreadIoEventLoopGroup
import io.netty.channel.nio.NioIoHandler
import io.netty.channel.socket.DatagramChannel
import io.netty.channel.socket.ServerSocketChannel
@@ -21,12 +13,7 @@ import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.channel.socket.nio.NioSocketChannel
import io.netty.handler.codec.compression.CompressionOptions
import io.netty.handler.codec.haproxy.HAProxyMessageDecoder
import io.netty.handler.codec.http.DefaultHttpContent
import io.netty.handler.codec.http.HttpContentCompressor
import io.netty.handler.codec.http.HttpDecoderConfig
import io.netty.handler.codec.http.HttpHeaderNames
import io.netty.handler.codec.http.HttpRequest
import io.netty.handler.codec.http.HttpServerCodec
import io.netty.handler.codec.http.*
import io.netty.handler.ssl.ClientAuth
import io.netty.handler.ssl.SslContext
import io.netty.handler.ssl.SslContextBuilder
@@ -37,39 +24,17 @@ import io.netty.handler.timeout.IdleStateEvent
import io.netty.handler.timeout.IdleStateHandler
import io.netty.util.AttributeKey
import io.netty.util.concurrent.EventExecutorGroup
import java.io.OutputStream
import java.net.InetSocketAddress
import java.nio.file.Files
import java.nio.file.Path
import java.security.PrivateKey
import java.security.cert.X509Certificate
import java.time.Duration
import java.time.Instant
import java.util.Arrays
import java.util.Base64
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Future
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import java.util.regex.Matcher
import java.util.regex.Pattern
import javax.naming.ldap.LdapName
import javax.net.ssl.SSLPeerUnverifiedException
import net.woggioni.rbcs.api.AsyncCloseable
import net.woggioni.rbcs.api.Configuration
import net.woggioni.rbcs.api.TelemetryController
import net.woggioni.rbcs.api.exception.ConfigurationException
import net.woggioni.rbcs.common.Cidr
import net.woggioni.rbcs.common.*
import net.woggioni.rbcs.common.PasswordSecurity.decodePasswordHash
import net.woggioni.rbcs.common.PasswordSecurity.hashPassword
import net.woggioni.rbcs.common.RBCS.getTrustManager
import net.woggioni.rbcs.common.RBCS.loadKeystore
import net.woggioni.rbcs.common.RBCS.loadService
import net.woggioni.rbcs.common.RBCS.toUrl
import net.woggioni.rbcs.common.Xml
import net.woggioni.rbcs.common.createLogger
import net.woggioni.rbcs.common.debug
import net.woggioni.rbcs.common.info
import net.woggioni.rbcs.server.otel.OtelIntegration
import net.woggioni.rbcs.server.otel.OtelSdkIntegration
import net.woggioni.rbcs.server.auth.AbstractNettyHttpAuthenticator
import net.woggioni.rbcs.server.auth.Authorizer
import net.woggioni.rbcs.server.auth.RoleAuthorizer
@@ -82,6 +47,23 @@ import net.woggioni.rbcs.server.handler.ReadTriggerDuplexHandler
import net.woggioni.rbcs.server.handler.ServerHandler
import net.woggioni.rbcs.server.throttling.BucketManager
import net.woggioni.rbcs.server.throttling.ThrottlingHandler
import java.io.OutputStream
import java.net.InetSocketAddress
import java.nio.file.Files
import java.nio.file.Path
import java.security.PrivateKey
import java.security.cert.X509Certificate
import java.time.Duration
import java.time.Instant
import java.util.*
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Future
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import java.util.regex.Matcher
import java.util.regex.Pattern
import javax.naming.ldap.LdapName
import javax.net.ssl.SSLPeerUnverifiedException
class RemoteBuildCacheServer(private val cfg: Configuration) {
@@ -433,7 +415,10 @@ class RemoteBuildCacheServer(private val cfg: Configuration) {
maxChunkSize = cfg.connection.chunkSize
}
pipeline.addLast(HttpServerCodec(httpDecoderConfig))
OtelIntegration.createHandler(cfg.isEnableTelemetry)?.let { pipeline.addLast(it) }
loadService(TelemetryController::class.java)
.firstOrNull()
?.createHandler()
?.let { pipeline.addLast(it) }
pipeline.addLast(ReadTriggerDuplexHandler.NAME, ReadTriggerDuplexHandler())
pipeline.addLast(MaxRequestSizeHandler.NAME, MaxRequestSizeHandler(cfg.connection.maxRequestSize))
pipeline.addLast(HttpChunkContentCompressor(1024))
@@ -528,7 +513,6 @@ class RemoteBuildCacheServer(private val cfg: Configuration) {
}
fun run(): ServerHandle {
OtelSdkIntegration.initialize(cfg.isEnableTelemetry)
// Create the multithreaded event loops for the server
val bossGroup = MultiThreadIoEventLoopGroup(1, NioIoHandler.newFactory())
val channelFactory = ChannelFactory<SocketChannel> { NioSocketChannel() }

View File

@@ -46,8 +46,6 @@ object Parser {
var groups = emptyMap<String, Group>()
var tls: Tls? = null
val serverPath = root.renderAttribute("path")
var enableTelemetry = root.renderAttribute("enable-telemetry")
?.let(String::toBoolean) ?: false
var incomingConnectionsBacklogSize = 1024
var authentication: Authentication? = null
for (child in root.asIterable()) {
@@ -235,7 +233,6 @@ object Parser {
}
}
return Configuration.of(
enableTelemetry,
host,
port,
proxyProtocolEnabled,

View File

@@ -29,7 +29,6 @@ object Serializer {
?.let { serverPath ->
attr("path", serverPath)
}
attr("enable-telemetry", conf.isEnableTelemetry.toString())
node("bind") {
attr("host", conf.host)
attr("port", conf.port.toString())

View File

@@ -1,32 +0,0 @@
package net.woggioni.rbcs.server.otel
import io.netty.channel.ChannelHandler
import io.opentelemetry.api.GlobalOpenTelemetry
import io.opentelemetry.instrumentation.netty.v4_1.NettyServerTelemetry
import net.woggioni.rbcs.common.createLogger
import net.woggioni.rbcs.common.warn
object OtelIntegration {
private val log = createLogger<OtelIntegration>()
val isAvailable: Boolean by lazy {
runCatching {
Class.forName("io.opentelemetry.api.OpenTelemetry")
}.fold(
onSuccess = { true },
onFailure = {
log.warn { "OpenTelemetry classes not on classpath, instrumentation disabled" }
false
},
)
}
fun createHandler(enabled: Boolean): ChannelHandler? {
return if (enabled && isAvailable) createHandlerInternal() else null
}
private fun createHandlerInternal(): ChannelHandler {
return NettyServerTelemetry.create(GlobalOpenTelemetry.get()).createCombinedHandler()
}
}

View File

@@ -1,58 +0,0 @@
package net.woggioni.rbcs.server.otel
import net.woggioni.rbcs.common.createLogger
import net.woggioni.rbcs.common.info
object OtelSdkIntegration {
private val log = createLogger<OtelSdkIntegration>()
private val isAvailable: Boolean by lazy {
runCatching {
Class.forName("io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk")
}.fold(
onSuccess = { true },
onFailure = {
log.info { "OpenTelemetry SDK autoconfigure not on classpath" }
false
},
)
}
private val appenderAvailable: Boolean by lazy {
runCatching {
Class.forName("io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender")
}.fold(
onSuccess = { true },
onFailure = {
log.info { "OpenTelemetry logback appender not on classpath" }
false
},
)
}
fun initialize(enabled: Boolean) {
if (!enabled || !isAvailable) return
log.info { "Initializing OpenTelemetry SDK with auto-configuration" }
val sdk = io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk.builder()
.setResultAsGlobal()
.build()
.openTelemetrySdk
if (appenderAvailable) {
runCatching {
val clazz = Class.forName("io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender")
clazz.getMethod("install", Class.forName("io.opentelemetry.api.OpenTelemetry"))
.invoke(null, sdk)
log.info { "OpenTelemetry logback appender installed" }
}.onFailure { ex ->
val msg = ex.localizedMessage ?: ex.javaClass.name
log.info { "Failed to install OpenTelemetry logback appender: $msg" }
}
}
log.info { "OpenTelemetry SDK initialized successfully" }
}
}

View File

@@ -2,8 +2,7 @@
<rbcs:server
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rbcs="urn:net.woggioni.rbcs.server"
xs:schemaLocation="urn:net.woggioni.rbcs.server jpms://net.woggioni.rbcs.server/net/woggioni/rbcs/server/schema/rbcs-server.xsd"
enable-telemetry="false">
xs:schemaLocation="urn:net.woggioni.rbcs.server jpms://net.woggioni.rbcs.server/net/woggioni/rbcs/server/schema/rbcs-server.xsd">
<bind host="127.0.0.1" port="8080" incoming-connections-backlog-size="1024"/>
<cache xs:type="rbcs:fileSystemCacheType" path="${sys:java.io.tmpdir}/rbcs" max-age="P7D"/>
</rbcs:server>

View File

@@ -59,14 +59,6 @@
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="enable-telemetry" type="xs:boolean" use="optional" default="false">
<xs:annotation>
<xs:documentation>
Enable OpenTelemetry distributed tracing for the server.
Even when enabled, telemetry only activates if OpenTelemetry classes are present on the classpath.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="bindType">

View File

@@ -32,7 +32,6 @@ abstract class AbstractBasicAuthServerTest : AbstractServerTest() {
override fun setUp() {
this.cacheDir = testDir.resolve("cache")
cfg = Configuration.of(
false,
"127.0.0.1",
getFreePort(),
false,

View File

@@ -138,14 +138,12 @@ abstract class AbstractTlsServerTest : AbstractServerTest() {
this.cacheDir = testDir.resolve("cache")
createKeyStoreAndTrustStore()
cfg = Configuration(
false,
"127.0.0.1",
getFreePort(),
serverPath,
false,
emptyList(),
100,
serverPath,
Configuration.EventExecutor(false),
Configuration.RateLimiter(true, 0x100000, 50),
Configuration.Connection(

View File

@@ -32,13 +32,12 @@ class NoAuthServerTest : AbstractServerTest() {
override fun setUp() {
this.cacheDir = testDir.resolve("cache")
cfg = Configuration(
false,
"127.0.0.1",
getFreePort(),
serverPath,
false,
emptyList(),
100,
serverPath,
Configuration.EventExecutor(false),
Configuration.RateLimiter(true, 0x100000, 50),
Configuration.Connection(

View File

@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<rbcs:server xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rbcs="urn:net.woggioni.rbcs.server"
xs:schemaLocation="urn:net.woggioni.rbcs.server jpms://net.woggioni.rbcs.server/net/woggioni/rbcs/server/schema/rbcs-server.xsd">
xs:schemaLocation="urn:net.woggioni.rbcs.server jpms://net.woggioni.rbcs.server/net/woggioni/rbcs/server/schema/rbcs-server.xsd"
path="/my/custom/path">
<bind host="127.0.0.1" port="11443" incoming-connections-backlog-size="22" proxy-protocol="true">
<trusted-proxies>
<allow cidr="192.168.0.11/32"/>

View File

@@ -33,4 +33,5 @@ include 'rbcs-cli'
include 'rbcs-client'
include 'rbcs-server'
include 'rbcs-servlet'
include 'rbcs-server-otel'
include 'docker'