Initial commit
This commit is contained in:
71
src/com/redstoner/modules/logs/LogEntry.java
Normal file
71
src/com/redstoner/modules/logs/LogEntry.java
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package com.redstoner.modules.logs;
|
||||||
|
|
||||||
|
public class LogEntry
|
||||||
|
{
|
||||||
|
public final int line;
|
||||||
|
public final int global_line;
|
||||||
|
public final String filename;
|
||||||
|
public final String raw;
|
||||||
|
|
||||||
|
public LogEntry(String raw, int line, int global_line)
|
||||||
|
{
|
||||||
|
this("Unkown", raw, line, global_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogEntry(String filename, String raw, int line, int global_line)
|
||||||
|
{
|
||||||
|
this.raw = resolveColors(raw);
|
||||||
|
this.line = line;
|
||||||
|
this.global_line = global_line;
|
||||||
|
this.filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String applyFormat(String format, boolean colors)
|
||||||
|
{
|
||||||
|
// Replace escaped % with placeholder
|
||||||
|
format = format.replace("%%", "§§");
|
||||||
|
// Line numbers
|
||||||
|
format = format.replace("%l", "" + line);
|
||||||
|
format = format.replace("%L", "" + global_line);
|
||||||
|
// Filename
|
||||||
|
format = format.replace("%f", filename);
|
||||||
|
// Strip colors
|
||||||
|
if (!colors)
|
||||||
|
format = format.replace("%r", raw.replaceAll("$.", ""));
|
||||||
|
else
|
||||||
|
format = format.replace("%r", raw);
|
||||||
|
// Convert placeholder back
|
||||||
|
format = format.replace("§§", "%");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveColors(String message)
|
||||||
|
{
|
||||||
|
message = message.replace("[0;30;22m", "§0");
|
||||||
|
message = message.replace("[0;34;22m", "§1");
|
||||||
|
message = message.replace("[0;32;22m", "§2");
|
||||||
|
message = message.replace("[0;36;22m", "§3");
|
||||||
|
message = message.replace("[0;31;22m", "§4");
|
||||||
|
message = message.replace("[0;35;22m", "§5");
|
||||||
|
message = message.replace("[0;33;22m", "§6");
|
||||||
|
message = message.replace("[0;37;22m", "§7");
|
||||||
|
message = message.replace("[0;30;1m", "§8");
|
||||||
|
message = message.replace("[0;34;1m", "§9");
|
||||||
|
message = message.replace("[0;32;1m", "§a");
|
||||||
|
message = message.replace("[0;36;1m", "§b");
|
||||||
|
message = message.replace("[0;31;1m", "§c");
|
||||||
|
message = message.replace("[0;35;1m", "§d");
|
||||||
|
message = message.replace("[0;33;1m", "§e");
|
||||||
|
message = message.replace("[0;37;1m", "§f");
|
||||||
|
|
||||||
|
message = message.replace("[5m", "§k");
|
||||||
|
message = message.replace("[21m", "§l");
|
||||||
|
message = message.replace("[9m", "§m");
|
||||||
|
message = message.replace("[4m", "§n");
|
||||||
|
message = message.replace("[3m", "§o");
|
||||||
|
|
||||||
|
message = message.replace("[m", "§r");
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
180
src/com/redstoner/modules/logs/LogHandler.java
Normal file
180
src/com/redstoner/modules/logs/LogHandler.java
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
package com.redstoner.modules.logs;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FilenameFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import com.redstoner.misc.Utils;
|
||||||
|
import com.redstoner.modules.datamanager.DataManager;
|
||||||
|
|
||||||
|
public class LogHandler extends Thread
|
||||||
|
{
|
||||||
|
private CommandSender sender;
|
||||||
|
private String regex, fileName;
|
||||||
|
private static ArrayList<CommandSender> stillSearching = new ArrayList<>();
|
||||||
|
public int totalFiles = 0;
|
||||||
|
public int filesSearched = 0;
|
||||||
|
public int totalLines = 0;
|
||||||
|
public int currentLine = 0;
|
||||||
|
|
||||||
|
protected LogHandler(CommandSender sender, String regex, String fileName)
|
||||||
|
{
|
||||||
|
this.sender = sender;
|
||||||
|
this.regex = regex;
|
||||||
|
this.fileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doSearch()
|
||||||
|
{
|
||||||
|
if (stillSearching.contains(sender))
|
||||||
|
{
|
||||||
|
Logs.logger.message(sender, true, "§4 DO NOT EVER TRY TO QUERY TWO SEARCHES AT ONCE. Go die...!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stillSearching.add(sender);
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Searches the logs for a certain regex and forwards any matches to the sender.
|
||||||
|
*
|
||||||
|
* @param sender the issuer of the search
|
||||||
|
* @param regex the regex to search for. Will be wrapped in "^.*" and ".*$" if it is missing line delimiters
|
||||||
|
* @param fileName the name of the files to search through. May contain wildcards. */
|
||||||
|
private void search(CommandSender sender, String regex, String fileName)
|
||||||
|
{
|
||||||
|
long starttime = System.currentTimeMillis();
|
||||||
|
int matches = 0;
|
||||||
|
Logs.logger.message(sender, "Starting log search for " + regex + " in " + fileName
|
||||||
|
+ "now. Please do not query any other searches until this one completes.");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!regex.startsWith("^"))
|
||||||
|
regex = "^.*" + regex;
|
||||||
|
if (!regex.endsWith("$"))
|
||||||
|
regex += ".*$";
|
||||||
|
boolean singleFile = true;
|
||||||
|
if (fileName.contains("*"))
|
||||||
|
singleFile = false;
|
||||||
|
File logFolder = Logs.getLogsDir();
|
||||||
|
File[] files = logFolder.listFiles(new FilenameFilter()
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(File dir, String name)
|
||||||
|
{
|
||||||
|
return name.matches(fileName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
totalFiles = files.length;
|
||||||
|
if (totalFiles == 0)
|
||||||
|
{
|
||||||
|
Logs.logger.message(sender, true, "No files found!");
|
||||||
|
stillSearching.remove(sender);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Logs.logger.message(sender, "A total of &e" + totalFiles + "&7 will be searched!");
|
||||||
|
|
||||||
|
boolean progress = (boolean) DataManager.getOrDefault(Utils.getID(sender), "Logs", "progress", true);
|
||||||
|
for (File file : files)
|
||||||
|
{
|
||||||
|
if (file.getName().endsWith(".gz"))
|
||||||
|
{
|
||||||
|
|
||||||
|
BufferedReader inputReader = new BufferedReader(
|
||||||
|
new InputStreamReader(new GZIPInputStream(new FileInputStream(file))));
|
||||||
|
matches += searchStream(inputReader, regex, sender, singleFile, file.getName());
|
||||||
|
inputReader.close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BufferedReader inputReader = new BufferedReader(new FileReader(file));
|
||||||
|
matches += searchStream(inputReader, regex, sender, singleFile, file.getName());
|
||||||
|
inputReader.close();
|
||||||
|
}
|
||||||
|
filesSearched++;
|
||||||
|
if (progress)
|
||||||
|
{
|
||||||
|
sender.sendMessage("§7So far, §e" + filesSearched + "§7/§e" + totalFiles + "§7 File(s) and §e"
|
||||||
|
+ totalLines + "§7 Line(s) were searched.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logs.logger.message(sender, true,
|
||||||
|
"An unexpected error occured, please check your search parameters and try again!");
|
||||||
|
stillSearching.remove(sender);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stillSearching.remove(sender);
|
||||||
|
if ((boolean) DataManager.getOrDefault(Utils.getID(sender), "Logs", "summary", true))
|
||||||
|
{
|
||||||
|
String[] message = new String[2];
|
||||||
|
message[0] = "§aYour search completed after " + (System.currentTimeMillis() - starttime) + "ms!";
|
||||||
|
message[1] = "§7In total: §e" + filesSearched + "§7 File(s) and §e" + totalLines
|
||||||
|
+ "§7 Line(s) were searched, §a" + matches + "§7 Match(es) were found!";
|
||||||
|
Logs.logger.message(sender, message);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This function searches through an InputStream to find a regex. If it finds a match, it will forward that match to the sender and increase the match counter.
|
||||||
|
*
|
||||||
|
* @param inputReader the input reader containing the data
|
||||||
|
* @param regex the regex to search for
|
||||||
|
* @param sender the issuer of the search
|
||||||
|
* @param singleFile true if only a single file is being searched, false if the original filename contained wildcards.
|
||||||
|
* @param filename the name of the file that is currently being searched
|
||||||
|
* @return how many matches it found
|
||||||
|
* @throws IOException if something goes wrong */
|
||||||
|
private int searchStream(BufferedReader inputReader, String regex, CommandSender sender, boolean singleFile,
|
||||||
|
String filename) throws IOException
|
||||||
|
{
|
||||||
|
String format = (String) DataManager.getOrDefault(Utils.getID(sender), "Logs", "format", Logs.defaultFormat);
|
||||||
|
boolean colors = (boolean) DataManager.getOrDefault(Utils.getID(sender), "Logs", "colors", true);
|
||||||
|
Player p = null;
|
||||||
|
if (sender instanceof Player)
|
||||||
|
p = (Player) sender;
|
||||||
|
int matches = 0;
|
||||||
|
String line = "";
|
||||||
|
currentLine = 0;
|
||||||
|
while ((line = inputReader.readLine()) != null)
|
||||||
|
{
|
||||||
|
totalLines++;
|
||||||
|
currentLine++;
|
||||||
|
if (line.matches(regex))
|
||||||
|
{
|
||||||
|
if (((p != null) && (!p.isOnline())))
|
||||||
|
{
|
||||||
|
stillSearching.remove(sender);
|
||||||
|
throw new IOException("The player has left during the search. Aborting now.");
|
||||||
|
}
|
||||||
|
LogEntry entry = new LogEntry(filename, line, currentLine, totalLines);
|
||||||
|
sender.sendMessage(entry.applyFormat(format, colors));
|
||||||
|
matches++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
search(sender, regex, fileName);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/com/redstoner/modules/logs/Logs.cmd
Normal file
33
src/com/redstoner/modules/logs/Logs.cmd
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
command log {
|
||||||
|
alias logs;
|
||||||
|
search [string:file(s)] [string:search...] {
|
||||||
|
run search_logs file(s) search;
|
||||||
|
help Performs the specified search operation on the logs. Wildcards are supported in filenames. Search string is a regex.;
|
||||||
|
type player;
|
||||||
|
}
|
||||||
|
format {
|
||||||
|
run show_format;
|
||||||
|
help Displays your current log output format with an example result.;
|
||||||
|
type player;
|
||||||
|
}
|
||||||
|
format_help {
|
||||||
|
run show_format_help;
|
||||||
|
help Displays all available placeholders for the formatting;
|
||||||
|
type player;
|
||||||
|
}
|
||||||
|
option_help {
|
||||||
|
run show_option_help;
|
||||||
|
help Displays all available options.;
|
||||||
|
type player;
|
||||||
|
}
|
||||||
|
set format [string:format] {
|
||||||
|
run set_format format;
|
||||||
|
help Sets a new log output format;
|
||||||
|
type player;
|
||||||
|
}
|
||||||
|
set [string:option] [boolean:state] {
|
||||||
|
run set_option option state;
|
||||||
|
help Allows you to enable or disable various features such as sumamries, live progress updates, etc...;
|
||||||
|
type player;
|
||||||
|
}
|
||||||
|
}
|
||||||
157
src/com/redstoner/modules/logs/Logs.java
Normal file
157
src/com/redstoner/modules/logs/Logs.java
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
package com.redstoner.modules.logs;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import com.nemez.cmdmgr.Command;
|
||||||
|
import com.redstoner.annotations.Commands;
|
||||||
|
import com.redstoner.annotations.Version;
|
||||||
|
import com.redstoner.misc.CommandHolderType;
|
||||||
|
import com.redstoner.modules.Module;
|
||||||
|
import com.redstoner.modules.ModuleLogger;
|
||||||
|
import com.redstoner.modules.datamanager.DataManager;
|
||||||
|
|
||||||
|
@Commands(CommandHolderType.File)
|
||||||
|
@Version(major = 4, minor = 0, revision = 0, compatible = 4)
|
||||||
|
public class Logs implements Module
|
||||||
|
{
|
||||||
|
public static final String defaultFormat = "§7 > %f: %r";
|
||||||
|
private final LogEntry example_1 = new LogEntry("1970-01-01-2.log.gz",
|
||||||
|
"[01:23:45] [Async Chat Thread - #1337/INFO]: §aFooBar §7→ §4THIS SERVER SUCKS", 14, 73);
|
||||||
|
private final LogEntry example_2 = new LogEntry("1970-01-01-2.log.gz",
|
||||||
|
"[01:23:45] [Server thread/INFO]: admin issued server command: /ban FooBar Ab00se", 15, 74);
|
||||||
|
protected static ModuleLogger logger;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void firstLoad()
|
||||||
|
{
|
||||||
|
Module.super.firstLoad();
|
||||||
|
DataManager.setConfig("logs.root", "/etc/minecraft/redstoner/logs");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onEnable()
|
||||||
|
{
|
||||||
|
Module.super.onEnable();
|
||||||
|
logger = getLogger();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File getLogsDir()
|
||||||
|
{
|
||||||
|
return new File((String) DataManager.getConfigOrDefault("logs.root", "../logs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(hook = "search_logs")
|
||||||
|
public boolean search_logs(CommandSender sender, String files, String search)
|
||||||
|
{
|
||||||
|
LogHandler handler = new LogHandler(sender, search, files);
|
||||||
|
handler.doSearch();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FORMATTING
|
||||||
|
@Command(hook = "show_format")
|
||||||
|
public boolean show_format(CommandSender sender)
|
||||||
|
{
|
||||||
|
showExample(sender);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(hook = "set_format")
|
||||||
|
public boolean set_format(CommandSender sender, String format)
|
||||||
|
{
|
||||||
|
if (format.equals("--reset"))
|
||||||
|
format = defaultFormat;
|
||||||
|
format = format.replace("&", "§").replace("$$", "&");
|
||||||
|
DataManager.setData(sender, "format", format);
|
||||||
|
showExample(sender, format);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showExample(CommandSender sender)
|
||||||
|
{
|
||||||
|
showExample(sender, (String) DataManager.getOrDefault(sender, "format", defaultFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showExample(CommandSender sender, String format)
|
||||||
|
{
|
||||||
|
sender.sendMessage(getLogger().getHeader());
|
||||||
|
sender.sendMessage("Your format is: " + format);
|
||||||
|
sender.sendMessage("Here's an example of what it would look like in an actual log search:");
|
||||||
|
boolean colors = (boolean) DataManager.getOrDefault(sender, "colors", true);
|
||||||
|
if ((boolean) DataManager.getOrDefault(sender, "progress", true))
|
||||||
|
{
|
||||||
|
sender.sendMessage("§7So far, §e1§7/§e2§7 File(s) and §e68§7 Line(s) were searched.");
|
||||||
|
}
|
||||||
|
sender.sendMessage(example_1.applyFormat(format, colors));
|
||||||
|
sender.sendMessage(example_2.applyFormat(format, colors));
|
||||||
|
if ((boolean) DataManager.getOrDefault(sender, "summary", true))
|
||||||
|
{
|
||||||
|
sender.sendMessage("§aSearch completed after 39ms!");
|
||||||
|
sender.sendMessage(
|
||||||
|
"§7In total: §e2§7 File(s) and §e105§7 Line(s) were searched, §a2§7 Match(es) were found!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(hook = "show_format_help")
|
||||||
|
public boolean format_help(CommandSender sender)
|
||||||
|
{
|
||||||
|
//@noformat
|
||||||
|
String[] format_help = new String[] {
|
||||||
|
" &e%l&cine&7 -> Linenumber in the current file",
|
||||||
|
" &e%L&cine&7 -> Global linenumber (sum of all previous files + current line)",
|
||||||
|
" &e%f&cile&7 -> Complete filename",
|
||||||
|
" &e%r&caw&7 -> The raw line containing the text as it appears in the logs",
|
||||||
|
"",
|
||||||
|
" &7Use %% to gain a literal %."};
|
||||||
|
//@format
|
||||||
|
getLogger().message(sender, format_help);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEARCH OPTIONS
|
||||||
|
@Command(hook = "show_option_help")
|
||||||
|
public boolean show_options(CommandSender sender)
|
||||||
|
{
|
||||||
|
List<String> options = new ArrayList<>(Option.values().length + 1);
|
||||||
|
options.add("Available options are:");
|
||||||
|
for (Option o : Option.values())
|
||||||
|
options.add(" - " + o.toString());
|
||||||
|
getLogger().message(sender, options.toArray(new String[] {}));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(hook = "set_option")
|
||||||
|
public boolean set_option(CommandSender sender, String option, boolean state)
|
||||||
|
{
|
||||||
|
option = option.toLowerCase();
|
||||||
|
Option o = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
o = Option.valueOf(option);
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e)
|
||||||
|
{}
|
||||||
|
if (o == null)
|
||||||
|
{
|
||||||
|
getLogger().message(sender, true,
|
||||||
|
"Invalid option! To get a list of all available options, run &e/logs option_help");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
DataManager.setData(sender, option, state);
|
||||||
|
getLogger().message(sender,
|
||||||
|
"Successfully turned displaying of &e" + option + (state ? " &aon&7!" : " &coff&7!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Option
|
||||||
|
{
|
||||||
|
summary,
|
||||||
|
progress,
|
||||||
|
colors
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user