Replace file logger with json based system

This commit is contained in:
Luck 2018-04-21 18:16:35 +01:00
parent 1b917f0901
commit f11ebe6166
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
3 changed files with 146 additions and 45 deletions

View File

@ -89,17 +89,16 @@ public abstract class AbstractConfigurateDao extends AbstractDao {
// the uuid cache instance
private final FileUuidCache uuidCache = new FileUuidCache();
// the action logger instance
private final FileActionLogger actionLogger = new FileActionLogger();
private final FileActionLogger actionLogger;
// the file used to store uuid data
private Path uuidDataFile;
// the file used to store logged actions
private Path actionLogFile;
protected AbstractConfigurateDao(LuckPermsPlugin plugin, ConfigurateLoader loader, String name, String dataDirectoryName) {
super(plugin, name);
this.loader = loader;
this.dataDirectoryName = dataDirectoryName;
this.actionLogger = new FileActionLogger(plugin);
}
/**
@ -135,15 +134,15 @@ public abstract class AbstractConfigurateDao extends AbstractDao {
Files.createDirectories(this.dataDirectory);
this.uuidDataFile = MoreFiles.createFileIfNotExists(this.dataDirectory.resolve("uuidcache.txt"));
this.actionLogFile = MoreFiles.createFileIfNotExists(this.dataDirectory.resolve("actions.log"));
this.uuidCache.load(this.uuidDataFile);
this.actionLogger.init(this.actionLogFile);
this.actionLogger.init(this.dataDirectory.resolve("actions.json"));
}
@Override
public void shutdown() {
this.uuidCache.save(this.uuidDataFile);
this.actionLogger.flush();
}
@Override
@ -152,10 +151,8 @@ public abstract class AbstractConfigurateDao extends AbstractDao {
}
@Override
public Log getLog() {
// File based daos don't support viewing log data from in-game.
// You can just read the file in a text editor.
return Log.empty();
public Log getLog() throws IOException {
return this.actionLogger.getLog();
}
protected ConfigurationNode processBulkUpdate(BulkUpdate bulkUpdate, ConfigurationNode node) {

View File

@ -25,48 +25,152 @@
package me.lucko.luckperms.common.storage.dao.file;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.common.command.CommandManager;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.internal.Streams;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.buffers.BufferedRequest;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.gson.JObject;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Date;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.ReentrantLock;
public class FileActionLogger {
private static final String LOG_FORMAT = "%s(%s): [%s] %s(%s) --> %s";
private final Logger actionLogger = Logger.getLogger("luckperms_actions");
public void init(Path file) {
try {
FileHandler fh = new FileHandler(file.toString(), 0, 1, true);
fh.setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return new Date(record.getMillis()).toString() + ": " + record.getMessage() + "\n";
}
});
this.actionLogger.addHandler(fh);
this.actionLogger.setUseParentHandlers(false);
this.actionLogger.setLevel(Level.ALL);
this.actionLogger.setFilter(record -> true);
} catch (Exception e) {
e.printStackTrace();
}
/**
* The path to save logger content to
*/
private Path contentFile;
/**
* Lock to ensure the file isn't written to by multiple threads
*/
private final ReentrantLock writeLock = new ReentrantLock();
/**
* The queue of entries pending save to the file
*/
private final Queue<LogEntry> entryQueue = new ConcurrentLinkedQueue<>();
private final SaveBuffer saveBuffer;
public FileActionLogger(LuckPermsPlugin plugin) {
this.saveBuffer = new SaveBuffer(plugin);
}
public void init(Path contentFile) {
this.contentFile = contentFile;
}
public void logAction(LogEntry entry) {
this.actionLogger.info(String.format(LOG_FORMAT,
(entry.getActor().equals(CommandManager.CONSOLE_UUID) ? "" : entry.getActor() + " "),
entry.getActorName(),
Character.toString(entry.getType().getCode()),
entry.getActed().map(e -> e.toString() + " ").orElse(""),
entry.getActedName(),
entry.getAction())
);
this.entryQueue.add(entry);
this.saveBuffer.request();
}
public void flush() {
this.writeLock.lock();
try {
// don't perform the i/o process if there's nothing to be written
if (this.entryQueue.peek() == null) {
return;
}
try {
// read existing array data into memory
JsonArray array;
if (Files.exists(this.contentFile)) {
try (JsonReader reader = new JsonReader(Files.newBufferedReader(this.contentFile, StandardCharsets.UTF_8))) {
array = Streams.parse(reader).getAsJsonArray();
} catch (IOException e) {
e.printStackTrace();
array = new JsonArray();
}
} else {
array = new JsonArray();
}
// poll the queue for new entries
for (LogEntry e; (e = this.entryQueue.poll()) != null; ) {
JObject object = new JObject()
.add("timestamp", e.getTimestamp())
.add("actor", e.getActor().toString())
.add("actorName", e.getActorName())
.add("type", Character.toString(e.getType().getCode()))
.add("actedName", e.getActedName())
.add("action", e.getAction());
if (e.getActed().isPresent()) {
object.add("acted", e.getActed().get().toString());
}
array.add(object.toJson());
}
// write the full content back to the file
try (JsonWriter writer = new JsonWriter(Files.newBufferedWriter(this.contentFile, StandardCharsets.UTF_8))) {
writer.setIndent(" ");
Streams.write(array, writer);
}
} catch (IOException e) {
e.printStackTrace();
}
} finally {
this.writeLock.unlock();
}
}
public Log getLog() throws IOException {
Log.Builder log = Log.builder();
try (JsonReader reader = new JsonReader(Files.newBufferedReader(this.contentFile, StandardCharsets.UTF_8))) {
JsonArray array = Streams.parse(reader).getAsJsonArray();
for (JsonElement element : array) {
JsonObject object = element.getAsJsonObject();
UUID actedUuid = null;
if (object.has("acted")) {
actedUuid = UUID.fromString(object.get("acted").getAsString());
}
ExtendedLogEntry e = ExtendedLogEntry.build()
.timestamp(object.get("timestamp").getAsLong())
.actor(UUID.fromString(object.get("actor").getAsString()))
.actorName(object.get("actorName").getAsString())
.type(LogEntry.Type.valueOf(object.get("type").getAsCharacter()))
.acted(actedUuid)
.actedName(object.get("actedName").getAsString())
.action(object.get("action").getAsString())
.build();
log.add(e);
}
}
return log.build();
}
private final class SaveBuffer extends BufferedRequest<Void> {
public SaveBuffer(LuckPermsPlugin plugin) {
super(2000L, 500L, plugin.getBootstrap().getScheduler().async());
}
@Override
protected Void perform() {
FileActionLogger.this.flush();
return null;
}
}
}

View File

@ -183,7 +183,7 @@ public class MongoDao extends AbstractDao {
.timestamp(d.getLong("timestamp"))
.actor(d.get("actor", UUID.class))
.actorName(d.getString("actorName"))
.type(LogEntry.Type.valueOf(d.getString("type").toCharArray()[0]))
.type(LogEntry.Type.valueOf(d.getString("type").charAt(0)))
.acted(actedUuid)
.actedName(d.getString("actedName"))
.action(d.getString("action"))