package com.samknows.libcore; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import com.samknows.measurement.SKApplication; import com.samknows.measurement.util.OtherUtils; import com.samknows.measurement.util.TimeUtils; import android.util.Log; public class SKAndroidLogger { private static File folder; private static final String ERROR = "Error"; private static final String WARNING = "Warning"; private static final String DEBUG = "Debug"; // This must be turned OFF for production builds! private static final boolean LOG_TO_FILE = false; private static void appendLog(String severity, String tag, String text) { Log.d("SKLogger - appendLog", tag + ":" + text); if (LOG_TO_FILE) { // This MUST be synchronized, as multiple threads might try to write at once! synchronized (SKAndroidLogger.class) { File logFile = new File(folder, "log.file"); if (!logFile.exists()) { try { boolean bRes = logFile.createNewFile(); SKPorting.sAssert(bRes); } catch (IOException e) { SKPorting.sAssert(false); } } try { // BufferedWriter for performance, true to set append to file flag BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); buf.append(TimeUtils.logString(System.currentTimeMillis())).append(" : "); buf.append(severity + " : "); buf.append(tag).append(" : "); buf.append(text); buf.newLine(); buf.close(); } catch (IOException e) { SKPorting.sAssert(false); } } } } private static String getStackTrace(Throwable t) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); return sw.toString(); } public static void setStorageFolder(File f) { // IGNORE the supplied folder, as it is in the CACHE area ... unless we have an exception! try { File storage = android.os.Environment.getExternalStorageDirectory(); String subFolderName = SKApplication.getAppInstance().getAppName(); File storageSubFolder = new File(storage, subFolderName); if (LOG_TO_FILE == true) { // Only make the folder, if we have logging enabled! //noinspection ResultOfMethodCallIgnored storageSubFolder.mkdir(); } folder = storageSubFolder; } catch (Exception e) { SKPorting.sAssert(false); folder = f; } // File writeHere = new File(storageSubFolder, fileName); // folder = f; } // This can dump-out a string longer than the build-in limit to Log.d! public static void d(String tag, String message) { final int chunkLength = 4000; if (message.length() > chunkLength) { final int chunkCount = message.length() / chunkLength; // integer division for (int i = 0; i <= chunkCount; i++) { try { int offset = i * chunkLength; String theChunk = message.substring(offset); if (theChunk.length() > chunkLength) { theChunk = theChunk.substring(0, 4000); } Log.d("", theChunk); } catch (IndexOutOfBoundsException e) { sAssert(SKAndroidLogger.class, false); } } appendLog(DEBUG, tag, message); return; } Log.d(tag, message); appendLog(DEBUG, tag, message); } public static void d(Object parent, String message) { Log.d(parent.getClass().getName(), message); appendLog(DEBUG, parent.getClass().getName(), message); } public static void d(Class clazz, String message) { Log.d(clazz.getName(), message); appendLog(DEBUG, clazz.getName(), message); } public static void e(String tag, String message) { Log.e(tag, message); appendLog(ERROR, tag, message); sAssert(false); } public static void e(Class clazz, String message) { Log.e(clazz.getName(), message); appendLog(ERROR, clazz.getName(), message); sAssert(clazz, false); } public static void e(Object parent, String message, Throwable t) { Log.e(parent.getClass().getName(), message, t); appendLog(ERROR, parent.getClass().getName(), message + " " + t.getMessage() + " " + getStackTrace(t)); sAssert(parent.getClass(), false); } public static void e(Object parent, String message) { Log.e(parent.getClass().getName(), message); appendLog(ERROR, parent.getClass().getName(), message); sAssert(parent.getClass(), false); } // If debugging, you should set a breakpoint here to trap all assertions! private static void sInternalCalledOnAssert() { } public static void sAssert(Class clazz, String message, final boolean check) { if (check == false) { if (message.length() > 0) { Log.e(clazz.getName(), "sAssertFailed (" + message + "): you can trap with a breakpoint in " + SKAndroidLogger.class.getName()); } else { Log.e(clazz.getName(), "sAssertFailed: you can trap with a breakpoint in " + SKAndroidLogger.class.getName()); } sInternalCalledOnAssert(); } } public static void sAssert(Class clazz, final boolean check) { sAssert(clazz, "", check); } public static void sAssert(String message, final boolean check) { if (check == false) { if ( (SKApplication.getAppInstance() == null && BuildConfig.DEBUG) || (OtherUtils.isDebuggable(SKApplication.getAppInstance().getApplicationContext())) ) { StackTraceElement[] elements = Thread.currentThread().getStackTrace(); String where = "?"; if (elements.length >= 4) { where = elements[3].toString(); } if (message.length() > 0) { Log.e("SKLOGGER", "sAssertFailed (" + message + "): you can trap with a breakpoint in " + where); } else { Log.e("SKLOGGER", "sAssertFailed: you can trap with a breakpoint in " + where); } } sInternalCalledOnAssert(); } } public static void sAssert(final boolean check) { if (check == false) { if ( (SKApplication.getAppInstance() == null && BuildConfig.DEBUG) || (OtherUtils.isDebuggable(SKApplication.getAppInstance().getApplicationContext())) ) { StackTraceElement[] elements = Thread.currentThread().getStackTrace(); String where = "?"; if (elements.length >= 4) { where = elements[3].toString(); } Log.e("SKLOGGER", "sAssertFailed: you can trap with a breakpoint in " + where); } sInternalCalledOnAssert(); } } public static void sAssertResourcesNotFoundExceptionNotRobolectric(Exception e) { boolean bIgnore = false; for (StackTraceElement item : e.getStackTrace()) { String className = item.getClassName(); if (className.startsWith("org.robolectric")) { return; } } SKPorting.sAssert(false); } }