Remade logging system, cleaned up BaseApp.
This commit is contained in:
@@ -2,14 +2,16 @@ package mightypork.gamecore.control;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.Thread.UncaughtExceptionHandler;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import mightypork.gamecore.audio.SoundSystem;
|
||||
import mightypork.gamecore.control.bus.EventBus;
|
||||
import mightypork.gamecore.control.bus.events.*;
|
||||
import mightypork.gamecore.control.interf.DefaultImpl;
|
||||
import mightypork.gamecore.control.interf.Destroyable;
|
||||
import mightypork.gamecore.control.interf.NoImpl;
|
||||
import mightypork.gamecore.control.timing.Updateable;
|
||||
import mightypork.gamecore.gui.screens.ScreenRegistry;
|
||||
import mightypork.gamecore.input.InputSystem;
|
||||
@@ -17,7 +19,7 @@ import mightypork.gamecore.loading.AsyncResourceLoader;
|
||||
import mightypork.gamecore.render.DisplaySystem;
|
||||
import mightypork.utils.files.InstanceLock;
|
||||
import mightypork.utils.logging.Log;
|
||||
import mightypork.utils.logging.LogInstance;
|
||||
import mightypork.utils.logging.LogWriter;
|
||||
|
||||
|
||||
/**
|
||||
@@ -26,7 +28,7 @@ import mightypork.utils.logging.LogInstance;
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public abstract class BaseApp implements AppAccess {
|
||||
public abstract class BaseApp implements AppAccess, UncaughtExceptionHandler {
|
||||
|
||||
// modules
|
||||
private InputSystem inputSystem;
|
||||
@@ -40,8 +42,9 @@ public abstract class BaseApp implements AppAccess {
|
||||
/**
|
||||
* Start the application
|
||||
*/
|
||||
public void start()
|
||||
public final void start()
|
||||
{
|
||||
Thread.setDefaultUncaughtExceptionHandler(this);
|
||||
|
||||
initialize();
|
||||
|
||||
@@ -57,7 +60,6 @@ public abstract class BaseApp implements AppAccess {
|
||||
*/
|
||||
protected void initialize()
|
||||
{
|
||||
|
||||
/*
|
||||
* Lock working directory
|
||||
*/
|
||||
@@ -69,8 +71,11 @@ public abstract class BaseApp implements AppAccess {
|
||||
/*
|
||||
* Setup logging
|
||||
*/
|
||||
final LogInstance log = createLog();
|
||||
org.newdawn.slick.util.Log.setLogSystem(new SlickLogRedirector(log));
|
||||
final LogWriter log = createLog();
|
||||
if (log != null) {
|
||||
Log.setMainLogger(log);
|
||||
org.newdawn.slick.util.Log.setLogSystem(new SlickLogRedirector(log));
|
||||
}
|
||||
|
||||
// only here it makes sense to log.
|
||||
Log.i("=== Commencing initialization sequence ===");
|
||||
@@ -82,6 +87,7 @@ public abstract class BaseApp implements AppAccess {
|
||||
eventBus = new EventBus();
|
||||
|
||||
Log.f3("Registering channels...");
|
||||
initDefaultBusChannels(eventBus);
|
||||
initBus(eventBus);
|
||||
|
||||
/*
|
||||
@@ -139,16 +145,16 @@ public abstract class BaseApp implements AppAccess {
|
||||
* Called at the beginning of the initialization sequence, right after lock
|
||||
* was obtained.
|
||||
*/
|
||||
@NoImpl
|
||||
@DefaultImpl
|
||||
protected void preInit()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Called at the end of init sequence, before main loop starts.
|
||||
*/
|
||||
@NoImpl
|
||||
@DefaultImpl
|
||||
protected void postInit()
|
||||
{
|
||||
}
|
||||
@@ -159,7 +165,13 @@ public abstract class BaseApp implements AppAccess {
|
||||
*
|
||||
* @return new log instance
|
||||
*/
|
||||
protected abstract LogInstance createLog();
|
||||
@DefaultImpl
|
||||
protected LogWriter createLog()
|
||||
{
|
||||
final LogWriter log = Log.create("runtime", new File("runtime.log"));
|
||||
log.setLevel(Level.ALL);
|
||||
return log;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -167,7 +179,12 @@ public abstract class BaseApp implements AppAccess {
|
||||
*
|
||||
* @param display
|
||||
*/
|
||||
protected abstract void initDisplay(DisplaySystem display);
|
||||
@DefaultImpl
|
||||
protected void initDisplay(DisplaySystem display)
|
||||
{
|
||||
display.createMainWindow(800, 600, true, false, "BaseApp using LWJGL display.");
|
||||
display.setTargetFps(60);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -175,7 +192,10 @@ public abstract class BaseApp implements AppAccess {
|
||||
*
|
||||
* @param audio
|
||||
*/
|
||||
protected abstract void initSoundSystem(SoundSystem audio);
|
||||
@DefaultImpl
|
||||
protected void initSoundSystem(SoundSystem audio)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -183,14 +203,20 @@ public abstract class BaseApp implements AppAccess {
|
||||
*
|
||||
* @param input
|
||||
*/
|
||||
protected abstract void initInputSystem(InputSystem input);
|
||||
@DefaultImpl
|
||||
protected void initInputSystem(InputSystem input)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize resource banks; {@link AsyncResourceLoader} is already
|
||||
* started.
|
||||
*/
|
||||
protected abstract void initResources();
|
||||
@DefaultImpl
|
||||
protected void initResources()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -198,7 +224,10 @@ public abstract class BaseApp implements AppAccess {
|
||||
*
|
||||
* @param screens
|
||||
*/
|
||||
protected abstract void initScreens(ScreenRegistry screens);
|
||||
@DefaultImpl
|
||||
protected void initScreens(ScreenRegistry screens)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -215,7 +244,13 @@ public abstract class BaseApp implements AppAccess {
|
||||
*
|
||||
* @param bus
|
||||
*/
|
||||
@DefaultImpl
|
||||
protected void initBus(EventBus bus)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private void initDefaultBusChannels(EventBus bus)
|
||||
{
|
||||
// framework events
|
||||
bus.addChannel(DestroyEvent.class, Destroyable.class);
|
||||
@@ -259,7 +294,7 @@ public abstract class BaseApp implements AppAccess {
|
||||
*/
|
||||
protected void onLockError()
|
||||
{
|
||||
System.err.println("Could not obtain lock file.\nOnly one instance can run at a time.");
|
||||
Log.e("Could not obtain lock file.\nOnly one instance can run at a time.");
|
||||
|
||||
//@formatter:off
|
||||
JOptionPane.showMessageDialog(
|
||||
@@ -279,7 +314,11 @@ public abstract class BaseApp implements AppAccess {
|
||||
*
|
||||
* @return lock file, or null to disable lock.
|
||||
*/
|
||||
protected abstract File getLockFile();
|
||||
@DefaultImpl
|
||||
protected File getLockFile()
|
||||
{
|
||||
return new File(".lock");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@@ -310,14 +349,41 @@ public abstract class BaseApp implements AppAccess {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void shutdown()
|
||||
@DefaultImpl
|
||||
protected void beforeShutdown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void uncaughtException(Thread t, Throwable e)
|
||||
{
|
||||
onCrash(e);
|
||||
}
|
||||
|
||||
|
||||
@DefaultImpl
|
||||
protected void onCrash(Throwable e)
|
||||
{
|
||||
Log.e("The game has crashed.", e);
|
||||
shutdown();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void shutdown()
|
||||
{
|
||||
beforeShutdown();
|
||||
|
||||
Log.i("Shutting down subsystems...");
|
||||
|
||||
if (getEventBus() != null) {
|
||||
getEventBus().send(new DestroyEvent());
|
||||
getEventBus().destroy();
|
||||
try {
|
||||
if (getEventBus() != null) {
|
||||
getEventBus().send(new DestroyEvent());
|
||||
getEventBus().destroy();
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
// ignore it
|
||||
}
|
||||
|
||||
Log.i("Terminating...");
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import mightypork.gamecore.control.bus.events.MainLoopTaskRequest;
|
||||
import mightypork.gamecore.control.bus.events.UpdateEvent;
|
||||
import mightypork.gamecore.control.interf.NoImpl;
|
||||
import mightypork.gamecore.control.interf.DefaultImpl;
|
||||
import mightypork.gamecore.control.timing.TimerDelta;
|
||||
import mightypork.gamecore.gui.components.Renderable;
|
||||
import mightypork.gamecore.gui.screens.ScreenRegistry;
|
||||
@@ -78,7 +78,7 @@ public abstract class GameLoop extends AppModule implements MainLoopTaskRequest.
|
||||
/**
|
||||
* Called before render
|
||||
*/
|
||||
@NoImpl
|
||||
@DefaultImpl
|
||||
protected void beforeRender()
|
||||
{
|
||||
//
|
||||
@@ -88,7 +88,7 @@ public abstract class GameLoop extends AppModule implements MainLoopTaskRequest.
|
||||
/**
|
||||
* Called after render
|
||||
*/
|
||||
@NoImpl
|
||||
@DefaultImpl
|
||||
protected void afterRender()
|
||||
{
|
||||
//
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package mightypork.gamecore.control;
|
||||
|
||||
|
||||
import mightypork.utils.logging.LogInstance;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import mightypork.utils.logging.LogWriter;
|
||||
|
||||
import org.newdawn.slick.util.LogSystem;
|
||||
|
||||
@@ -13,13 +15,13 @@ import org.newdawn.slick.util.LogSystem;
|
||||
*/
|
||||
public class SlickLogRedirector implements LogSystem {
|
||||
|
||||
LogInstance l;
|
||||
LogWriter l;
|
||||
|
||||
|
||||
/**
|
||||
* @param log log to redirect into
|
||||
*/
|
||||
public SlickLogRedirector(LogInstance log) {
|
||||
public SlickLogRedirector(LogWriter log) {
|
||||
this.l = log;
|
||||
}
|
||||
|
||||
@@ -27,49 +29,49 @@ public class SlickLogRedirector implements LogSystem {
|
||||
@Override
|
||||
public void error(String msg, Throwable e)
|
||||
{
|
||||
l.e(msg, e);
|
||||
l.log(Level.SEVERE, msg, e);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void error(Throwable e)
|
||||
{
|
||||
l.e(e);
|
||||
l.log(Level.SEVERE, null, e);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void error(String msg)
|
||||
{
|
||||
l.e(msg);
|
||||
l.log(Level.SEVERE, msg);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void warn(String msg)
|
||||
{
|
||||
l.w(msg);
|
||||
l.log(Level.WARNING, msg);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable e)
|
||||
{
|
||||
l.e(msg, e);
|
||||
l.log(Level.WARNING, msg, e);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void info(String msg)
|
||||
{
|
||||
l.i(msg);
|
||||
l.log(Level.INFO, msg);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void debug(String msg)
|
||||
{
|
||||
l.f3(msg);
|
||||
l.log(Level.FINEST, msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -9,14 +9,14 @@ import java.lang.annotation.Target;
|
||||
|
||||
|
||||
/**
|
||||
* Indicates that the marked method is not implemented and can be safely
|
||||
* overriden.
|
||||
* Marked method can be safely overriden; it's left blank (or with default
|
||||
* implementation) as a convenience.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target(value = { ElementType.METHOD })
|
||||
public @interface NoImpl {
|
||||
public @interface DefaultImpl {
|
||||
//
|
||||
}
|
||||
@@ -4,7 +4,7 @@ package mightypork.gamecore.gui.screens;
|
||||
import mightypork.gamecore.control.AppAccess;
|
||||
import mightypork.gamecore.control.AppSubModule;
|
||||
import mightypork.gamecore.control.bus.events.ScreenChangeEvent;
|
||||
import mightypork.gamecore.control.interf.NoImpl;
|
||||
import mightypork.gamecore.control.interf.DefaultImpl;
|
||||
import mightypork.gamecore.gui.components.Renderable;
|
||||
import mightypork.gamecore.gui.constraints.RectConstraint;
|
||||
import mightypork.gamecore.input.KeyBinder;
|
||||
@@ -130,7 +130,7 @@ public abstract class Screen extends AppSubModule implements Renderable, KeyBind
|
||||
/**
|
||||
* Called when the screen becomes active
|
||||
*/
|
||||
@NoImpl
|
||||
@DefaultImpl
|
||||
protected void onScreenEnter()
|
||||
{
|
||||
//
|
||||
@@ -140,7 +140,7 @@ public abstract class Screen extends AppSubModule implements Renderable, KeyBind
|
||||
/**
|
||||
* Called when the screen is no longer active
|
||||
*/
|
||||
@NoImpl
|
||||
@DefaultImpl
|
||||
protected void onScreenLeave()
|
||||
{
|
||||
//
|
||||
@@ -152,7 +152,7 @@ public abstract class Screen extends AppSubModule implements Renderable, KeyBind
|
||||
*
|
||||
* @param size screen size
|
||||
*/
|
||||
@NoImpl
|
||||
@DefaultImpl
|
||||
protected void onSizeChanged(Coord size)
|
||||
{
|
||||
//
|
||||
|
||||
@@ -2,7 +2,7 @@ package mightypork.gamecore.gui.screens;
|
||||
|
||||
|
||||
import mightypork.gamecore.control.AppSubModule;
|
||||
import mightypork.gamecore.control.interf.NoImpl;
|
||||
import mightypork.gamecore.control.interf.DefaultImpl;
|
||||
import mightypork.gamecore.gui.components.Renderable;
|
||||
import mightypork.gamecore.gui.constraints.RectConstraint;
|
||||
import mightypork.gamecore.input.KeyBinder;
|
||||
@@ -75,7 +75,7 @@ public abstract class ScreenLayer extends AppSubModule implements Comparable<Scr
|
||||
/**
|
||||
* Called when the screen becomes active
|
||||
*/
|
||||
@NoImpl
|
||||
@DefaultImpl
|
||||
protected void onScreenEnter()
|
||||
{
|
||||
//
|
||||
@@ -85,7 +85,7 @@ public abstract class ScreenLayer extends AppSubModule implements Comparable<Scr
|
||||
/**
|
||||
* Called when the screen is no longer active
|
||||
*/
|
||||
@NoImpl
|
||||
@DefaultImpl
|
||||
protected void onScreenLeave()
|
||||
{
|
||||
//
|
||||
@@ -97,7 +97,7 @@ public abstract class ScreenLayer extends AppSubModule implements Comparable<Scr
|
||||
*
|
||||
* @param size screen size
|
||||
*/
|
||||
@NoImpl
|
||||
@DefaultImpl
|
||||
protected void onSizeChanged(Coord size)
|
||||
{
|
||||
//
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.util.HashMap;
|
||||
import mightypork.gamecore.control.AppAccess;
|
||||
import mightypork.gamecore.control.AppModule;
|
||||
import mightypork.gamecore.control.bus.events.ScreenRequestEvent;
|
||||
import mightypork.gamecore.control.interf.NoImpl;
|
||||
import mightypork.gamecore.control.interf.DefaultImpl;
|
||||
import mightypork.gamecore.gui.components.Renderable;
|
||||
import mightypork.utils.logging.Log;
|
||||
|
||||
@@ -66,7 +66,7 @@ public class ScreenRegistry extends AppModule implements ScreenRequestEvent.List
|
||||
|
||||
|
||||
@Override
|
||||
@NoImpl
|
||||
@DefaultImpl
|
||||
protected void deinit()
|
||||
{
|
||||
//
|
||||
|
||||
@@ -2,10 +2,7 @@ package mightypork.rogue;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import mightypork.gamecore.audio.SoundSystem;
|
||||
import mightypork.gamecore.control.BaseApp;
|
||||
import mightypork.gamecore.control.GameLoop;
|
||||
import mightypork.gamecore.control.bus.EventBus;
|
||||
@@ -20,8 +17,6 @@ import mightypork.rogue.screens.test_bouncyboxes.ScreenTestBouncy;
|
||||
import mightypork.rogue.screens.test_cat_sound.ScreenTestCat;
|
||||
import mightypork.rogue.screens.test_font.ScreenTestFont;
|
||||
import mightypork.rogue.screens.test_render.ScreenTestRender;
|
||||
import mightypork.utils.logging.Log;
|
||||
import mightypork.utils.logging.LogInstance;
|
||||
|
||||
|
||||
/**
|
||||
@@ -31,31 +26,6 @@ import mightypork.utils.logging.LogInstance;
|
||||
*/
|
||||
public class App extends BaseApp {
|
||||
|
||||
/** instance pointer */
|
||||
private static BaseApp inst;
|
||||
|
||||
|
||||
/**
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args)
|
||||
{
|
||||
Config.init();
|
||||
Config.save();
|
||||
|
||||
Thread.setDefaultUncaughtExceptionHandler(new CrashHandler());
|
||||
|
||||
inst = new App();
|
||||
|
||||
try {
|
||||
inst.start();
|
||||
} catch (final Throwable t) {
|
||||
onCrash(t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void initScreens(ScreenRegistry screens)
|
||||
{
|
||||
@@ -71,9 +41,6 @@ public class App extends BaseApp {
|
||||
@Override
|
||||
protected void initBus(EventBus bus)
|
||||
{
|
||||
super.initBus(bus);
|
||||
|
||||
// custom channels
|
||||
bus.addChannel(ActionRequest.class, ActionRequest.Listener.class);
|
||||
|
||||
//bus.detailedLogging = true;
|
||||
@@ -115,26 +82,17 @@ public class App extends BaseApp {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void preInit()
|
||||
{
|
||||
// to get dot instead of comma in floats
|
||||
Locale.setDefault(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected LogInstance createLog()
|
||||
{
|
||||
final LogInstance log = Log.create("runtime", Paths.LOGS, 10);
|
||||
log.setFileLevel(Level.WARNING);
|
||||
log.setSysoutLevel(Level.ALL);
|
||||
log.enable(Config.LOGGING_ENABLED);
|
||||
log.enableSysout(Config.LOG_TO_STDOUT);
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected LogWriter createLog()
|
||||
// {
|
||||
// Locale.setDefault(Locale.ENGLISH);
|
||||
//
|
||||
// final LogWriter log = Log.create("runtime", Paths.LOG_FILE, 10);
|
||||
// log.setLevel(Level.WARNING);
|
||||
// log.enable(Config.LOGGING_ENABLED);
|
||||
//
|
||||
// return log;
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected void initDisplay(DisplaySystem display)
|
||||
@@ -144,13 +102,6 @@ public class App extends BaseApp {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void initSoundSystem(SoundSystem audio)
|
||||
{
|
||||
audio.setMasterVolume(1);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected GameLoop createLoop()
|
||||
{
|
||||
@@ -171,22 +122,4 @@ public class App extends BaseApp {
|
||||
return Paths.LOCK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle a crash
|
||||
*
|
||||
* @param error
|
||||
*/
|
||||
public static void onCrash(Throwable error)
|
||||
{
|
||||
if (Log.ready()) {
|
||||
Log.e("The game has crashed!", error);
|
||||
} else {
|
||||
System.err.println("The game has crashed!");
|
||||
error.printStackTrace();
|
||||
}
|
||||
|
||||
if (inst != null) inst.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package mightypork.rogue;
|
||||
|
||||
|
||||
import java.lang.Thread.UncaughtExceptionHandler;
|
||||
|
||||
|
||||
public class CrashHandler implements UncaughtExceptionHandler {
|
||||
|
||||
@Override
|
||||
public void uncaughtException(Thread t, Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
App.onCrash(e);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package mightypork.rogue;
|
||||
|
||||
|
||||
public class Main {
|
||||
|
||||
/**
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args)
|
||||
{
|
||||
Config.init();
|
||||
Config.save();
|
||||
|
||||
(new App()).start();
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,13 @@ public class Paths {
|
||||
private static final String APPDIR_NAME = "rogue";
|
||||
|
||||
public static final File WORKDIR = OsUtils.getWorkDir(APPDIR_NAME);
|
||||
public static final File LOGS = OsUtils.getWorkDir(APPDIR_NAME, "logs");
|
||||
public static final File SCREENSHOTS = OsUtils.getWorkDir(APPDIR_NAME, "screenshots");
|
||||
|
||||
public static final File LOG_FILE = new File(WORKDIR, "runtime.log");
|
||||
|
||||
public static final File SCREENSHOTS = new File(WORKDIR, "screenshots");
|
||||
|
||||
public static final File CONFIG = new File(WORKDIR, "config.ini");
|
||||
|
||||
public static final File LOCK = new File(WORKDIR, ".lock");
|
||||
|
||||
public static final String DIR_EFFECTS = "res/sounds/effects/";
|
||||
|
||||
@@ -71,8 +71,6 @@ public class LayerFlyingCat extends ScreenLayer implements Updateable, MouseButt
|
||||
size.update(delta);
|
||||
xPos.update(delta);
|
||||
yPos.update(delta);
|
||||
|
||||
System.out.println(cat.getRect());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
package mightypork.utils.logging;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import mightypork.utils.files.FileUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Logger that cleans directory & archives old logs
|
||||
*
|
||||
* @author MightyPork
|
||||
* @copy (c) 2014
|
||||
*/
|
||||
public class ArchivingLog extends SimpleLog {
|
||||
|
||||
/** Number of old logs to keep */
|
||||
private final int logs_to_keep;
|
||||
|
||||
|
||||
/**
|
||||
* Log
|
||||
*
|
||||
* @param name log name
|
||||
* @param file log file (in log directory)
|
||||
* @param oldLogCount number of old log files to keep: -1 all, 0 none.
|
||||
*/
|
||||
public ArchivingLog(String name, File file, int oldLogCount) {
|
||||
super(name, file);
|
||||
this.logs_to_keep = oldLogCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log, not keeping 5 last log files (default);
|
||||
*
|
||||
* @param name log name
|
||||
* @param file log file (in log directory)
|
||||
*/
|
||||
public ArchivingLog(String name, File file) {
|
||||
super(name, file);
|
||||
this.logs_to_keep = 5;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
cleanLoggingDirectory();
|
||||
|
||||
super.init();
|
||||
}
|
||||
|
||||
|
||||
private void cleanLoggingDirectory()
|
||||
{
|
||||
if (logs_to_keep == 0) return; // overwrite
|
||||
|
||||
final File log_file = getFile();
|
||||
final File log_dir = log_file.getParentFile();
|
||||
final String fname = FileUtils.getBasename(log_file.toString());
|
||||
|
||||
// move old file
|
||||
for (final File f : FileUtils.listDirectory(log_dir)) {
|
||||
if (!f.isFile()) continue;
|
||||
if (f.equals(getFile())) {
|
||||
|
||||
final Date d = new Date(f.lastModified());
|
||||
final String fbase = fname + '_' + (new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss")).format(d);
|
||||
final String suff = "." + getSuffix();
|
||||
String cntStr = "";
|
||||
File f2;
|
||||
|
||||
for (int cnt = 0; (f2 = new File(log_dir, fbase + cntStr + suff)).exists(); cntStr = "_" + (++cnt)) {}
|
||||
|
||||
f.renameTo(f2);
|
||||
}
|
||||
}
|
||||
|
||||
if (logs_to_keep == -1) return; // keep all
|
||||
|
||||
final List<File> oldLogs = FileUtils.listDirectory(log_dir, new FileFilter() {
|
||||
|
||||
@Override
|
||||
public boolean accept(File f)
|
||||
{
|
||||
if (f.isDirectory()) return false;
|
||||
if (!f.getName().endsWith(getSuffix())) return false;
|
||||
if (!f.getName().startsWith(fname)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Collections.sort(oldLogs, new Comparator<File>() {
|
||||
|
||||
@Override
|
||||
public int compare(File o1, File o2)
|
||||
{
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
});
|
||||
|
||||
// playing with fireee
|
||||
for (int i = 0; i < oldLogs.size() - logs_to_keep; i++) {
|
||||
oldLogs.get(i).delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return log filename suffix
|
||||
*/
|
||||
private String getSuffix()
|
||||
{
|
||||
return FileUtils.getExtension(getFile());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package mightypork.utils.logging;
|
||||
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
|
||||
public abstract class BaseLogMonitor implements LogMonitor {
|
||||
|
||||
private boolean enabled = true;
|
||||
private Level accepted = Level.ALL;
|
||||
|
||||
|
||||
@Override
|
||||
public void onMessageLogged(Level level, String message)
|
||||
{
|
||||
if (!enabled) return;
|
||||
if (accepted.intValue() > level.intValue()) return;
|
||||
|
||||
logMessage(level, message);
|
||||
}
|
||||
|
||||
|
||||
protected abstract void logMessage(Level level, String message);
|
||||
|
||||
|
||||
@Override
|
||||
public void setLevel(Level level)
|
||||
{
|
||||
this.accepted = level;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void enable(boolean flag)
|
||||
{
|
||||
this.enabled = flag;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,195 +2,306 @@ package mightypork.utils.logging;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import mightypork.utils.string.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* A log.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class Log {
|
||||
|
||||
/** enable static logging */
|
||||
private static boolean staticLogging = true;
|
||||
private static LogWriter main = null;
|
||||
private static boolean enabled = true;
|
||||
private static final LogToSysoutMonitor sysoMonitor = new LogToSysoutMonitor();
|
||||
private static final long start_ms = System.currentTimeMillis();
|
||||
|
||||
private static HashMap<String, SimpleLog> logs = new HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* Log FINE message in main logger
|
||||
* Create a logger. If another with the name already exists, it'll be
|
||||
* retrieved instead of creating a new one.
|
||||
*
|
||||
* @param logName log name (used for filename, should be application-unique)
|
||||
* @param logFile log file; old logs will be kept here too.
|
||||
* @param oldLogsCount number of old logs to keep, -1 infinite, 0 none.
|
||||
* @return the created Log instance
|
||||
*/
|
||||
public static synchronized LogWriter create(String logName, File logFile, int oldLogsCount)
|
||||
{
|
||||
if (logs.containsKey(logName)) return logs.get(logName);
|
||||
|
||||
final ArchivingLog log = new ArchivingLog(logName, logFile, oldLogsCount);
|
||||
log.init();
|
||||
|
||||
logs.put(logName, log);
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a logger. If another with the name already exists, it'll be
|
||||
* retrieved instead of creating a new one.
|
||||
*
|
||||
* @param logName log name (used for filename, must be application-unique)
|
||||
* @param logFile log file; old logs will be kept here too.
|
||||
* @return the created Log instance
|
||||
*/
|
||||
public static synchronized LogWriter create(String logName, File logFile)
|
||||
{
|
||||
if (logs.containsKey(logName)) return logs.get(logName);
|
||||
|
||||
final SimpleLog log = new SimpleLog(logName, logFile);
|
||||
log.init();
|
||||
|
||||
logs.put(logName, log);
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
|
||||
public static void setMainLogger(LogWriter log)
|
||||
{
|
||||
main = log;
|
||||
}
|
||||
|
||||
|
||||
public static void addMonitor(LogMonitor mon)
|
||||
{
|
||||
assertInited();
|
||||
|
||||
main.addMonitor(mon);
|
||||
}
|
||||
|
||||
|
||||
public static void removeMonitor(LogMonitor mon)
|
||||
{
|
||||
assertInited();
|
||||
|
||||
main.removeMonitor(mon);
|
||||
}
|
||||
|
||||
|
||||
private static void assertInited()
|
||||
{
|
||||
if (main == null) throw new IllegalStateException("Main logger not initialized.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log a message
|
||||
*
|
||||
* @param level message level
|
||||
* @param msg message text
|
||||
*/
|
||||
public static void log(Level level, String msg)
|
||||
{
|
||||
if (enabled) {
|
||||
final long ms = System.currentTimeMillis() - start_ms;
|
||||
sysoMonitor.onMessageLogged(level, formatMessage(level, msg, null, ms));
|
||||
|
||||
if (main != null) {
|
||||
main.log(level, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log a message
|
||||
*
|
||||
* @param level message level
|
||||
* @param msg message text
|
||||
* @param t thrown exception
|
||||
*/
|
||||
public static void log(Level level, String msg, Throwable t)
|
||||
{
|
||||
if (enabled) {
|
||||
final long ms = System.currentTimeMillis() - start_ms;
|
||||
sysoMonitor.onMessageLogged(level, formatMessage(level, msg, t, ms));
|
||||
|
||||
if (main != null) {
|
||||
main.log(level, msg, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log FINE message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public static void f1(String msg)
|
||||
{
|
||||
if (staticLogging && ready()) main.f1(msg);
|
||||
log(Level.FINE, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log FINER message in main logger
|
||||
* Log FINER message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public static void f2(String msg)
|
||||
{
|
||||
if (staticLogging && ready()) main.f2(msg);
|
||||
log(Level.FINER, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log FINEST message in main logger
|
||||
* Log FINEST message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public static void f3(String msg)
|
||||
{
|
||||
if (staticLogging && ready()) main.f3(msg);
|
||||
log(Level.FINEST, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log INFO message in main logger
|
||||
* Log INFO message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public static void i(String msg)
|
||||
{
|
||||
if (staticLogging && ready()) main.i(msg);
|
||||
log(Level.INFO, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log WARNING message in main logger
|
||||
* Log WARNING message (less severe than ERROR)
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public static void w(String msg)
|
||||
{
|
||||
if (staticLogging && ready()) {
|
||||
main.w(msg);
|
||||
} else {
|
||||
System.err.println(msg);
|
||||
}
|
||||
log(Level.WARNING, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log ERROR message in main logger
|
||||
* Log ERROR message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public static void e(String msg)
|
||||
{
|
||||
if (staticLogging && ready()) {
|
||||
main.e(msg);
|
||||
} else {
|
||||
System.err.println(msg);
|
||||
}
|
||||
log(Level.SEVERE, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log EXCEPTION and ERROR message in main logger
|
||||
* Log THROWING message
|
||||
*
|
||||
* @param msg message
|
||||
* @param thrown thrown exception
|
||||
*/
|
||||
public static void e(String msg, Throwable thrown)
|
||||
{
|
||||
if (staticLogging && ready()) {
|
||||
main.e(msg, thrown);
|
||||
} else {
|
||||
System.err.println(msg);
|
||||
thrown.printStackTrace();
|
||||
}
|
||||
log(Level.SEVERE, msg, thrown);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log EXCEPTION in main logger
|
||||
* Log exception thrown
|
||||
*
|
||||
* @param thrown thrown exception
|
||||
*/
|
||||
public static void e(Throwable thrown)
|
||||
{
|
||||
if (staticLogging && ready()) {
|
||||
main.e(thrown);
|
||||
} else {
|
||||
thrown.printStackTrace();
|
||||
}
|
||||
log(Level.SEVERE, null, thrown);
|
||||
}
|
||||
|
||||
|
||||
public static void enable(boolean flag)
|
||||
{
|
||||
if (staticLogging && ready()) main.enable(flag);
|
||||
enabled = flag;
|
||||
}
|
||||
|
||||
|
||||
public static void setSysoutLevel(Level level)
|
||||
{
|
||||
sysoMonitor.setLevel(level);
|
||||
}
|
||||
|
||||
|
||||
public static void setLevel(Level level)
|
||||
{
|
||||
assertInited();
|
||||
|
||||
main.setLevel(level);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable / disable static log delegate methods
|
||||
* Get stack trace from throwable
|
||||
*
|
||||
* @param flag enable
|
||||
* @param t
|
||||
* @return trace
|
||||
*/
|
||||
public static void enableStaticLogging(boolean flag)
|
||||
public static String getStackTrace(Throwable t)
|
||||
{
|
||||
staticLogging = flag;
|
||||
}
|
||||
|
||||
private static HashMap<String, LogInstance> logs = new HashMap<>();
|
||||
private static LogInstance main = null;
|
||||
|
||||
|
||||
/**
|
||||
* Create a logger. If this is the first logger made, then it'll be made
|
||||
* available via the static methods.
|
||||
*
|
||||
* @param logName log name (used for filename, must be application-unique)
|
||||
* @param logsDir directory to store logs in
|
||||
* @param oldLogsCount number of old logs to keep, -1 for infinite, 0 for
|
||||
* none.
|
||||
* @return the created Log instance
|
||||
*/
|
||||
public static synchronized LogInstance create(String logName, File logsDir, int oldLogsCount)
|
||||
{
|
||||
if (logs.containsKey(logName)) return logs.get(logName);
|
||||
final LogInstance log = new LogInstance(logName, logsDir, oldLogsCount);
|
||||
if (main == null) main = log;
|
||||
logs.put(logName, log);
|
||||
|
||||
return log;
|
||||
final StringWriter sw = new StringWriter();
|
||||
final PrintWriter pw = new PrintWriter(sw, true);
|
||||
t.printStackTrace(pw);
|
||||
pw.flush();
|
||||
sw.flush();
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a logger. If this is the first logger made, then it'll be made
|
||||
* available via the static methods.<br>
|
||||
* Old logs will be kept.
|
||||
*
|
||||
* @param logName log name (used for filename, must be application-unique)
|
||||
* @param logsDir directory to store logs in
|
||||
* @return the created Log instance
|
||||
*/
|
||||
public static synchronized LogInstance create(String logName, File logsDir)
|
||||
static String formatMessage(Level level, String message, Throwable throwable, long start_ms)
|
||||
{
|
||||
if (logs.containsKey(logName)) return logs.get(logName);
|
||||
final LogInstance log = new LogInstance(logName, logsDir, -1);
|
||||
if (main == null) main = log;
|
||||
logs.put(logName, log);
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
|
||||
public int addMonitor(LogMonitor mon)
|
||||
{
|
||||
if (!ready()) throw new IllegalStateException("Main logger not initialized.");
|
||||
final String nl = System.getProperty("line.separator");
|
||||
|
||||
return main.addMonitor(mon);
|
||||
}
|
||||
|
||||
|
||||
public void removeMonitor(int id)
|
||||
{
|
||||
if (!ready()) throw new IllegalStateException("Main logger not initialized.");
|
||||
if (message.equals("\n")) {
|
||||
return nl;
|
||||
}
|
||||
|
||||
main.removeMonitor(id);
|
||||
if (message.charAt(0) == '\n') {
|
||||
message = nl + message.substring(1);
|
||||
}
|
||||
|
||||
final long time_ms = (System.currentTimeMillis() - start_ms);
|
||||
final double time_s = time_ms / 1000D;
|
||||
final String time = String.format("%6.2f ", time_s);
|
||||
final String time_blank = StringUtils.repeat(" ", time.length());
|
||||
|
||||
String prefix = "[ ? ]";
|
||||
|
||||
if (level == Level.FINE) {
|
||||
prefix = "[ # ] ";
|
||||
} else if (level == Level.FINER) {
|
||||
prefix = "[ - ] ";
|
||||
} else if (level == Level.FINEST) {
|
||||
prefix = "[ ] ";
|
||||
} else if (level == Level.INFO) {
|
||||
prefix = "[ i ] ";
|
||||
} else if (level == Level.SEVERE) {
|
||||
prefix = "[!E!] ";
|
||||
} else if (level == Level.WARNING) {
|
||||
prefix = "[!W!] ";
|
||||
}
|
||||
|
||||
message = time + prefix + message.replaceAll("\n", nl + time_blank + prefix) + nl;
|
||||
|
||||
if (throwable != null) {
|
||||
message += getStackTrace(throwable);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
@@ -237,10 +348,4 @@ public class Log {
|
||||
|
||||
return (enclosing == null ? "" : str(enclosing) + sep) + name;
|
||||
}
|
||||
|
||||
|
||||
public static boolean ready()
|
||||
{
|
||||
return main != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,424 +0,0 @@
|
||||
package mightypork.utils.logging;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
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 mightypork.utils.files.FileUtils;
|
||||
import mightypork.utils.string.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Static logger class.
|
||||
*
|
||||
* @author MightyPork
|
||||
* @copy (c) 2014
|
||||
*/
|
||||
public class LogInstance {
|
||||
|
||||
/** log file */
|
||||
private final File file;
|
||||
|
||||
/** Log name */
|
||||
private final String name;
|
||||
|
||||
/** Number of old logs to keep */
|
||||
private final int logs_to_keep;
|
||||
|
||||
/** Logs dir */
|
||||
private final File log_dir;
|
||||
|
||||
/** Logger instance. */
|
||||
private Logger logger;
|
||||
|
||||
/** Logging enabled */
|
||||
private boolean enabled = true;
|
||||
|
||||
private boolean sysout = true;
|
||||
|
||||
private int monitorId = 0;
|
||||
private final HashMap<Integer, LogMonitor> monitors = new HashMap<>();
|
||||
|
||||
private LogToSysoutMonitor sysoutMonitor;
|
||||
|
||||
private final long started_ms;
|
||||
|
||||
|
||||
/**
|
||||
* Log
|
||||
*
|
||||
* @param name log name
|
||||
* @param dir log directory
|
||||
* @param oldLogCount number of old log files to keep: -1 all, 0 none.
|
||||
*/
|
||||
public LogInstance(String name, File dir, int oldLogCount) {
|
||||
this.name = name;
|
||||
this.file = new File(dir, name + getSuffix());
|
||||
this.log_dir = dir;
|
||||
this.logs_to_keep = oldLogCount;
|
||||
this.started_ms = System.currentTimeMillis();
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare logs for logging
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
logger = Logger.getLogger(name);
|
||||
|
||||
cleanLoggingDirectory();
|
||||
|
||||
FileHandler handler = null;
|
||||
|
||||
try {
|
||||
handler = new FileHandler(file.getPath());
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException("Failed to init log", e);
|
||||
}
|
||||
|
||||
handler.setFormatter(new LogFormatter());
|
||||
logger.addHandler(handler);
|
||||
|
||||
enabled = true;
|
||||
|
||||
sysoutMonitor = new LogToSysoutMonitor();
|
||||
|
||||
addMonitor(sysoutMonitor);
|
||||
|
||||
logger.setUseParentHandlers(false);
|
||||
logger.setLevel(Level.ALL);
|
||||
final String stamp = (new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")).format(new Date());
|
||||
i("Logger \"" + name + "\" initialized.\n" + stamp);
|
||||
}
|
||||
|
||||
|
||||
private void cleanLoggingDirectory()
|
||||
{
|
||||
if (logs_to_keep == 0) return; // overwrite
|
||||
|
||||
// move old file
|
||||
for (final File f : FileUtils.listDirectory(file.getParentFile())) {
|
||||
if (!f.isFile()) continue;
|
||||
if (f.equals(file)) {
|
||||
|
||||
final Date d = new Date(f.lastModified());
|
||||
final String fbase = name + '_' + (new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss")).format(d);
|
||||
final String suff = getSuffix();
|
||||
String cntStr = "";
|
||||
File f2;
|
||||
|
||||
for (int cnt = 0; (f2 = new File(log_dir, fbase + cntStr + suff)).exists(); cntStr = "_" + (++cnt)) {}
|
||||
|
||||
f.renameTo(f2);
|
||||
}
|
||||
}
|
||||
|
||||
if (logs_to_keep == -1) return; // keep all
|
||||
|
||||
final List<File> oldLogs = FileUtils.listDirectory(log_dir, new FileFilter() {
|
||||
|
||||
@Override
|
||||
public boolean accept(File f)
|
||||
{
|
||||
if (f.isDirectory()) return false;
|
||||
if (!f.getName().endsWith(getSuffix())) return false;
|
||||
if (!f.getName().startsWith(name)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Collections.sort(oldLogs, new Comparator<File>() {
|
||||
|
||||
@Override
|
||||
public int compare(File o1, File o2)
|
||||
{
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 0; i < oldLogs.size() - logs_to_keep; i++) {
|
||||
oldLogs.get(i).delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add log monitor
|
||||
*
|
||||
* @param mon monitor
|
||||
* @return assigned ID
|
||||
*/
|
||||
public synchronized int addMonitor(LogMonitor mon)
|
||||
{
|
||||
final int id = monitorId;
|
||||
monitorId++;
|
||||
monitors.put(id, mon);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a monitor by ID
|
||||
*
|
||||
* @param id monitor ID
|
||||
*/
|
||||
public synchronized void removeMonitor(int id)
|
||||
{
|
||||
monitors.remove(id);
|
||||
}
|
||||
|
||||
|
||||
public void setSysoutLevel(Level level)
|
||||
{
|
||||
sysoutMonitor.setLevel(level);
|
||||
}
|
||||
|
||||
|
||||
public void setFileLevel(Level level)
|
||||
{
|
||||
logger.setLevel(level);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable logging.
|
||||
*
|
||||
* @param flag do enable logging
|
||||
*/
|
||||
public void enable(boolean flag)
|
||||
{
|
||||
enabled = flag;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable printing logs to sysout
|
||||
*
|
||||
* @param flag do enable logging
|
||||
*/
|
||||
public void enableSysout(boolean flag)
|
||||
{
|
||||
sysout = flag;
|
||||
sysoutMonitor.enable(sysout);
|
||||
}
|
||||
|
||||
|
||||
public void log(Level level, String msg)
|
||||
{
|
||||
if (enabled) {
|
||||
logger.log(level, msg);
|
||||
|
||||
final String fmt = formatMessage(level, msg, null);
|
||||
|
||||
for (final LogMonitor mon : monitors.values()) {
|
||||
mon.onMessageLogged(level, fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void log(Level level, String msg, Throwable t)
|
||||
{
|
||||
if (enabled) {
|
||||
logger.log(level, msg, t);
|
||||
|
||||
final String fmt = formatMessage(level, msg, t);
|
||||
|
||||
for (final LogMonitor mon : monitors.values()) {
|
||||
mon.onMessageLogged(level, fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log FINE message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public void f1(String msg)
|
||||
{
|
||||
log(Level.FINE, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log FINER message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public void f2(String msg)
|
||||
{
|
||||
log(Level.FINER, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log FINEST message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public void f3(String msg)
|
||||
{
|
||||
log(Level.FINEST, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log INFO message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public void i(String msg)
|
||||
{
|
||||
log(Level.INFO, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log WARNING message (less severe than ERROR)
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public void w(String msg)
|
||||
{
|
||||
log(Level.WARNING, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log ERROR message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public void e(String msg)
|
||||
{
|
||||
log(Level.SEVERE, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log THROWING message
|
||||
*
|
||||
* @param msg message
|
||||
* @param thrown thrown exception
|
||||
*/
|
||||
public void e(String msg, Throwable thrown)
|
||||
{
|
||||
log(Level.SEVERE, msg, thrown);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log exception thrown
|
||||
*
|
||||
* @param thrown thrown exception
|
||||
*/
|
||||
public void e(Throwable thrown)
|
||||
{
|
||||
log(Level.SEVERE, null, thrown);
|
||||
}
|
||||
|
||||
/**
|
||||
* PowerCraft Log file formatter.
|
||||
*
|
||||
* @author MightyPork
|
||||
* @copy (c) 2012
|
||||
*/
|
||||
private class LogFormatter extends Formatter {
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record)
|
||||
{
|
||||
return LogInstance.this.formatMessage(record.getLevel(), record.getMessage(), record.getThrown());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return log filename suffix (incl. dot)
|
||||
*/
|
||||
protected String getSuffix()
|
||||
{
|
||||
return ".log";
|
||||
}
|
||||
|
||||
|
||||
private String formatMessage(Level level, String message, Throwable throwable)
|
||||
{
|
||||
|
||||
final String nl = System.getProperty("line.separator");
|
||||
|
||||
if (message.equals("\n")) {
|
||||
return nl;
|
||||
}
|
||||
|
||||
if (message.charAt(0) == '\n') {
|
||||
message = nl + message.substring(1);
|
||||
}
|
||||
|
||||
final long time_ms = (System.currentTimeMillis() - started_ms);
|
||||
final double time_s = time_ms / 1000D;
|
||||
final String time = String.format("%6.2f ", time_s);
|
||||
final String time_blank = StringUtils.repeat(" ", time.length());
|
||||
|
||||
String prefix = "[ ? ]";
|
||||
|
||||
if (level == Level.FINE) {
|
||||
prefix = "[ # ] ";
|
||||
} else if (level == Level.FINER) {
|
||||
prefix = "[ - ] ";
|
||||
} else if (level == Level.FINEST) {
|
||||
prefix = "[ ] ";
|
||||
} else if (level == Level.INFO) {
|
||||
prefix = "[ i ] ";
|
||||
} else if (level == Level.SEVERE) {
|
||||
prefix = "[!E!] ";
|
||||
} else if (level == Level.WARNING) {
|
||||
prefix = "[!W!] ";
|
||||
}
|
||||
|
||||
message = time + prefix + message.replaceAll("\n", nl + time_blank + prefix) + nl;
|
||||
|
||||
if (throwable != null) {
|
||||
message += getStackTrace(throwable);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get stack trace from throwable
|
||||
*
|
||||
* @param t
|
||||
* @return trace
|
||||
*/
|
||||
private static String getStackTrace(Throwable t)
|
||||
{
|
||||
final StringWriter sw = new StringWriter();
|
||||
final PrintWriter pw = new PrintWriter(sw, true);
|
||||
t.printStackTrace(pw);
|
||||
pw.flush();
|
||||
sw.flush();
|
||||
return sw.toString();
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,14 @@ package mightypork.utils.logging;
|
||||
import java.util.logging.Level;
|
||||
|
||||
|
||||
/**
|
||||
* Log monitor, receives all logged messages
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface LogMonitor {
|
||||
|
||||
/**
|
||||
* Message logged;
|
||||
*
|
||||
* @param level message level
|
||||
* @param message message text, already formatted.
|
||||
*/
|
||||
void onMessageLogged(Level level, String message);
|
||||
|
||||
|
||||
void setLevel(Level level);
|
||||
|
||||
|
||||
void enable(boolean flag);
|
||||
|
||||
}
|
||||
|
||||
@@ -4,24 +4,11 @@ package mightypork.utils.logging;
|
||||
import java.util.logging.Level;
|
||||
|
||||
|
||||
public class LogToSysoutMonitor implements LogMonitor {
|
||||
|
||||
private boolean enabled = true;
|
||||
private Level accepted = Level.ALL;
|
||||
|
||||
|
||||
public void setLevel(Level level)
|
||||
{
|
||||
this.accepted = level;
|
||||
}
|
||||
|
||||
public class LogToSysoutMonitor extends BaseLogMonitor {
|
||||
|
||||
@Override
|
||||
public void onMessageLogged(Level level, String message)
|
||||
protected void logMessage(Level level, String message)
|
||||
{
|
||||
if (!enabled) return;
|
||||
if (accepted.intValue() > level.intValue()) return;
|
||||
|
||||
if (level == Level.SEVERE || level == Level.WARNING) {
|
||||
System.err.print(message);
|
||||
} else {
|
||||
@@ -29,10 +16,4 @@ public class LogToSysoutMonitor implements LogMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void enable(boolean enable)
|
||||
{
|
||||
this.enabled = enable;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package mightypork.utils.logging;
|
||||
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
|
||||
/**
|
||||
* Log interface
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface LogWriter {
|
||||
|
||||
/**
|
||||
* Prepare logs for logging
|
||||
*/
|
||||
void init();
|
||||
|
||||
|
||||
/**
|
||||
* Add log monitor
|
||||
*
|
||||
* @param mon monitor
|
||||
*/
|
||||
void addMonitor(LogMonitor mon);
|
||||
|
||||
|
||||
/**
|
||||
* Remove a monitor
|
||||
*
|
||||
* @param removed monitor to remove
|
||||
*/
|
||||
void removeMonitor(LogMonitor removed);
|
||||
|
||||
|
||||
/**
|
||||
* Set logging level
|
||||
*
|
||||
* @param level
|
||||
*/
|
||||
void setLevel(Level level);
|
||||
|
||||
|
||||
/**
|
||||
* Enable logging.
|
||||
*
|
||||
* @param flag do enable logging
|
||||
*/
|
||||
void enable(boolean flag);
|
||||
|
||||
|
||||
/**
|
||||
* Log a message
|
||||
*
|
||||
* @param level message level
|
||||
* @param msg message text
|
||||
*/
|
||||
void log(Level level, String msg);
|
||||
|
||||
|
||||
/**
|
||||
* Log a message
|
||||
*
|
||||
* @param level message level
|
||||
* @param msg message text
|
||||
* @param t thrown exception
|
||||
*/
|
||||
void log(Level level, String msg, Throwable t);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
package mightypork.utils.logging;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* Basic logger
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class SimpleLog implements LogWriter {
|
||||
|
||||
/**
|
||||
* Log file formatter.
|
||||
*/
|
||||
class LogFormatter extends Formatter {
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record)
|
||||
{
|
||||
return Log.formatMessage(record.getLevel(), record.getMessage(), record.getThrown(), started_ms);
|
||||
}
|
||||
}
|
||||
|
||||
/** Log file */
|
||||
private final File file;
|
||||
|
||||
/** Log name */
|
||||
private final String name;
|
||||
|
||||
/** Logger instance. */
|
||||
private Logger logger;
|
||||
|
||||
private boolean enabled = true;
|
||||
private final HashSet<LogMonitor> monitors = new HashSet<>();
|
||||
private final long started_ms;
|
||||
|
||||
|
||||
public SimpleLog(String name, File file) {
|
||||
this.name = name;
|
||||
this.file = file;
|
||||
this.started_ms = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
logger = Logger.getLogger(getName());
|
||||
|
||||
FileHandler handler = null;
|
||||
try {
|
||||
handler = new FileHandler(getFile().getPath());
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException("Failed to init log.", e);
|
||||
}
|
||||
|
||||
handler.setFormatter(new LogFormatter());
|
||||
logger.addHandler(handler);
|
||||
logger.setUseParentHandlers(false);
|
||||
logger.setLevel(Level.ALL);
|
||||
|
||||
printHeader();
|
||||
}
|
||||
|
||||
|
||||
protected void printHeader()
|
||||
{
|
||||
final String stamp = (new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")).format(new Date());
|
||||
i("Logger \"" + getName() + "\" initialized.\n" + stamp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add log monitor
|
||||
*
|
||||
* @param mon monitor
|
||||
*/
|
||||
@Override
|
||||
public synchronized void addMonitor(LogMonitor mon)
|
||||
{
|
||||
monitors.add(mon);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a monitor
|
||||
*
|
||||
* @param removed monitor to remove
|
||||
*/
|
||||
@Override
|
||||
public synchronized void removeMonitor(LogMonitor removed)
|
||||
{
|
||||
monitors.remove(removed);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setLevel(Level level)
|
||||
{
|
||||
logger.setLevel(level);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void enable(boolean flag)
|
||||
{
|
||||
enabled = flag;
|
||||
}
|
||||
|
||||
|
||||
public File getFile()
|
||||
{
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void log(Level level, String msg)
|
||||
{
|
||||
if (enabled) {
|
||||
logger.log(level, msg);
|
||||
|
||||
final String fmt = Log.formatMessage(level, msg, null, started_ms);
|
||||
|
||||
for (final LogMonitor mon : monitors) {
|
||||
mon.onMessageLogged(level, fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void log(Level level, String msg, Throwable t)
|
||||
{
|
||||
if (enabled) {
|
||||
logger.log(level, msg, t);
|
||||
|
||||
final String fmt = Log.formatMessage(level, msg, t, started_ms);
|
||||
|
||||
for (final LogMonitor mon : monitors) {
|
||||
mon.onMessageLogged(level, fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log FINE message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public void f1(String msg)
|
||||
{
|
||||
log(Level.FINE, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log FINER message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public void f2(String msg)
|
||||
{
|
||||
log(Level.FINER, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log FINEST message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public void f3(String msg)
|
||||
{
|
||||
log(Level.FINEST, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log INFO message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public void i(String msg)
|
||||
{
|
||||
log(Level.INFO, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log WARNING message (less severe than ERROR)
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public void w(String msg)
|
||||
{
|
||||
log(Level.WARNING, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log ERROR message
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public void e(String msg)
|
||||
{
|
||||
log(Level.SEVERE, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log THROWING message
|
||||
*
|
||||
* @param msg message
|
||||
* @param thrown thrown exception
|
||||
*/
|
||||
public void e(String msg, Throwable thrown)
|
||||
{
|
||||
log(Level.SEVERE, msg, thrown);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log exception thrown
|
||||
*
|
||||
* @param thrown thrown exception
|
||||
*/
|
||||
public void e(Throwable thrown)
|
||||
{
|
||||
log(Level.SEVERE, null, thrown);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -54,6 +54,7 @@ public class StringUtils {
|
||||
public static String toLastChar(String s, char c)
|
||||
{
|
||||
if (s == null) return null;
|
||||
if (s.lastIndexOf(c) == -1) return s;
|
||||
return s.substring(0, s.lastIndexOf(c));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user