[Unity]收集报错日志(2)--安卓崩溃日志收集
之前不是写了篇收集报错日志上传ftp服务器的文章,那时候因为某些原因,我只有权限上传到ftp服务器上,但是在压测的时候发现很多问题,连接打不开,因为ftp有权限设置,还有连接人数上限,这就尴尬了,这就导致很多报错信息没有收到。这完全不符合需求,因此,需要后台PHP来处理。
PHP来处理就非常简单了,只需要上传字符串就行。性能上也优化了,皆大欢喜。代码就很简单,不说什么了。
/// <summary>
/// 上传错误日志
/// </summary>
public void UploadErrorToPHP(string error)
{
if (!Main.bIsCollectLog) return;
StringBuilder sb = new StringBuilder();
sb.Append(ErrorUploadUrl + "&error=" + error);
sb.Append("&uname=" + account);
System.DateTime nowTime = System.DateTime.Now;
var filename = "Unity_" + (nowTime.ToString("HH_mm_ss"));
sb.Append("&filename=" + filename);
#if UNITY_EDITOR
string system = "PC";
#elif UNITY_ANDROID
string system = "Android";
#elif UNITY_IOS
string system = "IOS";
#endif
sb.Append("&system=" + system);
RequestHttp(sb.ToString(), requetTimeOut);
}
private string RequestHttp(string url, int Timeout = 100000)
{
string requestPath = url;
string result = "";
HttpWebRequest httpWebReq = null;
Stream stream = null;
StreamReader reader = null;
try
{
httpWebReq = (HttpWebRequest)WebRequest.Create(requestPath);
//Debug.LogError(" httpWebReq.Timeout: " + httpWebReq.Timeout);
httpWebReq.Timeout = Timeout;
httpWebReq.KeepAlive = false;
stream = httpWebReq.GetResponse().GetResponseStream();
reader = new StreamReader(stream, Encoding.UTF8);
string line = string.Empty;
while (line != null)
{
line = reader.ReadLine();
result = result + line + "\n";
}
result = Decrypt(result);
reader.Close();
stream.Close();
}
catch (Exception e)
{
Debug.Log("RequestHttp In Error. url:" + url + "--" + e.Message);
}
finally
{
if (stream != null)
stream.Close();
if (reader != null)
reader.Close();
if (httpWebReq != null)
httpWebReq.Abort();
}
return result;
}
有了报错日志,需求又增加了,想要获取崩溃日志。但是这边又不想用Bugly这些插件,会影响性能,之前测试过,有降帧。所以只好在Java层上在实现一套上传崩溃日志功能,因为现在安卓版本在测试,所以安卓功能优先,就意味下次我还得处理一套iOS的功能,尴尬了。
之前有写过怎么获取java层的单例,这边也不再多说一遍,还是在之前写的安卓通用类上加了个接口。
开启接口
/**
* 开启java层上传异常信息
*/
public void InitCatchException()
{
if(ec != null)
return;
ec = new exceptioncatch();
ec.Init();
}
/**
* 修改java层上传异常信息的账号名
*/
public void SetAccount(String account)
{
if(ec != null)
{
ec.SetAccount(account);
}
}
捕获异常,需要注意的是要调用SystemClock.sleep(requetTimeOut)这个接口延迟一段时间关闭进程,不然还没上传数据到PHP就被关闭了。这个问题就导致我调了3,4个小时。在使用一段时间后,发现几乎没有收集到Java层的报错,之前写了个Android Demo测试,可以捕获到异常的,没有用Unity来测试,故意写个异常出来,Unity会捕获变成Unity层的错误,然后就调用了C#的上传报错日志接口。只好在网上继续搜索查找,然后找到了一个重要原因:setUncaughtExceptionHandler只对应注册的线程起作用,对应的线程,这就尴尬了,果然不熟悉Android和Java,后果太严重了。也查找到了setDefaultUncaughtExceptionHandler则是在所有线程上都起作用。换了接口后,一个下午就收集到了Java上的报错信息。又是一个坑被我趟过。
public class exceptioncatch implements Thread.UncaughtExceptionHandler {
private Thread.UncaughtExceptionHandler defaultThread;
private final String ErrorUploadUrl = "http://xxxxxxxxxxxxxx.php?";
private String account = "Login";
private int requetTimeOut = 5000;
public void Init()
{
Thread.setDefaultUncaughtExceptionHandler(this);//所有线程上都起作用
//Thread.currentThread().setUncaughtExceptionHandler(this);//只对应注册的线程起作用
defaultThread = Thread.getDefaultUncaughtExceptionHandler();
Log.e("ZP", "启动异常捕获");
}
public void SetAccount(String accoutStr)
{
account = accoutStr;
}
@Override
public void uncaughtException(Thread t, Throwable ex)
{
Log.e("ZP", "捕捉到了异常");
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
pw.close();
UploadErrorToPHP(sw.toString());
SystemClock.sleep(requetTimeOut);
defaultThread.uncaughtException(t, ex);
}
private void UploadErrorToPHP(String error)
{
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("(yyyy-mm-dd:HH:mm:ss)");
error = "[Java异常" + sdf.format(date) + "]" + error;
StringBuffer sb = new StringBuffer();
sb.append(ErrorUploadUrl + "error=" + error);
sb.append("&uname=" + account);
sdf = new SimpleDateFormat("HH_mm_ss");
String filename = "Java_" + sdf.format(date);
sb.append("&filename=" + filename);
sb.append("&system=Java");
RequestHttp(sb.toString());
}
private void RequestHttp(String requestUrl)
{
urlThread tempUrlThread = new urlThread();
tempUrlThread.SetRequestUrl(requestUrl);
Thread tempThread = new Thread(tempUrlThread);
tempThread.start();
}
上传到PHP
public class urlThread implements Runnable {
private String requestUrl;
public void SetRequestUrl(String requestUrl)
{
this.requestUrl = requestUrl;
}
@Override
public void run() {
Log.e("ZP","开始上传报错:" + requestUrl);
if(requestUrl != null && !requestUrl.isEmpty()) {
try {
URL url = new URL(requestUrl);
//返回一个URLConnection对象,它表示到URL所引用的远程对象的连接
URLConnection connection = url.openConnection();
connection.connect();
InputStream is = connection.getInputStream();
Log.e("ZP","完成上传报错");
} catch (Exception e) {
e.printStackTrace();
Log.e("ZP","上传exception:" + e.toString());
}
finally {
requestUrl = null;
}
}
}
}
Java我不是很熟悉,很多我都是按照C#的逻辑来实现的,找几个类似C#的方法来实现的,比如java的url我就是照着c#的webrequest来的,总计为了实现这个功能踩了还是蛮多的坑,记录下来防止以后继续踩坑。突然发现自己在Unity上写功能的时间少了很多,都是在弄这种奇奇怪怪的需求。
上一篇: JAVA异常——异常处理
下一篇: iOS 崩溃日志分析(个人总结,最实用)