- 浏览: 686173 次
- 性别:
- 来自: 合肥
文章分类
最新评论
-
di1984HIT:
学习了,学习了!
Tomcat的URL中文乱码解决以及传输优化 -
arottenapple:
...
我的二十一天CoreJava 学习笔记 -
黯淡流觞:
...
我的二十一天CoreJava 学习笔记 -
onlyOneToOne:
wsc830719 写道@RequestMapping(val ...
spring mvc3中 ResponseBody中文乱码 -
waj_615:
但是打印订单不是简单的string 啊
用java实现打印功能
原由:
log4j是很强大,可每次使用还要加入log4j包,还要使用配置文件。对于一般的小工具或小项目感觉还是有点大动作了。而且在使用log4j时每次还要每取个实例再传个参数来记录,感觉有点麻烦。就自己仿log4j使用jdk logger定制了一个自己的记录工具类。
工具类特点:
- 无配置文件,默认为info级别,控制台输出,无需改动即可满足一般开发需要。。
- 直接打log,在java文件中直接使用
Log.info("test");
即可,如果输出到文件,则自动按不同级别生成不同记录文件 - 使用四个级别的log。分别为
Log.debug(""); Log.info(""); Log.warn(""); Log.error("");
对于一般项目已经足够。 - log输出方式有两种,控制台输出和文件输出。输出格式两者统一。文件输出时的文件路径可定制。默认为class文件夹下,名称格式为 等级_时间.log 如: INFO_2011-10-12.log
工具类的使用:
直接默认配置
Log.debug("debug"); Log.info("info"); Log.info("info1"); Log.warn("warn"); Log.error("error"); try { throw new Exception("exception"); } catch (Exception e) { Log.error(e); }
结果:
2012-03-02 16:25:03 NewClass.java(Line:19): [INFO] info
2012-03-02 16:25:03 NewClass.java(Line:20): [INFO] info1
2012-03-02 16:25:03 NewClass.java(Line:21): [WARN] warn
2012-03-02 16:25:03 NewClass.java(Line:22): [ERROR] error
2012-03-02 16:25:03 NewClass.java(Line:26):
java.lang.Exception: exception
at com.dfhstudio.thoughtfly.util.NewClass.main(NewClass.java:24)
要想使用文件记录,要改点代码变量,看javadoc注释
费话不说,直接上代码
import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.security.AccessController; import java.security.PrivilegedAction; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.logging.ConsoleHandler; import java.util.logging.ErrorManager; import java.util.logging.Formatter; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.LogRecord; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * <b>自定义LOG工具,丁风华</b> * <ul> * <b>特点</b> * <li>无配置文件,默认为info级别,控制台输出,无需改动即可满足一般开发需要。。</li> * <li>直接打log,在java文件中直接使用 <code>Log.info("test");</code> 即可,如果输出到文件,则自动按不同级别生成不同记录文件</li> * <li>使用四个级别的log。分别为 <code>Log.debug(""); Log.info(""); Log.warn(""); Log.error("");</code> 对于一般项目已经足够。</li> * <li>log输出方式有两种,控制台输出和文件输出。输出格式两者统一。文件输出时的文件路径可定制。默认为class文件夹下,名称格式为 等级_时间.log 如: INFO_2011-10-12.log</li> * </ul> * <ul> * <b>输出到文件使用方法</b><br> * 更改构造器方法中的数据. private Log()<br> * 1.设置输出级别: setLogLevel("info");<br> * 2.设置输出到文件: HANDLER_FILE = true;<br> * 3.设置设置文件保存路径: LOG_FILE_PATH = "D:\\log\\";<br> * 4.设置每个文件的最大值: FILE_SIZE = 2000000; // *** 每个文件最大2M <br> * 5.设置每天最多生成多少个文件数量: FILE_MAX = 10; // *** 每天最多生成10个文件,最多不可超过100<br> * 6.设置log文件后缀名: LOG_FILE_LASTNAME = ".log"; * </ul> * <ul> * <b>更改记录内容的格式</b><br> * 可更改 dealInfoFormat 方法中的 formatMessage 变量值即可。 * </ul> * * @author DingFengHua */ public class Log { private Log() { setLogLevel("INFO"); HANDLER_CONSOLE = true; // *** 控制台输出 HANDLER_FILE = false; // *** 文件输出 // *** 如果不想使用文件打LOG,即 HANDLER_FILE = false;,则不用关心以下数据 // *** 自动创建路径文件夹 if (HANDLER_FILE) { // *** 1. LOG文件夹在class文件夹目录下 // LOG_FILE_PATH = new File(Log.class.getClassLoader().getResource(".").getFile()).toString() + "/log/"; // *** 2. 如果是web项目,LOG文件夹在项目根目录下 LOG_FILE_PATH = new File(Log.class.getClassLoader().getResource("/").getFile()).toString() + "/../../log/"; FILE_SIZE = 2000000; // *** 每个文件最大2M FILE_MAX = 10; // *** 每天最多生成10个文件,最多不可超过100 LOG_FILE_LASTNAME = ".log"; // *** 文件后缀名 } } /* * 以下内容不必更改********************************************************************************************************** */ /* ************************************************************************************************************************* */ private String getLogFileName(String level) { String firtFileName = LOG_FILE_PATH + level + "_" + getDateFormat("yyyy-MM-dd", new Date()) + LOG_FILE_LASTNAME; return firtFileName; } /** * 从字符串转换为JDKLOG的LEVEL等级 * * @param strLevel 自定义的等级字符串 * @return JDKLOG的等级 */ private Level getLogLevelFromString(String strLevel) { Level l = Level.INFO; if (LEVEL_DEBUG.equalsIgnoreCase(strLevel)) { l = Level.FINE; } if (LEVEL_WARN.equalsIgnoreCase(strLevel)) { l = Level.WARNING; } if (LEVEL_ERROR.equalsIgnoreCase(strLevel)) { l = Level.SEVERE; } return l; } /** * 低等级记录 * * @param info 记录信息 */ public static void debug(String info) { INSTANCE.log(LEVEL_DEBUG, "[" + LEVEL_DEBUG + "] " + info, null); } /** * 普通信息记录 * * @param info 记录信息 */ public static void info(String info) { INSTANCE.log(LEVEL_INFO, "[" + LEVEL_INFO + "] " + info, null); } /** * 警告信息记录 * * @param info 记录信息 */ public static void warn(String info) { INSTANCE.log(LEVEL_WARN, "[" + LEVEL_WARN + "] " + info, null); } /** * 错误信息记录 * * @param info 记录信息 */ public static void error(String info) { INSTANCE.log(LEVEL_ERROR, "[" + LEVEL_ERROR + "] " + info, null); } /** * 错误信息记录 * * @param info 异常 */ public static void error(Throwable info) { INSTANCE.log(LEVEL_ERROR, "", info); } /** * 处理记录信息 * * @param level 信息等级 * @param info 信息内容 * @param exception 异常信息 */ private void log(String level, String info, Throwable exception) { checkFileDate(level); Logger logger = Logger.getLogger(level); if (!logList.contains(level)) { logList.add(level); dealHander(logger); dealInfoFormat(logger); } logger.setLevel(logOutPutLevel); logger.log(getLogLevelFromString(level), info, exception); } /** * 内容格式化,默认内容格式为 时间 文件名(行数):[等级] 内容 * * @param logger JDK Log */ private void dealInfoFormat(Logger logger) { logger.setUseParentHandlers(false); StackTraceElement[] stackTraceElement = Thread.currentThread().getStackTrace(); final StackTraceElement element = stackTraceElement[stackTraceElement.length - 1]; for (Handler handler : logger.getHandlers()) { handler.setFormatter(new Formatter() { @Override public String format(LogRecord record) { StringBuilder formatMessage = new StringBuilder(); formatMessage.append(getDateFormat("yyyy-MM-dd HH:mm:ss", new Date())); formatMessage.append(" ").append(element.getFileName()).append("(Line:") .append(element.getLineNumber()).append("):").append(" ") .append(record.getMessage()).append("\n"); if (record.getThrown() != null) { try { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); record.getThrown().printStackTrace(pw); pw.close(); formatMessage.append(sw.toString()); } catch (Exception ex) { } } return formatMessage.toString(); } }); } } /** * 输出处理,控制台和文件,文件输出的文件名格式为 等级_yyyy-MM-dd.log 如果有多个文件,会在文件名后递增数字 * * @param logger jdk log */ private void dealHander(Logger logger) { boolean alreadyHasConsole = false, alreadyHasFile = false; Handler[] handlers = logger.getHandlers(); for (int i = 0; i < handlers.length; i++) { if (handlers[i] instanceof ConsoleHandler) { alreadyHasConsole = true; } else if (handlers[i] instanceof MyFileHandler) { alreadyHasFile = true; } } if (HANDLER_CONSOLE && !alreadyHasConsole) { ConsoleHandler ch = new ConsoleHandler(); ch.setLevel(logOutPutLevel); logger.addHandler(ch); } if (HANDLER_FILE && !alreadyHasFile) { String file = getLogFileName(logger.getName()); File f = new File(LOG_FILE_PATH); if (!f.isDirectory()) { f.mkdirs(); f.mkdir(); } try { MyFileHandler fh = new MyFileHandler(file, FILE_SIZE, FILE_MAX, true); fh.setLevel(logOutPutLevel); logger.addHandler(fh); } catch (IOException ex) { Logger.getLogger(Log.class.getName()).log(Level.SEVERE, null, ex); } catch (SecurityException ex) { Logger.getLogger(Log.class.getName()).log(Level.SEVERE, null, ex); } } } /** * 格式化时间到字符串 * * @param pattern 格式 * @param date 时间 * @return 格式化的字符串 */ private String getDateFormat(String pattern, Date date) { format.applyPattern(pattern); return format.format(date); } /** * 设置输出等级 * * @param level 自定义等级,可使用 debug,info,warn,error 忽略大小写 */ public final void setLogLevel(String level) { logOutPutLevel = getLogLevelFromString(level); } private void checkFileDate(String level) { File f = new File(getLogFileName(level)); if (!f.exists()) { for (Handler handler : Logger.getLogger(level).getHandlers()) { handler.close(); } logList.remove(level); } } private static String LOG_FILE_PATH; private Level logOutPutLevel; private int FILE_SIZE; private int FILE_MAX; private boolean HANDLER_FILE = false; private boolean HANDLER_CONSOLE = false; private static ArrayList<String> logList = new ArrayList<String>(); private String LOG_FILE_LASTNAME; private static String LEVEL_DEBUG = "DEBUG"; private static String LEVEL_INFO = "INFO"; private static String LEVEL_WARN = "WARN"; private static String LEVEL_ERROR = "ERROR"; private static Log INSTANCE = new Log(); SimpleDateFormat format = new SimpleDateFormat(); } /** * 自定义文件输出管理类,参考JDK FileHandler实现 * * @author DingFengHua */ class MyFileHandler extends StreamHandler { private MeteredStream meter; private boolean append; private int limit; // zero => no limit. private int count; private String pattern; private String lockFileName; private FileOutputStream lockStream; private File files[]; private static final int MAX_LOCKS = 100; private static java.util.HashMap<String, String> locks = new java.util.HashMap<String, String>(); private class MeteredStream extends OutputStream { OutputStream out; int written; MeteredStream(OutputStream out, int written) { this.out = out; this.written = written; } public void write(int b) throws IOException { out.write(b); written++; } @Override public void write(byte buff[]) throws IOException { out.write(buff); written += buff.length; } @Override public void write(byte buff[], int off, int len) throws IOException { out.write(buff, off, len); written += len; } @Override public void flush() throws IOException { out.flush(); } @Override public void close() throws IOException { out.close(); } } private void open(File fname, boolean append) throws IOException { int len = 0; if (append) { len = (int) fname.length(); } FileOutputStream fout = new FileOutputStream(fname.toString(), append); BufferedOutputStream bout = new BufferedOutputStream(fout); meter = new MeteredStream(bout, len); setOutputStream(meter); } public MyFileHandler() throws IOException, SecurityException { openFiles(); } public MyFileHandler(String pattern) throws IOException, SecurityException { if (pattern.length() < 1) { throw new IllegalArgumentException(); } this.pattern = pattern; this.limit = 0; this.count = 1; openFiles(); } public MyFileHandler(String pattern, boolean append) throws IOException, SecurityException { if (pattern.length() < 1) { throw new IllegalArgumentException(); } this.pattern = pattern; this.limit = 0; this.count = 1; this.append = append; openFiles(); } public MyFileHandler(String pattern, int limit, int count) throws IOException, SecurityException { if (limit < 0 || count < 1 || pattern.length() < 1) { throw new IllegalArgumentException(); } this.pattern = pattern; this.limit = limit; this.count = count; openFiles(); } public MyFileHandler(String pattern, int limit, int count, boolean append) throws IOException, SecurityException { if (limit < 0 || count < 1 || pattern.length() < 1) { throw new IllegalArgumentException(); } this.pattern = pattern; this.limit = limit; this.count = count; this.append = append; openFiles(); } private void openFiles() throws IOException { LogManager manager = LogManager.getLogManager(); manager.checkAccess(); if (count < 1) { throw new IllegalArgumentException("file count = " + count); } if (limit < 0) { limit = 0; } InitializationErrorManager em = new InitializationErrorManager(); setErrorManager(em); int unique = -1; for (;;) { unique++; if (unique > MAX_LOCKS) { throw new IOException("Couldn't get lock for " + pattern); } lockFileName = generate(pattern, 0, unique).toString() + ".lck"; synchronized (locks) { if (locks.get(lockFileName) != null) { continue; } FileChannel fc; try { lockStream = new FileOutputStream(lockFileName); fc = lockStream.getChannel(); } catch (IOException ix) { continue; } try { FileLock fl = fc.tryLock(); if (fl == null) { continue; } } catch (IOException ix) { } locks.put(lockFileName, lockFileName); break; } } files = new File[count]; for (int i = 0; i < count; i++) { files[i] = generate(pattern, i, unique); } if (append) { open(files[0], true); } else { rotate(); } Exception ex = em.lastException; if (ex != null) { if (ex instanceof IOException) { throw (IOException) ex; } else if (ex instanceof SecurityException) { throw (SecurityException) ex; } else { throw new IOException("Exception: " + ex); } } setErrorManager(new ErrorManager()); } private File generate(String pattern, int generation, int unique) throws IOException { File file = null; String word = ""; int ix = 0; boolean sawg = false; boolean sawu = false; while (ix < pattern.length()) { char ch = pattern.charAt(ix); ix++; char ch2 = 0; if (ix < pattern.length()) { ch2 = Character.toLowerCase(pattern.charAt(ix)); } if (ch == '/') { if (file == null) { file = new File(word); } else { file = new File(file, word); } word = ""; continue; } else if (ch == '%') { if (ch2 == 't') { String tmpDir = System.getProperty("java.io.tmpdir"); if (tmpDir == null) { tmpDir = System.getProperty("user.home"); } file = new File(tmpDir); ix++; word = ""; continue; } else if (ch2 == 'h') { file = new File(System.getProperty("user.home")); if (isSetUID()) { throw new IOException("can't use %h in set UID program"); } ix++; word = ""; continue; } else if (ch2 == 'g') { word = word + generation; sawg = true; ix++; continue; } else if (ch2 == 'u') { word = word + unique; sawu = true; ix++; continue; } else if (ch2 == '%') { word = word + "%"; ix++; continue; } } word = word + ch; } if (count > 1 && generation > 0 && !sawg) { word = word + "." + generation; } if (unique > 0 && !sawu) { word = word + "." + unique; } if (word.length() > 0) { if (file == null) { file = new File(word); } else { file = new File(file, word); } } return file; } private synchronized void rotate() { Level oldLevel = getLevel(); setLevel(Level.OFF); super.close(); for (int i = count - 2; i >= 0; i--) { File f1 = files[i]; File f2 = files[i + 1]; if (f1.exists()) { if (f2.exists()) { f2.delete(); } f1.renameTo(f2); } } try { open(files[0], false); } catch (IOException ix) { reportError(null, ix, ErrorManager.OPEN_FAILURE); } setLevel(oldLevel); } @Override public synchronized void publish(LogRecord record) { if (!isLoggable(record)) { return; } super.publish(record); flush(); if (limit > 0 && meter.written >= limit) { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { rotate(); return null; } }); } } @Override public synchronized void close() throws SecurityException { super.close(); if (lockFileName == null) { return; } try { lockStream.close(); } catch (Exception ex) { } synchronized (locks) { locks.remove(lockFileName); } new File(lockFileName).delete(); lockFileName = null; lockStream = null; } private static class InitializationErrorManager extends ErrorManager { Exception lastException; @Override public void error(String msg, Exception ex, int code) { lastException = ex; } } private static native boolean isSetUID(); }
发表评论
-
jetty快速开发时自实现提供jndi服务
2012-07-11 17:21 2252jndi一般是由容器提供,或是启动第三方服务jar包启动。 ... -
spring mvc3中 ResponseBody中文乱码
2012-07-11 14:48 4704使用spring mvc3的@ResponseBody注解以期 ... -
用Java Service Wrapper将java程序制作成系统服务进程
2012-05-23 14:35 10971用途 在做完一个项目程序后,有时会有两种需求想法。 1.在 ... -
根据颜色检查图片中的产品是否合格
2012-04-23 17:13 1398受朋友之托,做了一个小软件。只是一个练手,现将思路重现。 需 ... -
自制简易提醒器
2012-02-29 19:50 1350每次烧水和吃饭都忘了时间,就想要一个小闹钟。可网上的软件要不就 ... -
Log4j配置备查
2012-02-29 11:09 1200配置日志信息输出目的地,其语法为: log4j.append ... -
因练习正则而感受到丰富的解题思路
2011-11-14 15:07 1957不久前,在正则上终于可以登堂入室了,因担心久不练习而使其荒废, ... -
正则研究心得
2011-10-21 16:49 966自己感觉已经在正则上登堂入室了,终于也能体会到它的 ... -
正则表达式截取再整合字符串
2011-10-21 15:44 1496在百度知道中又看到一问题,有意思,可惜 ... -
找出一个字符串中由同一个字符组成的最长子串
2011-10-21 15:15 2098找出一个字符串中由同一个字符组成的最长子串 这是 ... -
设计模式核心笔录
2011-05-25 18:38 1071脑图内容整理成的PD ... -
struts2 iterator双重叠迭取值
2010-03-10 21:02 1243效果:Map<String,List<Derpa ... -
打包Zip文件下载
2010-03-10 12:19 1988项目里要把当个文件单 ... -
断点下载功能
2010-03-10 12:16 1485项目中要用到下载功能,发现一个断点下载的文章,还不错,归案备 ... -
页面头信息资料
2010-03-10 11:45 1797要做下载单个图片和多个图片打包后下载功能,收集了一下页面头信 ... -
JAVA WEB程序中添加定时器
2010-02-21 08:56 1058//这是我的定时器类, ... -
用java实现打印功能
2010-02-06 17:48 31620用java实现打印,java.awt中提供了一些 ... -
url中有加号
2010-02-05 09:27 3122url 中有些字符被转义,比如空格被编码成加号,于是传 ... -
java实现文件下载
2010-02-03 14:00 5125一、采用RequestDispatcher的方式进 ... -
session失效时间
2010-02-03 13:33 1806session-config元素为Web应用中的javax.s ...
相关推荐
**Log4j2漏洞检测工具详解** 在当前的IT环境中,安全问题日益凸显,特别是针对开源组件的安全漏洞。Log4j2,一个广泛使用的Java日志框架,最近曝出的重大安全漏洞(CVE-2021-44228,被称为Log4Shell)引起了全球的...
通常,更新Log4j2的步骤包括下载最新的JAR文件,替换旧版本的JAR,或者通过Maven或Gradle等构建工具更新依赖。 标签“若依 log4j2.16.0”明确了这个问题针对的是若依框架中的Log4j2组件,提醒用户要特别关注这个...
1. 扫描系统及应用的类路径,寻找Log4j2的依赖。 2. 检查Linux服务器上的各种服务和应用程序,确定它们是否使用了易受攻击的Log4j2版本。 3. 在容器环境下,如Docker,也能有效地进行安全检查。 4. 可能支持自动化...
“log4j漏洞扫描工具”是指用于检测和识别Apache Log4j框架中存在安全漏洞的专用软件。Log4j是Java编程语言中的一个流行日志记录库,2021年曝光的重大安全漏洞(被称为CVE-2021-44228或Log4Shell)使得恶意攻击者...
这篇博客“日志组件-仿log4j的配置”探讨了如何设计和实现一个模仿Log4j的日志解决方案。 首先,我们需要理解Log4j的基本工作原理。Log4j包含三个主要部分:Logger(日志器)、Appender(输出端)和Layout(格式化...
总的来说,Log4j 2是Java开发中不可或缺的工具,它提供强大的日志记录能力并注重性能和可扩展性。在选择和使用特定版本时,应密切关注安全更新,确保及时修补任何潜在的安全风险,以保护应用程序和用户数据的安全。...
总的来说,Log4j API为Java开发者提供了一个强大而灵活的日志解决方案,通过其丰富的功能和可定制性,能够适应各种项目的需求。对于使用Log4j的开发者来说,理解和掌握API的各个方面至关重要,以实现有效的日志管理...
1. **引入依赖**:在项目中添加Log4j 1.2.15.jar依赖,可以手动下载放入类路径,或者通过Maven或Gradle等构建工具进行管理。 2. **配置文件**:创建log4j.properties或log4j.xml配置文件,设置日志级别、Appender、...
在实际应用中,将`log4j.jar`添加到项目的类路径中,并根据项目需求定制`log4j.properties`,即可实现有效的日志管理。这不仅有助于问题排查,也有利于系统维护和性能优化,因为过多的日志可能会占用大量磁盘空间,...
### Log4J完整说明与配置解析 #### 一、Log4J简介 Log4J是Apache的一个开源项目,用于提供灵活的日志记录功能。通过它,开发者能够控制日志信息的输出级别、输出目的地(控制台、文件等)、格式化方式等。本文将...
#### 四、log4j的核心组件 log4j的核心组件主要包括**Loggers(记录器)**、**Appenders(输出源)**和**Layouts(布局)**。 1. **Loggers (记录器)**:负责生成日志信息,并决定是否发送日志信息到Appenders。记录器...
我们可以创建一个定制的PrintStream类,重写`print()`和`println()`方法,将调用转发给Log4j的Logger。下面是一个简单的实现: ```java public class Log4jPrintStream extends PrintStream { private Logger ...
- `log4j-1.2.14.jar`: 这是Log4j 1.2.14版本的jar包,包含了Log4j的全部类和方法,是使用Log4j进行日志记录的核心组件。 - `commons-logging-1.0.4.jar`: 这是Apache Commons Logging库,它是Java日志API的一个抽象...
通过分析和学习Log4j的源代码,开发者可以更好地理解和利用这个强大的工具,解决在实际项目中遇到的日志问题,定制自己的日志解决方案,或者为开源社区贡献新的特性或修复已知问题。总之,熟悉并掌握Log4j的内部工作...
Log4j是Apache组织提供的一款广泛使用的Java日志框架,因其高效、灵活和强大的功能而备受青睐。 **Log4j简介** Log4j是一个开源的日志记录库,主要设计用于Java应用程序。它允许程序员以可配置的方式控制日志信息...
总结来说,Log4j是一个强大的日志工具,它通过配置文件和简单的API为Java应用程序提供了定制化的日志记录功能。理解和掌握Log4j的使用,对于任何Java开发者来说都是十分有益的,因为它能够帮助优化调试过程,提升...
Log4j,作为Java世界中最广泛使用的日志框架之一,因其强大的功能和灵活的配置,成为了开发者的首选工具。本文将重点围绕Log4j 1.2.17版本展开,详细介绍其核心概念、使用方法以及配置细节。 1. **Log4j简介** Log...
3. **IDEA与log4j**: IntelliJ IDEA(简称IDEA)是一款流行的Java集成开发环境,它支持将log4j集成到项目中,通过配置pom.xml或build.gradle文件添加依赖,或者手动将log4j.jar添加到项目的类路径下,以便在IDEA中...
3. **导入使用**:在Java项目中使用Log4j非常简单,只需要将`log4j-2.17.1.jar`文件添加到项目的类路径(Classpath)中。对于Maven或Gradle项目,可以在依赖管理中添加相应的依赖条目。 4. **配置文件**:Log4j 的...
Log4j是一款由Apache出品的日志记录工具,它提供了灵活的日志级别控制和多样化的日志输出方式,广泛应用于Java应用的开发中。本文将深入解析log4j的配置与加载机制,帮助开发者更好地理解和应用log4j。 #### Log4j...