From 285e0501681b4d7164b0c79e947a828f948ca1ac Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Fri, 29 Nov 2024 13:46:45 +0700 Subject: [PATCH] feat: implemented pushing player event metrics --- api/build.gradle | 4 ++ .../msb3/api/metrics/PlayerEventMetrics.java | 50 +++++++++++++++++++ .../api/module/ClickhouseMetricsModule.java | 21 ++++++++ clickhouse/config.xml | 7 +++ clickhouse/docker-compose.yml | 11 ++++ clickhouse/init.sql | 11 ++++ clickhouse/users.xml | 18 +++++++ 7 files changed, 122 insertions(+) create mode 100644 api/src/main/java/ru/dragonestia/msb3/api/metrics/PlayerEventMetrics.java create mode 100644 api/src/main/java/ru/dragonestia/msb3/api/module/ClickhouseMetricsModule.java create mode 100644 clickhouse/config.xml create mode 100644 clickhouse/docker-compose.yml create mode 100644 clickhouse/init.sql create mode 100644 clickhouse/users.xml diff --git a/api/build.gradle b/api/build.gradle index a42f8be..b268a15 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -11,4 +11,8 @@ dependencies { api 'team.unnamed:creative-api:1.7.3' api 'team.unnamed:creative-serializer-minecraft:1.7.3' api 'team.unnamed:creative-server:1.7.3' + + api 'org.sql2o:sql2o:1.8.0' + api 'com.clickhouse:clickhouse-jdbc:0.7.1' + api 'org.lz4:lz4-java:1.8.0' } diff --git a/api/src/main/java/ru/dragonestia/msb3/api/metrics/PlayerEventMetrics.java b/api/src/main/java/ru/dragonestia/msb3/api/metrics/PlayerEventMetrics.java new file mode 100644 index 0000000..e54f37f --- /dev/null +++ b/api/src/main/java/ru/dragonestia/msb3/api/metrics/PlayerEventMetrics.java @@ -0,0 +1,50 @@ +package ru.dragonestia.msb3.api.metrics; + +import com.google.gson.Gson; +import lombok.extern.log4j.Log4j2; +import net.minestom.server.entity.Player; +import org.jetbrains.annotations.Nullable; +import ru.dragonestia.msb3.api.module.ClickhouseMetricsModule; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; + +@Log4j2 +public class PlayerEventMetrics { + + private static final int MAX_ALERTS = 5; + private static final AtomicInteger alertAboutModuleDisabled = new AtomicInteger(0); + private static final Gson GSON = new Gson(); + + private PlayerEventMetrics() {} + + public static void push(Player player, String eventName, @Nullable Object details) { + var sql2o = ClickhouseMetricsModule.getSql2o(); + + if (sql2o == null) { + var alerts = alertAboutModuleDisabled.incrementAndGet(); + if (alerts > MAX_ALERTS) return; + + log.warn("ClickhouseMetricsModule is not initialized. Skipping sending metrics [{}/{}]", alerts, MAX_ALERTS); + + if (alerts == MAX_ALERTS) { + log.warn("Disabling logs with warnings about ClickhouseMetricsModule"); + } + return; + } + + CompletableFuture.runAsync(() -> { + log.debug("Sending event '{}' for player '{}'({}) with data '{}'", eventName, player.getUsername(), player.getUuid(), GSON.toJson(details)); + try (var con = sql2o.open()) { + con.createQuery("insert into events (uuid, player_name, timestamp, event_type, details) values (:uuid, :player_name, now(), :event_type, :details)", false) + .addParameter("uuid", player.getUuid()) + .addParameter("player_name", player.getUsername()) + .addParameter("event_type", eventName) + .addParameter("details", GSON.toJson(details)) + .executeUpdate(); + } catch (Exception ex) { + log.error(ex, ex); + } + }); + } +} diff --git a/api/src/main/java/ru/dragonestia/msb3/api/module/ClickhouseMetricsModule.java b/api/src/main/java/ru/dragonestia/msb3/api/module/ClickhouseMetricsModule.java new file mode 100644 index 0000000..52c41ac --- /dev/null +++ b/api/src/main/java/ru/dragonestia/msb3/api/module/ClickhouseMetricsModule.java @@ -0,0 +1,21 @@ +package ru.dragonestia.msb3.api.module; + +import lombok.Getter; +import lombok.extern.log4j.Log4j2; +import org.sql2o.Sql2o; + +@Log4j2 +public class ClickhouseMetricsModule { + + @Getter private static Sql2o sql2o; + + private ClickhouseMetricsModule() {} + + public static synchronized void init(String url, String username, String password) { + if (sql2o != null) return; + + sql2o = new Sql2o(url, username, password); + + log.info("Enabled Clickhouse metrics module"); + } +} diff --git a/clickhouse/config.xml b/clickhouse/config.xml new file mode 100644 index 0000000..2a54396 --- /dev/null +++ b/clickhouse/config.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/clickhouse/docker-compose.yml b/clickhouse/docker-compose.yml new file mode 100644 index 0000000..574391b --- /dev/null +++ b/clickhouse/docker-compose.yml @@ -0,0 +1,11 @@ +version: '3' + +services: + clickhouse: + image: yandex/clickhouse-server + ports: + - '8123:8123' + volumes: + - './users.xml:/etc/clickhouse-server/users.d/users.xml' + - './init.sql:/docker-entrypoint-initdb.d/crate_database.sql' + - './config.xml:/etc/clickhouse-server/users.d/config.xml' \ No newline at end of file diff --git a/clickhouse/init.sql b/clickhouse/init.sql new file mode 100644 index 0000000..626dfdb --- /dev/null +++ b/clickhouse/init.sql @@ -0,0 +1,11 @@ +create database if not exists msb3; + +create table if not exists msb3.events +( + uuid UUID, + player_name String(32), + timestamp DateTime default now(), + event_type LowCardinality(String), + details Nullable(String) +) engine = ReplacingMergeTree partition by toYYYYMM(timestamp) +primary key (uuid, event_type, timestamp); diff --git a/clickhouse/users.xml b/clickhouse/users.xml new file mode 100644 index 0000000..c075cc5 --- /dev/null +++ b/clickhouse/users.xml @@ -0,0 +1,18 @@ + + + + + ::/1 + 127.0.0.1 + + default + default + + + example + default + default + msb3 + + + \ No newline at end of file