🆙 Chatlog logging

This commit is contained in:
duckietm
2026-04-08 08:05:11 +02:00
parent 6f2766547b
commit 7786ba8e8f
3 changed files with 52 additions and 22 deletions
@@ -7,6 +7,10 @@ import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
public class DatabaseLogger {
@@ -24,19 +28,41 @@ public class DatabaseLogger {
return;
}
if (this.loggables.isEmpty()) {
// Drain the queue into a local snapshot so new loggables that arrive
// during this save cycle roll into the next flush instead of extending
// the current one indefinitely.
List<DatabaseLoggable> snapshot = new ArrayList<>();
DatabaseLoggable next;
while ((next = this.loggables.poll()) != null) {
snapshot.add(next);
}
if (snapshot.isEmpty()) {
return;
}
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection()) {
while (!this.loggables.isEmpty()) {
DatabaseLoggable loggable = this.loggables.remove();
try (PreparedStatement statement = connection.prepareStatement(loggable.getQuery())) {
loggable.log(statement);
statement.executeBatch();
// Group by SQL query so each distinct statement only prepares and
// executeBatches once. LinkedHashMap preserves first-seen order so
// auto-increment ids on chat/log tables correlate with the time the
// events actually happened.
Map<String, List<DatabaseLoggable>> byQuery = new LinkedHashMap<>();
for (DatabaseLoggable loggable : snapshot) {
byQuery.computeIfAbsent(loggable.getQuery(), k -> new ArrayList<>()).add(loggable);
}
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection()) {
for (Map.Entry<String, List<DatabaseLoggable>> group : byQuery.entrySet()) {
List<DatabaseLoggable> entries = group.getValue();
try (PreparedStatement statement = connection.prepareStatement(group.getKey())) {
for (DatabaseLoggable loggable : entries) {
loggable.log(statement);
}
statement.executeBatch();
} catch (SQLException e) {
// One bad group shouldn't prevent other groups from flushing.
LOGGER.error("Exception caught while saving loggable group of size {}: {}",
entries.size(), group.getKey(), e);
}
}
} catch (SQLException e) {
LOGGER.error("Exception caught while saving loggables to database.", e);
@@ -1,15 +1,14 @@
package com.eu.habbo.habbohotel.messenger;
import com.eu.habbo.Emulator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.eu.habbo.core.DatabaseLoggable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Message implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(Message.class);
public class Message implements Runnable, DatabaseLoggable {
private static final String QUERY = "INSERT INTO chatlogs_private (user_from_id, user_to_id, message, timestamp) VALUES (?, ?, ?, ?)";
private final int fromId;
private final int toId;
@@ -26,18 +25,23 @@ public class Message implements Runnable {
@Override
public void run() {
//TODO Turn into scheduler
if (Messenger.SAVE_PRIVATE_CHATS) {
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("INSERT INTO chatlogs_private (user_from_id, user_to_id, message, timestamp) VALUES (?, ?, ?, ?)")) {
Emulator.getDatabaseLogger().store(this);
}
}
@Override
public String getQuery() {
return QUERY;
}
@Override
public void log(PreparedStatement statement) throws SQLException {
statement.setInt(1, this.fromId);
statement.setInt(2, this.toId);
statement.setString(3, this.message);
statement.setInt(4, this.timestamp);
statement.execute();
} catch (SQLException e) {
LOGGER.error("Caught SQL exception", e);
}
}
statement.addBatch();
}
public int getToId() {