闲鱼技术01 发表于 2022-12-31 18:07

记录货拉拉的glog日志框架和Protobuf数据框架的配套使用

glog 的优点


mmap 内存映射实现,支持同步/异步写入模式,采用自定义的二进制文件格式,上层可以自定义序列化方式,兼具灵活,高性能和容错能力。支持增量(按天)归档和全量(按文件)归档 、 日志流式压缩、加密,支持自动清理日志文件,SDK 包含基于 C++ 实现的日志读取功能。
具体背景及原理说明 可看该网址https://juejin.cn/post/7168662263337861133
1. glog日志框架的依赖


在需要的module 下的build.gradle 下
android{ defaultConfig {      ndk {            abiFilters "armeabi-v7a"//保留一个架构的so      }    }}dependencies { implementation "cn.huolala.glog.android:glog-android-static:1.0.0"//货拉拉的日志库}2. Protobuf数据框架的依赖


在项目的根目录下的build.gradle 下
dependencies {         classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.15' //    }2.1 Protobuf数据框架的依赖


在需要的module 下的build.gradle 下
apply plugin: 'com.google.protobuf'android{    compileOptions {      sourceCompatibility JavaVersion.VERSION_1_8      targetCompatibility JavaVersion.VERSION_1_8    }      sourceSets {      main {            // 定义proto文件目录 默认就是proto 可以不写改步骤 或者重新定义目录            proto {                srcDir 'src/main/proto'                include '*.proto'            }            java {                srcDir 'src/main/java'            }      }    }}dependencies { implementation 'com.google.protobuf:protobuf-lite:3.0.0'}protobuf {    protoc {             artifact = 'com.google.protobuf:protoc:3.7.0'    }    plugins {      javalite {                artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'      }    }// 默认路径为 build/generated/source/proto// 该目录下会按 buildType 生成 debug /release 目录    generatedFilesBaseDir = "$projectDir/src/main/xxx" //预编译生成的文件    generateProtoTasks {      all().each { task ->            task.builtins {                remove java            }            task.plugins {                javalite {}            }      }    }}3. 简单的封装使用

3.1glog 的封装及说明

   日志内容需要我们自己定义 来把要收集的堆栈信息及线程和异常进行整理成msg 写入import android.content.Context;import android.os.Process;import android.text.TextUtils;import android.util.Log;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.Arrays;import java.util.Date;import java.util.concurrent.atomic.AtomicLong;import glog.android.BuildConfig;import glog.android.Glog;/** * @author: tjf * @date: 2022-12-31 * @desc: Glog 日志框架简单的封装   先initialize 初始化 后再配置setGlogConfig日志信息 **/public class GlogManager {    private Glog glog;    Context context;    private GlogManager() {    }    public static GlogManager getInstance() {      return SingletonHelper.INSTANCE;    }    private static class SingletonHelper {      private static final GlogManager INSTANCE = new GlogManager();    }    public void initialize() {      Glog.initialize(BuildConfig.DEBUG ? Glog.InternalLogLevel.InternalLogLevelDebug :                Glog.InternalLogLevel.InternalLogLevelInfo);    }    // 初始化实例 配置glog    public void setGlogConfig(Context context) {      this.context = context;      int EXPIRES_SECS = 14 * 24 * 60 * 60; // 14 day //日志的定期删除时间 默认是 7天         final int TOTAL_ARCHIVE_SIZE_LIMIT = 56 * 1024 * 1024; // 56 MB每个日志文件的大小 限制 默认是16MB大小      glog = new Glog.Builder(context)                .protoName("glog_potbuf")         // 实例标识,相同标识的实例只创建一次 文件名的前缀                .rootDirectory(context.getFilesDir().getAbsolutePath() + "/glog")//日志存储的文件目录                // 默认在data/user/0/包名/files/glog/文件                .async(true)//是否异步写入                .expireSeconds(EXPIRES_SECS)//日志的定期删除时间                .compressMode(Glog.CompressMode.Zlib)//压缩格式默认开启压缩                .totalArchiveSizeLimit(TOTAL_ARCHIVE_SIZE_LIMIT)//每个日志文件的大小限制                .encryptMode(Glog.EncryptMode.AES)// 加密方式默认无                .key("")                            // ECDH Server public key加密的公钥                .incrementalArchive(true)      //支持增量(按天)归档 和 全量(按文件)归档;                // 默认 false 重命名缓存文件的方式归档true 增量归档,当天日志写入同一文件                .build();    }    //写入日志    public void glogWirter(String msg) {      glog.write(msg.getBytes());    }    //写入proto 格式的日志 tag的    public void glogWirtes_Potobuf(String tag, String msg) {      AtomicLong seq = new AtomicLong();      byte[] msgBytes = LogProtos.Log.newBuilder()                .setLogLevel(LogProtos.Log.Level.INFO)                .setSequence(seq.getAndIncrement())                .setTimestamp(String.valueOf(System.currentTimeMillis()))                .setPid(Process.myPid())                .setTid(String.valueOf(Thread.currentThread().getId()))                .setTag(tag)                .setMsg(msg)                .build()                .toByteArray();      glog.write(msgBytes);    }    //写入proto 格式的日志日志 级别 和tag和内容    public void glogWirtes_Potobuf(LogProtos.Log.Level logLevel, String tag, String msg) {      AtomicLong seq = new AtomicLong();      byte[] msgBytes = LogProtos.Log.newBuilder()                .setLogLevel(logLevel)                .setSequence(seq.getAndIncrement())                .setTimestamp(String.valueOf(System.currentTimeMillis()))                .setPid(Process.myPid())                .setTid(String.valueOf(Thread.currentThread().getId()))                .setTag(tag)                .setMsg(msg)                .build()                .toByteArray();      glog.write(msgBytes);    }    //释放清空    public void destroy() {      if (glog != null) {            glog.flush();            glog.destroy();      }    }    private final String TAG = "GlogDemo";    // 读取当天的日志type 1 普通格式2 proto 格式    public void readNewDateLog(int type) {      glog.flush();      String[] logArchiveFiles = glog.getArchivesOfDate(new Date().getTime() / 1000);      byte[] inBuf = new byte;      Log.i(TAG, "开始读取当天日志, 文件列表:" + Arrays.toString(logArchiveFiles));      for (int i = 0; i < logArchiveFiles.length; i++) {            String filename = logArchiveFiles;            try {                Glog.Reader readers = glog.openReader(filename);                String str;                StringBuilder stb = new StringBuilder();                while (true) {                  int count = readers.read(inBuf);                  if (count < 0) { // 读取结束                        break;                  } else if (count == 0) { // 破损恢复                        continue;                  }                  byte[] outBuf = new byte;                  System.arraycopy(inBuf, 0, outBuf, 0, count);                  if (type == 1) {                        str = new String(outBuf, "UTF8");                        Log.i(TAG, str);                  } else if (type == 2) {                        Log.i(TAG, LogProtos(LogProtos.Log.parseFrom(outBuf)));                  }                }            } catch (IOException e) {                e.printStackTrace();            }      }      Log.i(TAG, "读取完成");    }    // 读取放在assets下的glog 文件    public void readAssetsFile(String fileName) {      glog.flush();      String filePath = copyAssetAndWrite(context, fileName);      if (TextUtils.isEmpty(filePath)) {            Log.i(TAG, "没有该文件 无法解析");            return;      }      byte[] inBuf = new byte[(int) new File(filePath).length()];      Log.i(TAG, "开始读取, 文件名:" + filePath);      try {            Glog.Reader readers = glog.openReader(filePath);            while (true) {                int count = readers.read(inBuf);                if (count < 0) { // 读取结束                  break;                } else if (count == 0) { // 破损恢复                  continue;                }                byte[] outBuf = new byte;                System.arraycopy(inBuf, 0, outBuf, 0, count);                Log.i(TAG, LogProtos(LogProtos.Log.parseFrom(outBuf)));            }      } catch (IOException e) {            e.printStackTrace();      }      Log.i(TAG, "读取完成");    }    //Proto 格式的输出    private String LogProtos(LogProtos.Log logs) {      return "Log{" +                "sequence=" + logs.getSequence() +                ", timestamp='" + logs.getTimestamp() + '\'' +                ", logLevel=" + logs.getLogLevelValue() +                ", pid=" + logs.getPid() +                ", tid='" + logs.getTid() + '\'' +                ", tag='" + logs.getTag() + '\'' +                ", msg='" + logs.getMsg() + '\'' +                '}';    }    /**   * 读取assets 下的文件 到app的缓存目录下   *   * @param context   * @param fileName   * @return   */    public String copyAssetAndWrite(Context context, String fileName) {      try {            File cacheDir = context.getCacheDir();            if (!cacheDir.exists()) {                cacheDir.mkdirs();            }            File outFile = new File(cacheDir, fileName);            if (!outFile.exists()) {                boolean res = outFile.createNewFile();                if (!res) {                  return null;                }            } else {                if (outFile.length() > 10) {//表示已经写入一次                  return outFile.getPath();                }            }            InputStream is = context.getResources().getAssets().open(fileName);            FileOutputStream fos = new FileOutputStream(outFile);            byte[] buffer = new byte;            int byteCount;            while ((byteCount = is.read(buffer)) != -1) {                fos.write(buffer, 0, byteCount);            }            fos.flush();            is.close();            fos.close();            return outFile.getPath();      } catch (IOException e) {            e.printStackTrace();      }      return null;    }}3.2protos 的格式文件


在main 的同级 下新建一个proto文件夹新建一个日志类型的proto 的数据结构 Log.proto
建好后 通过AS 的build 下的 rebuild project 来创建 编译的LogProtos 文件生成
syntax = "proto3";//proto3 版本package glog;//包option java_package = "com.tjf.glogpotobufdemo";//包名称option java_outer_classname = "LogProtos";//别名message Log {enum Level {    INFO = 0;    DEBUG = 1;    VERBOSE = 2;    WARN = 3;    ERROR = 4;}int64 sequence = 1;string timestamp = 2;Level logLevel = 3;int32 pid = 4;string tid = 5;string tag = 6;string msg = 7;}4. 完结


元旦快乐
页: [1]
查看完整版本: 记录货拉拉的glog日志框架和Protobuf数据框架的配套使用