package com.bugsnag.android; import java.io.File; import java.io.FileWriter; import java.io.Writer; import java.util.Arrays; import java.util.List; import java.util.Locale; import android.content.Context; /** * Store and flush Error reports which couldn't be sent immediately due to * lack of network connectivity. */ class ErrorStore { private static final String UNSENT_ERROR_PATH = "/bugsnag-errors/"; private static final int MAX_STORED_ERRORS = 100; final Configuration config; final String path; ErrorStore(Configuration config, Context appContext) { this.config = config; String path; try { path = appContext.getCacheDir().getAbsolutePath() + UNSENT_ERROR_PATH; File outFile = new File(path); outFile.mkdirs(); if(!outFile.exists()) { Logger.warn("Could not prepare error storage directory"); path = null; } } catch(Exception e) { Logger.warn("Could not prepare error storage directory", e); path = null; } this.path = path; } // Flush any on-disk errors to Bugsnag void flush() { if(path == null) return; Async.run(new Runnable() { @Override public void run() { // Look up all saved error files File exceptionDir = new File(path); if(!exceptionDir.exists() || !exceptionDir.isDirectory()) return; File[] errorFiles = exceptionDir.listFiles(); if(errorFiles != null && errorFiles.length > 0) { Logger.info(String.format(Locale.US, "Sending %d saved error(s) to Bugsnag", errorFiles.length)); for(File errorFile : errorFiles) { try { Report report = new Report(config.getApiKey(), errorFile); HttpClient.post(config.getEndpoint(), report); Logger.info("Deleting sent error file " + errorFile.getName()); if (!errorFile.delete()) errorFile.deleteOnExit(); } catch (HttpClient.NetworkException e) { Logger.warn("Could not send previously saved error(s) to Bugsnag, will try again later", e); } catch (Exception e) { Logger.warn("Problem sending unsent error from disk", e); if (!errorFile.delete()) errorFile.deleteOnExit(); } } } } }); } // Write an error to disk, for later sending void write(Error error) { if(path == null) return; // Limit number of saved errors to prevent disk space issues File exceptionDir = new File(path); if (exceptionDir.isDirectory()) { File[] files = exceptionDir.listFiles(); if (files != null && files.length >= MAX_STORED_ERRORS) { // Sort files then delete the first one (oldest timestamp) Arrays.sort(files); Logger.warn(String.format("Discarding oldest error as stored error limit reached (%s)", files[0].getPath())); if (!files[0].delete()) { files[0].deleteOnExit(); } } } String filename = String.format(Locale.US, "%s%d.json", path, System.currentTimeMillis()); Writer out = null; try { out = new FileWriter(filename); JsonStream stream = new JsonStream(out); stream.value(error); stream.close(); Logger.info(String.format("Saved unsent error to disk (%s) ", filename)); } catch (Exception e) { Logger.warn(String.format("Couldn't save unsent error to disk (%s) ", filename), e); } finally { IOUtils.closeQuietly(out); } } }