Save logs to disk.

This commit is contained in:
akwizgran
2018-10-08 11:12:15 +01:00
parent ab682c82a3
commit 61407c3e06
8 changed files with 183 additions and 5 deletions

View File

@@ -46,6 +46,7 @@ import org.briarproject.briar.api.feed.FeedManager;
import org.briarproject.briar.api.forum.ForumManager;
import org.briarproject.briar.api.forum.ForumSharingManager;
import org.briarproject.briar.api.introduction.IntroductionManager;
import org.briarproject.briar.api.logging.PersistentLogManager;
import org.briarproject.briar.api.messaging.MessagingManager;
import org.briarproject.briar.api.messaging.PrivateMessageFactory;
import org.briarproject.briar.api.privategroup.GroupMessageFactory;
@@ -56,6 +57,7 @@ import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager
import org.briarproject.briar.api.test.TestDataCreator;
import java.util.concurrent.Executor;
import java.util.logging.Formatter;
import javax.inject.Singleton;
@@ -165,6 +167,10 @@ public interface AndroidComponent
FeatureFlags featureFlags();
PersistentLogManager persistentLogManager();
Formatter formatter();
void inject(SignInReminderReceiver briarService);
void inject(BriarService briarService);

View File

@@ -27,8 +27,12 @@ import org.briarproject.briar.android.reporting.BriarReportPrimer;
import org.briarproject.briar.android.reporting.BriarReportSenderFactory;
import org.briarproject.briar.android.reporting.DevReportActivity;
import org.briarproject.briar.android.util.UiUtils;
import org.briarproject.briar.api.logging.PersistentLogManager;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
@@ -36,6 +40,7 @@ import java.util.logging.Logger;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.acra.ReportField.ANDROID_VERSION;
import static org.acra.ReportField.APP_VERSION_CODE;
@@ -54,6 +59,7 @@ import static org.acra.ReportField.REPORT_ID;
import static org.acra.ReportField.STACK_TRACE;
import static org.acra.ReportField.USER_APP_START_DATE;
import static org.acra.ReportField.USER_CRASH_DATE;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
@ReportsCrashes(
@@ -120,9 +126,22 @@ public class BriarApplicationImpl extends Application
rootLogger.addHandler(logHandler);
rootLogger.setLevel(IS_DEBUG_BUILD ? FINE : INFO);
applicationComponent = createApplicationComponent();
PersistentLogManager logManager =
applicationComponent.persistentLogManager();
Formatter formatter = applicationComponent.formatter();
try {
File logDir = getDir("log", MODE_PRIVATE);
Handler handler = logManager.createLogHandler(logDir);
handler.setFormatter(formatter);
rootLogger.addHandler(handler);
} catch (IOException e) {
logException(LOG, WARNING, e);
}
LOG.info("Created");
applicationComponent = createApplicationComponent();
EmojiManager.install(new GoogleEmojiProvider());
}

View File

@@ -15,10 +15,12 @@ import org.acra.builder.ReportBuilder;
import org.acra.builder.ReportPrimer;
import org.briarproject.bramble.api.Pair;
import org.briarproject.briar.BuildConfig;
import org.briarproject.briar.android.AndroidComponent;
import org.briarproject.briar.android.BriarApplication;
import org.briarproject.briar.android.logging.BriefLogFormatter;
import org.briarproject.briar.api.logging.PersistentLogManager;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
@@ -37,6 +39,7 @@ import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE;
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
import static android.content.Context.ACTIVITY_SERVICE;
import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.content.Context.MODE_PRIVATE;
import static android.content.Context.WIFI_P2P_SERVICE;
import static android.content.Context.WIFI_SERVICE;
import static android.net.ConnectivityManager.TYPE_MOBILE;
@@ -81,13 +84,28 @@ public class BriarReportPrimer implements ReportPrimer {
// Log
BriarApplication app =
(BriarApplication) ctx.getApplicationContext();
AndroidComponent appComponent = app.getApplicationComponent();
PersistentLogManager logManager =
appComponent.persistentLogManager();
Formatter formatter = appComponent.formatter();
StringBuilder sb = new StringBuilder();
Formatter formatter = new BriefLogFormatter();
for (LogRecord record : app.getRecentLogRecords()) {
sb.append(formatter.format(record)).append('\n');
sb.append(formatter.format(record));
}
customData.put("Log", sb.toString());
sb = new StringBuilder();
try {
File logDir = ctx.getDir("log", MODE_PRIVATE);
for (String line : logManager.getPersistedLog(logDir)) {
sb.append(line).append('\n');
}
} catch (IOException e) {
sb.append("Could not recover persisted log: ").append(e);
}
customData.put("Persisted log", sb.toString());
// System memory
Object o = ctx.getSystemService(ACTIVITY_SERVICE);
ActivityManager am = (ActivityManager) o;

View File

@@ -0,0 +1,16 @@
package org.briarproject.briar.api.logging;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.logging.Handler;
@NotNullByDefault
public interface PersistentLogManager {
Handler createLogHandler(File dir) throws IOException;
Collection<String> getPersistedLog(File dir) throws IOException;
}

View File

@@ -6,6 +6,7 @@ import org.briarproject.briar.feed.DnsModule;
import org.briarproject.briar.feed.FeedModule;
import org.briarproject.briar.forum.ForumModule;
import org.briarproject.briar.introduction.IntroductionModule;
import org.briarproject.briar.logging.LoggingModule;
import org.briarproject.briar.messaging.MessagingModule;
import org.briarproject.briar.privategroup.PrivateGroupModule;
import org.briarproject.briar.privategroup.invitation.GroupInvitationModule;
@@ -22,6 +23,7 @@ import dagger.Module;
ForumModule.class,
GroupInvitationModule.class,
IntroductionModule.class,
LoggingModule.class,
MessagingModule.class,
PrivateGroupModule.class,
SharingModule.class,

View File

@@ -1,4 +1,4 @@
package org.briarproject.briar.android.logging;
package org.briarproject.briar.logging;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -47,6 +47,7 @@ public class BriefLogFormatter extends Formatter {
sb.append('\n');
appendThrowable(sb, t);
}
sb.append('\n');
return sb.toString();
}

View File

@@ -0,0 +1,23 @@
package org.briarproject.briar.logging;
import org.briarproject.briar.api.logging.PersistentLogManager;
import java.util.logging.Formatter;
import dagger.Module;
import dagger.Provides;
@Module
public class LoggingModule {
@Provides
Formatter provideFormatter() {
return new BriefLogFormatter();
}
@Provides
PersistentLogManager providePersistentLogManager(
PersistentLogManagerImpl logManager) {
return logManager;
}
}

View File

@@ -0,0 +1,93 @@
package org.briarproject.briar.logging;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.Scheduler;
import org.briarproject.briar.api.logging.PersistentLogManager;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Logger;
import java.util.logging.StreamHandler;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
import static java.util.Collections.emptyList;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
@ThreadSafe
@NotNullByDefault
class PersistentLogManagerImpl implements PersistentLogManager {
private static final Logger LOG =
Logger.getLogger(PersistentLogManagerImpl.class.getName());
private static final String LOG_FILE = "briar.log";
private static final String OLD_LOG_FILE = "briar.log.old";
private static final long FLUSH_INTERVAL_MS = MINUTES.toMillis(5);
private final ScheduledExecutorService scheduler;
private final Executor ioExecutor;
private final ShutdownManager shutdownManager;
private final Formatter formatter;
@Inject
PersistentLogManagerImpl(@Scheduler ScheduledExecutorService scheduler,
@IoExecutor Executor ioExecutor, ShutdownManager shutdownManager,
Formatter formatter) {
this.scheduler = scheduler;
this.ioExecutor = ioExecutor;
this.shutdownManager = shutdownManager;
this.formatter = formatter;
}
@Override
public Handler createLogHandler(File dir) throws IOException {
File logFile = new File(dir, LOG_FILE);
File oldLogFile = new File(dir, OLD_LOG_FILE);
if (oldLogFile.exists() && !oldLogFile.delete())
LOG.warning("Failed to delete old log file");
if (logFile.exists() && !logFile.renameTo(oldLogFile))
LOG.warning("Failed to rename log file");
try {
OutputStream out = new FileOutputStream(logFile);
StreamHandler handler = new StreamHandler(out, formatter);
scheduler.scheduleWithFixedDelay(() ->
ioExecutor.execute(handler::flush),
FLUSH_INTERVAL_MS, FLUSH_INTERVAL_MS, MILLISECONDS);
shutdownManager.addShutdownHook(handler::flush);
return handler;
} catch (SecurityException e) {
throw new IOException(e);
}
}
@Override
public Collection<String> getPersistedLog(File dir) throws IOException {
File oldLogFile = new File(dir, OLD_LOG_FILE);
if (oldLogFile.exists()) {
LOG.info("Reading old log file");
List<String> lines = new ArrayList<>();
Scanner s = new Scanner(oldLogFile);
while (s.hasNextLine()) lines.add(s.nextLine());
s.close();
return lines;
} else {
LOG.info("Old log file does not exist");
return emptyList();
}
}
}