Cocos2d-x 记录游戏日志并上传

前端之家收集整理的这篇文章主要介绍了Cocos2d-x 记录游戏日志并上传前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在游戏测试过程中我们可能会遇到有些偶发性的Bug不能复现,不能定位的问题,这就很尴尬了。
所以我们在这里实现一下实时记录游戏日志的功能


记录日志,具体记些什么呢?不可能把每一步都记的很清楚,但是我们在开发过程中,每一步可能会打印一些特定的输出,我们就在输出上做一些手脚,把它的每一行都记录下来。


环境:Cocos2d-x quick


if DEBUG_MODE then
	--把打印的log写入文件
	LOG_FILE_NAME = "log_file.txt"
	BACKUP_LOG_FILE_NAME = "backup_log_file.txt"
	--如果之前写过文件就把之前的替换成备份
	if io.exists(device.writablePath..LOG_FILE_NAME) then
		--检查之前是否有备份
		if io.exists(device.writablePath..BACKUP_LOG_FILE_NAME) then
			--如果有备份则删掉备份
			os.execute("rm "..device.writablePath..BACKUP_LOG_FILE_NAME)
		end
		--把之前的文件替换成备份文件
		io.open(device.writablePath..BACKUP_LOG_FILE_NAME,'a+')
		os.execute("mv " .. device.writablePath..LOG_FILE_NAME .. " " .. device.writablePath..BACKUP_LOG_FILE_NAME)
	end
	--新建一个新的空文件
	print(os.execute("touch "..device.writablePath..LOG_FILE_NAME))


	LOG_FILE_PATH = io.open(device.writablePath..LOG_FILE_NAME,'a+')
	--重写print 让打印的东西能同时写入到文件里
	old_print = print
	print = function (...)
		old_print(...)
		--写入
		if ... then
			local args = {...}
			local s = args[1]
			if #args > 1 then
				for i=2,#args do
					s = s .. "    |    " .. args[i]
				end
			end
			LOG_FILE_PATH:write(tostring(s).."\n")
			LOG_FILE_PATH:flush()
		end
	end
end



记录Log的方法就到此为止了,DEBUG_MODE在开启的时候没写一行print都会向文件里写入一行。


下面说一下上传

上传我们用了libcurl,因为在iOS和Android的系统中没有集成,所以不能直接调用os.execute(curl xxxxx),改在C++层进行上传的操作。

新建LogFile.cpp和LogFile.h两个文件

LogFile.cpp

//
//  LogFile.cpp
//  vegasnights
//
//  Created by DonLiu on 16/7/6.
//
//

#include "LogFile.h"

/* parse headers for Content-Length */
 size_t LogFile::getcontentlengthfunc(void *ptr,size_t size,size_t nmemb,void *stream)
{
    int r;
    long len = 0;
    /* _snscanf() is Win32 specific */
    //r = _snscanf(ptr,size * nmemb,"Content-Length: %ld\n",&len);
    r = sscanf((const char*)ptr,&len);
    if (r) /* Microsoft: we don't read the specs */
        *((long *) stream) = len;
    return size * nmemb;
}
/* discard downloaded data */
size_t LogFile::discardfunc(void *ptr,void *stream)
{
    return size * nmemb;
}
//write data to upload
size_t LogFile::writefunc(void *ptr,void *stream)
{
    return fwrite(ptr,size,nmemb,(FILE*)stream);
}
/* read data to upload */
size_t LogFile::readfunc(void *ptr,void *stream)
{
    FILE *f = (FILE*)stream;
    size_t n;
    if (ferror(f))
        return CURL_READFUNC_ABORT;
    n = fread(ptr,f) * size;
    return n;
}
int LogFile::upload(CURL *curlhandle,const char * remotepath,const char * localpath,const char * userpwd,long timeout,long tries)
{
    FILE *f;
    long uploaded_len = 0;
    CURLcode r = CURLE_GOT_NOTHING;
    int c;
    f = fopen(localpath,"rb");
    if (f == NULL) {
        perror(NULL);
        return 0;
    }
    curl_easy_setopt(curlhandle,CURLOPT_UPLOAD,1L);
    curl_easy_setopt(curlhandle,CURLOPT_URL,remotepath);
    curl_easy_setopt(curlhandle,CURLOPT_USERPWD,userpwd);
    curl_easy_setopt(curlhandle,CURLOPT_CONNECTTIMEOUT,1);
    if (timeout)
        curl_easy_setopt(curlhandle,CURLOPT_FTP_RESPONSE_TIMEOUT,timeout);
    curl_easy_setopt(curlhandle,CURLOPT_HEADERFUNCTION,getcontentlengthfunc);
    curl_easy_setopt(curlhandle,CURLOPT_HEADERDATA,&uploaded_len);
    curl_easy_setopt(curlhandle,CURLOPT_WRITEFUNCTION,discardfunc);
    curl_easy_setopt(curlhandle,CURLOPT_READFUNCTION,readfunc);
    curl_easy_setopt(curlhandle,CURLOPT_READDATA,f);
    curl_easy_setopt(curlhandle,CURLOPT_FTPPORT,"-"); /* disable passive mode */
    curl_easy_setopt(curlhandle,CURLOPT_FTP_CREATE_MISSING_DIRS,CURLOPT_VERBOSE,1L);
    for (c = 0; (r != CURLE_OK) && (c < tries); c++) {
        /* are we resuming? */
        if (c) { /* yes */
            /* determine the length of the file already written */
            /*
             * With NOBODY and NOHEADER,libcurl will issue a SIZE
             * command,but the only way to retrieve the result is
             * to parse the returned Content-Length header. Thus,* getcontentlengthfunc(). We need discardfunc() above
             * because HEADER will dump the headers to stdout
             * without it.
             */
            curl_easy_setopt(curlhandle,CURLOPT_NOBODY,1L);
            curl_easy_setopt(curlhandle,CURLOPT_HEADER,1L);
            r = curl_easy_perform(curlhandle);
            if (r != CURLE_OK)
                continue;
            curl_easy_setopt(curlhandle,0L);
            curl_easy_setopt(curlhandle,0L);
            fseek(f,uploaded_len,SEEK_SET);
            curl_easy_setopt(curlhandle,CURLOPT_APPEND,1L);
        }
        else { /* no */
            curl_easy_setopt(curlhandle,0L);
        }
        r = curl_easy_perform(curlhandle);
    }
    fclose(f);
    if (r == CURLE_OK)
        return 1;
    else {
        fprintf(stderr,"%s\n",curl_easy_strerror(r));
        return 0;
    }
}
// 下载
int LogFile::download(CURL *curlhandle,long tries)
{
    FILE *f;
    curl_off_t local_file_len = -1 ;
    long filesize =0 ;
    CURLcode r = CURLE_GOT_NOTHING;
    struct stat file_info;
    int use_resume = 0;
    //获取本地文件大小信息
    if(stat(localpath,&file_info) == 0)
    {
        local_file_len = file_info.st_size;
        use_resume = 1;
    }
    //追加方式打开文件,实现断点续传
    f = fopen(localpath,"ab+");
    if (f == NULL) {
        perror(NULL);
        return 0;
    }
    curl_easy_setopt(curlhandle,userpwd);
    //连接超时设置
    curl_easy_setopt(curlhandle,timeout);
    //设置头处理函数
    curl_easy_setopt(curlhandle,&filesize);
    // 设置断点续传
    curl_easy_setopt(curlhandle,CURLOPT_RESUME_FROM_LARGE,use_resume?local_file_len:0);
    curl_easy_setopt(curlhandle,writefunc);
    curl_easy_setopt(curlhandle,CURLOPT_WRITEDATA,CURLOPT_NOPROGRESS,1L);
    r = curl_easy_perform(curlhandle);
    fclose(f);
    if (r == CURLE_OK)
        return 1;
    else {
        fprintf(stderr,curl_easy_strerror(r));
        return 0;
    }
}

void LogFile::lua_upload(const char * remotepath,const char *localpath,const char * userpwd){
    CURL *curlhandle = curl_easy_init();
    upload(curlhandle,remotepath,localpath,userpwd,1,3);
    curl_easy_cleanup(curlhandle);
    curl_global_cleanup();
}

LogFile.h:
//
//  LogFile.hpp
//  vegasnights
//
//  Created by DonLiu on 16/7/6.
//
//

#ifndef LogFile_hpp
#define LogFile_hpp

#include <stdlib.h>
#include <stdio.h>
#include <curl/curl.h>
#include <sys/stat.h>

class LogFile {
public:
    static size_t getcontentlengthfunc(void *ptr,void *stream);
    static size_t discardfunc(void *ptr,void *stream);
    static size_t writefunc(void *ptr,void *stream);
    static size_t readfunc(void *ptr,void *stream);
    static int upload(CURL *curlhandle,long tries);
    static int download(CURL *curlhandle,long tries);
    static void lua_upload(const char * remotepath,const char * userpwd);
};

#endif /* LogFile_hpp */
很清爽的一段代码。我把lua_upload这个方法抛到Lua里了,直接调用就好。

猜你在找的Cocos2d-x相关文章