是否有任何 sdk 可以记录生产应用程序中的异常、事件和错误?
Is there any sdk to log exceptions, events and errors in production app?
我想在生产期间捕获我的应用程序中的所有未 expected/undesirable 事件。我想要一些可以将错误日志文件发送到服务器的东西,我可以通过 Web 应用程序轻松读取它。你知道这类事情吗?
使用 Mint 获取每个异常日志或使用 MonkeyTalk 获取应用程序的所有日志记录。
如果您需要获取所有 unexpected/undesirable 异常。
请把这一行放在你的 类 中,你需要得到 Log
.
ErrorReporter.getInstance().Init(YOURACTIVITY.this);
你可以使用这个ErrorReporter.Class
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Date;
import java.util.Random;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Environment;
import android.os.StatFs;
import com.example.demogetlog.R;
public class ErrorReporter implements Thread.UncaughtExceptionHandler {
String VersionName;
String PackageName;
String FilePath;
String PhoneModel;
String AndroidVersion;
String Board;
String Brand;
// String CPU_ABI;
String Device;
String Display;
String FingerPrint;
String Host;
String ID;
String Manufacturer;
String Model;
String Product;
String Tags;
long Time;
String Type;
String User;
private Thread.UncaughtExceptionHandler PreviousHandler;
private static ErrorReporter S_mInstance;
private Context CurContext;
public void Init( Context context )
{
PreviousHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler( this );
RecoltInformations( context );
CurContext = context;
}
public long getAvailableInternalMemorySize() {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks * blockSize;
}
public long getTotalInternalMemorySize() {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks * blockSize;
}
void RecoltInformations( Context context )
{
PackageManager pm = context.getPackageManager();
try
{
PackageInfo pi;
// Version
pi = pm.getPackageInfo(context.getPackageName(), 0);
VersionName = pi.versionName;
// Package name
PackageName = pi.packageName;
// Files dir for storing the stack traces
FilePath = context.getFilesDir().getAbsolutePath();
// Device model
PhoneModel = android.os.Build.MODEL;
// Android version
AndroidVersion = android.os.Build.VERSION.RELEASE;
Board = android.os.Build.BOARD;
Brand = android.os.Build.BRAND;
//CPU_ABI = android.os.Build.;
Device = android.os.Build.DEVICE;
Display = android.os.Build.DISPLAY;
FingerPrint = android.os.Build.FINGERPRINT;
Host = android.os.Build.HOST;
ID = android.os.Build.ID;
//Manufacturer = android.os.Build.;
Model = android.os.Build.MODEL;
Product = android.os.Build.PRODUCT;
Tags = android.os.Build.TAGS;
Time = android.os.Build.TIME;
Type = android.os.Build.TYPE;
User = android.os.Build.USER;
}
catch (NameNotFoundException e)
{
e.printStackTrace();
}
}
public String CreateInformationString()
{
String ReturnVal = "";
ReturnVal += "Version : " + VersionName;
ReturnVal += "\n";
ReturnVal += "Package : " + PackageName;
ReturnVal += "\n";
ReturnVal += "FilePath : " + FilePath;
ReturnVal += "\n";
ReturnVal += "Phone Model" + PhoneModel;
ReturnVal += "\n";
ReturnVal += "Android Version : " + AndroidVersion;
ReturnVal += "\n";
ReturnVal += "Board : " + Board;
ReturnVal += "\n";
ReturnVal += "Brand : " + Brand;
ReturnVal += "\n";
ReturnVal += "Device : " + Device;
ReturnVal += "\n";
ReturnVal += "Display : " + Display;
ReturnVal += "\n";
ReturnVal += "Finger Print : " + FingerPrint;
ReturnVal += "\n";
ReturnVal += "Host : " + Host;
ReturnVal += "\n";
ReturnVal += "ID : " + ID;
ReturnVal += "\n";
ReturnVal += "Model : " + Model;
ReturnVal += "\n";
ReturnVal += "Product : " + Product;
ReturnVal += "\n";
ReturnVal += "Tags : " + Tags;
ReturnVal += "\n";
ReturnVal += "Time : " + Time;
ReturnVal += "\n";
ReturnVal += "Type : " + Type;
ReturnVal += "\n";
ReturnVal += "User : " + User;
ReturnVal += "\n";
ReturnVal += "Total Internal memory : " + getTotalInternalMemorySize();
ReturnVal += "\n";
ReturnVal += "Available Internal memory : " + getAvailableInternalMemorySize();
ReturnVal += "\n";
return ReturnVal;
}
@Override
public void uncaughtException(Thread thread, Throwable e) {
String Report = "";
Date CurDate = new Date();
Report += "Error Report collected on : " + CurDate.toString();
Report += "\n";
Report += "\n";
Report += "Informations :";
Report += "\n";
Report += "==============";
Report += "\n";
Report += "\n";
Report += CreateInformationString();
Report += "\n\n";
Report += "Stack : \n";
Report += "======= \n";
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
e.printStackTrace(printWriter);
String stacktrace = result.toString();
Report += stacktrace;
Report += "\n";
Report += "Cause : \n";
Report += "======= \n";
// If the exception was thrown in a background thread inside
// AsyncTask, then the actual exception can be found with getCause
Throwable cause = e.getCause();
while (cause != null)
{
cause.printStackTrace( printWriter );
Report += result.toString();
cause = cause.getCause();
}
printWriter.close();
Report += "**** End of current Report ***";
SaveAsFile(Report);
//SendErrorMail( Report );
CheckErrorAndSendMail(CurContext);
PreviousHandler.uncaughtException(thread, e);
}
static ErrorReporter getInstance()
{
if ( S_mInstance == null )
S_mInstance = new ErrorReporter();
return S_mInstance;
}
private void SendErrorMail( Context _context, String ErrorContent )
{
Intent sendIntent = new Intent(Intent.ACTION_SEND);
String subject = _context.getResources().getString( R.string.CrashReport_MailSubject );
String body = _context.getResources().getString( R.string.CrashReport_MailBody ) +
"\n\n"+
ErrorContent+
"\n\n";
sendIntent.putExtra(Intent.EXTRA_EMAIL,
new String[] {"YOURMAILID"});
sendIntent.putExtra(Intent.EXTRA_TEXT, body);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
sendIntent.setType("message/rfc822");
_context.startActivity( Intent.createChooser(sendIntent, "Title: Please choose for Email") );
}
private void SaveAsFile( String ErrorContent )
{
try
{
Random generator = new Random();
int random = generator.nextInt(99999);
String FileName = "stack-" + random + ".stacktrace";
FileOutputStream trace = CurContext.openFileOutput( FileName, Context.MODE_PRIVATE);
trace.write(ErrorContent.getBytes());
trace.close();
}
catch(IOException ioe) {
// ...
}
}
private String[] GetErrorFileList()
{
File dir = new File( FilePath + "/");
// Try to create the files folder if it doesn't exist
dir.mkdir();
// Filter for ".stacktrace" files
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".stacktrace");
}
};
return dir.list(filter);
}
private boolean bIsThereAnyErrorFile()
{
return GetErrorFileList().length > 0;
}
public void CheckErrorAndSendMail(Context _context )
{
try
{
if ( bIsThereAnyErrorFile() )
{
String WholeErrorText = "";
String[] ErrorFileList = GetErrorFileList();
int curIndex = 0;
// We limit the number of crash reports to send ( in order not to be too slow )
final int MaxSendMail = 50;
for ( String curString : ErrorFileList )
{
if ( curIndex++ <= MaxSendMail )
{
WholeErrorText+="New Trace collected :\n";
WholeErrorText+="=====================\n ";
String filePath = FilePath + "/" + curString;
BufferedReader input = new BufferedReader(new FileReader(filePath));
String line;
while (( line = input.readLine()) != null)
{
WholeErrorText += line + "\n";
}
input.close();
}
// DELETE FILES !!!!
File curFile = new File( FilePath + "/" + curString );
curFile.delete();
}
SendErrorMail( _context , WholeErrorText );
}
}
catch( Exception e )
{
e.printStackTrace();
}
}
}
Flurry 分析
crashlytics
他们会给你生产应用程序中的日志和错误。我认为这很适合你
我想在生产期间捕获我的应用程序中的所有未 expected/undesirable 事件。我想要一些可以将错误日志文件发送到服务器的东西,我可以通过 Web 应用程序轻松读取它。你知道这类事情吗?
使用 Mint 获取每个异常日志或使用 MonkeyTalk 获取应用程序的所有日志记录。
如果您需要获取所有 unexpected/undesirable 异常。
请把这一行放在你的 类 中,你需要得到 Log
.
ErrorReporter.getInstance().Init(YOURACTIVITY.this);
你可以使用这个ErrorReporter.Class
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Date;
import java.util.Random;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Environment;
import android.os.StatFs;
import com.example.demogetlog.R;
public class ErrorReporter implements Thread.UncaughtExceptionHandler {
String VersionName;
String PackageName;
String FilePath;
String PhoneModel;
String AndroidVersion;
String Board;
String Brand;
// String CPU_ABI;
String Device;
String Display;
String FingerPrint;
String Host;
String ID;
String Manufacturer;
String Model;
String Product;
String Tags;
long Time;
String Type;
String User;
private Thread.UncaughtExceptionHandler PreviousHandler;
private static ErrorReporter S_mInstance;
private Context CurContext;
public void Init( Context context )
{
PreviousHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler( this );
RecoltInformations( context );
CurContext = context;
}
public long getAvailableInternalMemorySize() {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks * blockSize;
}
public long getTotalInternalMemorySize() {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks * blockSize;
}
void RecoltInformations( Context context )
{
PackageManager pm = context.getPackageManager();
try
{
PackageInfo pi;
// Version
pi = pm.getPackageInfo(context.getPackageName(), 0);
VersionName = pi.versionName;
// Package name
PackageName = pi.packageName;
// Files dir for storing the stack traces
FilePath = context.getFilesDir().getAbsolutePath();
// Device model
PhoneModel = android.os.Build.MODEL;
// Android version
AndroidVersion = android.os.Build.VERSION.RELEASE;
Board = android.os.Build.BOARD;
Brand = android.os.Build.BRAND;
//CPU_ABI = android.os.Build.;
Device = android.os.Build.DEVICE;
Display = android.os.Build.DISPLAY;
FingerPrint = android.os.Build.FINGERPRINT;
Host = android.os.Build.HOST;
ID = android.os.Build.ID;
//Manufacturer = android.os.Build.;
Model = android.os.Build.MODEL;
Product = android.os.Build.PRODUCT;
Tags = android.os.Build.TAGS;
Time = android.os.Build.TIME;
Type = android.os.Build.TYPE;
User = android.os.Build.USER;
}
catch (NameNotFoundException e)
{
e.printStackTrace();
}
}
public String CreateInformationString()
{
String ReturnVal = "";
ReturnVal += "Version : " + VersionName;
ReturnVal += "\n";
ReturnVal += "Package : " + PackageName;
ReturnVal += "\n";
ReturnVal += "FilePath : " + FilePath;
ReturnVal += "\n";
ReturnVal += "Phone Model" + PhoneModel;
ReturnVal += "\n";
ReturnVal += "Android Version : " + AndroidVersion;
ReturnVal += "\n";
ReturnVal += "Board : " + Board;
ReturnVal += "\n";
ReturnVal += "Brand : " + Brand;
ReturnVal += "\n";
ReturnVal += "Device : " + Device;
ReturnVal += "\n";
ReturnVal += "Display : " + Display;
ReturnVal += "\n";
ReturnVal += "Finger Print : " + FingerPrint;
ReturnVal += "\n";
ReturnVal += "Host : " + Host;
ReturnVal += "\n";
ReturnVal += "ID : " + ID;
ReturnVal += "\n";
ReturnVal += "Model : " + Model;
ReturnVal += "\n";
ReturnVal += "Product : " + Product;
ReturnVal += "\n";
ReturnVal += "Tags : " + Tags;
ReturnVal += "\n";
ReturnVal += "Time : " + Time;
ReturnVal += "\n";
ReturnVal += "Type : " + Type;
ReturnVal += "\n";
ReturnVal += "User : " + User;
ReturnVal += "\n";
ReturnVal += "Total Internal memory : " + getTotalInternalMemorySize();
ReturnVal += "\n";
ReturnVal += "Available Internal memory : " + getAvailableInternalMemorySize();
ReturnVal += "\n";
return ReturnVal;
}
@Override
public void uncaughtException(Thread thread, Throwable e) {
String Report = "";
Date CurDate = new Date();
Report += "Error Report collected on : " + CurDate.toString();
Report += "\n";
Report += "\n";
Report += "Informations :";
Report += "\n";
Report += "==============";
Report += "\n";
Report += "\n";
Report += CreateInformationString();
Report += "\n\n";
Report += "Stack : \n";
Report += "======= \n";
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
e.printStackTrace(printWriter);
String stacktrace = result.toString();
Report += stacktrace;
Report += "\n";
Report += "Cause : \n";
Report += "======= \n";
// If the exception was thrown in a background thread inside
// AsyncTask, then the actual exception can be found with getCause
Throwable cause = e.getCause();
while (cause != null)
{
cause.printStackTrace( printWriter );
Report += result.toString();
cause = cause.getCause();
}
printWriter.close();
Report += "**** End of current Report ***";
SaveAsFile(Report);
//SendErrorMail( Report );
CheckErrorAndSendMail(CurContext);
PreviousHandler.uncaughtException(thread, e);
}
static ErrorReporter getInstance()
{
if ( S_mInstance == null )
S_mInstance = new ErrorReporter();
return S_mInstance;
}
private void SendErrorMail( Context _context, String ErrorContent )
{
Intent sendIntent = new Intent(Intent.ACTION_SEND);
String subject = _context.getResources().getString( R.string.CrashReport_MailSubject );
String body = _context.getResources().getString( R.string.CrashReport_MailBody ) +
"\n\n"+
ErrorContent+
"\n\n";
sendIntent.putExtra(Intent.EXTRA_EMAIL,
new String[] {"YOURMAILID"});
sendIntent.putExtra(Intent.EXTRA_TEXT, body);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
sendIntent.setType("message/rfc822");
_context.startActivity( Intent.createChooser(sendIntent, "Title: Please choose for Email") );
}
private void SaveAsFile( String ErrorContent )
{
try
{
Random generator = new Random();
int random = generator.nextInt(99999);
String FileName = "stack-" + random + ".stacktrace";
FileOutputStream trace = CurContext.openFileOutput( FileName, Context.MODE_PRIVATE);
trace.write(ErrorContent.getBytes());
trace.close();
}
catch(IOException ioe) {
// ...
}
}
private String[] GetErrorFileList()
{
File dir = new File( FilePath + "/");
// Try to create the files folder if it doesn't exist
dir.mkdir();
// Filter for ".stacktrace" files
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".stacktrace");
}
};
return dir.list(filter);
}
private boolean bIsThereAnyErrorFile()
{
return GetErrorFileList().length > 0;
}
public void CheckErrorAndSendMail(Context _context )
{
try
{
if ( bIsThereAnyErrorFile() )
{
String WholeErrorText = "";
String[] ErrorFileList = GetErrorFileList();
int curIndex = 0;
// We limit the number of crash reports to send ( in order not to be too slow )
final int MaxSendMail = 50;
for ( String curString : ErrorFileList )
{
if ( curIndex++ <= MaxSendMail )
{
WholeErrorText+="New Trace collected :\n";
WholeErrorText+="=====================\n ";
String filePath = FilePath + "/" + curString;
BufferedReader input = new BufferedReader(new FileReader(filePath));
String line;
while (( line = input.readLine()) != null)
{
WholeErrorText += line + "\n";
}
input.close();
}
// DELETE FILES !!!!
File curFile = new File( FilePath + "/" + curString );
curFile.delete();
}
SendErrorMail( _context , WholeErrorText );
}
}
catch( Exception e )
{
e.printStackTrace();
}
}
}
Flurry 分析
crashlytics
他们会给你生产应用程序中的日志和错误。我认为这很适合你