First draft of implementation (#1)
* First draft of implementation Readme will follow * Rename id. * Exclude `commons-io` to disable build warnings * Simplify metrics and add documentation
This commit is contained in:
parent
dc38b3715e
commit
c8977d7175
23 changed files with 1345 additions and 1 deletions
|
@ -0,0 +1,32 @@
|
|||
package io.kokuwa.keycloak.metrics;
|
||||
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventListenerProvider;
|
||||
import org.keycloak.events.admin.AdminEvent;
|
||||
|
||||
/**
|
||||
* Listener for {@link Event} and {@link AdminEvent}.
|
||||
*
|
||||
* @author Stephan Schnabel
|
||||
*/
|
||||
public class MicrometerEventListener implements EventListenerProvider, AutoCloseable {
|
||||
|
||||
private final MicrometerEventRecorder recorder;
|
||||
|
||||
MicrometerEventListener(MicrometerEventRecorder recorder) {
|
||||
this.recorder = recorder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
recorder.userEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(AdminEvent event, boolean includeRepresentation) {
|
||||
recorder.adminEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package io.kokuwa.keycloak.metrics;
|
||||
|
||||
import javax.enterprise.inject.spi.CDI;
|
||||
|
||||
import org.keycloak.Config.Scope;
|
||||
import org.keycloak.events.EventListenerProvider;
|
||||
import org.keycloak.events.EventListenerProviderFactory;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
|
||||
/**
|
||||
* Factory for {@link MicrometerEventListener}, uses {@link MeterRegistry} from CDI.
|
||||
*
|
||||
* @author Stephan Schnabel
|
||||
*/
|
||||
public class MicrometerEventListenerFactory implements EventListenerProviderFactory {
|
||||
|
||||
private MicrometerEventRecorder recorder;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "metrics-listener";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Scope config) {}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
recorder = new MicrometerEventRecorder(CDI.current().select(MeterRegistry.class).get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventListenerProvider create(KeycloakSession session) {
|
||||
return new MicrometerEventListener(recorder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package io.kokuwa.keycloak.metrics;
|
||||
|
||||
import org.keycloak.events.EventListenerSpi;
|
||||
import org.keycloak.provider.Provider;
|
||||
|
||||
/**
|
||||
* Factory for {@link MicrometerEventListener}.
|
||||
*
|
||||
* @author Stephan Schnabel
|
||||
*/
|
||||
public class MicrometerEventListenerSpi extends EventListenerSpi {
|
||||
|
||||
@Override
|
||||
public boolean isInternal() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Micrometer Metrics Provider";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return MicrometerEventListener.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<MicrometerEventListenerFactory> getProviderFactoryClass() {
|
||||
return MicrometerEventListenerFactory.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package io.kokuwa.keycloak.metrics;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.admin.AdminEvent;
|
||||
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
|
||||
/**
|
||||
* Micrometer based recorder for events.
|
||||
*
|
||||
* @author Stephan Schnabel
|
||||
*/
|
||||
public class MicrometerEventRecorder {
|
||||
|
||||
private final Map<String, Counter> counters = new HashMap<>();
|
||||
private final MeterRegistry registry;
|
||||
|
||||
MicrometerEventRecorder(MeterRegistry registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
void adminEvent(AdminEvent event) {
|
||||
counter("keycloak_event_admin",
|
||||
"realm", toBlankIfNull(event.getRealmId()),
|
||||
"resource", toBlankIfNull(event.getResourceType()),
|
||||
"operation", toBlankIfNull(event.getOperationType()),
|
||||
"error", toBlankIfNull(event.getError()));
|
||||
}
|
||||
|
||||
void userEvent(Event event) {
|
||||
counter("keycloak_event_user",
|
||||
"realm", toBlankIfNull(event.getRealmId()),
|
||||
"type", toBlankIfNull(event.getType()),
|
||||
"client", toBlankIfNull(event.getClientId()),
|
||||
"error", toBlankIfNull(event.getError()));
|
||||
}
|
||||
|
||||
private void counter(String counter, String... tags) {
|
||||
counters.computeIfAbsent(counter + Arrays.toString(tags), string -> registry.counter(counter, tags))
|
||||
.increment();
|
||||
}
|
||||
|
||||
private String toBlankIfNull(Object value) {
|
||||
return value == null ? "" : value.toString();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue