diff --git a/build.gradle b/build.gradle index 76cd99ae..8d66a269 100644 --- a/build.gradle +++ b/build.gradle @@ -26,6 +26,7 @@ dependencies { compile 'com.google.code.gson:gson:2.8.0' compile 'org.mindrot:jbcrypt:0.3m' compile 'com.google.guava:guava:20.0' + compile 'com.annimon:stream:1.1.4' androidTestCompile 'com.android.support.test:rules:0.5' } diff --git a/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java b/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java index 659c0645..8244242b 100644 --- a/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java +++ b/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java @@ -9,6 +9,9 @@ import android.preference.PreferenceManager; import android.text.TextUtils; import android.util.Log; +import com.annimon.stream.Stream; +import com.google.common.base.Charsets; +import com.google.common.io.Files; import com.nutomic.syncthingandroid.BuildConfig; import java.io.BufferedReader; @@ -30,29 +33,22 @@ import eu.chainfire.libsuperuser.Shell; public class SyncthingRunnable implements Runnable { private static final String TAG = "SyncthingRunnable"; - private static final String TAG_NATIVE = "SyncthingNativeCode"; - private static final String TAG_NICE = "SyncthingRunnableIoNice"; - private static final String TAG_KILL = "SyncthingRunnableKill"; - public static final String UNIT_TEST_PATH = "was running"; - /** * Path to the native, integrated syncthing binary, relative to the data folder */ public static final String BINARY_NAME = "lib/libsyncthing.so"; + private static final int LOG_FILE_MAX_LINES = 1000; private static final AtomicReference mSyncthing = new AtomicReference<>(); - private final Context mContext; - private final String mSyncthingBinary; - private String[] mCommand; - private String mErrorLog; + private final File mLogFile; public enum Command { generate, // Generate keys, a config file and immediately exit. @@ -68,6 +64,7 @@ public class SyncthingRunnable implements Runnable { public SyncthingRunnable(Context context, Command command) { mContext = context; mSyncthingBinary = mContext.getApplicationInfo().dataDir + "/" + BINARY_NAME; + mLogFile = new File(mContext.getExternalFilesDir(null), "syncthing.log"); switch (command) { case generate: mCommand = new String[]{ mSyncthingBinary, "-generate", mContext.getFilesDir().toString() }; @@ -92,10 +89,12 @@ public class SyncthingRunnable implements Runnable { mContext = context; mSyncthingBinary = mContext.getApplicationInfo().dataDir + "/" + BINARY_NAME; mCommand = manualCommand; + mLogFile = new File(mContext.getExternalFilesDir(null), "syncthing.log"); } @Override public void run() { + trimLogFile(); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); int ret; // Make sure Syncthing is executable @@ -327,14 +326,16 @@ public class SyncthingRunnable implements Runnable { private Thread log(final InputStream is, final int priority, final boolean saveLog) { Thread t = new Thread(() -> { try { - InputStreamReader isr = new InputStreamReader(is, "UTF-8"); + InputStreamReader isr = new InputStreamReader(is, Charsets.UTF_8); BufferedReader br = new BufferedReader(isr); String line; while ((line = br.readLine()) != null) { Log.println(priority, TAG_NATIVE, line); - if (saveLog) + if (saveLog) { mErrorLog += line + "\n"; + Files.append(line + "\n", mLogFile, Charsets.UTF_8); + } } } catch (IOException e) { Log.w(TAG, "Failed to read Syncthing's command line output", e); @@ -344,4 +345,18 @@ public class SyncthingRunnable implements Runnable { return t; } + /** + * Only keep last {@link #LOG_FILE_MAX_LINES} lines in log file, to avoid bloat. + */ + private void trimLogFile() { + try { + String lines = Stream.of(Files.readLines(mLogFile, Charsets.UTF_8)) + .limit(LOG_FILE_MAX_LINES) + .reduce("", (a, b) -> a + b + "\n"); + Files.write(lines, mLogFile, Charsets.UTF_8); + } catch (IOException e) { + Log.w(TAG, "Failed to trim log file", e); + } + } + }