{"id":31984123,"url":"https://github.com/licola-exist/llogger","last_synced_at":"2025-10-15T04:03:43.050Z","repository":{"id":217383390,"uuid":"133310272","full_name":"LiCola-Exist/LLogger","owner":"LiCola-Exist","description":"日志工具，丰富的打印功能，支持写入本地文件，支持Java环境","archived":false,"fork":false,"pushed_at":"2019-06-27T09:22:57.000Z","size":2330,"stargazers_count":11,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-23T02:25:53.193Z","etag":null,"topics":["android","log","logcat","logger"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LiCola-Exist.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-05-14T05:43:54.000Z","updated_at":"2022-11-03T06:53:59.000Z","dependencies_parsed_at":"2024-01-16T03:41:34.628Z","dependency_job_id":"9e67ee88-d5a0-44d8-9dd8-612be786265e","html_url":"https://github.com/LiCola-Exist/LLogger","commit_stats":null,"previous_names":["licola-exist/llogger"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/LiCola-Exist/LLogger","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiCola-Exist%2FLLogger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiCola-Exist%2FLLogger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiCola-Exist%2FLLogger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiCola-Exist%2FLLogger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LiCola-Exist","download_url":"https://codeload.github.com/LiCola-Exist/LLogger/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiCola-Exist%2FLLogger/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279047063,"owners_count":26092683,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-15T02:00:07.814Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","log","logcat","logger"],"created_at":"2025-10-15T04:03:22.181Z","updated_at":"2025-10-15T04:03:43.041Z","avatar_url":"https://github.com/LiCola-Exist.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# [LLogger](https://github.com/LiCola/LLogger)\n\n[ ![Download](https://api.bintray.com/packages/licola/maven/LLogger/images/download.svg) ](https://bintray.com/licola/maven/LLogger/_latestVersion)\n\n# 作用\n日志工具，支持更多信息的打印\n - 支持打印行号、方法、内部类名，支持在Logcat中的点击行号跳转代码\n - 支持空参，单一参数，多参数打印\n - 支持log日志信息写入本地文件,以时间为节点，避免日志内容过长，且支持获取和压缩打包log文件\n - 支持Java环境log打印，打印内容近似Android-Logcat风格\n - 支持JSON字符串、JSON对象、JSON数组友好格式化打印\n - 支持代码追踪调试，trace()方法打印方法调用栈（看源码效率工具）\n - 支持超长4000+字符串长度打印\n - ~~支持UI主线程耗时任务检测(Android环境)，打印耗时任务相关代码行~~\n - 支持运行环境中多个LLogger日志实例，以外观模式简化调用（主要使用），并可以创建多个实例，以细分管理日志\n - 支持日志内容懒求值，即按需使用避免不会输出的log内容带来的影响\n\n# 引用\n\n```java\n  implementation \"com.licola:llogger:1.5.1\"\n```\n\n# 更新日志\n - 1.4.3:优化log文件写入的IO操作\n - 1.4.4:加入Json信息写入日志操作\n - 1.4.5:修复在特殊Android运行环境(如Xposed)的情况下某些log信息无效情况\n - 1.4.6:修改部分对象使用方式，优化内存。\n - 1.4.8:加入日志对象的创建，并暴露给外部使用，以实现运行环境多个LLogger日志。\n - 1.4.9:对日志文件读写加入读写锁处理，处理多线程同时写入漏写问题。\n - 1.5.0:优化项目结构，优化内存和锁，加入日志内容懒求值功能，即实现内容提供者功能Supplier。\n - 1.5.1:开放更多api，支持数组内容打印。\n# 使用\n外观模式，静态方法，一行代码调用\n```java\n    LLogger.d();\n    LLogger.d(\"debug\");\n    LLogger.d(\"debug\", \"more info\");\n    LLogger.json(jsonObject);\n    LLogger.trace();//打印方法调用栈\n    \n    List\u003cFile\u003e logFileAll = LLogger.logList();//获取全部日志文件\n    File logZipFile = LLogger.logZipFile(\"log.zip\", 24);//获取前24小时的日志文件并打包压缩到zip包中，如果为0表示当前小时，\n    \n    LLogger.v(new LSupplier\u003cString\u003e() {\n          @Override\n          public String get() {\n            return \"懒求值verbose\";\n          }\n        });\n    LLogger.v(() -\u003e \"懒求值verbose Java8写法\");\n    LLogger.jsonObject(() -\u003e jsonObject);\n    LLogger.jsonArray(() -\u003e jsonArray);\n    \n```\n\n# 配置\nLLogger默认不打印log，默认不写入log文件。\n默认tag为```LLogger```，提供静态方法一行参数控制日志。\n\n在实际项目需要配置参数，建议在```Application```类中初始化配置，下面示例代码\n```java\n/**\n * Created by LiCola on 2018/5/14.\n */\npublic class MyApplication extends Application {\n\n    public static final String LOG_FILE_DIR = \"log-files\";\n  \n    public static final String TAG = \"Demo\";\n  \n    @Override\n    public void onCreate() {\n      super.onCreate();\n  \n      /**\n       * 空参初始化：使用默认tag，默认打印行号，不写本地日志文件。\n       */\n  //    LLogger.init();\n  \n      /**\n       * 初始化：显示行号，配置tag，不写本地日志文件\n       */\n  //    LLogger.init(true,TAG);\n  \n      /**\n       * 1：建议log文件存放在项目内部存储中，避免读写外部存储的权限处理\n       * 2：建议在cache下指定二级目录 存放log文件 避免cache中文件杂乱\n       */\n      File logDir = new File(getCacheDir(), LOG_FILE_DIR);\n  \n      /**\n       * 初始化：显示行号，配置tag，log信息写入本地目录\n       */\n      LLogger.init(true, TAG, logDir);\n  \n    }\n}\n```\n# 效果图\n\n![log信息](https://github.com/LiCola/LLogger/blob/master/image/android-log.png)\n\n# 其他使用\n创建LLogger日志实例，在某些模块使用（不同的日志实例拥有不同的日志目录）\n```java\n      LLogger lLogger = LLogger.create(false, \"Other\", new File(getCacheDir(), \"other\"));\n      lLogger.printLog(LLogger.V);\n      lLogger.printLog(LLogger.D);\n      lLogger.printJson(new JSONObject().put(\"key\", \"value\"));\n      lLogger.printTrace();\n      \n      List\u003cFile\u003e files = lLogger.fetchLogList(2);\n```\n# 关于懒求值\n在日常开发中日志的打印以及打印带来的效率影响是可以接受的，但是在线上环境我们需要关闭或者禁用日志打印功能。\n这里在已经提供了关闭方式，即不调起init相关方法，\n```java\n//  LLogger.init()\n```\n注释掉之后，就不会初始化全局的类成员实例，从而`LLogger.d(\"debug\")`就不会有打印结果（关于其他的LLogger日志实例应该不创建实例来关闭）。\n\n即使关闭了日志，但是仍会有\n```java\n  LLogger.d(\"特殊情况下该内容使用有性能消耗\")\n```\n\n这是因为Java的参数传值方式决定的，先计算参数再进入方法块。\n所以这里就提供了懒求值日志，提供选择使用。\n```java\n    //如果没有init，都不会调起get方法，进而避免多余的参数计算带来的性能消耗\n    LLogger.v(new LSupplier\u003cString\u003e() {\n          @Override\n          public String get() {\n            return \"懒求值verbose\";\n          }\n        });\n    LLogger.v(() -\u003e \"懒求值verbose Java8写法\");\n```\n\n# 关于log本地文件\n可以看到上图的```LLogger_2018-06-04_18.log```日志行，表示创建以小时为节点的log文件。\n\n**文件名格式：文件名前缀_日期信息_小时信息**\n\n采用小时为节点，写入到本地文件，是为了避免信息太过冗长。\n效果如下:\n\n![log文件信息](https://github.com/LiCola/LLogger/blob/master/image/log-file.png)\n\n基本仿照Logcat格式：也是支持点击行号跳转代码\n```log\nlog：18:26:04.068 main Verbose/Demo: [ (MainActivity.java:25)#onClickLogV ] verbose\n格式：时间 线程名 log类型/Tag：[ (类名:行号)#方法名 ] 参数\n```\n\n# 获取log文件\n因为log文件以时间为节点分开，会存在大量的日志文件，所以提供静态方法获取日志文件列表或压缩日志文件\n```java\n    List\u003cFile\u003e files = LLogger.fetchLogList();//获取所有的日志文件列表\n    List\u003cFile\u003e files = LLogger.fetchLogList(24);//获取前24小时内的日志文件列表\n\n    File logZipFile = LLogger.makeLogZipFile(\"log.zip\");//打包所有的日志文件\n    File logZipFile = LLogger.makeLogZipFile(\"log.zip\", 0);//打包当前时间的日志文件 ，如果为0表示当前小时\n\n```\n\n# 关于Java环境\nLLogger内部初始化时判定运行环境，如果是Java环境，也可以打印出log信息\n![java环境-log信息](https://github.com/LiCola/LLogger/blob/master/image/java-log.png)\n\n基本仿照Logcat格式：也是支持点击行号跳转代码\n```log\nlog：06-04 19:02:18.971 main Debug/Java: [ (JavaMain.java:17)#main ] execute\n格式：日期 时间 线程名 log类型/Tag：[ (类名:行号)#方法名 ] 参数\n```\n\n具体比如在IDEA的纯Java环境也可以在Run中打印出丰富的信息\n\n# 混淆\n因为日志库中代码有线程方法栈的使用（Thread.currentThread().getStackTrace()），对代码结构敏感，如果开启混淆代码结构变化，导致方法内联等就会让日志库打印信息错误。\n所以需要在依赖该库的项目里的\"proguard-rules.pro\"文件添加\n```proguard\n#llogger的混淆配置\n-keep class com.licola.llogger.**{*;}\n```\n\n开启混淆的同时可能会改变类和方法的名称，这样就会导致日志行打印的部分信息无效。\n我正在考虑在混淆版本中修改日志输出结构，然后用proguard的retrace.jar库加载mapping.txt映射信息恢复原有代码信息\n\n# 优化\n日志文件的写入肯定是IO操作，这在移动设备是一大性能优化方向。\n考虑日志的使用场景，随时可能发生写日志数据。且需要保证日志的完整性，当程序发生Crash或进程被杀死后需要保证日志完整写入。\n这就限制了在写日志的优化方向，不能使用内存Buffer缓存日志避免IO，因为内存在Crash时就无法保证数据正常。\n所以就提出了高性能方案：mmap，内存映射文件。具体使用就是`MappedByteBuffer`类映射本地文件进行读写。\n\n## 结果\n`MappedByteBuffer`-内存映射方案 `FileWriter`-普通IO，比对。\n目前在PC设备（i7/16G）上能够达到优化0.05ms效果（20W次log写入测试）。\n在移动设备上因为的内存GC的影响太大，无法具体确认优化效果，只能简单说能够达到1ms级别的优化效果。\n\n\n\n# 参考\n- [KLog](https://github.com/ZhaoKaiQiang/KLog),感谢提供基础思路。 \n- [Android 高性能日志写入方案](https://juejin.im/post/5b6d26016fb9a04f86065cdf)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flicola-exist%2Fllogger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flicola-exist%2Fllogger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flicola-exist%2Fllogger/lists"}