Init
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
package fr.doap.llog;
|
||||
|
||||
public interface ILogger {
|
||||
|
||||
public void log(LogMsg aLogMsg);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package fr.doap.llog;
|
||||
|
||||
public class L {
|
||||
|
||||
static private L mL = new L();
|
||||
|
||||
static public LogMsg l(int aSeverity, Throwable aThrowable, String aTag, String aMsg, Object ... aArgs) {
|
||||
String lMsg = aMsg;
|
||||
if (aArgs != null && aArgs.length > 0) lMsg = String.format(aMsg, aArgs);
|
||||
LogMsg lLogMsg = new LogMsg(aSeverity, aThrowable, aTag, lMsg);
|
||||
mL.mLooper.post(lLogMsg);
|
||||
return lLogMsg;
|
||||
}
|
||||
|
||||
private LogLooper mLooper = new LogLooper();
|
||||
|
||||
private ILogger mLogger;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package fr.doap.llog;
|
||||
|
||||
public class LogLooper extends ThreadLooper {
|
||||
|
||||
public void post(LogMsg aLogMsg) {
|
||||
add(new LLMsg(aLogMsg));
|
||||
}
|
||||
|
||||
public class LLMsg implements WorkItem {
|
||||
public LLMsg(LogMsg aLogMsg) { mLogMsg = aLogMsg; }
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i=mLogMsg.getCallerIndex(); i<mLogMsg.mSTE.length; i++) {
|
||||
StackTraceElement lS = mLogMsg.mSTE[i];
|
||||
System.out.println(lS.getClassName() + "." + lS.getMethodName() + ": " + mLogMsg.mMessage + " (" + lS.getFileName() + ":" + lS.getLineNumber() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
private LogMsg mLogMsg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package fr.doap.llog;
|
||||
|
||||
public class LogMsg {
|
||||
public long mTime;
|
||||
public Throwable mThrowable;
|
||||
public Thread mCallerThread;
|
||||
|
||||
public String mMessage;
|
||||
public int mSeverity;
|
||||
public String mTag;
|
||||
|
||||
public StackTraceElement[] mSTE;
|
||||
|
||||
|
||||
public LogMsg(int aSeverity, Throwable aThrowable, String aTag, String aMsg) {
|
||||
mTime = System.currentTimeMillis();
|
||||
mThrowable = aThrowable;
|
||||
mCallerThread = Thread.currentThread();
|
||||
|
||||
mMessage = aMsg;
|
||||
mTag = aTag;
|
||||
mSeverity = aSeverity;
|
||||
|
||||
mSTE = Thread.currentThread().getStackTrace();
|
||||
}
|
||||
|
||||
public int getCallerIndex() {
|
||||
int lI = mSTE.length-1;
|
||||
while (!mSTE[lI].getClassName().startsWith("fr.doap.llog.") && lI>=0) lI--;
|
||||
return lI+1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package fr.doap.llog;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
public class ThreadLooper {
|
||||
|
||||
public interface WorkItem {
|
||||
void run();
|
||||
}
|
||||
|
||||
public void add(WorkItem aWorkItem) {
|
||||
if (mLooperThread == null) createThreadLooper();
|
||||
|
||||
Thread thread = Thread.currentThread();
|
||||
if (!mCallerThreads.contains(thread)&&(!thread.isDaemon())) addCallerThread(thread);
|
||||
|
||||
mMessageQueue.add(aWorkItem);
|
||||
if (!mFlushing) {
|
||||
synchronized (this) {
|
||||
notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onThreadInit() {}
|
||||
|
||||
protected void onBeforeFlush() {}
|
||||
|
||||
protected void onStartWaiting() {}
|
||||
|
||||
protected void onShutdownThread() {}
|
||||
|
||||
protected void onUncaughtException(Thread t, Throwable e) {
|
||||
/*
|
||||
L.e("Uncaught Exception '"+e+"' in thread '"+t.getName()+"' : flushing...");
|
||||
L.e("Uncaught Exception '"+e.getMessage()+"' in thread '"+t.getName()+"' : flushing...");
|
||||
L.e("Uncaught Exception '"+e.getLocalizedMessage()+"' in thread '"+t.getName()+"' : flushing...");
|
||||
*/
|
||||
System.out.println("Caller threads : "+ mCallerThreads);
|
||||
System.out.println("Removing "+t);
|
||||
mCallerThreads.remove(t);
|
||||
mLooperThread.interrupt();
|
||||
if (e.getCause() != null) System.out.println("Cause: "+e.getCause());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
protected synchronized void createThreadLooper() {
|
||||
mLooperThread = new Thread(new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
onThreadInit();
|
||||
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
flushAll();
|
||||
synchronized (ThreadLooper.this) {
|
||||
try {
|
||||
mFlushing = false;
|
||||
onStartWaiting();
|
||||
ThreadLooper.this.wait();
|
||||
} catch(InterruptedException e) {
|
||||
System.out.println("Interrupted");
|
||||
System.out.println("Caller threads: "+ mCallerThreads);
|
||||
if (mCallerThreads.isEmpty()) Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
flushAll();
|
||||
onShutdownThread();
|
||||
mLooperThread = null;
|
||||
}
|
||||
});
|
||||
mLooperThread.setName(getClass().getSimpleName()+"-"+hashCode());
|
||||
mLooperThread.start();
|
||||
}
|
||||
|
||||
private void flushAll() {
|
||||
if (!mFlushing) {
|
||||
mFlushing = true;
|
||||
onBeforeFlush();
|
||||
while (!mMessageQueue.isEmpty()) {
|
||||
WorkItem lWorkItem = mMessageQueue.poll();
|
||||
lWorkItem.run();
|
||||
}
|
||||
}
|
||||
mFlushing = false;
|
||||
}
|
||||
|
||||
private void addCallerThread(Thread t) {
|
||||
mCallerThreads.add(t);
|
||||
new CustomUncaughtExceptionHandler(t);
|
||||
Thread join = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
t.join();
|
||||
} catch (InterruptedException e) {}
|
||||
mCallerThreads.remove(t);
|
||||
if ((mLooperThread != null)&&!mLooperThread.isInterrupted()) mLooperThread.interrupt();
|
||||
}
|
||||
|
||||
};
|
||||
join.setName("Finalizer-"+getClass().getSimpleName()+"-"+hashCode());
|
||||
join.start();
|
||||
}
|
||||
|
||||
private Thread mLooperThread;
|
||||
private ConcurrentLinkedQueue<WorkItem> mMessageQueue = new ConcurrentLinkedQueue<>();
|
||||
private Set<Thread> mCallerThreads = new HashSet<>();
|
||||
private boolean mFlushing = false;
|
||||
|
||||
|
||||
/**
|
||||
* Classe pour les UncaughtExceptionHandler
|
||||
*/
|
||||
private class CustomUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
public CustomUncaughtExceptionHandler(Thread t) {
|
||||
mUncaughtExceptionHandler = t.getUncaughtExceptionHandler();
|
||||
t.setUncaughtExceptionHandler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
onUncaughtException(t, e);
|
||||
flushAll();
|
||||
mCallerThreads.remove(t);
|
||||
if ((mLooperThread != null)&&!mLooperThread.isInterrupted()) mLooperThread.interrupt();
|
||||
if (mUncaughtExceptionHandler != null) mUncaughtExceptionHandler.uncaughtException(t, e);
|
||||
}
|
||||
|
||||
private Thread.UncaughtExceptionHandler mUncaughtExceptionHandler;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package fr.doap.test;
|
||||
|
||||
import fr.doap.llog.L;
|
||||
|
||||
public class Test {
|
||||
|
||||
public static void main(String[] args) {
|
||||
L.l(1, null, "test", "Message sans format");
|
||||
test1();
|
||||
}
|
||||
|
||||
protected static void test1() {
|
||||
L.l(1, null, "test", "Message avec format: %s", "toto");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user