log4j几个tips

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:

log4j是很常用的日志框架,这里总结几个小知识点:

1. logger是以名称为key,logger为value的形式存储在Hashtable里,所以,logger作为入参不需要传入引用,直接输入名称get即可。

LogFactoryImpl.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

/**

* The {@link org.apache.commons.logging.Log} instances that have

* already been created, keyed by logger name.

*/

protected Hashtable instances = new Hashtable();

public Log getInstance(String name) throws LogConfigurationException {

Log instance = (Log) instances.get(name);

if (instance == null) {

instance = newInstance(name);

instances.put(name, instance);

}

return (instance);

}

2. logger的继承关系是根据名称的“.”分割来区分,表现为子logger打印日志时遍历父logger里的appender的进行日志打印。

Category.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public

void callAppenders(LoggingEvent event) {

int writes = 0;

for(Category c = this; c != null; c=c.parent) {

// Protected against simultaneous call to addAppender, removeAppender,...

synchronized(c) {

if(c.aai != null) {

writes += c.aai.appendLoopOnAppenders(event);

}

if(!c.additive) {

break;

}

}

}

if(writes == 0) {

repository.emitNoAppenderWarning(this);

}

}

3.定义模块名为常量,按模块名称取logger,解决项目里包名类名相同日志无法区分问题。

贴代码:
示例一

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

package com.zoo;

import java.util.Properties;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.apache.log4j.PropertyConfigurator;

/**

*

* @author yankai913@gmail.com

* @date 2014年12月22日

*/

public class LogTest {

static final Log log = LogFactory.getLog(LogTest.class);

public static void main(String[] args) {

Properties properties = new Properties();

properties.setProperty("log4j.rootLogger", "DEBUG,stdout");

properties.setProperty("log4j.appender.stdout", "org.apache.log4j.ConsoleAppender");

properties.setProperty("log4j.appender.stdout.layout", "org.apache.log4j.PatternLayout");

properties.setProperty("log4j.appender.stdout.layout.ConversionPattern",

"%d [%t] %-5p %C{6} (%F:%L) - %m%n");

// log4j的继承关系是"."

// log --> com.zoo.LogTest

// log2(父log) --> com.zoo

// log3(父log2) --> com

// 以此类推

// 子logger的继承关系表现是,子logger打印日志时,遍历父logger里的appender

// 进行日志打印,"com.zoo.LogTest"的父子logger分别是:

// "com.zoo.LogTest"的logger -> "com.zoo"的logger -> "root"的logger。

// 以下这句话定义了上述的log2(即父log),导致日志打印2次。

properties.setProperty("log4j.logger.com.zoo", "INFO, stdout");

// 以下这句话定义com.zoo包的logger(即log2)的appender不被继承,日志打印只有一条。

properties.setProperty("log4j.additivity.com.zoo", "false");

PropertyConfigurator.configure(properties);

System.out.println(log);

log.info("Hello World!");

System.out.println("end");

}

}

示例二

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

package com.zoo;

import java.util.Properties;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.apache.log4j.PropertyConfigurator;

/**

*

* @author yankai913@gmail.com

* @date 2014年12月22日

*/

public class LogTest2 {

// 定义公共的logerName,按module分

static final String Module1_LogName = "Module1";

static final String Module2_LogName = "Module2";

public static void main(String[] args) {

Properties properties = new Properties();

properties.setProperty("log4j.rootLogger", "DEBUG,file");

properties.setProperty("log4j.appender.file", "org.apache.log4j.FileAppender");

properties.setProperty("log4j.appender.file.layout", "org.apache.log4j.PatternLayout");

properties.setProperty("log4j.appender.file.layout.ConversionPattern",

"%d [%t] %-5p %c{1} %C{6} (%F:%L) - %m%n");

properties.setProperty("log4j.appender.file.append", "true");

properties.setProperty("log4j.appender.file.file", "logtest2.log");

PropertyConfigurator.configure(properties);

// 比较同名称的log,结果为true,所以log作为入参不需要传入引用,直接get即可。

System.out.println(Module1.log.equals(ServiceImpl_1.log));

System.out.println(Module2.log.equals(ServiceImpl_2.log));

// 按模块搜索查看日志,关键词就是模块名称,即上面的Module1,Module2。

// 解决包名类名完全一样,但是在不同模块的日志查询。

Module1.println();

Module2.println();

ServiceImpl_1.println();

ServiceImpl_2.println();

System.out.println("end");

}

public static class Module1 {

public static Log log = LogFactory.getLog(Module1_LogName);

public static void println() {

log.info("this is module1");

}

}

public static class Module2 {

public static Log log = LogFactory.getLog(Module2_LogName);

public static void println() {

log.info("this is module2");

}

}

public static class ServiceImpl_1 {

public static Log log = LogFactory.getLog(Module1_LogName);

public static void println() {

log.info("this is service");

}

}

public static class ServiceImpl_2 {

public static Log log = LogFactory.getLog(Module2_LogName);

public static void println() {

log.info("this is service");

}

}

}

练习代码看这里


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
6月前
|
机器学习/深度学习 JavaScript 前端开发
你不知道的console.log用法
在JavaScript中,使用`console.log()`时,通过大括号能显示变量名和值。`console.table(data, columns)`用于格式化打印表格。常用方法包括:`console.log()`
56 0
|
算法
Tips In C
C语言中的使用操作 宏定义时使用do while防止语句的分离, 但是不使用与需要有返回值的语句, 这个时候可以参考第二条 宏定义时使用({}), ()加上{}的方式, 在代码中填写逻辑算法, 最后的一条语句就是该宏定义的返回值; 在使用该宏定义时需要以";"结尾
811 0
|
XML 数据格式
|
XML 数据格式
|
程序员 C++
|
SQL 数据库 C++