Java tutorial
/* * This file is part of GriefPrevention, licensed under the MIT License (MIT). * * Copyright (c) Ryan Hamshire * Copyright (c) contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package me.ryanhamshire.griefprevention.logging; import com.google.common.io.Files; import me.ryanhamshire.griefprevention.DataStore; import me.ryanhamshire.griefprevention.GriefPreventionPlugin; import org.spongepowered.api.Sponge; import org.spongepowered.api.scheduler.Scheduler; import java.io.File; import java.nio.charset.Charset; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; public class CustomLogger { private final SimpleDateFormat timestampFormat = new SimpleDateFormat("HH:mm"); private final SimpleDateFormat filenameFormat = new SimpleDateFormat("yyyy_MM_dd"); private final String logFolderPath = DataStore.dataLayerFolderPath + File.separator + "Logs"; private final int secondsBetweenWrites = 10; // stringbuilder is not thread safe, stringbuffer is private StringBuffer queuedEntries = new StringBuffer(); public CustomLogger() { // ensure log folder exists File logFolder = new File(this.logFolderPath); logFolder.mkdirs(); // delete any outdated log files immediately this.deleteExpiredLogs(); // unless disabled, schedule recurring tasks int daysToKeepLogs = GriefPreventionPlugin.getGlobalConfig().getConfig().logging.loggingDaysToKeep; if (daysToKeepLogs > 0) { Scheduler scheduler = Sponge.getGame().getScheduler(); scheduler.createTaskBuilder().async().execute(new EntryWriter()) .delay(this.secondsBetweenWrites, TimeUnit.SECONDS) .interval(this.secondsBetweenWrites, TimeUnit.SECONDS).submit(GriefPreventionPlugin.instance); scheduler.createTaskBuilder().async().execute(new ExpiredLogRemover()).delay(1, TimeUnit.DAYS) .interval(1, TimeUnit.DAYS).submit(GriefPreventionPlugin.instance); } } private static final Pattern inlineFormatterPattern = Pattern.compile("."); public void addEntry(String entry, CustomLogEntryTypes entryType) { // if disabled, do nothing int daysToKeepLogs = GriefPreventionPlugin.getGlobalConfig().getConfig().logging.loggingDaysToKeep; if (daysToKeepLogs == 0) { return; } // if entry type is not enabled, do nothing if (!this.isEnabledType(entryType)) { return; } // otherwise write to the in-memory buffer, after removing formatters Matcher matcher = inlineFormatterPattern.matcher(entry); entry = matcher.replaceAll(""); String timestamp = this.timestampFormat.format(new Date()); this.queuedEntries.append(timestamp + " " + entry + "\n"); } private boolean isEnabledType(CustomLogEntryTypes entryType) { if (entryType == CustomLogEntryTypes.Exception) { return true; } if (entryType == CustomLogEntryTypes.SocialActivity && !GriefPreventionPlugin.getGlobalConfig().getConfig().logging.loggingSocialActions) { return false; } if (entryType == CustomLogEntryTypes.SuspiciousActivity && !GriefPreventionPlugin.getGlobalConfig().getConfig().logging.loggingSuspiciousActivity) { return false; } if (entryType == CustomLogEntryTypes.AdminActivity && !GriefPreventionPlugin.getGlobalConfig().getConfig().logging.loggingAdminActivity) { return false; } if (entryType == CustomLogEntryTypes.Debug && !GriefPreventionPlugin.debugLogging) { return false; } return true; } void writeEntries() { try { // if nothing to write, stop here if (this.queuedEntries.length() == 0) { return; } // determine filename based on date String filename = this.filenameFormat.format(new Date()) + ".log"; String filepath = this.logFolderPath + File.separator + filename; File logFile = new File(filepath); // dump content Files.append(this.queuedEntries.toString(), logFile, Charset.forName("UTF-8")); // in case of a failure to write the above due to exception, // the unwritten entries will remain the buffer for the next write // to retry this.queuedEntries.setLength(0); } catch (Exception e) { e.printStackTrace(); } } private void deleteExpiredLogs() { try { // get list of log files File logFolder = new File(this.logFolderPath); File[] files = logFolder.listFiles(); // delete any created before x days ago int daysToKeepLogs = GriefPreventionPlugin.getGlobalConfig().getConfig().logging.loggingDaysToKeep; Calendar expirationBoundary = Calendar.getInstance(); expirationBoundary.add(Calendar.DATE, -daysToKeepLogs); for (int i = 0; i < files.length; i++) { File file = files[i]; if (file.isDirectory()) { continue; // skip any folders } String filename = file.getName().replace(".log", ""); String[] dateParts = filename.split("_"); // format is // yyyy_MM_dd if (dateParts.length != 3) { continue; } try { int year = Integer.parseInt(dateParts[0]); int month = Integer.parseInt(dateParts[1]) - 1; int day = Integer.parseInt(dateParts[2]); Calendar filedate = Calendar.getInstance(); filedate.set(year, month, day); if (filedate.before(expirationBoundary)) { file.delete(); } } catch (NumberFormatException e) { // throw this away - effectively ignoring any files without // the correct filename format GriefPreventionPlugin.addLogEntry( "Ignoring an unexpected file in the abridged logs folder: " + file.getName(), CustomLogEntryTypes.Debug, false); } } } catch (Exception e) { e.printStackTrace(); } } // transfers the internal buffer to a log file private class EntryWriter implements Runnable { @Override public void run() { writeEntries(); } } private class ExpiredLogRemover implements Runnable { @Override public void run() { deleteExpiredLogs(); } } }