mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 23:12:06 -03:30
OpenTelemetry Tracing: Visualize JGroups communication (#39659)
Closes #39658 Signed-off-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
parent
98612bbb67
commit
7fd3380b19
@ -63,6 +63,13 @@ In order to maintain backwards compatibility, {project_name}'s upgrade will modi
|
||||
|
||||
For more information about client configuration, please see link:{adminguide_link}#_client-saml-configuration[Creating a SAML client] chapter in the {adminguide_name}.
|
||||
|
||||
=== Tracing extended for embedded Infinispan caches
|
||||
|
||||
When tracing is enabled, now also calls to other nodes of a {project_name} cluster will create spans in the traces.
|
||||
|
||||
To disable this kind of tracing, set the option `tracing-infinispan-enabled` to `false`.
|
||||
|
||||
|
||||
// ------------------------ Deprecated features ------------------------ //
|
||||
== Deprecated features
|
||||
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
package org.keycloak.infinispan.module.factory;
|
||||
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import jakarta.enterprise.inject.Instance;
|
||||
import jakarta.enterprise.inject.spi.CDI;
|
||||
import org.infinispan.factories.AbstractComponentFactory;
|
||||
import org.infinispan.factories.AutoInstantiableFactory;
|
||||
import org.infinispan.factories.annotations.DefaultFactoryFor;
|
||||
import org.infinispan.factories.scopes.Scope;
|
||||
import org.infinispan.factories.scopes.Scopes;
|
||||
import org.infinispan.telemetry.InfinispanTelemetry;
|
||||
import org.infinispan.telemetry.impl.DisabledInfinispanTelemetry;
|
||||
|
||||
@Scope(Scopes.GLOBAL)
|
||||
@DefaultFactoryFor(classes = InfinispanTelemetry.class)
|
||||
public class InfinispanTelemetryFactory extends AbstractComponentFactory implements AutoInstantiableFactory {
|
||||
|
||||
@Override
|
||||
public Object construct(String componentName) {
|
||||
CDI<Object> current;
|
||||
try {
|
||||
current = CDI.current();
|
||||
} catch (IllegalStateException e) {
|
||||
// No CDI context, assume tracing is not available
|
||||
return new DisabledInfinispanTelemetry();
|
||||
}
|
||||
Instance<OpenTelemetry> selector = current.select(OpenTelemetry.class);
|
||||
if (!selector.isResolvable()) {
|
||||
return new DisabledInfinispanTelemetry();
|
||||
} else {
|
||||
return new OpenTelemetryService(selector.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package org.keycloak.infinispan.module.factory;
|
||||
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.propagation.TextMapGetter;
|
||||
import org.infinispan.telemetry.InfinispanSpan;
|
||||
import org.infinispan.telemetry.InfinispanSpanAttributes;
|
||||
import org.infinispan.telemetry.InfinispanSpanContext;
|
||||
import org.infinispan.telemetry.InfinispanTelemetry;
|
||||
|
||||
public class OpenTelemetryService implements InfinispanTelemetry, TextMapGetter<InfinispanSpanContext> {
|
||||
|
||||
private static final String INFINISPAN_SERVER_TRACING_NAME = "org.infinispan.server.tracing";
|
||||
private static final String INFINISPAN_SERVER_TRACING_VERSION = "1.0.0";
|
||||
|
||||
private final Tracer tracer;
|
||||
private volatile String nodeName = "n/a";
|
||||
|
||||
public OpenTelemetryService(OpenTelemetry openTelemetry) {
|
||||
this.tracer = openTelemetry.getTracer(INFINISPAN_SERVER_TRACING_NAME, INFINISPAN_SERVER_TRACING_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> InfinispanSpan<T> startTraceRequest(String operationName, InfinispanSpanAttributes attributes) {
|
||||
// The original Infininspan implementation allows for filtering via the trace attributes. We don't support this here and instead trace everything.
|
||||
|
||||
var builder = tracer.spanBuilder(operationName)
|
||||
.setSpanKind(SpanKind.SERVER);
|
||||
// the parent context is inherited automatically,
|
||||
// because the parent span is created in the same process
|
||||
|
||||
return createOpenTelemetrySpan(builder, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> InfinispanSpan<T> startTraceRequest(String operationName, InfinispanSpanAttributes attributes, InfinispanSpanContext context) {
|
||||
// The original Infinispan implementation allows for filtering via the trace attributes. We don't support this here and instead trace everything
|
||||
|
||||
var builder = tracer.spanBuilder(operationName)
|
||||
.setSpanKind(SpanKind.SERVER)
|
||||
.setParent(Context.current().with(Span.current()));
|
||||
|
||||
return createOpenTelemetrySpan(builder, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNodeName(String nodeName) {
|
||||
if (nodeName != null) {
|
||||
this.nodeName = nodeName;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> InfinispanSpan<T> createOpenTelemetrySpan(SpanBuilder builder, InfinispanSpanAttributes attributes) {
|
||||
attributes.cacheName().ifPresent(cacheName -> builder.setAttribute("cache", cacheName));
|
||||
builder.setAttribute("category", attributes.category().toString());
|
||||
builder.setAttribute("server.address", nodeName);
|
||||
return new OpenTelemetrySpan<>(builder.startSpan());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> keys(InfinispanSpanContext ctx) {
|
||||
return ctx.keys();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(InfinispanSpanContext ctx, String key) {
|
||||
assert ctx != null;
|
||||
return ctx.getKey(key);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package org.keycloak.infinispan.module.factory;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import org.infinispan.telemetry.InfinispanSpan;
|
||||
import org.infinispan.telemetry.SafeAutoClosable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class OpenTelemetrySpan<T> implements InfinispanSpan<T> {
|
||||
|
||||
private final Span span;
|
||||
private final Scope scope;
|
||||
|
||||
public OpenTelemetrySpan(Span span) {
|
||||
this.span = Objects.requireNonNull(span);
|
||||
// TODO: This is actually wrong if you are doing asynchronous calls, but it allows the JGroups calls to be nested
|
||||
// This should be fixed in ISPN 16+ so that it is no longer needed
|
||||
// https://github.com/infinispan/infinispan/issues/15287
|
||||
this.scope = span.makeCurrent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SafeAutoClosable makeCurrent() {
|
||||
//noinspection resource
|
||||
Scope scope = span.makeCurrent();
|
||||
return scope::close;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete() {
|
||||
scope.close();
|
||||
span.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordException(Throwable throwable) {
|
||||
span.setStatus(StatusCode.ERROR, "Error during the cache request processing");
|
||||
span.recordException(throwable);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2025 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.jgroups.header;
|
||||
|
||||
import org.jgroups.Header;
|
||||
import org.jgroups.util.Util;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Header which carries an OpenTelemetry {@link io.opentelemetry.api.trace.Span} between requests and responses
|
||||
*
|
||||
* @author Bela Ban
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class TracerHeader extends Header {
|
||||
public static final short ID = 1050;
|
||||
protected final Map<String, String> ctx = new HashMap<>();
|
||||
|
||||
public TracerHeader() {
|
||||
}
|
||||
|
||||
public short getMagicId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
public Supplier<? extends Header> create() {
|
||||
return TracerHeader::new;
|
||||
}
|
||||
|
||||
public void put(String key, String value) {
|
||||
ctx.put(key, value);
|
||||
}
|
||||
|
||||
public String get(String key) {
|
||||
return ctx.get(key);
|
||||
}
|
||||
|
||||
public Set<String> keys() {
|
||||
return ctx.keySet();
|
||||
}
|
||||
|
||||
public int serializedSize() {
|
||||
int size = Integer.BYTES;
|
||||
int num_attrs = ctx.size();
|
||||
if (num_attrs > 0) {
|
||||
for (Map.Entry<String, String> entry : ctx.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String val = entry.getValue();
|
||||
size += Util.size(key) + Util.size(val);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public void writeTo(DataOutput out) throws IOException {
|
||||
out.writeInt(ctx.size());
|
||||
if (!ctx.isEmpty()) {
|
||||
for (Map.Entry<String, String> e : ctx.entrySet()) {
|
||||
Util.writeString(e.getKey(), out);
|
||||
Util.writeString(e.getValue(), out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void readFrom(DataInput in) throws IOException {
|
||||
int size = in.readInt();
|
||||
if (size > 0) {
|
||||
for (int i = 0; i < size; i++)
|
||||
ctx.put(Util.readString(in), Util.readString(in));
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ctx.toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 2025 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.jgroups.protocol;
|
||||
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.context.propagation.TextMapGetter;
|
||||
import org.jgroups.Message;
|
||||
import org.jgroups.Version;
|
||||
import org.jgroups.annotations.MBean;
|
||||
import org.jgroups.annotations.Property;
|
||||
import org.jgroups.stack.Protocol;
|
||||
import org.jgroups.util.MessageBatch;
|
||||
import org.keycloak.jgroups.header.TracerHeader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides Open Telemetry (https://opentelemetry.io/) tracing for JGroups. It should be placed just above the
|
||||
* transport.<br/>
|
||||
* When a message is sent, a {@link TracerHeader} is added with the (optional) parent span.
|
||||
* When received a new span is started (as a child span, if the parent span in the header is non-null), and ended when
|
||||
* the the thread returns.
|
||||
*
|
||||
* @author Bela Ban
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@MBean(description = "Records OpenTelemetry traces of sent and received messages")
|
||||
public class OPEN_TELEMETRY extends Protocol {
|
||||
public static final short OPEN_TELEMETRY_ID = 1026;
|
||||
protected OpenTelemetry otel;
|
||||
protected Tracer tracer;
|
||||
|
||||
@Property(description = "When active, traces are recorded, otherwise not")
|
||||
protected boolean active = true;
|
||||
|
||||
public boolean active() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public OPEN_TELEMETRY active(boolean f) {
|
||||
active = activate(f);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void start() throws Exception {
|
||||
super.start();
|
||||
activate(active);
|
||||
}
|
||||
|
||||
public Object down(Message msg) {
|
||||
if (!active || !Span.current().getSpanContext().isValid())
|
||||
return down_prot.down(msg);
|
||||
|
||||
SpanBuilder spanBuilder = tracer.spanBuilder("JGroups.sendSingleMessage");
|
||||
if (Span.current().isRecording()) {
|
||||
if (msg.getDest() != null) {
|
||||
spanBuilder.setAttribute("kc.jgroups.dest", msg.getDest().toString());
|
||||
}
|
||||
if (msg.getSrc() != null) {
|
||||
spanBuilder.setAttribute("kc.jgroups.src", msg.getSrc().toString());
|
||||
}
|
||||
}
|
||||
Span span = spanBuilder.startSpan();
|
||||
try (var ignored = span.makeCurrent()) {
|
||||
TracerHeader hdr = new TracerHeader();
|
||||
populateHeader(hdr); // will populate if a span exists (created by the caller)
|
||||
msg.putHeader(OPEN_TELEMETRY_ID, hdr);
|
||||
return down_prot.down(msg);
|
||||
} catch (Throwable t) {
|
||||
span.setStatus(StatusCode.ERROR, String.format("failed delivering single message to %s", msg.dest()));
|
||||
span.recordException(t);
|
||||
throw t;
|
||||
} finally {
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Object up(Message msg) {
|
||||
if (!active)
|
||||
return up_prot.up(msg);
|
||||
|
||||
TracerHeader hdr = msg.getHeader(OPEN_TELEMETRY_ID);
|
||||
if (hdr != null) {
|
||||
Context extractedContext = otel.getPropagators().getTextMapPropagator()
|
||||
.extract(Context.current(), hdr, TEXT_MAP_GETTER);
|
||||
|
||||
Span span = tracer.spanBuilder("JGroups.deliverSingleMessage")
|
||||
.setSpanKind(SpanKind.SERVER)
|
||||
.setParent(extractedContext).startSpan();
|
||||
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
span.setAttribute("from", msg.src().toString());
|
||||
return up_prot.up(msg);
|
||||
} catch (Throwable t) {
|
||||
span.setStatus(StatusCode.ERROR, String.format("failed delivering single message from %s", msg.src()));
|
||||
span.recordException(t);
|
||||
throw t;
|
||||
} finally {
|
||||
span.end();
|
||||
}
|
||||
} else {
|
||||
return up_prot.up(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void up(MessageBatch batch) {
|
||||
if (!active) {
|
||||
if (!batch.isEmpty())
|
||||
up_prot.up(batch);
|
||||
return;
|
||||
}
|
||||
List<Span> spans = new ArrayList<>(batch.size());
|
||||
int index = 0, batch_size = batch.size();
|
||||
for (Message msg : batch) {
|
||||
index++;
|
||||
TracerHeader hdr = msg.getHeader(OPEN_TELEMETRY_ID);
|
||||
if (hdr != null) {
|
||||
Context extractedContext = otel.getPropagators().getTextMapPropagator()
|
||||
.extract(Context.current(), hdr, TEXT_MAP_GETTER);
|
||||
|
||||
Span span = tracer.spanBuilder("deliver-batched-msg")
|
||||
.setSpanKind(SpanKind.SERVER)
|
||||
.setParent(extractedContext).startSpan();
|
||||
span.setAttribute("batch-msg", String.format("%d/%d", index, batch_size));
|
||||
spans.add(span);
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (!batch.isEmpty())
|
||||
up_prot.up(batch);
|
||||
} catch (Throwable t) {
|
||||
spans.forEach(s -> {
|
||||
s.setStatus(StatusCode.ERROR, String.format("failed delivering batched message from %s", batch.sender()))
|
||||
.recordException(t);
|
||||
});
|
||||
throw t;
|
||||
} finally {
|
||||
spans.forEach(Span::end);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void populateHeader(TracerHeader hdr) {
|
||||
// Inject the request with the *current* Context, which contains our current Span.
|
||||
W3CTraceContextPropagator.getInstance().inject(Context.current(), hdr, (carrier, key, val) -> hdr.put(key, val));
|
||||
}
|
||||
|
||||
protected static final TextMapGetter<TracerHeader> TEXT_MAP_GETTER =
|
||||
new TextMapGetter<>() {
|
||||
@Override
|
||||
public String get(TracerHeader carrier, String key) {
|
||||
return carrier.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> keys(TracerHeader carrier) {
|
||||
return carrier.keys();
|
||||
}
|
||||
};
|
||||
|
||||
protected boolean activate(boolean flag) {
|
||||
if (flag && otel == null)
|
||||
otel = GlobalOpenTelemetry.get();
|
||||
if (flag && tracer == null)
|
||||
tracer = otel.getTracer("org.jgroups.trace", Version.printVersion());
|
||||
return flag;
|
||||
}
|
||||
|
||||
}
|
||||
@ -74,6 +74,7 @@ public class DefaultCacheEmbeddedConfigProviderFactory implements CacheEmbeddedC
|
||||
// Configuration
|
||||
public static final String CONFIG = "configFile";
|
||||
private static final String METRICS = "metricsEnabled";
|
||||
public static final String TRACING = "tracingEnabled";
|
||||
private static final String HISTOGRAMS = "metricsHistogramsEnabled";
|
||||
public static final String STACK = "stack";
|
||||
public static final String NODE_NAME = "nodeName";
|
||||
|
||||
@ -60,6 +60,8 @@ import org.keycloak.connections.jpa.JpaConnectionProviderFactory;
|
||||
import org.keycloak.connections.jpa.util.JpaUtils;
|
||||
import org.keycloak.infinispan.util.InfinispanUtils;
|
||||
import org.keycloak.jgroups.protocol.KEYCLOAK_JDBC_PING2;
|
||||
import org.keycloak.jgroups.protocol.OPEN_TELEMETRY;
|
||||
import org.keycloak.jgroups.header.TracerHeader;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||
@ -82,6 +84,8 @@ public final class JGroupsConfigurator {
|
||||
// Use custom Keycloak JDBC_PING implementation that workarounds issue https://issues.redhat.com/browse/JGRP-2870
|
||||
// The id 1025 follows this instruction: https://github.com/belaban/JGroups/blob/38219e9ec1c629fa2f7929e3b53d1417d8e60b61/conf/jg-protocol-ids.xml#L85
|
||||
ClassConfigurator.addProtocol((short) 1025, KEYCLOAK_JDBC_PING2.class);
|
||||
ClassConfigurator.addProtocol((short) 1026, OPEN_TELEMETRY.class);
|
||||
ClassConfigurator.add(TracerHeader.ID, TracerHeader.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,7 +101,8 @@ public final class JGroupsConfigurator {
|
||||
transportOf(holder).stack(stack);
|
||||
}
|
||||
configureTransport(config);
|
||||
configureDiscovery(holder, session);
|
||||
boolean tracingEnabled = config.getBoolean(DefaultCacheEmbeddedConfigProviderFactory.TRACING, false);
|
||||
configureDiscovery(holder, session, tracingEnabled);
|
||||
configureTls(holder, session);
|
||||
warnDeprecatedStack(holder);
|
||||
}
|
||||
@ -177,7 +182,7 @@ public final class JGroupsConfigurator {
|
||||
return socketFactory;
|
||||
}
|
||||
|
||||
private static void configureDiscovery(ConfigurationBuilderHolder holder, KeycloakSession session) {
|
||||
private static void configureDiscovery(ConfigurationBuilderHolder holder, KeycloakSession session, boolean tracingEnabled) {
|
||||
var stackXmlAttribute = transportStackOf(holder);
|
||||
if (stackXmlAttribute.isModified() && !isJdbcPingStack(stackXmlAttribute.get())) {
|
||||
logger.debugf("Custom stack configured (%s). JDBC_PING discovery disabled.", stackXmlAttribute.get());
|
||||
@ -194,7 +199,7 @@ public final class JGroupsConfigurator {
|
||||
var stackName = transportStackOf(holder).get();
|
||||
var isUdp = stackName.endsWith("udp");
|
||||
var tableName = JpaUtils.getTableNameForNativeQuery("JGROUPS_PING", em);
|
||||
var stack = getProtocolConfigurations(tableName, isUdp);
|
||||
var stack = getProtocolConfigurations(tableName, isUdp, tracingEnabled);
|
||||
var connectionFactory = (JpaConnectionProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class);
|
||||
holder.addJGroupsStack(new JpaFactoryAwareJGroupsChannelConfigurator(stackName, stack, connectionFactory, isUdp), null);
|
||||
|
||||
@ -202,7 +207,7 @@ public final class JGroupsConfigurator {
|
||||
JGroupsConfigurator.logger.info("JGroups JDBC_PING discovery enabled.");
|
||||
}
|
||||
|
||||
private static List<ProtocolConfiguration> getProtocolConfigurations(String tableName, boolean udp) {
|
||||
private static List<ProtocolConfiguration> getProtocolConfigurations(String tableName, boolean udp, boolean tracingEnabled) {
|
||||
var list = new ArrayList<ProtocolConfiguration>(udp ? 1 : 2);
|
||||
list.add(new ProtocolConfiguration(KEYCLOAK_JDBC_PING2.class.getName(),
|
||||
Map.of(
|
||||
@ -224,6 +229,12 @@ public final class JGroupsConfigurator {
|
||||
if (!udp && InfinispanUtils.isVirtualThreadsEnabled())
|
||||
list.add(new ProtocolConfiguration(TCP.class.getSimpleName(), Map.of("bundler_type", "per-destination")));
|
||||
|
||||
if (tracingEnabled) {
|
||||
list.add(new ProtocolConfiguration(OPEN_TELEMETRY.class.getName(), Map.of(
|
||||
"stack.combine", "INSERT_ABOVE",
|
||||
"stack.position", udp ? "UDP" : "TCP"
|
||||
)));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@ -85,4 +85,11 @@ public class TracingOptions {
|
||||
.description("OpenTelemetry compression method used to compress payloads. If unset, compression is disabled.")
|
||||
.defaultValue(TracingCompression.none)
|
||||
.build();
|
||||
|
||||
public static final Option<Boolean> TRACING_INFINISPAN_ENABLED = new OptionBuilder<>("tracing-infinispan-enabled", Boolean.class)
|
||||
.category(OptionCategory.TRACING)
|
||||
.description("Enables the OpenTelemetry tracing for embedded Infinispan.")
|
||||
.defaultValue(true)
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
@ -185,7 +185,7 @@ final class CachingPropertyMappers {
|
||||
return getOptionalKcValue(CachingOptions.CACHE_REMOTE_HOST_PROPERTY).isPresent();
|
||||
}
|
||||
|
||||
private static boolean cacheSetToInfinispan() {
|
||||
public static boolean cacheSetToInfinispan() {
|
||||
if (InfinispanUtils.isRemoteInfinispan()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
package org.keycloak.quarkus.runtime.configuration.mappers;
|
||||
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.config.TracingOptions;
|
||||
import org.keycloak.quarkus.runtime.cli.PropertyException;
|
||||
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||
import org.keycloak.utils.StringUtil;
|
||||
@ -29,6 +30,7 @@ import java.net.URL;
|
||||
import static org.keycloak.config.TracingOptions.TRACING_COMPRESSION;
|
||||
import static org.keycloak.config.TracingOptions.TRACING_ENABLED;
|
||||
import static org.keycloak.config.TracingOptions.TRACING_ENDPOINT;
|
||||
import static org.keycloak.config.TracingOptions.TRACING_INFINISPAN_ENABLED;
|
||||
import static org.keycloak.config.TracingOptions.TRACING_JDBC_ENABLED;
|
||||
import static org.keycloak.config.TracingOptions.TRACING_PROTOCOL;
|
||||
import static org.keycloak.config.TracingOptions.TRACING_RESOURCE_ATTRIBUTES;
|
||||
@ -91,6 +93,11 @@ public class TracingPropertyMappers {
|
||||
.mapFrom(TRACING_ENABLED)
|
||||
.isEnabled(TracingPropertyMappers::isTracingEnabled, TRACING_ENABLED_MSG)
|
||||
.to("quarkus.datasource.jdbc.telemetry")
|
||||
.build(),
|
||||
fromOption(TRACING_INFINISPAN_ENABLED)
|
||||
.mapFrom(TracingOptions.TRACING_ENABLED)
|
||||
.to("kc.spi-cache-embedded--default--tracing-enabled")
|
||||
.isEnabled(TracingPropertyMappers::isTracingAndEmbeddedInfinispanEnabled, "tracing and embedded Infinispan is enabled")
|
||||
.build()
|
||||
};
|
||||
}
|
||||
@ -129,8 +136,8 @@ public class TracingPropertyMappers {
|
||||
return Configuration.isTrue(TRACING_ENABLED);
|
||||
}
|
||||
|
||||
public static boolean isTracingJdbcEnabled() {
|
||||
return Configuration.isTrue(TRACING_JDBC_ENABLED);
|
||||
public static boolean isTracingAndEmbeddedInfinispanEnabled() {
|
||||
return Configuration.isTrue(TRACING_ENABLED) && CachingPropertyMappers.cacheSetToInfinispan();
|
||||
}
|
||||
|
||||
private static boolean isValidUrl(String url) {
|
||||
|
||||
@ -368,6 +368,9 @@ Tracing:
|
||||
--tracing-endpoint <url>
|
||||
OpenTelemetry endpoint to connect to. Default: http://localhost:4317.
|
||||
Available only when Tracing is enabled.
|
||||
--tracing-infinispan-enabled <true|false>
|
||||
Enables the OpenTelemetry tracing for embedded Infinispan. Default: true.
|
||||
Available only when tracing and embedded Infinispan is enabled.
|
||||
--tracing-jdbc-enabled <true|false>
|
||||
Enables the OpenTelemetry JDBC tracing. Default: true. Available only when
|
||||
Tracing is enabled.
|
||||
|
||||
@ -368,6 +368,9 @@ Tracing:
|
||||
--tracing-endpoint <url>
|
||||
OpenTelemetry endpoint to connect to. Default: http://localhost:4317.
|
||||
Available only when Tracing is enabled.
|
||||
--tracing-infinispan-enabled <true|false>
|
||||
Enables the OpenTelemetry tracing for embedded Infinispan. Default: true.
|
||||
Available only when tracing and embedded Infinispan is enabled.
|
||||
--tracing-jdbc-enabled <true|false>
|
||||
Enables the OpenTelemetry JDBC tracing. Default: true. Available only when
|
||||
Tracing is enabled.
|
||||
|
||||
@ -599,6 +599,9 @@ Tracing:
|
||||
--tracing-endpoint <url>
|
||||
OpenTelemetry endpoint to connect to. Default: http://localhost:4317.
|
||||
Available only when Tracing is enabled.
|
||||
--tracing-infinispan-enabled <true|false>
|
||||
Enables the OpenTelemetry tracing for embedded Infinispan. Default: true.
|
||||
Available only when tracing and embedded Infinispan is enabled.
|
||||
--tracing-jdbc-enabled <true|false>
|
||||
Enables the OpenTelemetry JDBC tracing. Default: true. Available only when
|
||||
Tracing is enabled.
|
||||
|
||||
@ -600,6 +600,9 @@ Tracing:
|
||||
--tracing-endpoint <url>
|
||||
OpenTelemetry endpoint to connect to. Default: http://localhost:4317.
|
||||
Available only when Tracing is enabled.
|
||||
--tracing-infinispan-enabled <true|false>
|
||||
Enables the OpenTelemetry tracing for embedded Infinispan. Default: true.
|
||||
Available only when tracing and embedded Infinispan is enabled.
|
||||
--tracing-jdbc-enabled <true|false>
|
||||
Enables the OpenTelemetry JDBC tracing. Default: true. Available only when
|
||||
Tracing is enabled.
|
||||
|
||||
@ -531,6 +531,9 @@ Tracing:
|
||||
--tracing-endpoint <url>
|
||||
OpenTelemetry endpoint to connect to. Default: http://localhost:4317.
|
||||
Available only when Tracing is enabled.
|
||||
--tracing-infinispan-enabled <true|false>
|
||||
Enables the OpenTelemetry tracing for embedded Infinispan. Default: true.
|
||||
Available only when tracing and embedded Infinispan is enabled.
|
||||
--tracing-protocol <protocol>
|
||||
OpenTelemetry protocol used for the telemetry data. Possible values are: grpc,
|
||||
http/protobuf. Default: grpc. Available only when Tracing is enabled.
|
||||
|
||||
@ -599,6 +599,9 @@ Tracing:
|
||||
--tracing-endpoint <url>
|
||||
OpenTelemetry endpoint to connect to. Default: http://localhost:4317.
|
||||
Available only when Tracing is enabled.
|
||||
--tracing-infinispan-enabled <true|false>
|
||||
Enables the OpenTelemetry tracing for embedded Infinispan. Default: true.
|
||||
Available only when tracing and embedded Infinispan is enabled.
|
||||
--tracing-jdbc-enabled <true|false>
|
||||
Enables the OpenTelemetry JDBC tracing. Default: true. Available only when
|
||||
Tracing is enabled.
|
||||
|
||||
@ -597,6 +597,9 @@ Tracing:
|
||||
--tracing-endpoint <url>
|
||||
OpenTelemetry endpoint to connect to. Default: http://localhost:4317.
|
||||
Available only when Tracing is enabled.
|
||||
--tracing-infinispan-enabled <true|false>
|
||||
Enables the OpenTelemetry tracing for embedded Infinispan. Default: true.
|
||||
Available only when tracing and embedded Infinispan is enabled.
|
||||
--tracing-jdbc-enabled <true|false>
|
||||
Enables the OpenTelemetry JDBC tracing. Default: true. Available only when
|
||||
Tracing is enabled.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user