欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[Unity]收集报错日志(2)--安卓崩溃日志收集

程序员文章站 2022-04-21 17:49:52
...

       之前不是写了篇收集报错日志上传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上写功能的时间少了很多,都是在弄这种奇奇怪怪的需求。

相关标签: Unity Java