From 78fe74783db41da781570f8ea725ad7f22b06cb8 Mon Sep 17 00:00:00 2001 From: Martin Reinhardt Date: Fri, 8 Feb 2019 16:16:32 +0100 Subject: [PATCH 1/2] feat(Events): Adding client id and ip address to exporter see #9 --- .../events/MonitoringEventListenerProvider.java | 10 ++++++++++ .../MonitoringEventListenerProviderTest.java | 15 +++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/larscheidschmitzhermes/keycloak/events/MonitoringEventListenerProvider.java b/src/main/java/com/larscheidschmitzhermes/keycloak/events/MonitoringEventListenerProvider.java index a55b355..f545e89 100644 --- a/src/main/java/com/larscheidschmitzhermes/keycloak/events/MonitoringEventListenerProvider.java +++ b/src/main/java/com/larscheidschmitzhermes/keycloak/events/MonitoringEventListenerProvider.java @@ -17,6 +17,8 @@ public class MonitoringEventListenerProvider implements EventListenerProvider { private final char DELIMITER = ';'; private final char LABEL_VALUE_DELIMITER = '='; private final String REALM = "realm"; + private final String CLIENT_ID = "client_id"; + private final String IP_ADDRESS = "ip_address"; private final String TYPE = "type"; private final String OPERATION = "operation"; private final String RESOURCE = "resource"; @@ -43,6 +45,10 @@ private String generateMetricName(Event event) { sb.append(DELIMITER); sb.append(generateLabel(REALM, event.getRealmId())); sb.append(DELIMITER); + sb.append(generateLabel(CLIENT_ID, event.getClientId())); + sb.append(DELIMITER); + sb.append(generateLabel(IP_ADDRESS, event.getIpAddress())); + sb.append(DELIMITER); sb.append(generateLabel(TYPE, event.getType().toString())); return sb.toString(); } @@ -53,6 +59,10 @@ private String generateMetricName(AdminEvent event) { sb.append(DELIMITER); sb.append(generateLabel(REALM, event.getRealmId())); sb.append(DELIMITER); + sb.append(generateLabel(CLIENT_ID, event.getAuthDetails().getClientId())); + sb.append(DELIMITER); + sb.append(generateLabel(IP_ADDRESS, event.getAuthDetails().getIpAddress())); + sb.append(DELIMITER); sb.append(generateLabel(OPERATION, event.getOperationType().toString())); sb.append(DELIMITER); sb.append(generateLabel(RESOURCE, event.getResourceType().toString())); diff --git a/src/test/java/com/larscheidschmitzhermes/keycloak/events/MonitoringEventListenerProviderTest.java b/src/test/java/com/larscheidschmitzhermes/keycloak/events/MonitoringEventListenerProviderTest.java index 696f221..5821593 100644 --- a/src/test/java/com/larscheidschmitzhermes/keycloak/events/MonitoringEventListenerProviderTest.java +++ b/src/test/java/com/larscheidschmitzhermes/keycloak/events/MonitoringEventListenerProviderTest.java @@ -12,6 +12,7 @@ import org.keycloak.events.Event; import org.keycloak.events.EventType; import org.keycloak.events.admin.AdminEvent; +import org.keycloak.events.admin.AuthDetails; import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.ResourceType; @@ -21,14 +22,20 @@ public class MonitoringEventListenerProviderTest { private Event event() { Event event = new Event(); + event.setClientId("23"); + event.setIpAddress("4.4.4.4"); event.setRealmId("test-realm"); event.setType(EventType.LOGIN); return event; } private AdminEvent adminEvent() { + AuthDetails details = new AuthDetails(); + details.setClientId("42"); + details.setIpAddress("1.2.3.4"); AdminEvent event = new AdminEvent(); event.setRealmId("test-realm"); + event.setAuthDetails(details); event.setOperationType(OperationType.UPDATE); event.setResourceType(ResourceType.CLIENT); return event; @@ -40,7 +47,7 @@ public void shouldGenerateFilesWithCorrectNamesForNormalEvents() throws IOExcept listener.onEvent(event()); - File expectedFile = new File(tmp.getRoot().getAbsolutePath() + File.separator + "keycloak_events_total;realm=test-realm;type=LOGIN"); + File expectedFile = new File(tmp.getRoot().getAbsolutePath() + File.separator + "keycloak_events_total;realm=test-realm;client_id=23;ip_address=4.4.4.4;type=LOGIN"); MatcherAssert.assertThat(expectedFile.exists(), Is.is(true)); MatcherAssert.assertThat(FileUtils.readFileToString(expectedFile), Is.is("1")); @@ -52,7 +59,7 @@ public void shouldGenerateFilesWithCorrectNamesForAdminEvents() throws IOExcepti listener.onEvent(adminEvent(), false); - File expectedFile = new File(tmp.getRoot().getAbsolutePath() + File.separator + "keycloak_admin_events_total;realm=test-realm;operation=UPDATE;resource=CLIENT"); + File expectedFile = new File(tmp.getRoot().getAbsolutePath() + File.separator + "keycloak_admin_events_total;realm=test-realm;client_id=42;ip_address=1.2.3.4;operation=UPDATE;resource=CLIENT"); MatcherAssert.assertThat(expectedFile.exists(), Is.is(true)); MatcherAssert.assertThat(FileUtils.readFileToString(expectedFile), Is.is("1")); @@ -61,7 +68,7 @@ public void shouldGenerateFilesWithCorrectNamesForAdminEvents() throws IOExcepti @Test public void shouldProperlyIncreaseCounterForNormalEvents() throws IOException { MonitoringEventListenerProvider listener = new MonitoringEventListenerProvider(tmp.getRoot().getAbsolutePath()); - File existingCounter = new File(tmp.getRoot().getAbsolutePath() + File.separator + "keycloak_events_total;realm=test-realm;type=LOGIN"); + File existingCounter = new File(tmp.getRoot().getAbsolutePath() + File.separator + "keycloak_events_total;realm=test-realm;client_id=23;ip_address=4.4.4.4;type=LOGIN"); FileUtils.writeStringToFile(existingCounter, "100"); listener.onEvent(event()); @@ -72,7 +79,7 @@ public void shouldProperlyIncreaseCounterForNormalEvents() throws IOException { @Test public void shouldProperlyIncreaseCounterForAdminEvents() throws IOException { MonitoringEventListenerProvider listener = new MonitoringEventListenerProvider(tmp.getRoot().getAbsolutePath()); - File existingCounter = new File(tmp.getRoot().getAbsolutePath() + File.separator + "keycloak_admin_events_total;realm=test-realm;operation=UPDATE;resource=CLIENT"); + File existingCounter = new File(tmp.getRoot().getAbsolutePath() + File.separator + "keycloak_admin_events_total;realm=test-realm;client_id=42;ip_address=1.2.3.4;operation=UPDATE;resource=CLIENT"); FileUtils.writeStringToFile(existingCounter, "100"); listener.onEvent(adminEvent(), false); From 9d5ef8ce2841336080a4f14d33f80ea72fee97d7 Mon Sep 17 00:00:00 2001 From: Martin Reinhardt Date: Tue, 2 Apr 2019 08:45:50 +0200 Subject: [PATCH 2/2] docs(README): Adding metrics data to docs --- README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 38d99d2..1f72376 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,17 @@ This project counts those events and allows you to expose them to `prometheus` w ## What metrics do you get? This project will help you expose two metrics: -- `keycloak_events_total` with labels +- `keycloak_events_total` with labels - realm="String", - - type="[`org.keycloak.events.EventType`](https://github.com/keycloak/keycloak/blob/master/server-spi-private/src/main/java/org/keycloak/events/EventType.java)" -- `keycloak_admin_events_total` with labels + - type="[`org.keycloak.events.EventType`](https://github.com/keycloak/keycloak/blob/master/server-spi-private/src/main/java/org/keycloak/events/EventType.java)", + - client_id="String", + - ip_address="String" +- `keycloak_admin_events_total` with labels - realm="String" - operation="[`org.keycloak.events.admin.OperationType`](https://github.com/keycloak/keycloak/blob/master/server-spi-private/src/main/java/org/keycloak/events/admin/OperationType.java)" - - resource="[`org.keycloak.events.admin.ResourceType`](https://github.com/keycloak/keycloak/blob/master/server-spi-private/src/main/java/org/keycloak/events/admin/ResourceType.java)" + - resource="[`org.keycloak.events.admin.ResourceType`](https://github.com/keycloak/keycloak/blob/master/server-spi-private/src/main/java/org/keycloak/events/admin/ResourceType.java)", + - client_id="String", + - ip_address="String" The magic lies in the labels. The labels basically expose the underlying keycloak event details and allow for detailed filtering. The unique metric + label combination's value will be increased by one whenever an event of this type is emmited in keycloak. ## Setup @@ -48,5 +52,5 @@ Make sure you do this for every realm you want to monitor! ### Getting your metrics into prometheus Once everything is setup in keycloak, you will start seeing files like `keycloak_admin_events_total;realm=master;operation=CREATE;resource=USER` in your configured events directory. These files contain a number stating how often an event with the given parameters was emitted. -The naming scheme is compatible with [`prometheus-filesystem-exporter`](https://github.com/larscheid-schmitzhermes/prometheus-filesystem-exporter), +The naming scheme is compatible with [`prometheus-filesystem-exporter`](https://github.com/larscheid-schmitzhermes/prometheus-filesystem-exporter), which you should run next to keycloak to get your events exposed in a prometheus compatible format.