如何借助Quarkus和MicroMeter为Keycloak 22添加自定义指标
如何将自定义指标合并到Keycloak 22.0.1+原生Prometheus指标端点?
问题背景
- Keycloak 22.0.1及以上版本基于Quarkus构建,原生支持Prometheus格式的MicroMeter指标
- 需编写扩展JAR,通过
EventListenerProvider和RealmResourceProvider添加自定义指标(比如按Realm统计的登录次数) - 当前实现:参考同类项目自定义了
PrometheusMeterRegistry,通过/auth/realms/master/custom-metrics端点暴露,但Prometheus仅能抓取一个URL,无法合并原生指标与自定义指标
核心疑问
如何将自定义指标添加到Keycloak原生的MeterRegistry中?是否需要编写Quarkus扩展以通过@Inject注入MeterRegistry?有没有Keycloak SPI可直接获取原生MeterRegistry?
解决方案
1. 直接通过CDI注入原生MeterRegistry(无需Quarkus扩展)
Keycloak的Quarkus运行时已将MeterRegistry作为CDI Bean暴露,在Keycloak SPI实现类中可直接用@Inject注入,无需额外编写Quarkus扩展。
示例代码(自定义EventListenerProviderFactory):
import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; import jakarta.inject.Inject; import org.keycloak.events.EventListenerProvider; import org.keycloak.events.EventListenerProviderFactory; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; public class RealmLoginMetricsFactory implements EventListenerProviderFactory { @Inject private MeterRegistry meterRegistry; private Counter realmLoginCounter; @Override public void init(org.keycloak.Config.Scope config) { // 注册按Realm维度统计的登录次数指标 realmLoginCounter = Counter.builder("keycloak_realm_login_total") .description("Total number of successful logins per realm") .register(meterRegistry); } @Override public EventListenerProvider create(KeycloakSession session) { return new RealmLoginMetricsListener(realmLoginCounter, session); } @Override public void postInit(KeycloakSessionFactory factory) {} @Override public void close() {} @Override public String getId() { return "realm-login-metrics"; } }
在自定义EventListener中触发指标累加:
public class RealmLoginMetricsListener implements EventListenerProvider { private final Counter loginCounter; private final KeycloakSession session; public RealmLoginMetricsListener(Counter loginCounter, KeycloakSession session) { this.loginCounter = loginCounter; this.session = session; } @Override public void onEvent(Event event) { if (EventType.LOGIN.equals(event.getType())) { // 按Realm打标签 loginCounter.tag("realm", event.getRealmId()).increment(); } } @Override public void close() {} }
最后在META-INF/services/org.keycloak.events.EventListenerProviderFactory文件中添加SPI实现类全路径,确保Keycloak能扫描到。
2. 利用Keycloak 22+新增的MetricsProvider SPI
Keycloak 22及以上版本提供了MetricsProvider SPI,专门用于扩展原生指标体系,无需手动管理MeterRegistry:
- 实现
org.keycloak.metrics.MetricsProvider接口 - 在
init方法中注册自定义指标,Keycloak会自动将其合并到原生的/metrics端点 - 该SPI会自动关联Keycloak上下文,无需手动处理Realm等维度的标签
3. 关键注意事项
- 禁止自行实例化PrometheusMeterRegistry:这会导致指标分散在不同端点,无法合并
- 确保SPI类被正确扫描:必须在
META-INF/services下添加对应SPI的配置文件 - 指标命名规范:建议使用
keycloak_前缀,避免与Quarkus原生指标冲突
内容的提问来源于stack exchange,提问作者lathspell
相关产品推荐
相关产品推荐

