package com.o3dr.android.client.utils; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.util.Log; import com.o3dr.android.client.BuildConfig; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; import timber.log.Timber; /** * Timber Tree to log specific log levels to a file */ public class LogToFileTree extends Timber.DebugTree { private static final SimpleDateFormat LOG_DATE_FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US); private static final SimpleDateFormat FILE_DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd_HH_mm", Locale.US); private final LinkedBlockingQueue<String> logQueue = new LinkedBlockingQueue<>(); private PrintStream logOutputFile; private Thread dequeueThread; private final AtomicBoolean isRunning = new AtomicBoolean(false); private final Date date = new Date(); @Override protected void log(int priority, String tag, String message, Throwable t) { super.log(priority, tag, message, t); if (isLoggableToFile(priority)) { String logOutput = getLogMessage(priority, tag, message); logQueue.add(logOutput); } } private boolean isLoggableToFile(int priority) { return priority >= BuildConfig.LOG_FILE_LEVEL; } private String getLogMessage(int priority, String tag, String message) { String priorityShort = getPriorityString(priority); date.setTime(System.currentTimeMillis()); return String.format("%s %s/%s : %s", LOG_DATE_FORMAT.format(date), priorityShort, tag, message); } private String getPriorityString(int priority) { String priorityString = null; switch (priority) { case Log.ASSERT: priorityString = "ASSERT"; break; case Log.ERROR: priorityString = "E"; break; case Log.WARN: priorityString = "W"; break; case Log.INFO: priorityString = "I"; break; case Log.DEBUG: priorityString = "D"; break; case Log.VERBOSE: priorityString = "V"; break; default: priorityString = ""; break; } return priorityString; } public void createFileStartLogging(final Context context) { if (dequeueThread != null && dequeueThread.isAlive()) { stopLoggingThread(); } dequeueThread = new Thread(new Runnable() { public void run() { PackageInfo pInfo; String version = ""; try { pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); version = pInfo.versionName; } catch (PackageManager.NameNotFoundException e) { Timber.w("Failed to get package info"); } File rootDir = context.getExternalFilesDir(null); File dir = new File(rootDir, "/log_cat/"); dir.mkdirs(); String fileName = String.format("%s_%s.log", version, FILE_DATE_FORMAT.format(new Date())); File logFile = new File(dir, fileName); try { logOutputFile = new PrintStream(new FileOutputStream(logFile, true)); while (isRunning.get()) { try { String message = logQueue.take(); logOutputFile.println(message); } catch (InterruptedException e) { Timber.w("Failed to receive message from logQueue"); } } } catch (IOException e) { Timber.w("Failed to open file"); } finally { isRunning.set(false); if (logOutputFile != null) { logOutputFile.close(); } } } }); isRunning.set(true); dequeueThread.start(); } public void stopLoggingThread() { if (dequeueThread != null) { isRunning.set(false); dequeueThread.interrupt(); dequeueThread = null; } } }