所以我们在这里实现一下实时记录游戏日志的功能。
记录日志,具体记些什么呢?不可能把每一步都记的很清楚,但是我们在开发过程中,每一步可能会打印一些特定的输出,我们就在输出上做一些手脚,把它的每一行都记录下来。
环境: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里了,直接调用就好。