Enhance Log
This commit is contained in:
1 parent
6c200bfbf5
commit
f2588cc71a
4 files changed
+219
-21
No files matched your search
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.util;
|
||||
|
||||
import android.os.Environment;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Something about this app
|
||||
*/
|
||||
public final class AppConfig {
|
||||
|
||||
private static final String APP_FOLDER_NAME = "EhViewer";
|
||||
|
||||
public static @Nullable File getAppFolder() {
|
||||
if (Environment.getExternalStorageState()
|
||||
.equals(android.os.Environment.MEDIA_MOUNTED)) {
|
||||
return new File(Environment.getExternalStorageDirectory(), APP_FOLDER_NAME);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static @Nullable File getFileInAppFolder(String filename) {
|
||||
File appFolder = getAppFolder();
|
||||
if (appFolder != null) {
|
||||
return new File(appFolder, filename);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-1
@@ -15,5 +15,23 @@
|
||||
|
||||
package com.hippo.util;
|
||||
|
||||
public final class Storage {
|
||||
import java.io.File;
|
||||
|
||||
public final class FileUtils {
|
||||
|
||||
public static boolean ensureFile(File file) {
|
||||
return file != null && (!file.exists() || file.isFile());
|
||||
}
|
||||
|
||||
public static boolean ensureDirectory(File file) {
|
||||
if (file != null) {
|
||||
if (file.exists()) {
|
||||
return file.isDirectory();
|
||||
} else {
|
||||
return file.mkdirs();
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
package com.hippo.util;
|
||||
|
||||
import android.os.Looper;
|
||||
import android.os.Process;
|
||||
|
||||
import com.hippo.ehviewer.BuildConfig;
|
||||
@@ -23,8 +22,11 @@ import com.hippo.ehviewer.BuildConfig;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Log {
|
||||
@@ -33,14 +35,20 @@ public class Log {
|
||||
|
||||
private static final String NO_MESSAGE = "No Message";
|
||||
|
||||
private static final SaveLogThreadPool mSaveLogThreadPool;
|
||||
private static final Pool<SaveMsgTask> mSaveLogTaskPool;
|
||||
private static final SaveLogThreadExecutor sSaveLogThreadPool;
|
||||
private static final Pool<SaveMsgTask> sSaveLogTaskPool;
|
||||
|
||||
private static final File sLogFile = new File("/sdcard/EhViewer/log.log"); // TODO
|
||||
private static final DateFormat sDataFormat;
|
||||
|
||||
private static final File sLogFile;
|
||||
private static final boolean sSupportSaveLog;
|
||||
|
||||
static {
|
||||
mSaveLogThreadPool = new SaveLogThreadPool();
|
||||
mSaveLogTaskPool = new Pool<>(10);
|
||||
sSaveLogThreadPool = new SaveLogThreadExecutor();
|
||||
sSaveLogTaskPool = new Pool<>(10);
|
||||
sDataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.ENGLISH);
|
||||
sLogFile = AppConfig.getFileInAppFolder("ehviewer.log");
|
||||
sSupportSaveLog = FileUtils.ensureFile(sLogFile);
|
||||
}
|
||||
|
||||
private static String avoidNull(String str) {
|
||||
@@ -56,24 +64,27 @@ public class Log {
|
||||
}
|
||||
|
||||
private static void appendSaveLogTask(long time, String msg, Throwable tr) {
|
||||
SaveMsgTask task = mSaveLogTaskPool.obtain();
|
||||
if (!sSupportSaveLog) {
|
||||
return;
|
||||
}
|
||||
|
||||
SaveMsgTask task = sSaveLogTaskPool.obtain();
|
||||
if (task == null) {
|
||||
task = new SaveMsgTask();
|
||||
}
|
||||
task.setParams(time, msg, tr);
|
||||
|
||||
try {
|
||||
mSaveLogThreadPool.execute(task);
|
||||
sSaveLogThreadPool.execute(task);
|
||||
} catch (Throwable t) {
|
||||
Log.e("Get error when save message to file", t);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Need a better serial thread executor
|
||||
private static class SaveLogThreadPool extends ThreadPoolExecutor {
|
||||
private static class SaveLogThreadExecutor extends SerialThreadExecutor {
|
||||
|
||||
public SaveLogThreadPool() {
|
||||
super(0, 1, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
|
||||
public SaveLogThreadExecutor() {
|
||||
super(10L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
|
||||
new PriorityThreadFactory("SaveLog", Process.THREAD_PRIORITY_BACKGROUND));
|
||||
}
|
||||
|
||||
@@ -81,7 +92,7 @@ public class Log {
|
||||
if (r instanceof SaveMsgTask) {
|
||||
SaveMsgTask task = (SaveMsgTask) r;
|
||||
task.clear();
|
||||
mSaveLogTaskPool.recycle(task);
|
||||
sSaveLogTaskPool.recycle(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,15 +115,13 @@ public class Log {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
Log.d("MainLooper thread is " + Looper.getMainLooper().getThread().toString());
|
||||
Log.d("This thread is " + Thread.currentThread().toString());
|
||||
|
||||
FileWriter fw = null;
|
||||
try {
|
||||
fw = new FileWriter(sLogFile, true);
|
||||
fw.append(Long.toString(mTime)).append(" : ").append(mMsg).append("\n")
|
||||
.append(Log.getStackTraceString(mTr));
|
||||
fw.append(sDataFormat.format(new Date(mTime))).append(" ").append(mMsg).append("\n");
|
||||
if (mTr != null) {
|
||||
fw.append(Log.getStackTraceString(mTr)).append("\n");
|
||||
}
|
||||
fw.flush(); // TODO Only do flush when the thread is about to close
|
||||
} catch (IOException e) {
|
||||
Log.e("Get error when save message to file", e);
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.util;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class SerialThreadExecutor implements Executor, Runnable {
|
||||
|
||||
private long mKeepAliveTime;
|
||||
private BlockingQueue<Runnable> mWorkQueue;
|
||||
private ThreadFactory mThreadFactory;
|
||||
|
||||
private transient Thread mThread;
|
||||
|
||||
private final Lock mThreadLock = new ReentrantLock();
|
||||
private final Object mWaitLock = new Object();
|
||||
|
||||
public SerialThreadExecutor(long keepAliveTime, TimeUnit unit,
|
||||
BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
|
||||
mKeepAliveTime = unit.toMillis(keepAliveTime);
|
||||
mWorkQueue = workQueue;
|
||||
mThreadFactory = threadFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(@NonNull Runnable command) {
|
||||
try {
|
||||
mWorkQueue.put(command);
|
||||
ensureThread();
|
||||
} catch (Exception e) {
|
||||
putFailed(command, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureThread() {
|
||||
mThreadLock.lock();
|
||||
if (mThread == null) {
|
||||
mThread = mThreadFactory.newThread(this);
|
||||
mThread.start();
|
||||
} else {
|
||||
synchronized (mWaitLock) {
|
||||
mWaitLock.notifyAll();
|
||||
}
|
||||
}
|
||||
mThreadLock.unlock();
|
||||
}
|
||||
|
||||
protected void putFailed(@NonNull Runnable command, @NonNull Exception e) {
|
||||
}
|
||||
|
||||
protected void beforeExecute(Thread t, Runnable r) {
|
||||
}
|
||||
|
||||
protected void afterExecute(Runnable r, Throwable t) {
|
||||
}
|
||||
|
||||
protected void beforeExcute() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean hasWait = false;
|
||||
|
||||
for (;;) {
|
||||
mThreadLock.lock();
|
||||
|
||||
if (mWorkQueue.isEmpty()) {
|
||||
if (hasWait) {
|
||||
mThread = null;
|
||||
mThreadLock.unlock();
|
||||
// Have waitted enough time
|
||||
break;
|
||||
} else {
|
||||
hasWait = true;
|
||||
synchronized (mWaitLock) {
|
||||
mThreadLock.unlock();
|
||||
try {
|
||||
mWaitLock.wait(mKeepAliveTime);
|
||||
} catch (InterruptedException e) {
|
||||
// Empty
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mThreadLock.unlock();
|
||||
}
|
||||
|
||||
hasWait = false;
|
||||
Runnable runnable = mWorkQueue.poll();
|
||||
if (runnable != null) {
|
||||
beforeExecute(mThread, runnable);
|
||||
Throwable throwable = null;
|
||||
try {
|
||||
runnable.run();
|
||||
} catch (Throwable tr) {
|
||||
throwable = tr;
|
||||
}
|
||||
afterExecute(runnable, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user