Browse Source

v1.0.0开发:zap日志模块调整为java开发

#Suyghur 3 years ago
parent
commit
d7bf0d4cd4
46 changed files with 1734 additions and 927 deletions
  1. 2 2
      build.gradle
  2. 2 4
      demo/src/main/java/com/dolin/demo/DemoApplication.kt
  3. 1 0
      demo/src/main/java/com/dolin/demo/ZapActivity.kt
  4. 15 6
      library_zap/CMakeLists.txt
  5. 7 5
      library_zap/build.gradle
  6. 17 0
      library_zap/buildJar.gradle
  7. 0 0
      library_zap/consumer-rules.pro
  8. 99 1
      library_zap/proguard-rules.pro
  9. 82 0
      library_zap/publish.gradle
  10. 16 3
      library_zap/shell/decompress_log.py
  11. 180 0
      library_zap/src/main/cpp/third_part/buffer/buffer.cpp
  12. 2 1
      library_zap/src/main/cpp/third_part/buffer/buffer.h
  13. 78 0
      library_zap/src/main/cpp/third_part/buffer/buffer_flush.cpp
  14. 167 0
      library_zap/src/main/cpp/third_part/buffer/buffer_header.cpp
  15. 59 0
      library_zap/src/main/cpp/third_part/buffer/file_flush.cpp
  16. 0 0
      library_zap/src/main/cpp/third_part/kit/common_log.h
  17. 1 1
      library_zap/src/main/cpp/zap.cpp
  18. 11 0
      library_zap/src/main/java/com/dolin/zap/Version.java
  19. 0 12
      library_zap/src/main/java/com/dolin/zap/Version.kt
  20. 82 0
      library_zap/src/main/java/com/dolin/zap/Zap.java
  21. 0 86
      library_zap/src/main/java/com/dolin/zap/Zap.kt
  22. 0 68
      library_zap/src/main/java/com/dolin/zap/crashlytics/JavaCrashCatcher.kt
  23. 112 0
      library_zap/src/main/java/com/dolin/zap/entity/Config.java
  24. 0 117
      library_zap/src/main/java/com/dolin/zap/entity/Config.kt
  25. 3 5
      library_zap/src/main/java/com/dolin/zap/entity/Level.java
  26. 63 0
      library_zap/src/main/java/com/dolin/zap/entity/ZapData.java
  27. 0 65
      library_zap/src/main/java/com/dolin/zap/entity/ZapData.kt
  28. 68 0
      library_zap/src/main/java/com/dolin/zap/format/DateFileFormatter.java
  29. 0 50
      library_zap/src/main/java/com/dolin/zap/format/DateFileFormatter.kt
  30. 103 0
      library_zap/src/main/java/com/dolin/zap/impl/Record2MMap.java
  31. 0 93
      library_zap/src/main/java/com/dolin/zap/impl/Record2MMap.kt
  32. 223 0
      library_zap/src/main/java/com/dolin/zap/impl/ZapPrint.java
  33. 0 194
      library_zap/src/main/java/com/dolin/zap/impl/ZapPrint.kt
  34. 0 10
      library_zap/src/main/java/com/dolin/zap/internal/ICatch.kt
  35. 12 0
      library_zap/src/main/java/com/dolin/zap/internal/IFormatter.java
  36. 0 11
      library_zap/src/main/java/com/dolin/zap/internal/IFormatter.kt
  37. 25 0
      library_zap/src/main/java/com/dolin/zap/internal/IPrint.java
  38. 0 26
      library_zap/src/main/java/com/dolin/zap/internal/IPrint.kt
  39. 16 0
      library_zap/src/main/java/com/dolin/zap/internal/IRecord.java
  40. 0 16
      library_zap/src/main/java/com/dolin/zap/internal/IRecord.kt
  41. 91 0
      library_zap/src/main/java/com/dolin/zap/lifecycle/ZapLifecycle.java
  42. 0 58
      library_zap/src/main/java/com/dolin/zap/lifecycle/ZapLifecycle.kt
  43. 40 0
      library_zap/src/main/java/com/dolin/zap/util/LevelUtils.java
  44. 0 29
      library_zap/src/main/java/com/dolin/zap/util/LevelUtils.kt
  45. 157 0
      library_zap/src/main/java/com/dolin/zap/util/LogFileUtils.java
  46. 0 64
      library_zap/src/main/java/com/dolin/zap/util/LogFileUtils.kt

+ 2 - 2
build.gradle

@@ -3,7 +3,7 @@ buildscript {
 
     ext.COMM_LIB_DEV_ENABLE = true
     // 混淆开关
-    ext.MINIFY_ENABLE = false
+    ext.MINIFY_ENABLE = true
     // ndk版本
     ext.NDK_VERSION = '21.3.6528147'
     // kotlin版本
@@ -42,4 +42,4 @@ allprojects {
 
 task clean(type: Delete) {
     delete rootProject.buildDir
-}
+}

+ 2 - 4
demo/src/main/java/com/dolin/demo/DemoApplication.kt

@@ -2,9 +2,9 @@ package com.dolin.demo
 
 import android.app.Application
 import android.content.Context
+import com.dolin.zap.Zap
 import com.dolin.zap.entity.Config
 import com.dolin.zap.entity.Level
-import com.dolin.zap.Zap
 
 /**
  * @author #Suyghur.
@@ -26,13 +26,11 @@ class DemoApplication : Application() {
                 //缓存日志最低等级
                 .setRecordLevel(Level.DEBUG)
                 //是否开启压缩缓存日志内容
-                .setRecordCompressEnable(true)
+                .setCompressEnable(true)
                 //缓存文件的过期时间
                 .setOverdueDay(3)
                 //缓存文件大小限制,超过则会自动扩容新文件
                 .setFileSizeLimitDay(15)
-                //缓存文件内容是否压缩
-                .setRecordCompressEnable(false)
                 .create()
         Zap.initialize(this, config)
     }

+ 1 - 0
demo/src/main/java/com/dolin/demo/ZapActivity.kt

@@ -19,6 +19,7 @@ class ZapActivity : Activity(), View.OnClickListener {
             Item(1, "INFO日志"),
             Item(2, "WARNING日志"),
             Item(3, "ERROR日志"),
+            Item(4, "目录测试"),
     )
 
     override fun onCreate(savedInstanceState: Bundle?) {

+ 15 - 6
library_zap/CMakeLists.txt

@@ -10,24 +10,33 @@ cmake_minimum_required(VERSION 3.4.1)
 # You can define multiple libraries, and CMake builds them for you.
 # Gradle automatically packages shared libraries with your APK.
 
-include_directories(src/main/cpp/include)
+set(PUBLISH TRUE)
+
+include_directories(src/main/cpp/third_part/buffer)
+include_directories(src/main/cpp/third_part/kit)
 aux_source_directory(src/main/cpp/ DIR_SOURCE)
+aux_source_directory(src/main/cpp/third_part/buffer DIR_BUFFER)
 add_library(
         dolin-zap
         SHARED
         ${DIR_SOURCE}
+        ${DIR_BUFFER}
 )
 
 #动态方式加载 STATIC:表示静态的.a的库 SHARED:表示.so的库
-add_library(dolin-comm SHARED IMPORTED)
+#add_library(dolin-comm SHARED IMPORTED)
 
 #设置要连接的so的相对路径
 #${CMAKE_SOURCE_DIR}:表示CMake.txt的当前文件夹路径
 #${ANDROID_ABI}:编译时会自动根据CPU架构去选择相应的库
-set_target_properties(dolin-comm PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/../soLibs/comm/${ANDROID_ABI}/libdolin-comm.so)
-
+#set_target_properties(dolin-comm PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/../soLibs/comm/${ANDROID_ABI}/libdolin-comm.so)
+#if (${PUBLISH})
+#    #set_target_properties(dolin-comm PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/../soLibs/comm/${ANDROID_ABI}/libdolin-comm.so)
+#else ()
+#    set_target_properties(dolin-comm PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/../soLibs/comm/${ANDROID_ABI}/libdolin-comm.so)
+#endif ()
 ##添加第三方头文件
-target_include_directories(dolin-zap PRIVATE ${CMAKE_SOURCE_DIR}/src/main/cpp/third_part)
+#target_include_directories(dolin-zap PRIVATE ${CMAKE_SOURCE_DIR}/src/main/cpp/third_part)
 
 # Searches for a specified prebuilt library and stores the path as a
 # variable. Because CMake includes system libraries in the search path by
@@ -47,7 +56,7 @@ find_library( # Sets the name of the path variable.
 
 target_link_libraries( # Specifies the target library.
         dolin-zap
-        dolin-comm
+#        dolin-comm
         # Links the target library to the log library
         # included in the NDK.
         ${log-lib})

+ 7 - 5
library_zap/build.gradle

@@ -1,6 +1,5 @@
 plugins {
     id 'com.android.library'
-    id 'kotlin-android'
 }
 
 android {
@@ -61,7 +60,10 @@ android {
 }
 
 dependencies {
-    implementation "org.jetbrains.kotlin:kotlin-stdlib:$KOTLIN_VERSION"
-    implementation 'androidx.core:core-ktx:1.3.2'
-    compileOnly project(':library_comm')
-}
+//    implementation "org.jetbrains.kotlin:kotlin-stdlib:$KOTLIN_VERSION"
+//    implementation 'androidx.core:core-ktx:1.3.2'
+//    implementation project(':library_comm')
+}
+
+//apply from: 'publish.gradle'
+apply from: 'buildJar.gradle'

+ 17 - 0
library_zap/buildJar.gradle

@@ -0,0 +1,17 @@
+def SDK_BASE_NAME = 'dolin_zap'
+def SDK_VERSION = '1.0.0'
+def SEPARATOR = '_'
+def SDK_DST_PATH = 'build/jar/'
+def ZIP_FILE = file('build/intermediates/aar_main_jar/release/classes.jar')
+
+task deleteBaseBuild(type: Delete) {
+    delete SDK_DST_PATH
+}
+
+task makeJar(type: Jar) {
+    from zipTree(ZIP_FILE)
+    baseName = SDK_BASE_NAME + SEPARATOR + SDK_VERSION
+    destinationDir = file(SDK_DST_PATH)
+}
+
+makeJar.dependsOn(deleteBaseBuild, build)

+ 0 - 0
library_zap/consumer-rules.pro


+ 99 - 1
library_zap/proguard-rules.pro

@@ -18,4 +18,102 @@
 
 # If you keep the line number information, uncomment this to
 # hide the original source file name.
-#-renamesourcefileattribute SourceFile
+#-renamesourcefileattribute SourceFile
+
+# 代码混淆压缩比,在0~7之间,默认为5,一般不做修改
+-optimizationpasses 7
+# 混合时不使用大小写混合,混合后的类名为小写
+-dontusemixedcaseclassnames
+# 指定不去忽略非公共库的类
+-dontskipnonpubliclibraryclasses
+-dontoptimize
+# 这句话能够使我们的项目混淆后产生映射文件
+# 包含有类名->混淆后类名的映射关系
+-verbose
+-ignorewarnings
+# 指定不去忽略非公共库的类成员
+-dontskipnonpubliclibraryclassmembers
+# 指定混淆是采用的算法,后面的参数是一个过滤器
+# 这个过滤器是谷歌推荐的算法,一般不做更改
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+# 保留java与js交互注解
+-keepattributes *Annotation*
+-keepattributes *JavascriptInterface*
+
+# 保留内部类
+-keepattributes Exceptions,InnerClasses
+
+# 保留泛型
+-keepattributes Signature
+
+-keepnames class * implements java.io.Serializable
+-keepclassmembers class * implements java.io.Serializable {
+   static final long serialVersionUID;
+   private static final java.io.ObjectStreamField[] serialPersistentFields;
+   !static !transient <fields>;
+   private void writeObject(java.io.ObjectOutputStream);
+   private void readObject(java.io.ObjectInputStream);
+   java.lang.Object writeReplace();
+   java.lang.Object readResolve();
+}
+
+-keepclassmembers class **.R$* {
+    public static <fields>;
+}
+-keep class **.R$* {
+ *;
+}
+
+-keep public class * extends android.app.Activity{
+	public <fields>;
+	public <methods>;
+}
+-keep public class * extends android.app.Application{
+	public <fields>;
+	public <methods>;
+}
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+
+
+-keepclassmembers enum * {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
+
+-keepclasseswithmembers class * {
+	public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembers class * {
+	public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclasseswithmembernames class *{
+	native <methods>;
+}
+
+-keep class * implements android.os.Parcelable {
+  public static final android.os.Parcelable$Creator *;
+}
+
+-keepclasseswithmembers class * {
+    ... *JNI*(...);
+}
+
+-keepclasseswithmembernames class * {
+	... *JRI*(...);
+}
+
+-keep class **JNI* {*;}
+
+-keep class com.dolin.zap.Version{public <fields>;public <methods>;}
+-keep class com.dolin.zap.Zap{public <fields>;public <methods>;}
+-keep class com.dolin.zap.impl.Record2MMap{*;}
+-keep class com.dolin.zap.entity.Level{*;}
+-keep class com.dolin.zap.entity.Config{public <fields>;public <methods>;}
+-keep class com.dolin.zap.entity.Config$Builder{public <fields>;public <methods>;}

+ 82 - 0
library_zap/publish.gradle

@@ -0,0 +1,82 @@
+apply plugin: 'maven'
+apply plugin: 'signing'
+
+def PUBLISH_GROUP_ID = "io.github.suyghur.dolin"
+def PUBLISH_ARTIFACT_ID = "zap"
+def PUBLISH_VERSION = "0.0.1"
+
+Properties properties = new Properties()
+properties.load(project.rootProject.file('local.properties').newDataInputStream())
+
+def ossrhUsername = properties.getProperty("SonaType.user")
+def ossrhPassword = properties.getProperty("SonaType.pwd")
+
+task androidSourcesJar(type: Jar) {
+    archiveClassifier.set('source')
+    if (project.plugins.findPlugin('com.android.library')) {
+        from android.sourceSets.main.java.srcDirs
+    } else {
+        form sourceSets.main.java.srcDirs
+    }
+}
+
+artifacts {
+    archives androidSourcesJar
+}
+
+signing {
+    required {
+        gradle.taskGraph.hasTask("uploadArchives")
+    }
+    sign configurations.archives
+}
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            beforeDeployment {
+                MavenDeployment deployment -> signing.signPom(deployment)
+            }
+
+            repository(url: "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") {
+                authentication(userName: ossrhUsername, password: ossrhPassword)
+            }
+
+            snapshotRepository(url: "https://s01.oss.sonatype.org/content/repositories/snapshots/") {
+                authentication(userName: ossrhUsername, password: ossrhPassword)
+            }
+
+            pom.groupId = PUBLISH_GROUP_ID
+            pom.artifactId = PUBLISH_ARTIFACT_ID
+            pom.version = PUBLISH_VERSION
+
+            pom.project {
+                name "${PUBLISH_GROUP_ID}:${PUBLISH_ARTIFACT_ID}"
+                packaging 'aar'
+                description 'a log framework of Android'
+                url 'https://github.com/Suyghur'
+
+                scm {
+                    connection 'scm:git:github.com/Suyghur/Dolin.git'
+                    developerConnection 'scm:git:ssh://github.com/Suyghur/Dolin.git'
+                    url 'https://github.com/Suyghur/Dolin'
+                }
+
+                licenses {
+                    license {
+                        name 'The Apache License, Version 2.0'
+                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+                    }
+                }
+
+                developers {
+                    developer {
+                        id 'Suyghur'
+                        name 'Suyghur'
+                        email 'suyghurmjp@outlook.com'
+                    }
+                }
+            }
+        }
+    }
+}

+ 16 - 3
library_zap/shell/decompress_log.py

@@ -3,10 +3,10 @@ import os
 import sys
 
 
-def decompress(args):
+def decompress_py2(args):
     decompressor = zlib.decompressobj(-zlib.MAX_WBITS)
     src = args[0]
-    dst = args[1]
+    dst = src[:len(src) - 4] + "-decompress.zap"
     _buffer = []
     with open(src, "rb") as src_fp:
         _buffer = bytearray(os.path.getsize(src))
@@ -16,5 +16,18 @@ def decompress(args):
         dst_fp.write(tmp)
 
 
+def decompress_py3(args):
+    decompressor = zlib.decompressobj(-zlib.MAX_WBITS)
+    src = args[0]
+    dst = src[:len(src) - 4] + "-decompress.zap"
+    with open(src, "rb") as src_fp:
+        _buffer = src_fp.read()
+    with open(dst, "w+") as dst_fp:
+        tmp = decompressor.decompress(_buffer)
+        dst_fp.write(bytes.decode(tmp))
+
+
 if __name__ == "__main__":
-    decompress(sys.args[1:])
+    decompress_py3(sys.argv[1:])
+    # py2用下面的方法
+    # decompress_py2(sys.argv[1:])

+ 180 - 0
library_zap/src/main/cpp/third_part/buffer/buffer.cpp

@@ -0,0 +1,180 @@
+//
+// Created by #Suyghur, on 4/7/21.
+//
+
+#include "buffer.h"
+#include "../kit/common_log.h"
+
+Buffer::Buffer(char *ptr, size_t buffer_size) : buffer_ptr(ptr), buffer_size(buffer_size), buffer_header(buffer_ptr, buffer_size) {}
+
+Buffer::~Buffer() {
+    Release();
+}
+
+void Buffer::InitData(char *log_path, size_t log_path_len, size_t limit_size, bool _compress) {
+    std::lock_guard<std::recursive_mutex> lck_release(log_mtx);
+    memset(buffer_ptr, '\0', buffer_size);
+
+    dolin_common::Header header{};
+    header.magic = kMagicHeader;
+    header.log_path_len = log_path_len;
+    header.log_path = log_path;
+    header.log_len = 0;
+    header.limit_size = limit_size;
+    header.compress = _compress;
+
+    buffer_header.InitHeader(header);
+    InitCompress(_compress);
+
+    data_ptr = (char *) buffer_header.GetDataPtr();
+    write_ptr = (char *) buffer_header.GetWritePtr();
+
+    OpenLogFile(log_path);
+}
+
+void Buffer::SetLength(size_t len) {
+    buffer_header.SetLogLen(len);
+}
+
+size_t Buffer::GetLength() {
+    return write_ptr - data_ptr;
+}
+
+size_t Buffer::Append(const char *log, size_t len) {
+    std::lock_guard<std::recursive_mutex> lck_append(log_mtx);
+    if (GetLength() == 0) {
+        InitCompress(compress);
+    }
+
+    size_t free_size = EmptySize();
+    size_t write_size;
+    if (compress) {
+        zStream.avail_in = (uInt) len;
+        zStream.next_in = (Bytef *) log;
+
+        zStream.avail_out = (uInt) free_size;
+        zStream.next_out = (Bytef *) write_ptr;
+
+        if (Z_OK != deflate(&zStream, Z_SYNC_FLUSH)) {
+            return 0;
+        }
+
+        write_size = free_size - zStream.avail_out;
+    } else {
+        write_size = len <= free_size ? len : free_size;
+        memcpy(write_ptr, log, write_size);
+    }
+    write_ptr += write_size;
+    SetLength(GetLength());
+    return write_size;
+}
+
+void Buffer::Release() {
+    std::lock_guard<std::recursive_mutex> lck_release(log_mtx);
+    if (compress && Z_NULL != zStream.state) {
+        deflateEnd(&zStream);
+    }
+    if (map_buffer) {
+        munmap(buffer_ptr, buffer_size);
+    } else {
+        delete[]buffer_ptr;
+    }
+    if (log_file_ptr != nullptr) {
+        fclose(log_file_ptr);
+    }
+}
+
+size_t Buffer::EmptySize() {
+    return buffer_size - (write_ptr - buffer_ptr);
+}
+
+char *Buffer::GetLogPath() {
+    return buffer_header.GetLogPath();
+}
+
+void Buffer::SetFileFlush(FileFlush *flush) {
+    file_flush_ptr = flush;
+}
+
+void Buffer::CallFileFlush() {
+    CallFileFlush(file_flush_ptr);
+}
+
+void Buffer::CallFileFlush(FileFlush *flush) {
+    CallFileFlush(flush, nullptr);
+}
+
+void Buffer::CallFileFlush(FileFlush *flush, Buffer *buffer) {
+    if (flush == nullptr) {
+        if (buffer != nullptr) {
+            delete buffer;
+        }
+        return;
+    }
+
+    std::lock_guard<std::recursive_mutex> lck_flush(log_mtx);
+    if (GetLength() > 0) {
+        if (compress && Z_NULL != zStream.state) {
+            deflateEnd(&zStream);
+        }
+        auto *buffer_flush = new BufferFlush(log_file_ptr);
+        buffer_flush->Write(data_ptr, GetLength());
+        buffer_flush->ReleaseThiz(buffer);
+        Clear();
+        flush->AsyncFlush(buffer_flush);
+    } else {
+        delete buffer;
+    }
+}
+
+void Buffer::ExpLogPath(char *path, size_t limit_size) {
+    if (log_file_ptr != nullptr) {
+        CallFileFlush();
+    }
+    InitData(path, strlen(path), limit_size, compress);
+
+}
+
+void Buffer::Clear() {
+    std::lock_guard<std::recursive_mutex> lck_clear(log_mtx);
+    write_ptr = data_ptr;
+    memset(write_ptr, '\0', EmptySize());
+    SetLength(GetLength());
+}
+
+bool Buffer::InitCompress(bool _compress) {
+    compress = _compress;
+    if (compress) {
+        zStream.zalloc = Z_NULL;
+        zStream.zfree = Z_NULL;
+        zStream.opaque = Z_NULL;
+        return Z_OK == deflateInit2(&zStream, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+    }
+    return false;
+}
+
+bool Buffer::OpenLogFile(const char *path) {
+    if (path != nullptr) {
+        FILE *file = fopen(path, "ab+");
+        if (file != nullptr) {
+            log_file_ptr = file;
+            return true;
+        }
+    }
+    return false;
+}
+
+bool Buffer::IsCurrentLogFileOversize() {
+    return GetCurrentLogFileSize() >= buffer_header.GetLimitSize();
+}
+
+size_t Buffer::GetCurrentLogFileSize() {
+    size_t size = 0;
+    if (log_file_ptr != nullptr) {
+        fseek(log_file_ptr, 0, SEEK_END);
+        size = ftell(log_file_ptr);
+    }
+    return size;
+}
+
+

+ 2 - 1
library_zap/src/main/cpp/third_part/buffer/buffer.h

@@ -59,7 +59,8 @@ private:
 
     BufferHeader buffer_header;
     z_stream zStream{};
-
+//    size_t part_num = 1;
+//    size_t limit_size = 0;
     bool compress = false;
 
     void Clear();

+ 78 - 0
library_zap/src/main/cpp/third_part/buffer/buffer_flush.cpp

@@ -0,0 +1,78 @@
+//
+// Created by #Suyghur, on 2021/4/7.
+//
+
+#include <cmath>
+#include <cstring>
+#include "buffer_flush.h"
+
+BufferFlush::BufferFlush(FILE *log_file, size_t size) : capacity(size), log_file_ptr(log_file) {}
+
+BufferFlush::~BufferFlush() {
+    if (data_ptr != nullptr) {
+        delete[] data_ptr;
+    }
+    if (release_ptr != nullptr) {
+//        delete release_ptr;
+        ::operator delete(release_ptr);
+    }
+
+}
+
+/**
+ * 填充缓存
+ */
+void BufferFlush::Write(void *data, size_t len) {
+    if (data_ptr == nullptr) {
+        capacity = (size_t) fmax(capacity, len);
+        data_ptr = new char[capacity]{0};
+        write_ptr = data_ptr;
+    }
+
+
+    size_t empty_size = EmptySize();
+    if (len < empty_size) {
+        memcpy(write_ptr, data, len);
+        write_ptr += len;
+    } else {
+        size_t now_len = GetLength();
+        size_t new_capacity = now_len + len;
+        char *data_tmp = new char[new_capacity]{0};
+        memcpy(data_tmp, data_ptr, now_len);
+        memcpy(data_tmp + now_len, data, len);
+        char *old_data = data_ptr;
+        data_ptr = data_tmp;
+        write_ptr = data_ptr + new_capacity;
+        delete[]old_data;
+    }
+}
+
+void BufferFlush::Reset() {
+    if (data_ptr != nullptr) {
+        memset(data_ptr, 0, capacity);
+        write_ptr = data_ptr;
+    }
+}
+
+size_t BufferFlush::GetLength() {
+    if (data_ptr != nullptr && write_ptr != nullptr) {
+        return write_ptr - data_ptr;
+    }
+    return 0;
+}
+
+void *BufferFlush::GetPtr() {
+    return data_ptr;
+}
+
+FILE *BufferFlush::GetLogFile() {
+    return log_file_ptr;
+}
+
+void BufferFlush::ReleaseThiz(void *buffer) {
+    this->release_ptr = buffer;
+}
+
+size_t BufferFlush::EmptySize() {
+    return capacity - GetLength();
+}

+ 167 - 0
library_zap/src/main/cpp/third_part/buffer/buffer_header.cpp

@@ -0,0 +1,167 @@
+//
+// Created by #Suyghur, on 2021/4/7.
+//
+
+#include "buffer_header.h"
+#include "../kit/common_log.h"
+
+dolin_common::BufferHeader::BufferHeader(void *data, size_t size) : data_ptr((char *) data), data_size(size) {}
+
+dolin_common::BufferHeader::~BufferHeader() = default;
+
+void dolin_common::BufferHeader::InitHeader(dolin_common::Header &header) {
+    if ((sizeof(char) + sizeof(size_t) + sizeof(size_t) + header.log_path_len) > data_size) {
+        return;
+    }
+    memcpy(data_ptr, &header.magic, sizeof(char));
+    //log长度
+    memcpy(data_ptr + sizeof(char), &header.log_len, sizeof(size_t));
+    //log路径长度
+    memcpy(data_ptr + sizeof(char) + sizeof(size_t), &header.log_path_len, sizeof(size_t));
+    //log路径
+    memcpy(data_ptr + sizeof(char) + sizeof(size_t) + sizeof(size_t), header.log_path, header.log_path_len);
+    //限制大小
+    memcpy(data_ptr + sizeof(char) + sizeof(size_t) + sizeof(size_t) + header.log_path_len, &header.limit_size, sizeof(size_t));
+    //是否压缩
+    char compress = 0;
+    if (header.compress) {
+        compress = 1;
+    }
+    memcpy(data_ptr + sizeof(char) + sizeof(size_t) + sizeof(size_t) + header.log_path_len + sizeof(size_t) + sizeof(size_t), &compress, sizeof(char));
+
+}
+
+/**
+ * 获取原始头(不加长度)
+ */
+void *dolin_common::BufferHeader::GetOriginPtr() {
+    return data_ptr;
+}
+
+/**
+ * 获取头部信息(包含头信息长度)
+ */
+void *dolin_common::BufferHeader::GetDataPtr() {
+    return data_ptr + GetHeaderLen();
+}
+
+/**
+ * 获取写入信息(包含头信息长度和日志长度)
+ */
+void *dolin_common::BufferHeader::GetWritePtr() {
+    return data_ptr + GetHeaderLen() + GetLogLen();
+}
+
+dolin_common::Header *dolin_common::BufferHeader::GetHeader() {
+    auto *header = new Header();
+    if (IsAvailable()) {
+        header->magic = kMagicHeader;
+
+        size_t log_len = 0;
+        memcpy(&log_len, data_ptr + sizeof(char), sizeof(size_t));
+        header->log_len = log_len;
+
+        size_t log_path_len = 0;
+        memcpy(&log_path_len, data_ptr + sizeof(char) + sizeof(size_t), sizeof(size_t));
+        header->log_path_len = log_path_len;
+
+        char *log_path = new char[log_path_len + 1];
+        memset(log_path, 0, log_path_len + 1);
+        memcpy(log_path, data_ptr + sizeof(char) + sizeof(size_t) + sizeof(size_t), log_path_len);
+        header->log_path = log_path;
+
+        size_t limit_size = 0;
+        memcpy(&limit_size, data_ptr + sizeof(char) + sizeof(size_t) + sizeof(size_t) + log_path_len, sizeof(size_t));
+        header->limit_size = limit_size;
+
+        char compress = (data_ptr + sizeof(char) + sizeof(size_t) + sizeof(size_t) + log_path_len + sizeof(size_t))[0];
+        header->compress = compress == 1;
+
+
+        LOGD("JNI-> log_len : %d", log_len);
+        LOGD("JNI-> log_path_len : %d", log_path_len);
+        LOGD("JNI-> log_path : %s", log_path);
+        LOGD("JNI-> limit_size : %d", limit_size);
+        LOGD("JNI-> compress : %c", compress);
+    }
+    return header;
+}
+
+size_t dolin_common::BufferHeader::GetHeaderLen() {
+    if (IsAvailable()) {
+        return CalculateHeaderLen(GetLogPathLen());
+    }
+    return 0;
+}
+
+void dolin_common::BufferHeader::SetLogLen(size_t len) {
+    if (IsAvailable()) {
+        memcpy(data_ptr + sizeof(char), &len, sizeof(size_t));
+    }
+}
+
+size_t dolin_common::BufferHeader::GetLogLen() {
+    if (IsAvailable()) {
+        size_t len = 0;
+        memcpy(&len, data_ptr + sizeof(char), sizeof(size_t));
+        //log长度总是大于0并小于buffer_size减去header长度的
+        if (len > 0 && len < (data_size - GetHeaderLen())) {
+            return len;
+        }
+    }
+    return 0;
+}
+
+size_t dolin_common::BufferHeader::GetLogPathLen() {
+    if (IsAvailable()) {
+        size_t len = 0;
+        memcpy(&len, data_ptr + sizeof(char) + sizeof(size_t), sizeof(size_t));
+        //log path 的长度不能大于整个buffer减去header中其他数据的长度
+        if (len > 0 && len < data_size - CalculateHeaderLen(0)) {
+            return len;
+        }
+    }
+    return 0;
+}
+
+char *dolin_common::BufferHeader::GetLogPath() {
+    if (IsAvailable()) {
+        size_t log_path_len = GetLogPathLen();
+        if (log_path_len > 0) {
+            char *log_path = new char[log_path_len + 1];
+            memset(log_path, 0, log_path_len + 1);
+            memcpy(log_path, data_ptr + sizeof(char) + sizeof(size_t) + sizeof(size_t), log_path_len);
+            return log_path;
+        }
+    }
+    return nullptr;
+}
+
+
+size_t dolin_common::BufferHeader::GetLimitSize() {
+    size_t size = 0;
+    if (IsAvailable()) {
+        memcpy(&size, data_ptr + sizeof(char) + sizeof(size_t) + sizeof(size_t) + GetLogPathLen(), sizeof(size_t));
+    }
+    return size;
+}
+
+
+bool dolin_common::BufferHeader::IsCompress() {
+    if (IsAvailable()) {
+        return ((data_ptr + sizeof(char) + sizeof(size_t) + sizeof(size_t) + GetLogPathLen() + sizeof(size_t))[0]) == 1;
+    }
+    return false;
+}
+
+bool dolin_common::BufferHeader::IsAvailable() {
+    return data_ptr[0] == kMagicHeader;
+}
+
+size_t dolin_common::BufferHeader::CalculateHeaderLen(size_t path_len) {
+    return sizeof(char) + sizeof(size_t) + sizeof(size_t) + path_len + sizeof(size_t) + sizeof(char);
+}
+
+
+
+

+ 59 - 0
library_zap/src/main/cpp/third_part/buffer/file_flush.cpp

@@ -0,0 +1,59 @@
+//
+// Created by #Suyghur, on 2021/4/7.
+//
+
+#include "file_flush.h"
+
+FileFlush::FileFlush() {
+    async_thread = std::thread(&FileFlush::AsyncLogThread, this);
+}
+
+FileFlush::~FileFlush() {
+    StopFlush();
+}
+
+bool FileFlush::AsyncFlush(BufferFlush *buffer) {
+    std::unique_lock <std::mutex> lck_async_flush(async_mtx);
+    if (exit) {
+        delete buffer;
+        return false;
+    }
+    async_buffer.push_back(buffer);
+    async_condition.notify_all();
+    return true;
+}
+
+void FileFlush::StopFlush() {
+    exit = true;
+    async_condition.notify_all();
+    async_thread.join();
+}
+
+void FileFlush::AsyncLogThread() {
+    while (true) {
+        std::unique_lock <std::mutex> lck_async_log_thread(async_mtx);
+        while (!async_buffer.empty()) {
+            BufferFlush *data = async_buffer.back();
+            async_buffer.pop_back();
+            Flush(data);
+        }
+        if (exit) {
+            return;
+        }
+        async_condition.wait(lck_async_log_thread);
+    }
+}
+
+/**
+ * 写文件
+ */
+ssize_t FileFlush::Flush(BufferFlush *buffer) {
+    ssize_t written = 0;
+    FILE *log_file = buffer->GetLogFile();
+    if (log_file != nullptr && buffer->GetLength() > 0) {
+        written = fwrite(buffer->GetPtr(), buffer->GetLength(), 1, log_file);
+        fflush(log_file);
+    }
+    delete buffer;
+    return written;
+}

+ 0 - 0
library_zap/src/main/cpp/third_part/buffer/common_log.h → library_zap/src/main/cpp/third_part/kit/common_log.h


+ 1 - 1
library_zap/src/main/cpp/zap.cpp

@@ -9,7 +9,7 @@
 #include "third_part/buffer/buffer.h"
 #include "third_part/buffer/file_flush.h"
 #include "third_part/buffer/buffer_header.h"
-#include "third_part/buffer/common_log.h"
+#include "third_part/kit/common_log.h"
 
 static FileFlush *pFileFlush = nullptr;
 

+ 11 - 0
library_zap/src/main/java/com/dolin/zap/Version.java

@@ -0,0 +1,11 @@
+package com.dolin.zap;
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/05/19
+ */
+public class Version {
+    public static final String VERSION = "1.0.0";
+
+    public static final String FULL_VERSION = "Zap_" + VERSION;
+}

+ 0 - 12
library_zap/src/main/java/com/dolin/zap/Version.kt

@@ -1,12 +0,0 @@
-package com.dolin.zap
-
-/**
- * @author #Suyghur.
- * Created on 4/7/21
- */
-object Version {
-
-    const val VERSION = "1.0.0"
-
-    const val FULL_VERSION = "Zap_$VERSION"
-}

+ 82 - 0
library_zap/src/main/java/com/dolin/zap/Zap.java

@@ -0,0 +1,82 @@
+package com.dolin.zap;
+
+import android.app.Application;
+
+import com.dolin.zap.entity.Config;
+import com.dolin.zap.impl.ZapPrint;
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/05/19
+ */
+public class Zap {
+
+    private static boolean hasInitialized = false;
+
+    public static void initialize(Application application, Config config) {
+        ZapPrint.getInstance().initialize(application, config);
+        hasInitialized = true;
+    }
+
+    public static void recycle() {
+        if (hasInitialized) {
+            ZapPrint.getInstance().recycle();
+        }
+    }
+
+    public static void d(Object obj) {
+        if (hasInitialized) {
+            ZapPrint.getInstance().d(obj);
+        }
+    }
+
+    public static void d(String tag, Object obj) {
+        if (hasInitialized) {
+            ZapPrint.getInstance().d(tag, obj);
+        }
+    }
+
+    public static void i(Object obj) {
+        if (hasInitialized) {
+            ZapPrint.getInstance().i(obj);
+        }
+    }
+
+    public static void i(String tag, Object obj) {
+        if (hasInitialized) {
+            ZapPrint.getInstance().i(tag, obj);
+        }
+    }
+
+    public static void w(Object obj) {
+        if (hasInitialized) {
+            ZapPrint.getInstance().w(obj);
+        }
+    }
+
+    public static void w(String tag, Object obj) {
+        if (hasInitialized) {
+            ZapPrint.getInstance().w(tag, obj);
+        }
+    }
+
+    public static void e(Object obj) {
+        if (hasInitialized) {
+            ZapPrint.getInstance().e(obj);
+        }
+    }
+
+    public static void e(String tag, Object obj) {
+        if (hasInitialized) {
+            ZapPrint.getInstance().e(tag, obj);
+        }
+    }
+
+    public static String getVersion() {
+        return Version.VERSION;
+    }
+
+    public static String getFullVersion() {
+        return Version.FULL_VERSION;
+    }
+}

+ 0 - 86
library_zap/src/main/java/com/dolin/zap/Zap.kt

@@ -1,86 +0,0 @@
-package com.dolin.zap
-
-import android.app.Application
-import com.dolin.zap.entity.Config
-import com.dolin.zap.impl.ZapPrint
-
-/**
- * @author #Suyghur.
- * Created on 4/7/21
- */
-object Zap {
-
-    private lateinit var sZapPrint: ZapPrint
-    private var hasInitialized = false
-
-    @JvmStatic
-    fun initialize(application: Application, config: Config) {
-        sZapPrint = ZapPrint.instance()
-        sZapPrint.initialize(application, config)
-        hasInitialized = true
-    }
-
-    @JvmStatic
-    fun recycle() {
-        if (hasInitialized)
-            sZapPrint.recycle()
-    }
-
-    @JvmStatic
-    fun d(any: Any?) {
-        if (hasInitialized)
-            sZapPrint.d(any)
-    }
-
-    @JvmStatic
-    fun d(tag: String, any: Any?) {
-        if (hasInitialized)
-            sZapPrint.d(tag, any)
-    }
-
-    @JvmStatic
-    fun i(any: Any?) {
-        if (hasInitialized)
-            sZapPrint.i(any)
-    }
-
-    @JvmStatic
-    fun i(tag: String, any: Any?) {
-        if (hasInitialized)
-            sZapPrint.i(tag, any)
-    }
-
-    @JvmStatic
-    fun w(any: Any?) {
-        if (hasInitialized)
-            sZapPrint.w(any)
-    }
-
-    @JvmStatic
-    fun w(tag: String, any: Any?) {
-        if (hasInitialized)
-            sZapPrint.w(tag, any)
-    }
-
-    @JvmStatic
-    fun e(any: Any?) {
-        if (hasInitialized)
-            sZapPrint.e(any)
-    }
-
-    @JvmStatic
-    fun e(tag: String, any: Any?) {
-        if (hasInitialized)
-            sZapPrint.e(tag, any)
-    }
-
-    @JvmStatic
-    fun getVersion(): String {
-        return Version.VERSION
-    }
-
-    @JvmStatic
-    fun getFullVersion(): String {
-        return Version.FULL_VERSION
-    }
-}

+ 0 - 68
library_zap/src/main/java/com/dolin/zap/crashlytics/JavaCrashCatcher.kt

@@ -1,68 +0,0 @@
-package com.dolin.zap.crashlytics
-
-import android.os.Process
-import com.dolin.zap.Zap
-import kotlin.system.exitProcess
-
-/**
- * @author #Suyghur.
- * Created on 4/12/21
- */
-class JavaCrashCatcher : Thread.UncaughtExceptionHandler {
-
-    private val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
-
-    private var intercept = false
-
-    fun initialize() {
-        try {
-            Thread.setDefaultUncaughtExceptionHandler(this)
-        } catch (e: Exception) {
-            Zap.e("JavaCrashCatcher->setDefaultUncaughtExceptionHandler() error , ${e.localizedMessage}")
-        }
-    }
-
-    override fun uncaughtException(t: Thread, e: Throwable) {
-        if (defaultHandler != null) {
-            Thread.setDefaultUncaughtExceptionHandler(defaultHandler)
-        }
-        try {
-            handleException(t, e)
-        } catch (e: Exception) {
-            Zap.e("JavaCrashCatcher->handlerException error , ${e.localizedMessage}")
-        }
-        if (intercept) {
-            Process.killProcess(Process.myPid())
-            exitProcess(10)
-        } else {
-            defaultHandler?.apply {
-                uncaughtException(t, e)
-            }
-        }
-
-    }
-
-    private fun handleException(t: Thread, e: Throwable) {
-
-    }
-
-
-    companion object {
-
-        fun getInstance(): JavaCrashCatcher {
-            return JavaCrashCatcherHolder.INSTANCE
-        }
-
-        private object JavaCrashCatcherHolder {
-            val INSTANCE = JavaCrashCatcher()
-        }
-
-        /**
-         * 防止单例对象在反序列化时重新生成对象
-         */
-        private fun readResolve(): Any {
-            return JavaCrashCatcherHolder.INSTANCE
-        }
-    }
-
-}

+ 112 - 0
library_zap/src/main/java/com/dolin/zap/entity/Config.java

@@ -0,0 +1,112 @@
+package com.dolin.zap.entity;
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/05/19
+ */
+public class Config {
+
+    public String logFolderDir;
+    public String tag;
+    public Level logcatLevel;
+    public Level recordLevel;
+    public boolean recordEnable;
+    public boolean compressEnable;
+    public long overdueDayMs;
+    public int fileSizeLimitDayByte;
+
+    private Config(Builder builder) {
+        this.logFolderDir = builder.logFolderDir;
+        this.tag = builder.tag;
+        this.logcatLevel = builder.logcatLevel;
+        this.recordLevel = builder.recordLevel;
+        this.recordEnable = builder.recordEnable;
+        this.compressEnable = builder.compressEnable;
+        this.overdueDayMs = builder.overdueDay * 24 * 3600 * 1000L;
+        this.fileSizeLimitDayByte = builder.fileSizeLimitDay * 1024 * 1024;
+    }
+
+    @Override
+    public String toString() {
+        return "Config{" +
+                "logFolderDir='" + logFolderDir + '\'' +
+                ", tag='" + tag + '\'' +
+                ", logcatLevel=" + logcatLevel +
+                ", recordLevel=" + recordLevel +
+                ", recordEnable=" + recordEnable +
+                ", compressEnable=" + compressEnable +
+                ", overdueDayMs=" + overdueDayMs +
+                ", fileSizeLimitDayByte=" + fileSizeLimitDayByte +
+                '}';
+    }
+
+    public static final class Builder {
+        private String logFolderDir = "";
+        private String tag = "";
+        private Level logcatLevel = Level.DEBUG;
+        private Level recordLevel = Level.DEBUG;
+        private boolean recordEnable = true;
+        private boolean compressEnable = true;
+        private long overdueDay = 3;
+        private int fileSizeLimitDay = 15;
+
+        /**
+         * 日志存储路径,默认是应用的私有目录下dolin文件夹
+         */
+        public Builder setLogFolderDir(String logFolderDir) {
+            this.logFolderDir = logFolderDir;
+            return this;
+        }
+
+        public Builder setTag(String tag) {
+            this.tag = tag;
+            return this;
+        }
+
+        /**
+         * 允许输出到logcat的日志的最低级别,默认为DEBUG级别
+         */
+        public Builder setLogcatLevel(Level logcatLevel) {
+            this.logcatLevel = logcatLevel;
+            return this;
+        }
+
+        /**
+         * 允许记录到文件的日志的最低级别, 默认为DEBUG级别
+         */
+        public Builder setRecordLevel(Level recordLevel) {
+            this.recordLevel = recordLevel;
+            return this;
+        }
+
+        public Builder setRecordEnable(boolean recordEnable) {
+            this.recordEnable = recordEnable;
+            return this;
+        }
+
+        public Builder setCompressEnable(boolean compressEnable) {
+            this.compressEnable = compressEnable;
+            return this;
+        }
+
+        /**
+         * 日志过期天数,过期日志将自动清除,默认为3
+         */
+        public Builder setOverdueDay(long overdueDay) {
+            this.overdueDay = overdueDay;
+            return this;
+        }
+
+        /**
+         * 单天日志文件存储上限,单位 MB,默认为15
+         */
+        public Builder setFileSizeLimitDay(int fileSizeLimitDay) {
+            this.fileSizeLimitDay = fileSizeLimitDay;
+            return this;
+        }
+
+        public Config create() {
+            return new Config(this);
+        }
+    }
+}

+ 0 - 117
library_zap/src/main/java/com/dolin/zap/entity/Config.kt

@@ -1,117 +0,0 @@
-package com.dolin.zap.entity
-
-/**
- * @author #Suyghur.
- * Created on 4/7/21
- */
-class Config private constructor(builder: Builder) {
-
-    var logFolderDir = ""
-        private set
-    var tag = ""
-        private set
-    var logcatLevel: Level
-        private set
-    var recordLevel: Level
-        private set
-    var recordEnable: Boolean
-        private set
-    var compressEnable: Boolean
-        private set
-    var overdueDayMs = 0L
-        private set
-    var fileSizeLimitDayByte = 0
-        private set
-
-
-    init {
-        this.logFolderDir = builder.folderDir
-        this.tag = builder.tag
-        this.logcatLevel = builder.logcatLevel
-        this.recordLevel = builder.recordLevel
-        this.recordEnable = builder.recordEnable
-        this.compressEnable = builder.compressEnable
-        this.overdueDayMs = builder.overdueDay * 24 * 3600 * 1000L
-        this.fileSizeLimitDayByte = builder.fileSizeLimitDay * 1024 * 1024
-    }
-
-    override fun toString(): String {
-        return "Config{" +
-                "logDir='" + logFolderDir + '\'' +
-                ", logcatLevel=" + logcatLevel +
-                ", recordLevel=" + recordLevel +
-                ", overdueDayMs=" + overdueDayMs +
-                ", fileSizeLimitDayByte=" + fileSizeLimitDayByte +
-                '}'
-    }
-
-    class Builder {
-        internal var folderDir = ""
-        internal var tag = ""
-        internal var logcatLevel = Level.DEBUG
-        internal var recordLevel = Level.DEBUG
-        internal var recordEnable = true
-        internal var compressEnable = true
-        internal var overdueDay = 3
-        internal var fileSizeLimitDay = 15
-
-        /**
-         * 日志存储路径,默认是应用的私有目录下dolin文件夹
-         */
-        fun setFolderDir(folderDir: String): Builder {
-            this.folderDir = folderDir
-            return this
-        }
-
-        fun setLogTag(tag: String): Builder {
-            this.tag = tag
-            return this
-        }
-
-        /**
-         * 允许输出到logcat的日志的最低级别,默认为[Level.DEBUG]级别
-         */
-        fun setLogcatLevel(level: Level): Builder {
-            this.logcatLevel = level
-            return this
-        }
-
-        /**
-         * 允许记录到文件的日志的最低级别, 默认为[Level.DEBUG]级别
-         */
-        fun setRecordLevel(level: Level): Builder {
-            this.recordLevel = level
-            return this
-        }
-
-        fun setRecordEnable(enable: Boolean): Builder {
-            this.recordEnable = enable
-            return this
-        }
-
-        fun setRecordCompressEnable(enable: Boolean): Builder {
-            this.compressEnable = enable
-            return this
-        }
-
-        /**
-         * 日志过期天数,过期日志将自动清除,默认为3
-         */
-        fun setOverdueDay(overdueDay: Int): Builder {
-            this.overdueDay = overdueDay
-            return this
-        }
-
-        /**
-         * 单天日志文件存储上限,单位 MB,默认为15
-         */
-        fun setFileSizeLimitDay(mb: Int): Builder {
-            this.fileSizeLimitDay = mb
-            return this
-        }
-
-        fun create(): Config {
-            return Config(this)
-        }
-    }
-}

+ 3 - 5
library_zap/src/main/java/com/dolin/zap/entity/Level.kt → library_zap/src/main/java/com/dolin/zap/entity/Level.java

@@ -1,15 +1,13 @@
-package com.dolin.zap.entity
+package com.dolin.zap.entity;
 
 /**
  * @author #Suyghur.
- * Created on 4/7/21
+ * Created on 2021/05/19
  */
-enum class Level {
+public enum Level {
     NONE,
     DEBUG,
     INFO,
     WARNING,
     ERROR,
 }
-
-

+ 63 - 0
library_zap/src/main/java/com/dolin/zap/entity/ZapData.java

@@ -0,0 +1,63 @@
+package com.dolin.zap.entity;
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/05/19
+ */
+public class ZapData {
+
+    private static final int MAX_POOL_SIZE = 50;
+    private static final Object sPoolSync = new Object();
+    private static ZapData sPool = null;
+    public static int sPoolSize = 0;
+
+
+    public Level level = Level.NONE;
+    public String tag = "";
+    public String msg = "";
+    private ZapData next = null;
+
+    public static ZapData obtain() {
+        synchronized (sPoolSync) {
+            if (sPool != null) {
+                ZapData data = sPool;
+                sPool = data.next;
+                data.next = null;
+                sPoolSize--;
+                return data;
+            }
+        }
+        return new ZapData();
+    }
+
+    public static ZapData obtain(Level level, String tag, String msg) {
+        ZapData data = obtain();
+        data.level = level;
+        data.tag = tag;
+        data.msg = msg;
+        return data;
+    }
+
+    public void recycle() {
+        this.level = Level.NONE;
+        this.tag = "";
+        this.msg = "";
+        synchronized (sPoolSync) {
+            if (sPoolSize < MAX_POOL_SIZE) {
+                next = sPool;
+                sPool = this;
+                sPoolSize++;
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "ZapData{" +
+                "level=" + level +
+                ", tag='" + tag + '\'' +
+                ", msg='" + msg + '\'' +
+                ", next=" + next +
+                '}';
+    }
+}

+ 0 - 65
library_zap/src/main/java/com/dolin/zap/entity/ZapData.kt

@@ -1,65 +0,0 @@
-package com.dolin.zap.entity
-
-/**
- * 参考[android.os.Message]的享元模式
- * @author #Suyghur.
- * Created on 4/8/21
- */
-class ZapData {
-
-    var level: Level = Level.NONE
-    var tag = ""
-    var msg: String = ""
-    private var next: ZapData? = null
-
-    fun recycle() {
-        level = Level.NONE
-        tag = ""
-        msg = ""
-        synchronized(sPoolSync) {
-            if (sPoolSize < MAX_POOL_SIZE) {
-                next = sPool
-                sPool = this
-                sPoolSize++
-            }
-        }
-    }
-
-    override fun toString(): String {
-        return "ZapData{" +
-                "level=" + level.name +
-                ", tag='" + tag + '\'' +
-                ", msg='" + msg + '\'' +
-                '}'
-    }
-
-    companion object {
-        private val sPoolSync = Any()
-        private var sPool: ZapData? = null
-        private var sPoolSize = 0
-        private const val MAX_POOL_SIZE = 50
-
-        @JvmStatic
-        fun obtain(): ZapData {
-            synchronized(sPoolSync) {
-                if (sPool != null) {
-                    val data = sPool
-                    sPool = data!!.next
-                    data.next = null
-                    sPoolSize--
-                    return data
-                }
-            }
-            return ZapData()
-        }
-
-        @JvmStatic
-        fun obtain(level: Level, tag: String, msg: String): ZapData {
-            val data = obtain()
-            data.level = level
-            data.tag = tag
-            data.msg = msg
-            return data
-        }
-    }
-}

+ 68 - 0
library_zap/src/main/java/com/dolin/zap/format/DateFileFormatter.java

@@ -0,0 +1,68 @@
+package com.dolin.zap.format;
+
+import android.text.TextUtils;
+
+import com.dolin.zap.entity.Level;
+import com.dolin.zap.internal.IFormatter;
+import com.dolin.zap.util.LevelUtils;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/05/19
+ */
+public class DateFileFormatter implements IFormatter {
+
+    private SimpleDateFormat simpleDateFormat;
+    private Date date = null;
+    private String lastDateFormatted = "";
+    private StringBuffer stringBuffer;
+    private int timeLength = 0;
+
+    public DateFileFormatter() {
+        this("yyyy-MM-dd HH:mm:ss");
+    }
+
+    public DateFileFormatter(String pattern) {
+        simpleDateFormat = new SimpleDateFormat(pattern, Locale.getDefault());
+        stringBuffer = new StringBuffer();
+        //重置秒数
+        Calendar.getInstance().set(Calendar.SECOND, 0);
+        date = Calendar.getInstance().getTime();
+    }
+
+    private void resetTimePrefix() {
+        if (stringBuffer == null) {
+            return;
+        }
+        if (stringBuffer.length() > 0) {
+            stringBuffer.delete(0, stringBuffer.length());
+        }
+        timeLength = stringBuffer.append(lastDateFormatted).append(" ").length();
+    }
+
+    private String formatString(Level level, String tag, String msg) {
+        if (stringBuffer == null) {
+            return "";
+        }
+        if (stringBuffer.length() > timeLength) {
+            stringBuffer.delete(timeLength, stringBuffer.length());
+        }
+        return stringBuffer.append("[").append(LevelUtils.getShortLevelName(level)).append("]")
+                .append(tag).append(": ").append(msg).append("\n").toString();
+    }
+
+    @Override
+    public synchronized String format(Level level, String tag, String msg) {
+        if ((System.currentTimeMillis() - date.getTime()) > 1000 || TextUtils.isEmpty(lastDateFormatted)) {
+            date.setTime(System.currentTimeMillis());
+            lastDateFormatted = simpleDateFormat.format(date);
+            resetTimePrefix();
+        }
+        return formatString(level, tag, msg);
+    }
+}

+ 0 - 50
library_zap/src/main/java/com/dolin/zap/format/DateFileFormatter.kt

@@ -1,50 +0,0 @@
-package com.dolin.zap.format
-
-import android.text.TextUtils
-import com.dolin.zap.entity.Level
-import com.dolin.zap.internal.IFormatter
-import com.dolin.zap.util.LevelUtils
-import java.text.SimpleDateFormat
-import java.util.*
-
-/**
- * @author #Suyghur.
- * Created on 4/8/21
- */
-class DateFileFormatter : IFormatter {
-
-    private val pattern = "yyyy-MM-dd HH:mm:ss"
-    private var simpleDateFormat: SimpleDateFormat = SimpleDateFormat(pattern, Locale.getDefault())
-    private var date: Date
-    private var lastDateFormatted = ""
-    private var stringBuilder: StringBuilder = StringBuilder()
-    private var timeLength = 0
-
-    init {
-        Calendar.getInstance()[Calendar.SECOND] = 0
-        date = Calendar.getInstance().time
-    }
-
-    private fun resetTimePrefix() {
-        if (stringBuilder.isNotEmpty()) {
-            stringBuilder.delete(0, stringBuilder.length)
-        }
-        timeLength = stringBuilder.append(lastDateFormatted).append(" ").length
-    }
-
-    private fun formatString(level: Level, tag: String, msg: String): String {
-        if (stringBuilder.length > timeLength) {
-            stringBuilder.delete(timeLength, stringBuilder.length)
-        }
-        return stringBuilder.append("[${LevelUtils.getShortLevelName(level)}]").append(tag).append(": ").append(msg).append("\n").toString()
-    }
-
-    override fun format(level: Level, tag: String, msg: String): String {
-        if ((System.currentTimeMillis() - date.time) > 1000 || TextUtils.isEmpty(lastDateFormatted)) {
-            date.time = System.currentTimeMillis()
-            lastDateFormatted = simpleDateFormat.format(date)
-            resetTimePrefix()
-        }
-        return formatString(level, tag, msg)
-    }
-}

+ 103 - 0
library_zap/src/main/java/com/dolin/zap/impl/Record2MMap.java

@@ -0,0 +1,103 @@
+package com.dolin.zap.impl;
+
+import com.dolin.zap.internal.IRecord;
+import com.dolin.zap.util.LogFileUtils;
+
+import java.io.File;
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/05/19
+ */
+public class Record2MMap implements IRecord {
+
+    private long ptr = 0L;
+    private String logPath = "";
+    private String logDate = "";
+    private String logFilePath = "";
+    private int limitSize = 0;
+    private int num = 1;
+
+    static {
+        System.loadLibrary("dolin-zap");
+    }
+
+    public Record2MMap(String bufferPath, String logPath, String logDate, int capacity, int limitSize, boolean compress) {
+        this.num = LogFileUtils.getLogFileNumByDate(logPath, logDate);
+        this.logPath = logPath;
+        this.logDate = logDate;
+        this.limitSize = limitSize;
+        if (num > 1) {
+            this.logFilePath = logPath + File.separator + logDate + "-p" + num + ".zap";
+        } else {
+            this.logFilePath = logPath + File.separator + logDate + ".zap";
+        }
+        try {
+            this.ptr = initNative(bufferPath, logFilePath, capacity, limitSize, compress);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void write(String msg) {
+        if (ptr != 0L) {
+            try {
+                writeNative(ptr, msg);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    public void asyncFlush() {
+        if (ptr != 0L) {
+            try {
+                //自动扩容
+                if (isLogFileOverSizeNative(ptr)) {
+                    this.num += 1;
+                    this.logFilePath = logPath + File.separator + logDate + "-p" + num + ".zap";
+                    expLogFileNative(ptr, logFilePath, limitSize);
+                }
+                asyncFlushNative(ptr);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    public void expLogFile(String path, int limitSize) {
+        if (ptr != 0L) {
+            try {
+                expLogFileNative(ptr, path, limitSize);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    public void release() {
+        if (ptr != 0L) {
+            try {
+                releaseNative(ptr);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private static native long initNative(String bufferPath, String logFilePath, int capacity, int limitSize, boolean compress);
+
+    private native void writeNative(long ptr, String msg);
+
+    private native void asyncFlushNative(long ptr);
+
+    private native void expLogFileNative(long ptr, String path, int limitSize);
+
+    private native void releaseNative(long ptr);
+
+    private native boolean isLogFileOverSizeNative(long ptr);
+}

+ 0 - 93
library_zap/src/main/java/com/dolin/zap/impl/Record2MMap.kt

@@ -1,93 +0,0 @@
-package com.dolin.zap.impl
-
-import com.dolin.zap.internal.IRecord
-import com.dolin.zap.util.LogFileUtils
-import java.io.File
-
-/**
- * @author #Suyghur.
- * Created on 4/7/21
- */
-class Record2MMap(bufferDir: String,private val logDir:String, private val logDate: String,
-                  capacity: Int, private val limitSize: Int, compress: Boolean) : IRecord {
-
-    //buffer指针
-    private var ptr = 0L
-    private var logPath: String
-    private var num = 1
-
-    init {
-        System.loadLibrary("dolin-zap")
-        num = LogFileUtils.getLogFileNumByDate(logDir, logDate)
-        logPath = if (num > 1) {
-            "$logDir/$logDate-p$num.zap"
-        } else {
-            "$logDir/$logDate.zap"
-        }
-        try {
-            ptr = initNative(bufferDir, logPath, capacity, limitSize, compress)
-        } catch (e: Exception) {
-            e.printStackTrace()
-        }
-    }
-
-    override fun write(msg: String) {
-        if (ptr != 0L) {
-            try {
-                writeNative(ptr, msg)
-            } catch (e: Exception) {
-                e.printStackTrace()
-            }
-        }
-    }
-
-    override fun asyncFlush() {
-        if (ptr != 0L) {
-            try {
-                //自动扩容
-                if (isLogFileOverSizeNative(ptr)) {
-                    logPath = "$logDir/$logDate-p${num + 1}.zap"
-                    expLogFileNative(ptr, logPath, limitSize)
-                }
-                asyncFlushNative(ptr)
-            } catch (e: Exception) {
-                e.printStackTrace()
-            }
-        }
-    }
-
-    override fun expLogFile(path: String, limitSize: Int) {
-        if (ptr != 0L) {
-            try {
-                expLogFileNative(ptr, path, limitSize)
-            } catch (e: Exception) {
-                e.printStackTrace()
-            }
-        }
-    }
-
-    override fun release() {
-        if (ptr != 0L) {
-            try {
-                releaseNative(ptr)
-            } catch (e: Exception) {
-                e.printStackTrace()
-            }
-        }
-    }
-
-    private external fun writeNative(ptr: Long, msg: String)
-
-    private external fun asyncFlushNative(ptr: Long)
-
-    private external fun expLogFileNative(ptr: Long, path: String, limitSize: Int)
-
-    private external fun releaseNative(ptr: Long)
-
-    private external fun isLogFileOverSizeNative(ptr: Long): Boolean
-
-    companion object {
-        @JvmStatic
-        private external fun initNative(bufferPath: String, logPath: String, capacity: Int, limitSize: Int, compress: Boolean): Long
-    }
-}

+ 223 - 0
library_zap/src/main/java/com/dolin/zap/impl/ZapPrint.java

@@ -0,0 +1,223 @@
+package com.dolin.zap.impl;
+
+import android.app.Application;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.dolin.zap.entity.Config;
+import com.dolin.zap.entity.Level;
+import com.dolin.zap.entity.ZapData;
+import com.dolin.zap.format.DateFileFormatter;
+import com.dolin.zap.internal.IPrint;
+import com.dolin.zap.lifecycle.ZapLifecycle;
+import com.dolin.zap.util.LogFileUtils;
+
+import java.io.File;
+import java.lang.reflect.Array;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/05/19
+ */
+public class ZapPrint implements IPrint {
+
+    private static final int MAX_LENGTH_OF_SINGLE_MESSAGE = 4063;
+    private boolean hasinitialized = false;
+    private String tag = "";
+    private String logFolderDir = "";
+    private Level logcatLevel = Level.DEBUG;
+    private Level recordLevel = Level.DEBUG;
+    private Record2MMap record2MMap = null;
+    private DateFileFormatter dateFileFormatter = null;
+
+    private ZapPrint() {
+        dateFileFormatter = new DateFileFormatter();
+    }
+
+    public static ZapPrint getInstance() {
+        return ZapPrintHolder.INSTANCE;
+    }
+
+    /**
+     * 防止单例对象在反序列化时重新生成对象
+     */
+    private static Object readResolve() {
+        return ZapPrintHolder.INSTANCE;
+    }
+
+    public void initialize(final Application application, final Config config) {
+        if (hasinitialized) {
+            return;
+        }
+        String date = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
+
+        if (TextUtils.isEmpty(config.logFolderDir)) {
+            this.logFolderDir = LogFileUtils.getLogFolderDir(application);
+        } else {
+            this.logFolderDir = config.logFolderDir;
+        }
+
+        if (TextUtils.isEmpty(config.tag)) {
+            this.tag = "dolin_zap";
+        } else {
+            this.tag = config.tag;
+        }
+
+        this.logcatLevel = config.logcatLevel;
+        this.recordLevel = config.recordLevel;
+
+        String bufferPath = logFolderDir + File.separator + "zap.cache";
+        String logPath = LogFileUtils.getLogDir(logFolderDir, date);
+
+        if (config.recordEnable) {
+            record2MMap = new Record2MMap(bufferPath, logPath, date, 1024 * 400, config.fileSizeLimitDayByte, config.compressEnable);
+            ZapLifecycle.getInstance().registerZapLifeCallback(application, record2MMap);
+        }
+
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                LogFileUtils.cleanOverdueLog(application, config.overdueDayMs);
+            }
+        }).start();
+
+    }
+
+
+    @Override
+    public void d(Object obj) {
+        d(tag, obj);
+    }
+
+    @Override
+    public void d(String tag, Object obj) {
+        print(Level.DEBUG, tag, obj);
+    }
+
+    @Override
+    public void i(Object obj) {
+        i(tag, obj);
+    }
+
+    @Override
+    public void i(String tag, Object obj) {
+        print(Level.INFO, tag, obj);
+    }
+
+    @Override
+    public void w(Object obj) {
+        w(tag, obj);
+    }
+
+    @Override
+    public void w(String tag, Object obj) {
+        print(Level.WARNING, tag, obj);
+    }
+
+    @Override
+    public void e(Object obj) {
+        e(tag, obj);
+    }
+
+    @Override
+    public void e(String tag, Object obj) {
+        print(Level.ERROR, tag, obj);
+    }
+
+    private boolean interceptLogcat(Level level) {
+        return level.ordinal() < logcatLevel.ordinal();
+    }
+
+    private boolean interceptRecord(Level level) {
+        return level.ordinal() < recordLevel.ordinal();
+    }
+
+    private void print(Level level, String tag, Object obj) {
+        String msg = "";
+        if (obj == null) {
+            msg = "null";
+        } else {
+            Class<?> clz = obj.getClass();
+            if (clz.isArray()) {
+                StringBuilder sb = new StringBuilder(clz.getSimpleName());
+                sb.append("[ ");
+                for (int i = 0; i < Array.getLength(obj); i++) {
+                    if (i != 0) {
+                        sb.append(", ");
+                    }
+                    Object tmp = Array.get(obj, i);
+                    sb.append(tmp);
+                }
+                sb.append(" ]");
+                msg = sb.toString();
+            } else {
+                msg = obj + "";
+            }
+        }
+
+        ZapData data = ZapData.obtain(level, tag, msg);
+        if (!interceptLogcat(level)) {
+            printInner(data);
+        }
+        if (!interceptRecord(level)) {
+            doRecord(data);
+        }
+        data.recycle();
+    }
+
+    private void printInner(ZapData data) {
+        if (data.msg.length() <= MAX_LENGTH_OF_SINGLE_MESSAGE) {
+            doPrint(data.level, data.tag, data.msg);
+            return;
+        }
+        int msgLength = data.msg.length();
+        int start = 0;
+        int end = start + MAX_LENGTH_OF_SINGLE_MESSAGE;
+        while (start < msgLength) {
+            doPrint(data.level, data.tag, data.msg.substring(start, end));
+            start = end;
+            end = Math.min(start + MAX_LENGTH_OF_SINGLE_MESSAGE, msgLength);
+        }
+    }
+
+    private void doPrint(Level level, String tag, String msg) {
+        switch (level) {
+            case DEBUG:
+                Log.d(tag, msg);
+                break;
+            case WARNING:
+                Log.w(tag, msg);
+                break;
+            case ERROR:
+                Log.e(tag, msg);
+                break;
+            case NONE:
+            case INFO:
+            default:
+                Log.i(tag, msg);
+                break;
+        }
+    }
+
+    private void doRecord(ZapData data) {
+        if (record2MMap != null) {
+            record2MMap.write(dateFileFormatter.format(data.level, data.tag, data.msg));
+        }
+    }
+
+    public void recycle() {
+        if (record2MMap != null) {
+            ZapLifecycle.getInstance().unregisterZapLifeCallback();
+            record2MMap.asyncFlush();
+            record2MMap.release();
+        }
+    }
+
+    private static final class ZapPrintHolder {
+        private static final ZapPrint INSTANCE = new ZapPrint();
+    }
+
+}

+ 0 - 194
library_zap/src/main/java/com/dolin/zap/impl/ZapPrint.kt

@@ -1,194 +0,0 @@
-package com.dolin.zap.impl
-
-import android.app.Application
-import android.text.TextUtils
-import android.util.Log
-import com.dolin.zap.entity.Config
-import com.dolin.zap.entity.Level
-import com.dolin.zap.entity.ZapData
-import com.dolin.zap.format.DateFileFormatter
-import com.dolin.zap.internal.IPrint
-import com.dolin.zap.lifecycle.ZapLifecycle
-import com.dolin.zap.util.LogFileUtils
-import java.lang.reflect.Array
-import java.text.SimpleDateFormat
-import java.util.*
-
-/**
- * @author #Suyghur.
- * Created on 4/7/21
- */
-class ZapPrint : IPrint {
-
-    private var hasInitialized: Boolean = false
-    private var tag = ""
-    private var logFolderDir = ""
-    private var logcatLevel = Level.NONE
-    private var recordLevel = Level.NONE
-    private var record2MMap: Record2MMap? = null
-    private var dateFileFormatter: DateFileFormatter = DateFileFormatter()
-
-    fun initialize(application: Application, config: Config) {
-        if (hasInitialized) {
-            return
-        }
-
-        val date = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date())
-
-        this.logFolderDir = if (TextUtils.isEmpty(config.logFolderDir)) {
-            LogFileUtils.getLogFolderDir(application)
-        } else {
-            config.logFolderDir
-        }
-
-        this.tag = if (TextUtils.isEmpty(config.tag)) {
-            "dolin_zap"
-        } else {
-            config.tag
-        }
-
-        this.logcatLevel = config.logcatLevel
-        this.recordLevel = config.recordLevel
-
-        val bufferPath = "$logFolderDir/zap.cache"
-        val logPath = LogFileUtils.getLogDir(logFolderDir, date)
-
-        if (config.recordEnable) {
-            record2MMap = Record2MMap(bufferPath, logPath, date, 1024 * 400, config.fileSizeLimitDayByte, config.compressEnable)
-            ZapLifecycle.registerZapLifeCallback(application, record2MMap!!)
-        }
-
-        Thread {
-            LogFileUtils.cleanOverdueLog(logFolderDir, config.overdueDayMs)
-        }.start()
-    }
-
-    fun recycle() {
-        record2MMap?.apply {
-            ZapLifecycle.unregisterZapLifeCallback()
-            asyncFlush()
-            release()
-        }
-    }
-
-    override fun d(any: Any?) {
-        d(tag, any)
-    }
-
-    override fun d(tag: String, any: Any?) {
-        print(Level.DEBUG, tag, any)
-    }
-
-    override fun i(any: Any?) {
-        i(tag, any)
-    }
-
-    override fun i(tag: String, any: Any?) {
-        print(Level.INFO, tag, any)
-    }
-
-    override fun w(any: Any?) {
-        w(tag, any)
-    }
-
-    override fun w(tag: String, any: Any?) {
-        print(Level.WARNING, tag, any)
-    }
-
-    override fun e(any: Any?) {
-        e(tag, any)
-    }
-
-    override fun e(tag: String, any: Any?) {
-        print(Level.ERROR, tag, any)
-    }
-
-    private fun interceptLogcat(level: Level): Boolean {
-        return level.ordinal < logcatLevel.ordinal
-    }
-
-    private fun interceptRecord(level: Level): Boolean {
-        return level.ordinal < recordLevel.ordinal
-    }
-
-    private fun print(level: Level, tag: String, any: Any?) {
-        val msg = if (any == null) {
-            "null"
-        } else {
-            val clz: Class<*> = any.javaClass
-            if (clz.isArray) {
-                val sb = StringBuilder(clz.simpleName)
-                sb.append("[ ")
-                for (i in 0 until Array.getLength(any)) {
-                    if (i != 0) {
-                        sb.append(", ")
-                    }
-                    val tmp = Array.get(any, i)
-                    sb.append(tmp)
-                }
-                sb.append(" ]")
-                sb.toString()
-            } else {
-                "$any"
-            }
-        }
-        val data = ZapData.obtain(level, tag, msg)
-        if (!interceptLogcat(level)) {
-            printInner(data)
-        }
-        if (!interceptRecord(level)) {
-            doRecord(data)
-        }
-        data.recycle()
-    }
-
-    private fun printInner(data: ZapData) {
-        if (data.msg.length <= MAX_LENGTH_OF_SINGLE_MESSAGE) {
-            doPrint(data.level, data.tag, data.msg)
-            return
-        }
-        val msgLength = data.msg.length
-        var start = 0
-        var end = start + MAX_LENGTH_OF_SINGLE_MESSAGE
-        while (start < msgLength) {
-            doPrint(data.level, data.tag, data.msg.substring(start, end))
-            start = end
-            end = (start + MAX_LENGTH_OF_SINGLE_MESSAGE).coerceAtMost(msgLength)
-        }
-    }
-
-    private fun doPrint(level: Level, tag: String, msg: String) {
-        when (level) {
-            Level.DEBUG -> Log.d(tag, msg)
-            Level.INFO -> Log.i(tag, msg)
-            Level.WARNING -> Log.w(tag, msg)
-            Level.ERROR -> Log.e(tag, msg)
-            else -> Log.i(tag, msg)
-        }
-    }
-
-    private fun doRecord(data: ZapData) {
-        record2MMap?.write(dateFileFormatter.format(data.level, data.tag, data.msg))
-    }
-
-    companion object {
-
-        const val MAX_LENGTH_OF_SINGLE_MESSAGE = 4063
-
-        fun instance(): ZapPrint {
-            return LoggerPrintHolder.INSTANCE
-        }
-
-        private object LoggerPrintHolder {
-            val INSTANCE = ZapPrint()
-        }
-
-        /**
-         * 防止单例对象在反序列化时重新生成对象
-         */
-        private fun readResolve(): Any {
-            return LoggerPrintHolder.INSTANCE
-        }
-    }
-
-}

+ 0 - 10
library_zap/src/main/java/com/dolin/zap/internal/ICatch.kt

@@ -1,10 +0,0 @@
-package com.dolin.zap.internal
-
-/**
- * @author #Suyghur.
- * Created on 4/12/21
- */
-interface ICatch {
-
-    fun onCatch()
-}

+ 12 - 0
library_zap/src/main/java/com/dolin/zap/internal/IFormatter.java

@@ -0,0 +1,12 @@
+package com.dolin.zap.internal;
+
+import com.dolin.zap.entity.Level;
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/05/19
+ */
+public interface IFormatter {
+
+    String format(Level level, String tag, String msg);
+}

+ 0 - 11
library_zap/src/main/java/com/dolin/zap/internal/IFormatter.kt

@@ -1,11 +0,0 @@
-package com.dolin.zap.internal
-
-import com.dolin.zap.entity.Level
-
-/**
- * @author #Suyghur.
- * Created on 4/8/21
- */
-interface IFormatter {
-    fun format(level: Level, tag: String, msg: String): String
-}

+ 25 - 0
library_zap/src/main/java/com/dolin/zap/internal/IPrint.java

@@ -0,0 +1,25 @@
+package com.dolin.zap.internal;
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/05/19
+ */
+public interface IPrint {
+
+    void d(Object obj);
+
+    void d(String tag, Object obj);
+
+    void i(Object obj);
+
+    void i(String tag, Object obj);
+
+    void w(Object obj);
+
+    void w(String tag, Object obj);
+
+    void e(Object obj);
+
+    void e(String tag, Object obj);
+
+}

+ 0 - 26
library_zap/src/main/java/com/dolin/zap/internal/IPrint.kt

@@ -1,26 +0,0 @@
-package com.dolin.zap.internal
-
-/**
- * @author #Suyghur.
- * Created on 4/7/21
- */
-interface IPrint {
-
-
-    fun d(any: Any?)
-
-    fun d(tag: String, any: Any?)
-
-    fun i(any: Any?)
-
-    fun i(tag: String, any: Any?)
-
-    fun w(any: Any?)
-
-    fun w(tag: String, any: Any?)
-
-    fun e(any: Any?)
-
-    fun e(tag: String, any: Any?)
-
-}

+ 16 - 0
library_zap/src/main/java/com/dolin/zap/internal/IRecord.java

@@ -0,0 +1,16 @@
+package com.dolin.zap.internal;
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/05/19
+ */
+public interface IRecord {
+
+    void write(String msg);
+
+    void asyncFlush();
+
+    void expLogFile(String path, int limitSize);
+
+    void release();
+}

+ 0 - 16
library_zap/src/main/java/com/dolin/zap/internal/IRecord.kt

@@ -1,16 +0,0 @@
-package com.dolin.zap.internal
-
-/**
- * @author #Suyghur.
- * Created on 4/7/21
- */
-interface IRecord {
-
-    fun write(msg: String)
-
-    fun asyncFlush()
-
-    fun expLogFile(path: String, limitSize: Int)
-
-    fun release()
-}

+ 91 - 0
library_zap/src/main/java/com/dolin/zap/lifecycle/ZapLifecycle.java

@@ -0,0 +1,91 @@
+package com.dolin.zap.lifecycle;
+
+import android.app.Activity;
+import android.app.Application;
+import android.os.Bundle;
+
+import com.dolin.zap.impl.Record2MMap;
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/05/19
+ */
+public class ZapLifecycle {
+
+    private static volatile ZapLifecycle mInstance = null;
+
+    private Application application = null;
+    private Record2MMap record2MMap = null;
+
+
+    private final Application.ActivityLifecycleCallbacks callback = new Application.ActivityLifecycleCallbacks() {
+        @Override
+        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+
+        }
+
+        @Override
+        public void onActivityStarted(Activity activity) {
+
+        }
+
+        @Override
+        public void onActivityResumed(Activity activity) {
+
+        }
+
+        @Override
+        public void onActivityPaused(Activity activity) {
+            if (record2MMap != null) {
+                record2MMap.asyncFlush();
+            }
+        }
+
+        @Override
+        public void onActivityStopped(Activity activity) {
+
+        }
+
+        @Override
+        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+
+        }
+
+        @Override
+        public void onActivityDestroyed(Activity activity) {
+
+        }
+    };
+
+
+    private ZapLifecycle() {
+
+    }
+
+    public static ZapLifecycle getInstance() {
+        if (mInstance == null) {
+            synchronized (ZapLifecycle.class) {
+                if (mInstance == null) {
+                    mInstance = new ZapLifecycle();
+                }
+            }
+        }
+        return mInstance;
+    }
+
+    public void registerZapLifeCallback(Application application, Record2MMap record2MMap) {
+        this.application = application;
+        this.record2MMap = record2MMap;
+        application.registerActivityLifecycleCallbacks(callback);
+    }
+
+    public void unregisterZapLifeCallback() {
+        if (application != null) {
+            application.unregisterActivityLifecycleCallbacks(callback);
+            this.application = null;
+        }
+        if (record2MMap != null) {
+            this.record2MMap = null;
+        }
+    }
+}

+ 0 - 58
library_zap/src/main/java/com/dolin/zap/lifecycle/ZapLifecycle.kt

@@ -1,58 +0,0 @@
-package com.dolin.zap.lifecycle
-
-import android.app.Activity
-import android.app.Application
-import android.os.Bundle
-import com.dolin.zap.impl.Record2MMap
-
-
-/**
- * @author #Suyghur.
- * Created on 4/8/21
- */
-object ZapLifecycle {
-
-    private var record2MMap: Record2MMap? = null
-    private var application: Application? = null
-
-    private val callback = object : Application.ActivityLifecycleCallbacks {
-        override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
-        }
-
-        override fun onActivityStarted(activity: Activity) {
-        }
-
-        override fun onActivityResumed(activity: Activity) {
-        }
-
-        override fun onActivityPaused(activity: Activity) {
-            record2MMap?.asyncFlush()
-        }
-
-        override fun onActivityStopped(activity: Activity) {
-        }
-
-        override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
-        }
-
-        override fun onActivityDestroyed(activity: Activity) {
-        }
-    }
-
-    fun registerZapLifeCallback(application: Application, record2MMap: Record2MMap) {
-        ZapLifecycle.application = application
-        ZapLifecycle.record2MMap = record2MMap
-        application.registerActivityLifecycleCallbacks(callback)
-    }
-
-    fun unregisterZapLifeCallback() {
-        application?.apply {
-            unregisterActivityLifecycleCallbacks(callback)
-            application = null
-        }
-        record2MMap?.apply {
-            record2MMap = null
-        }
-
-    }
-}

+ 40 - 0
library_zap/src/main/java/com/dolin/zap/util/LevelUtils.java

@@ -0,0 +1,40 @@
+package com.dolin.zap.util;
+
+import com.dolin.zap.entity.Level;
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/05/19
+ */
+public class LevelUtils {
+
+    public static String getLevelName(Level level) {
+        return level.name();
+    }
+
+    public static String getShortLevelName(Level level) {
+        String name;
+        switch (level) {
+            case NONE:
+            case DEBUG:
+                name = "D";
+                break;
+            case INFO:
+                name = "I";
+                break;
+            case WARNING:
+                name = "W";
+                break;
+            case ERROR:
+                name = "E";
+                break;
+            default:
+                if (level.ordinal() < Level.DEBUG.ordinal()) {
+                    name = "D";
+                } else {
+                    name = "E";
+                }
+        }
+        return name;
+    }
+}

+ 0 - 29
library_zap/src/main/java/com/dolin/zap/util/LevelUtils.kt

@@ -1,29 +0,0 @@
-package com.dolin.zap.util
-
-import com.dolin.zap.entity.Level
-
-/**
- * @author #Suyghur.
- * Created on 4/8/21
- */
-object LevelUtils {
-
-    fun getLevelName(level: Level): String {
-        return level.name
-    }
-
-    fun getShortLevelName(level: Level): String {
-        return when (level) {
-            Level.DEBUG -> "D"
-            Level.INFO -> "I"
-            Level.WARNING -> "W"
-            Level.ERROR -> "E"
-            else ->
-                if (level.ordinal < Level.DEBUG.ordinal) {
-                    "D"
-                } else {
-                    "E"
-                }
-        }
-    }
-}

+ 157 - 0
library_zap/src/main/java/com/dolin/zap/util/LogFileUtils.java

@@ -0,0 +1,157 @@
+package com.dolin.zap.util;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.File;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/05/19
+ */
+public class LogFileUtils {
+
+
+    public static void cleanOverdueLog(Context context, long overdueDayMs) {
+        File folder = new File(getLogFolderDir(context));
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
+        File[] files = folder.listFiles();
+        if (files != null) {
+            for (File f : files) {
+                if (f.isDirectory() && isFileOverdue(f, overdueDayMs, format)) {
+                    deleteDirectory(f.getPath());
+                }
+            }
+        }
+    }
+
+//    public static void cleanOverdueLog(String folderPath, long overdueDayMs) {
+//        File folder = new File(folderPath);
+//        if (!folder.exists()) {
+//            return;
+//        }
+//        File[] files = folder.listFiles();
+//        if (files != null) {
+//            for (File f : files) {
+//                if (f.isDirectory()) {
+//                    cleanOverdueLog(folderPath, overdueDayMs);
+//                } else {
+//                    if (isFileOverdue(f, overdueDayMs)) {
+//                        f.delete();
+//                    }
+//                }
+//            }
+//        }
+//    }
+
+    private static boolean isFileOverdue(File file, long overdueDayMs) {
+        return (System.currentTimeMillis() - file.lastModified()) > overdueDayMs;
+    }
+
+    private static boolean isFileOverdue(File file, long overdueDayMs, SimpleDateFormat format) {
+        String time = file.getName();
+        Log.d("dolin_zap", "time : " + time);
+        try {
+            Date date = format.parse(time);
+            if (date != null) {
+                long ts = date.getTime();
+                Log.d("dolin_zap", "ts : " + ts);
+                return (System.currentTimeMillis() - ts) > overdueDayMs;
+            }
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    public static String getLogFolderDir(Context context) {
+        File folder = context.getExternalFilesDir("dolin/zap");
+        if (folder == null) {
+            folder = new File(context.getFilesDir(), "dolin/zap");
+        }
+        if (!folder.exists()) {
+            folder.mkdirs();
+        }
+        return folder.getAbsolutePath();
+    }
+
+    public static String getLogDir(String folderPath, String date) {
+        File folder = new File(folderPath + File.separator + date);
+        if (!folder.exists()) {
+            folder.mkdirs();
+        }
+        return folder.getAbsolutePath();
+    }
+
+    public static int getLogFileNumByDate(String folderPath, String date) {
+        int num = 0;
+        File folder = new File(folderPath);
+        if (!folder.exists()) {
+            return num;
+        }
+        File[] files = folder.listFiles();
+        if (files == null) {
+            return num;
+        } else {
+            return files.length;
+        }
+    }
+
+    public static boolean deleteFile(String path) {
+        if (TextUtils.isEmpty(path)) {
+            return false;
+        }
+        File file = new File(path);
+        if (file.exists()) {
+            return file.delete();
+        }
+        return false;
+    }
+
+    /**
+     * 删除文件夹以及所有子目录和文件
+     */
+    public static boolean deleteDirectory(String path) {
+        if (TextUtils.isEmpty(path)) {
+            return false;
+        }
+        boolean flag;
+        // 如果path不以文件分隔符结尾,自动添加文件分隔符
+        if (!path.endsWith(File.separator)) {
+            path = path + File.separator;
+        }
+        File dirFile = new File(path);
+        // 如果dir对应的文件不存在,或者不是一个目录,则退出
+        if (!dirFile.exists() || !dirFile.isDirectory()) {
+            return false;
+        }
+        flag = true;
+        // 删除文件夹下的所有文件(包括子目录)
+        File[] files = dirFile.listFiles();
+        if (files != null && files.length > 0) {
+            for (File file : files) {
+                if (file.isFile()) {
+                    // 删除子文件
+                    flag = deleteFile(file.getAbsolutePath());
+                } else {
+                    // 删除子目录
+                    flag = deleteDirectory(file.getAbsolutePath());
+                }
+                if (!flag) {
+                    break;
+                }
+            }
+        }
+        if (!flag) {
+            return false;
+        }
+        // 删除当前目录
+        return dirFile.delete();
+    }
+
+}

+ 0 - 64
library_zap/src/main/java/com/dolin/zap/util/LogFileUtils.kt

@@ -1,64 +0,0 @@
-package com.dolin.zap.util
-
-import android.content.Context
-import java.io.File
-
-/**
- * @author #Suyghur.
- * Created on 4/15/2021
- */
-object LogFileUtils {
-
-    fun cleanOverdueLog(folderPath: String, overdueDayMs: Long) {
-        val folder = File(folderPath)
-        if (!folder.exists()) {
-            return
-        }
-        folder.walk().maxDepth(1)
-                .filter { it.isFile }
-                .filter { it.extension == "zap" }
-                .forEach {
-                    if (isFileOverdue(it, overdueDayMs)) {
-                        it.delete()
-                    }
-                }
-    }
-
-    private fun isFileOverdue(file: File, overdueDayMs: Long): Boolean {
-        return System.currentTimeMillis() - file.lastModified() > overdueDayMs
-    }
-
-    fun getLogFolderDir(context: Context): String {
-        var folder = context.getExternalFilesDir("dolin/zap")
-        if (folder == null) {
-            folder = File(context.filesDir, "dolin/zap")
-        }
-        if (!folder.exists()) {
-            folder.mkdirs()
-        }
-        return folder.absolutePath
-    }
-
-    fun getLogDir(folderDir: String, date: String): String {
-        val folder = File("$folderDir/$date")
-        if (!folder.exists()) {
-            folder.mkdirs()
-        }
-        return folder.absolutePath
-    }
-
-    fun getLogFileNumByDate(folderPath: String, date: String): Int {
-        var num = 0
-        val folder = File(folderPath)
-        if (!folder.exists()) {
-            return num
-        }
-        repeat(folder.walk().maxDepth(1)
-                .filter { it.isFile }
-//                .filter { it.name.startsWith(date) }
-                .count()) {
-            num++
-        }
-        return num
-    }
-}