将所有异常写入文件
Write all exception in file
我正在使用 Timber 将一些日志写入位于设备上的文件中。现在,我正在使用 HTTP 拦截器编写我选择的日志和来自服务器的一些响应。但我想在文件中写入所有异常(例如致命异常)。 Timber 或其他图书馆可以吗?
目前我正在使用 Fabric,但我的应用并不总是与外部世界有互联网连接
P.S。我想在没有 try/catch
的情况下编写所有致命异常
TimberLooger.class
public class FileLoggingTree
{
/**
* Sends an error message to LogCat and to a log file.
* @param context The context of the application.
* @param logMessageTag A tag identifying a group of log messages. Should be a constant in the
* class calling the logger.
* @param logMessage The message to add to the log.
*/
public static void e(Context context, String logMessageTag, String logMessage)
{
if (!Log.isLoggable(logMessageTag, Log.ERROR))
return;
int logResult = Log.e(logMessageTag, logMessage);
if (logResult > 0)
logToFile(context, logMessageTag, logMessage);
}
/**
* Sends an error message and the exception to LogCat and to a log file.
* @param context The context of the application.
* @param logMessageTag A tag identifying a group of log messages. Should be a constant in the
* class calling the logger.
* @param logMessage The message to add to the log.
* @param throwableException An exception to log
*/
public static void e
(Context context, String logMessageTag, String logMessage, Throwable throwableException)
{
if (!Log.isLoggable(logMessageTag, Log.ERROR))
return;
int logResult = Log.e(logMessageTag, logMessage, throwableException);
if (logResult > 0)
logToFile(context, logMessageTag,
logMessage + "\r\n" + Log.getStackTraceString(throwableException));
}
// The i and w method for info and warning logs
// should be implemented in the same way as the e method for error logs.
/**
* Sends a message to LogCat and to a log file.
* @param context The context of the application.
* @param logMessageTag A tag identifying a group of log messages. Should be a constant in the
* class calling the logger.
* @param logMessage The message to add to the log.
*/
public static void v(Context context, String logMessageTag, String logMessage)
{
// If the build is not debug, do not try to log, the logcat be
// stripped at compilation.
if (!BuildConfig.DEBUG || !Log.isLoggable(logMessageTag, Log.VERBOSE))
return;
int logResult = Log.v(logMessageTag, logMessage);
if (logResult > 0)
logToFile(context, logMessageTag, logMessage);
}
/**
* Sends a message and the exception to LogCat and to a log file.
* @param logMessageTag A tag identifying a group of log messages. Should be a constant in the
* class calling the logger.
* @param logMessage The message to add to the log.
* @param throwableException An exception to log
*/
public static void v
(Context context,String logMessageTag, String logMessage, Throwable throwableException)
{
// If the build is not debug, do not try to log, the logcat be
// stripped at compilation.
if (!BuildConfig.DEBUG || !Log.isLoggable(logMessageTag, Log.VERBOSE))
return;
int logResult = Log.v(logMessageTag, logMessage, throwableException);
if (logResult > 0)
logToFile(context, logMessageTag,
logMessage + "\r\n" + Log.getStackTraceString(throwableException));
}
// The d method for debug logs should be implemented in the same way as the v method for verbose logs.
/**
* Gets a stamp containing the current date and time to write to the log.
* @return The stamp for the current date and time.
*/
private static String getDateTimeStamp()
{
Date dateNow = Calendar.getInstance().getTime();
// My locale, so all the log files have the same date and time format
return (DateFormat.getDateTimeInstance
(DateFormat.SHORT, DateFormat.SHORT, Locale.CANADA_FRENCH).format(dateNow));
}
/**
* Writes a message to the log file on the device.
* @param logMessageTag A tag identifying a group of log messages.
* @param logMessage The message to add to the log.
*/
private static void logToFile(Context context, String logMessageTag, String logMessage)
{
try
{
// Gets the log file from the root of the primary storage. If it does
// not exist, the file is created.
File logFile = new File(Environment.getRootDirectory(),
"TestApplicationLog.txt");
if (!logFile.exists())
logFile.createNewFile();
// Write the message to the log with a timestamp
BufferedWriter writer = new BufferedWriter(new FileWriter(logFile, true));
writer.write(String.format("%1s [%2s]:%3s\r\n",
getDateTimeStamp(), logMessageTag, logMessage));
writer.close();
// Refresh the data so it can seen when the device is plugged in a
// computer. You may have to unplug and replug to see the latest
// changes
MediaScannerConnection.scanFile(context,
new String[] { logFile.toString() },
null,
null);
}
catch (IOException e)
{
Log.e("com.cindypotvin.Logger", "Unable to log exception to file.");
}
}
}
TimberLogger.class
public class TimberLooger extends Timber.DebugTree {
private static final String TAG = FileLoggingTree.class.getSimpleName();
private Context context;
public TimberLooger(Context context) {
this.context = context;
}
@Override
protected void log(int priority, String tag, String message, Throwable t) {
try {
File direct = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/FileLocation");
if (!direct.exists()) {
direct.mkdir();
}
String fileNameTimeStamp = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date());
String logTimeStamp = new SimpleDateFormat("E MMM dd yyyy 'at' hh:mm:ss:SSS aaa", Locale.getDefault()).format(new Date());
String fileName = fileNameTimeStamp + ".html";
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/FileLocation" + File.separator + fileName);
file.createNewFile();
if (file.exists()) {
OutputStream fileOutputStream = new FileOutputStream(file, true);
fileOutputStream.write(("<p style=\"background:lightgray;\"><strong style=\"background:lightblue;\">  " + logTimeStamp + " :  </strong>  " + message + "</p>").getBytes());
fileOutputStream.close();
}
//if (context != null)
//MediaScannerConnection.scanFile(context, new String[]{file.getAbsolutePath()}, null, null);
} catch (Exception e) {
Log.e(TAG, "Error while logging into file : " + e);
}
}
}
是的,可以使用 Timber 将异常写入文件。为此,您必须创建自定义木材树,如下例(在 Kotlin 中):
import timber.log.Timber
class FileLogTree : Timber.Tree() {
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
if (priority == Log.ERROR) {
try {
val directory = Environment.getExternalStoragePublicDirectory("${Environment.DIRECTORY_DOCUMENTS}/logs")
if (!directory.exists())
directory.mkdirs()
val fileName = "myLog.txt"
val file = File("${directory.absolutePath}${File.separator}$fileName")
file.createNewFile()
if (file.exists()) {
val fos = FileOutputStream(file, true)
fos.write("$message\n".toByteArray(Charsets.UTF_8))
fos.close()
}
} catch (e: IOException){
Log.println(Log.ERROR,"FileLogTree", "Error while logging into file: $e")
}
}
}
}
稍后,在您的 Timber 初始化过程中,设置此自定义树:
Timber.plant(FileLogTree())
在此示例中,Timber 会将所有 "Timber.e()" 日志写入您的 documents/logs 文件夹中名为 "myLog.txt" 的文件。
您还需要 WRITE_EXTERNAL_STORAGE
权限才能使用该自定义树。您可以在 .
上阅读有关获得此权限的更多信息
至于 "get all exceptions" 部分,您必须创建一个自定义的 Uncaught Exception Handler 并在您的应用程序(或活动)启动后更改默认值 Thread.UncaughtExceptionHandler
。为此,请调用:Thread.setDefaultUncaughtExceptionHandler(new YourExceptionHandler(context));
。在该处理程序中,您可以选择如何处理异常(如调用 Timber.e()
)。
检查 to learn more on how to implement that. Alternatively, you can take a look at this link,这家伙制作了其中一个处理程序来解决这些崩溃问题。您可以将其与您的自定义树一起使用,以将详细信息保存在您的日志文件中。
我正在使用 Timber 将一些日志写入位于设备上的文件中。现在,我正在使用 HTTP 拦截器编写我选择的日志和来自服务器的一些响应。但我想在文件中写入所有异常(例如致命异常)。 Timber 或其他图书馆可以吗?
目前我正在使用 Fabric,但我的应用并不总是与外部世界有互联网连接
P.S。我想在没有 try/catch
的情况下编写所有致命异常TimberLooger.class
public class FileLoggingTree
{
/**
* Sends an error message to LogCat and to a log file.
* @param context The context of the application.
* @param logMessageTag A tag identifying a group of log messages. Should be a constant in the
* class calling the logger.
* @param logMessage The message to add to the log.
*/
public static void e(Context context, String logMessageTag, String logMessage)
{
if (!Log.isLoggable(logMessageTag, Log.ERROR))
return;
int logResult = Log.e(logMessageTag, logMessage);
if (logResult > 0)
logToFile(context, logMessageTag, logMessage);
}
/**
* Sends an error message and the exception to LogCat and to a log file.
* @param context The context of the application.
* @param logMessageTag A tag identifying a group of log messages. Should be a constant in the
* class calling the logger.
* @param logMessage The message to add to the log.
* @param throwableException An exception to log
*/
public static void e
(Context context, String logMessageTag, String logMessage, Throwable throwableException)
{
if (!Log.isLoggable(logMessageTag, Log.ERROR))
return;
int logResult = Log.e(logMessageTag, logMessage, throwableException);
if (logResult > 0)
logToFile(context, logMessageTag,
logMessage + "\r\n" + Log.getStackTraceString(throwableException));
}
// The i and w method for info and warning logs
// should be implemented in the same way as the e method for error logs.
/**
* Sends a message to LogCat and to a log file.
* @param context The context of the application.
* @param logMessageTag A tag identifying a group of log messages. Should be a constant in the
* class calling the logger.
* @param logMessage The message to add to the log.
*/
public static void v(Context context, String logMessageTag, String logMessage)
{
// If the build is not debug, do not try to log, the logcat be
// stripped at compilation.
if (!BuildConfig.DEBUG || !Log.isLoggable(logMessageTag, Log.VERBOSE))
return;
int logResult = Log.v(logMessageTag, logMessage);
if (logResult > 0)
logToFile(context, logMessageTag, logMessage);
}
/**
* Sends a message and the exception to LogCat and to a log file.
* @param logMessageTag A tag identifying a group of log messages. Should be a constant in the
* class calling the logger.
* @param logMessage The message to add to the log.
* @param throwableException An exception to log
*/
public static void v
(Context context,String logMessageTag, String logMessage, Throwable throwableException)
{
// If the build is not debug, do not try to log, the logcat be
// stripped at compilation.
if (!BuildConfig.DEBUG || !Log.isLoggable(logMessageTag, Log.VERBOSE))
return;
int logResult = Log.v(logMessageTag, logMessage, throwableException);
if (logResult > 0)
logToFile(context, logMessageTag,
logMessage + "\r\n" + Log.getStackTraceString(throwableException));
}
// The d method for debug logs should be implemented in the same way as the v method for verbose logs.
/**
* Gets a stamp containing the current date and time to write to the log.
* @return The stamp for the current date and time.
*/
private static String getDateTimeStamp()
{
Date dateNow = Calendar.getInstance().getTime();
// My locale, so all the log files have the same date and time format
return (DateFormat.getDateTimeInstance
(DateFormat.SHORT, DateFormat.SHORT, Locale.CANADA_FRENCH).format(dateNow));
}
/**
* Writes a message to the log file on the device.
* @param logMessageTag A tag identifying a group of log messages.
* @param logMessage The message to add to the log.
*/
private static void logToFile(Context context, String logMessageTag, String logMessage)
{
try
{
// Gets the log file from the root of the primary storage. If it does
// not exist, the file is created.
File logFile = new File(Environment.getRootDirectory(),
"TestApplicationLog.txt");
if (!logFile.exists())
logFile.createNewFile();
// Write the message to the log with a timestamp
BufferedWriter writer = new BufferedWriter(new FileWriter(logFile, true));
writer.write(String.format("%1s [%2s]:%3s\r\n",
getDateTimeStamp(), logMessageTag, logMessage));
writer.close();
// Refresh the data so it can seen when the device is plugged in a
// computer. You may have to unplug and replug to see the latest
// changes
MediaScannerConnection.scanFile(context,
new String[] { logFile.toString() },
null,
null);
}
catch (IOException e)
{
Log.e("com.cindypotvin.Logger", "Unable to log exception to file.");
}
}
}
TimberLogger.class
public class TimberLooger extends Timber.DebugTree {
private static final String TAG = FileLoggingTree.class.getSimpleName();
private Context context;
public TimberLooger(Context context) {
this.context = context;
}
@Override
protected void log(int priority, String tag, String message, Throwable t) {
try {
File direct = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/FileLocation");
if (!direct.exists()) {
direct.mkdir();
}
String fileNameTimeStamp = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date());
String logTimeStamp = new SimpleDateFormat("E MMM dd yyyy 'at' hh:mm:ss:SSS aaa", Locale.getDefault()).format(new Date());
String fileName = fileNameTimeStamp + ".html";
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/FileLocation" + File.separator + fileName);
file.createNewFile();
if (file.exists()) {
OutputStream fileOutputStream = new FileOutputStream(file, true);
fileOutputStream.write(("<p style=\"background:lightgray;\"><strong style=\"background:lightblue;\">  " + logTimeStamp + " :  </strong>  " + message + "</p>").getBytes());
fileOutputStream.close();
}
//if (context != null)
//MediaScannerConnection.scanFile(context, new String[]{file.getAbsolutePath()}, null, null);
} catch (Exception e) {
Log.e(TAG, "Error while logging into file : " + e);
}
}
}
是的,可以使用 Timber 将异常写入文件。为此,您必须创建自定义木材树,如下例(在 Kotlin 中):
import timber.log.Timber
class FileLogTree : Timber.Tree() {
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
if (priority == Log.ERROR) {
try {
val directory = Environment.getExternalStoragePublicDirectory("${Environment.DIRECTORY_DOCUMENTS}/logs")
if (!directory.exists())
directory.mkdirs()
val fileName = "myLog.txt"
val file = File("${directory.absolutePath}${File.separator}$fileName")
file.createNewFile()
if (file.exists()) {
val fos = FileOutputStream(file, true)
fos.write("$message\n".toByteArray(Charsets.UTF_8))
fos.close()
}
} catch (e: IOException){
Log.println(Log.ERROR,"FileLogTree", "Error while logging into file: $e")
}
}
}
}
稍后,在您的 Timber 初始化过程中,设置此自定义树:
Timber.plant(FileLogTree())
在此示例中,Timber 会将所有 "Timber.e()" 日志写入您的 documents/logs 文件夹中名为 "myLog.txt" 的文件。
您还需要 WRITE_EXTERNAL_STORAGE
权限才能使用该自定义树。您可以在
至于 "get all exceptions" 部分,您必须创建一个自定义的 Uncaught Exception Handler 并在您的应用程序(或活动)启动后更改默认值 Thread.UncaughtExceptionHandler
。为此,请调用:Thread.setDefaultUncaughtExceptionHandler(new YourExceptionHandler(context));
。在该处理程序中,您可以选择如何处理异常(如调用 Timber.e()
)。
检查