{"id":26920877,"url":"https://github.com/tanpenggood/learning-java-log","last_synced_at":"2026-06-22T18:31:37.227Z","repository":{"id":105356814,"uuid":"438928032","full_name":"tanpenggood/learning-java-log","owner":"tanpenggood","description":"Fully master Java Log System.","archived":false,"fork":false,"pushed_at":"2021-12-19T15:09:28.000Z","size":15,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-01T22:51:03.344Z","etag":null,"topics":["jcl","jul","log4j","log4j2","logback","slf4j"],"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/tanpenggood.png","metadata":{"files":{"readme":"README-cn.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-16T09:14:50.000Z","updated_at":"2022-09-28T05:43:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"e609acc7-ddff-4a45-aea6-9a12a54fb2cb","html_url":"https://github.com/tanpenggood/learning-java-log","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tanpenggood/learning-java-log","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tanpenggood%2Flearning-java-log","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tanpenggood%2Flearning-java-log/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tanpenggood%2Flearning-java-log/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tanpenggood%2Flearning-java-log/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tanpenggood","download_url":"https://codeload.github.com/tanpenggood/learning-java-log/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tanpenggood%2Flearning-java-log/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34661702,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-22T02:00:06.391Z","response_time":106,"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":["jcl","jul","log4j","log4j2","logback","slf4j"],"created_at":"2025-04-01T22:49:07.979Z","updated_at":"2026-06-22T18:31:37.221Z","avatar_url":"https://github.com/tanpenggood.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 学习Java日志体系\n\n## 项目结构\n\n```\n├─java-log-impl           # Java各个日志实现（jul、log4j、log4j2、logback）\n├─java-log-api-jcl        # commons logging\n├─java-log-api-slf4j      # slf4j\n└─log4j2-vulnerabilities  # log4j2安全漏洞复现\n```\n\n## Log4j2 CVE-2021-44228 复现步骤\n   \n1. cd `log4j2-vulnerabilities`\n2. 启动`com.itplh.log4j2.RmiServer`\n3. 运行`com.itplh.log4j2.TestLog4j2UseJndi`\n\n## Java日志体系实现方案\n\n- 接口\n    - JCL（Apache Commons Logging）\n    - Slf4j\n\n- 实现\n    - JUL（java.util.logging）\n    - log4j\n    - log4j2\n    - logback\n\n## JCL（Apache Commons Logging，又名Jakarta Commons Logging）\n\n1. cd `java-log-api-jcl`\n2. 运行 `com.itplh.jcl.TestCommonsLogging`，观察日志输出\n3. 调整 `commons-logging.properties` 中 Log 的具体实现，再重新运行程序，观察日志输出\n\n### 原理\n\n查找`org.apache.commons.logging.Log`的实现类，进行日志框架的绑定，调用栈如下：\n\n```\nLog log = LogFactory.getLog(\"jcl\");\n    |- getLog:669, LogFactory (org.apache.commons.logging)\n        |- getInstance:292, LogFactoryImpl (org.apache.commons.logging.impl)\n            |- newInstance:541, LogFactoryImpl (org.apache.commons.logging.impl)\n                |- discoverLogImplementation:790, LogFactoryImpl (org.apache.commons.logging.impl)\n                    |- createLogFromClass:960, LogFactoryImpl (org.apache.commons.logging.impl)\n```\n\ncommons-logging获取日志对象的全过程，具体文字总结如下：\n\n```\n获取当前线程的classLoader,根据classLoader从缓存中获取LogFactroy,使用的缓存是WeakHashTable对象;如果缓存中存在，则返回，没有则进入下面流程；\n \n读取classpath下的commons-logging.properties文件，判断其中是否设置了use_tccl属性，如果不为空则判断，该属性的值是否为false,若为false，则将baseClassLoader替换为当前类的classLoader；\n \n接着，继续获取LogFactory对象，此步骤分为4种方式：\n    (1)在系统属性中查找“org.apache.commons.logging.LogFactory”属性的值，根据值生成LogFactory对象；\n    (2)通过资源“META-INF/services/org.apache.commons.logging.LogFactory”文件，获取的值生成LogFactory对象；\n    (3)通过配置文件commons-logging.properties，获取以“org.apache.commons.logging.LogFactory”为key的值，根据值生成logFactory；\n    (4)如果以上均不成功，则创建系统默认的日志工厂：org.apache.commons.logging.impl.LogFactoryImpl\n \n成功获取日志工厂后，根据类名获取日志对象；\n \n主要逻辑在discoverLogImplementation方法中：\n    (1)检查commons-logging.properties文件中是否存在“org.apache.commons.logging.Log”属性，若存在则创建具体的日志对象；若不存在，进行下面逻辑；\n    (2)遍历classesToDiscover数组，该数组存有日志具体实现类的全限定类名：org.apache.commons.logging.impl.Log4JLogger、org.apache.commons.logging.impl.Jdk14Logger、org.apache.commons.logging.impl.Jdk13LumberjackLogger、org.apache.commons.logging.impl.SimpleLog；\n    (3)根据数组中存着的全限定类名，按照顺序依次加载Class文件，进行实例化操作，最后返回Log实例，默认为Jdk14Logger；\n```\n## Slf4j适配解决方案\n\n1. cd `java-log-api-slf4j`\n2. 运行 `com.itplh.slf4j.TestSlf4j`，观察日志输出\n3. 调整 `pom.xml` 中 slf4j适配到各个日志的依赖关系，再重新运行程序，观察日志输出\n\n### 原理\n\n查找适配器包中的`org.slf4j.impl.StaticLoggerBinder`类，进行日志框架的绑定，调用栈如下：\n\n```\nLogger logger = LoggerFactory.getLogger(\"slf4j\");\n    |- getLogger:362, LoggerFactory (org.slf4j)\n        |- getILoggerFactory:417, LoggerFactory (org.slf4j)\n            |- performInitialization:124, LoggerFactory (org.slf4j)\n                |- bind:146, LoggerFactory (org.slf4j)\n                    |- findPossibleStaticLoggerBinderPathSet:301, LoggerFactory (org.slf4j)\n```\n\n\u003e 当classpath中有多个`org.slf4j.impl.StaticLoggerBinder`时，最终由JVM类加载机制决定加载其中的一个。\n\n## Slf4j桥接方案\n\n## Spring日志方案实战\n\n## 参考\n\n[Apache Log4j](https://logging.apache.org/log4j/1.2/index.html)\n\n[Apache Log4j 2](https://logging.apache.org/log4j/2.x/index.html)\n\n[logback](http://logback.qos.ch/)\n\n[Apache Commons Logging](https://commons.apache.org/proper/commons-logging/)\n\n[Simple Logging Facade for Java (SLF4J)](http://www.slf4j.org/)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftanpenggood%2Flearning-java-log","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftanpenggood%2Flearning-java-log","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftanpenggood%2Flearning-java-log/lists"}