Skip to content
This repository has been archived by the owner on Nov 3, 2022. It is now read-only.

[WIP] File based command logging #321

Merged
merged 1 commit into from
Aug 24, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/main/java/io/github/nucleuspowered/nucleus/Nucleus.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import io.github.nucleuspowered.nucleus.internal.TextFileController;
import io.github.nucleuspowered.nucleus.internal.guice.QuickStartInjectorModule;
import io.github.nucleuspowered.nucleus.internal.guice.SubInjectorModule;
import io.github.nucleuspowered.nucleus.internal.interfaces.Reloadable;
import io.github.nucleuspowered.nucleus.internal.messages.ConfigMessageProvider;
import io.github.nucleuspowered.nucleus.internal.messages.MessageProvider;
import io.github.nucleuspowered.nucleus.internal.messages.ResourceMessageProvider;
Expand All @@ -40,6 +39,7 @@
import io.github.nucleuspowered.nucleus.internal.services.WarmupManager;
import io.github.nucleuspowered.nucleus.modules.core.config.CoreConfigAdapter;
import io.github.nucleuspowered.nucleus.modules.core.events.NucleusReloadConfigEvent;
import io.github.nucleuspowered.nucleus.util.ThrowableAction;
import ninja.leaping.configurate.ConfigurationOptions;
import ninja.leaping.configurate.hocon.HoconConfigurationLoader;
import org.slf4j.Logger;
Expand Down Expand Up @@ -80,7 +80,7 @@ public class Nucleus {
private ChatUtil chatUtil;
private Injector injector;
private SubInjectorModule subInjectorModule = new SubInjectorModule();
private List<Reloadable> reloadableList = Lists.newArrayList();
private List<ThrowableAction<? extends Exception>> reloadableList = Lists.newArrayList();

private InternalServiceManager serviceManager = new InternalServiceManager(this);
private MessageProvider messageProvider = new ResourceMessageProvider();
Expand Down Expand Up @@ -268,8 +268,8 @@ public void reload() {
tfc.load();
}

for (Reloadable r : reloadableList) {
r.onReload();
for (ThrowableAction<? extends Exception> r : reloadableList) {
r.action();
}
} catch (Exception e) {
e.printStackTrace();
Expand Down Expand Up @@ -351,7 +351,7 @@ public void addTextFileController(String id, Asset asset, Path file) throws IOEx
}
}

public void registerReloadable(Reloadable reloadable) {
public void registerReloadable(ThrowableAction<? extends Exception> reloadable) {
reloadableList.add(reloadable);
}

Expand Down
26 changes: 24 additions & 2 deletions src/main/java/io/github/nucleuspowered/nucleus/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
import com.google.common.collect.Lists;
import com.google.common.reflect.ClassPath;
import io.github.nucleuspowered.nucleus.api.data.interfaces.EndTimestamp;
import io.github.nucleuspowered.nucleus.internal.interfaces.VoidFunction;
import io.github.nucleuspowered.nucleus.internal.messages.MessageProvider;
import io.github.nucleuspowered.nucleus.internal.qsml.module.StandardModule;
import io.github.nucleuspowered.nucleus.util.Action;
import org.spongepowered.api.CatalogType;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.entity.living.player.Player;
Expand All @@ -25,14 +25,20 @@
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.zip.GZIPOutputStream;

public class Util {

Expand Down Expand Up @@ -131,7 +137,7 @@ public static String getTimeStringFromSeconds(long time) {
}
}

public static <T extends EndTimestamp> Optional<T> testForEndTimestamp(Optional<T> omd, VoidFunction function) {
public static <T extends EndTimestamp> Optional<T> testForEndTimestamp(Optional<T> omd, Action function) {
if (omd.isPresent()) {
T md = omd.get();
if (md.getEndTimestamp().isPresent() && md.getEndTimestamp().get().isBefore(Instant.now())) {
Expand Down Expand Up @@ -305,4 +311,20 @@ public static List<Subject> getParentSubjects(Subject pl) {
return Lists.newArrayList();
}
}

public static boolean compressAndDeleteFile(Path from) throws IOException {
// Get the file.
if (Files.exists(from)) {
Path to = Paths.get(from.toString() + ".gz");
try (OutputStream os = new GZIPOutputStream(new FileOutputStream(to.toFile()))) {
Files.copy(from, os);
os.flush();
Files.delete(from);
}

return true;
}

return false;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* This file is part of Nucleus, licensed under the MIT License (MIT). See the LICENSE.txt file
* at the root of this project for more details.
*/
package io.github.nucleuspowered.nucleus.logging;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import io.github.nucleuspowered.nucleus.Util;

import java.io.Closeable;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Iterator;
import java.util.function.Function;

public class DateRotatableFileLogger implements Closeable {

private final static Path nucleusBase = Paths.get("logs/nucleus");

private final Path directory;
private final String filenamePrefix;
private Instant currentDate;
private LogFile file;
private final Function<String, String> formatter;
private boolean isClosed = false;

public DateRotatableFileLogger(String directory, String filenamePrefix, Function<String, String> formatter) throws IOException {
Preconditions.checkNotNull(directory);
Preconditions.checkNotNull(filenamePrefix);

this.directory = nucleusBase.resolve(directory);
this.filenamePrefix = filenamePrefix;
this.formatter = formatter == null ? s -> s : formatter;
Files.createDirectories(this.directory);
}

private void openFile() throws IOException {
if (isClosed) {
throw new IllegalStateException();
}

if (file != null && !file.isClosed()) {
try {
file.close();
} finally {
file = null;
}
}

int count = 0;
boolean go = false;
String fileName;
do {
count++;
fileName = directory.toString() + "/" + filenamePrefix + "-" + DateTimeFormatter.ofPattern("yyyy-MM-dd").format(Instant.now().atZone(ZoneId.systemDefault())) + "-" + count + ".log";
Path nextFile = Paths.get(fileName);
if (Files.exists(nextFile)) {
try {
Util.compressAndDeleteFile(nextFile);
} catch (IOException e) {
e.printStackTrace();
}
} else if (!Files.exists(Paths.get(fileName + ".gz"))) {
file = new LogFile(nextFile, formatter);
go = true;
}
} while(!go);

currentDate = Instant.now().truncatedTo(ChronoUnit.DAYS);
}

public void logEntry(String entry) throws IOException {
if (isClosed) {
throw new IllegalStateException();
}

logEntry(Lists.newArrayList(entry), true);
}

public void logEntry(Iterable<String> entry) throws IOException {
if (isClosed) {
throw new IllegalStateException();
}

logEntry(entry, true);
}

private void logEntry(Iterable<String> entry, boolean retryOnError) throws IOException {
if (file == null || file.isClosed() || Instant.now().truncatedTo(ChronoUnit.DAYS).isAfter(currentDate)) {
openFile();
}

try {
Iterator<String> iterator = entry.iterator();
while (iterator.hasNext()) {
file.writeLine(iterator.next());
iterator.remove();
}

file.flush();
} catch (IOException e) {
if (retryOnError) {
logEntry(entry, false);
} else {
throw e;
}
}
}

@Override
public void close() throws IOException {
if (isClosed) {
return;
}

if (file != null && !file.isClosed()) {
file.close();
file = null;
this.isClosed = true;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package io.github.nucleuspowered.nucleus.logging;
/*
* This file is part of Nucleus, licensed under the MIT License (MIT). See the LICENSE.txt file
* at the root of this project for more details.
*/
import com.google.common.base.Preconditions;
import io.github.nucleuspowered.nucleus.Util;

import javax.annotation.Nonnull;
import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.Function;

class LogFile implements Closeable {

private final Path location;
private final Function<String, String> formatter;
private final BufferedWriter outputStream;
private boolean isClosed = false;

@Nonnull
LogFile(final Path location, Function<String, String> stringFormatter) throws IOException {
Preconditions.checkNotNull(location);
Preconditions.checkNotNull(stringFormatter);

this.location = location;
this.outputStream = Files.newBufferedWriter(location);
this.formatter = stringFormatter;
}

@Nonnull
void writeLine(String line) throws IOException {
try {
outputStream.write(formatter.apply(line));
outputStream.newLine();
} catch (IOException e) {
close();
throw e;
}
}

void flush() throws IOException {
outputStream.flush();
}

boolean isClosed() {
return isClosed;
}

@Override
public void close() throws IOException {
if (isClosed) {
return;
}

try {
outputStream.close();
} finally {
isClosed = true;

Util.compressAndDeleteFile(location);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import io.github.nucleuspowered.nucleus.internal.qsml.module.ConfigurableModule;
import io.github.nucleuspowered.nucleus.modules.commandlogger.config.CommandLoggerConfigAdapter;
import io.github.nucleuspowered.nucleus.modules.commandlogger.handlers.CommandLoggerHandler;
import io.github.nucleuspowered.nucleus.modules.core.config.CoreConfigAdapter;
import uk.co.drnaylor.quickstart.annotations.ModuleData;

@ModuleData(id = "command-logger", name = "Command Logger")
Expand All @@ -15,4 +17,14 @@ public class CommandLoggerModule extends ConfigurableModule<CommandLoggerConfigA
public CommandLoggerConfigAdapter getAdapter() {
return new CommandLoggerConfigAdapter();
}

@Override
protected void performPreTasks() throws Exception {
super.performPreTasks();

CommandLoggerHandler clh = new CommandLoggerHandler(nucleus, nucleus.getInjector().getInstance(CommandLoggerConfigAdapter.class), nucleus.getInjector().getInstance(CoreConfigAdapter.class));
serviceManager.registerService(CommandLoggerHandler.class, clh);
nucleus.registerReloadable(clh::onReload);
clh.onReload();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
package io.github.nucleuspowered.nucleus.modules.commandlogger.config;

import com.google.common.collect.ImmutableList;
import ninja.leaping.configurate.objectmapping.Setting;
import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;

Expand All @@ -22,6 +23,9 @@ public class CommandLoggerConfig {
@Setting(value = "command-filter", comment = "loc:config.commandlogger.list")
private List<String> commandsToFilter = new ArrayList<>();

@Setting(value = "log-to-file", comment = "loc:config.commandlogger.file")
private boolean logToFile = false;

public LoggerTargetConfig getLoggerTarget() {
return loggerTarget;
}
Expand All @@ -31,6 +35,10 @@ public boolean isWhitelist() {
}

public List<String> getCommandsToFilter() {
return commandsToFilter;
return ImmutableList.copyOf(commandsToFilter);
}

public boolean isLogToFile() {
return logToFile;
}
}