This commit is contained in:
2021-02-10 20:54:19 +01:00
commit 63290cd3a2
11 changed files with 556 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
package fr.doap.llog;
public interface ILogger {
public void log(LogMsg aLogMsg);
}
+18
View File
@@ -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;
}
+22
View File
@@ -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;
}
}
+32
View File
@@ -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;
}
}
+15
View File
@@ -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");
}
}