log4j在web工程中的应用
这是来某外包公司的第五个星期,时间过得真快啊,又到了周一,也意味着来这里打了4周的酱油啦。
公司没人对我负责,基本上处于放羊的状态,指派的任务无人讲解,看起来遥遥无期,口袋空空(没钱),更惨的是精神世界也空空(主要一天敲不到50行代码,看着其他同学在其他公司BAT啦,网易啦,突飞猛进,感觉好虚),这么久啥都没学到?
也不是吧,回忆一下上周老大给讲的log4j,于是决定趁着没忘干净赶快整理一下,主要借助了其他博客的精华,回忆着老大的谆谆教诲,整理一下。
说正事之前先吐槽一下艹蛋的win10系统,强制自动更新,在8.10分抛给我一个10分钟后自动重启的通知,之后就趁我早晨脑袋蒙圈在10分钟后强制重启进行了更新,
自动重启了N次,更新了一个半钟头,比重装还慢...而且更新之后也没发现哪里有不一样的地方。事后琢磨如果不想更新可以这么做:把系统时间往前调整(逃软件试用期也用过这一招),或者在控制面板中设置禁止自动更新。
在配置log4j的过程中回顾了一下以前的知识,提出了3个问题。
一.web基础回顾
1.1什么是web工程
一个web工程,就是符合一套web标准(工程组织形式个人理解就是源代码,中间代码,各种文件怎么放),因为只有符合一个统一的标准,服务器才能更好的识别,运行。
左图:下面没有介绍的基本没用到,所以也懒得理解了...
是eclipse中一个名为web_log4j的web工程,src顾名思义就是源码,下面存放着若干.java文件,我们面向对象编程就是在这里写类,写方法
jreSystemLibrary是java运行依赖的类库,自动生成
webApplibrary下面是工程引用的外部jar包,一个引用过程是这样的:将jar包文件拷贝到工程中,右击buildpath,buildpath相当于将jar包里面的类引入,
比如之前【beanUtile.封装】这样的代码是没有提示的,buildpath之后,该代码出现了提示,按照提示import之后就可以使用beanUtil这个工具类,
前后对比说明buildpath完成了jar包中的类导入到工程中的作用。引用外部类还可以采用直接引用的方式[add external jars],不利于代码移植性,就不介绍啦。
(举个例子,你电脑上log4j.jar在c盘,换了一台电脑跑,程序还去c盘找这个文件,找不到就会报错)
这里要说清楚所谓引用类,就不得不说一下什么是jar包,jar包其实就是打包压缩好的一堆.class文件,引用就是把外部的.class文件组合到工程里面的过程。如果想要查看jar包的源码,
还需要导入源码。有趣的是自己也可以将一堆.class文件在cmd命令下打成jar包,自创jar包。
在一个web工程中,依靠的是工程名:web_log4j提供对外访问,对内web_log4j抽象成根目录/(内部总使用相对路径访问),对于路径问题有篇博客解释的超级精辟:java获取路径问题,
(一个常用做法是从当前类拿到完整路径,或者是通过容器得到)
获得路径可以通过IO流做输入输出,还有读取配置文件也需要路径,所以路径很重要。
这里插播一个有趣的问题,下面的代码是错误的,错在哪里?
public static String s1=this.getClass().getClassLoader().getResource("/").getPath();
或者说:java的static方法里面为什么不能用this关键字?
这和jvm有关,jvm首先加载的是静态部分,而this的含义是指当前对象,静态部分加载进入的时候对象还没有创建。
这里再插播一个对比jdk,jre,jvm,
我们利用JDK(调用JAVA API)开发了属于我们自己的JAVA程序后,通过JDK中的编译程序(javac)将我们的文本java文件编译成JAVA字节码,
在JRE上运行这些JAVA字节码,JVM解析这些字节码,映射到CPU指令集或OS的系统调用
回到web工程的主题:
右图:build文件夹下存放着编译好的.class文件,src放源码,webcontent下面的web-info存放着jar包和配置文件
工程运行所依赖的配置文件(.properties文件:比如用于配置数据库连接的用户名,密码;.xml文件,配置类,常数等关系的文件);.class文件(外部jar包,src编译形成的.class文件)
至此全部介绍完毕,其中大部分位于web-inf目录下,由此可见这是一个很重要的目录。而web.xml关系到一个web工程全局的初始化设置,接下来就说一说我所见过的配置,看明白了web.xml文件,这个工程用到哪些技术,是怎样一个结构基本上有了一个全局性的了解。
1.2一个web.xml文件的解读
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>LogLearning</display-name> <servlet> <servlet-name>Log4JTestServlet</servlet-name> <servlet-class>com.mucfc.Log4JTestServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Log4JTestServlet</servlet-name> <url-pattern>/test</url-pattern> </servlet-mapping> <!-- Spring 容器加载 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 设置根目录 --> <context-param> <param-name>webAppRootKey</param-name> <param-value>webapp.root</param-value> </context-param> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>/WEB-INF/classes/log4j.properties</param-value> </context-param> <!-- 3000表示 开一条watchdog线程每60秒扫描一下配置文件的变化;这样便于日志存放位置的改变 --> <context-param> <param-name>log4jRefreshInterval</param-name> <param-value>3000</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> </web-app>
最前面是约束,这个web.xml中主要配置了servlet和listener
servlet包含两个标签<servlet>和<servlet-mapping>
其中servlet-name可以随便起,但是俩标签里的name一定要一致,之所以这样做,是因为前一个servlet绑定了servlet类(拿到request,response处理并且返回的代码,说简单点,控制代码就写在<servlet-class>指定的类里面,而且指定了初始化参数),后一个url-mapping(假设配成/test)则是提供了访问路径:如localhost:8080/web_log4j/test,就是在访问这个servlet呢,访问路径和后台代码要绑定,靠的是共有的名字,所谓的servlet之所以能实现交互的原因就是这样。既有访问路径,又有后台处理代码,request和response是一堆邮差,扮演了信息载体的角色。
listener标签则配置了监听器,其中org类位于jar包中,这里所谓的监听器到底是什么东西呢?
1.随着web应用的启动开始启动,也就是说一开始就发挥了作用
2.不负责响应用户的请求,也就是说只有一行<listener>类</listener>,无需配置url
第一个监听器:ContextLoaderListener和
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
搭配使用,使得context载入配置文件applicationContext.xml(里面放置着配置好的bean),所谓classpath指代的是web-info/classes目录,直接把spring的配置关系载入了
webapp.root可以用于获取系统根目录,具体代码System.getRoot("...")
第二个监听器:log4jConfigListener
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>
搭配使用载入了log4j文件的位置。
对监听器作用理解如下:
只有一行,配置指向jar包里面的某个类,和某些特定参数配合使用,为其指定初始化模式(比如显示了配置文件位置)
这里也可以做一个逆向思考:计算机不是人,怎么读取配置文件呢?web.xml首先是web默认的全局配置文件,里面配置了监听器从应用启动开始启动
通过一些参数来找到配置文件。
二 log4j的使用
2.1log4j介绍
就是跟日志挂钩的东西,大部分web应用部署在linux上,要想时时刻刻记录运行状态,就得依靠一种叫日志的东西,运行状态,出错,异常统统记录在案,出问题了回头也能查到,日志的实体就是.log后缀的文件。
Log4j由三个重要的组件构成:日志信息的优先级,日志信息的输出目的地,日志信息的输出格式。日志信息的优先级从高到低有ERROR、WARN、 INFO、DEBUG,分别用来指定这条日志信息的重要程度;日志信息的输出目的地指定了日志将打印到控制台还是文件中;而输出格式则控制了日志信息的显 示内容。
2.2log4j.properties文件解读
### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
log4j.rootLogger = debug,stdout,D,E
定义”顶“为debug,意为debug以下的信息都可以输出,appenderName1为stdout(用于控制台输出),D(debug),E(error)
PatternLayout表示按照指定格式输出,才有后面的规则
[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n:
除了特殊含义字符,其他字符按照原样输出
p:[debug]级别,d:日期样式,l:输出日志事件发生的位置,n:回车换行,m:指定的消息(这才是重点)
除了控制台,还指定了error.log和debug.log作为输出文件
2.3log4j的代码应用
static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName ()[一般是当前类,因为记载了当前类的debug信息] )
PropertyConfigurator.configure ( String configFilename) :读取使用Java的特性文件编写的配置文件。
[这一步也可以在spring中配置指定的路径]
Logger.debug ( Object message ) ; :跟上面对应的m一样,输出debug信息
三遗留问题
3.1上面仅仅是做了一个实验,相当于helloword,在实际应用中,log4j是如何记载产生的异常的?
或者说,上面的message是自己写的,如果一段代码跑崩了,日志是怎样记录信息的?
3.2每天产生数以万计的日志记录,如何查看?里面有没有什么技巧?