码迷,mamicode.com
首页 > 其他好文 > 详细

使用Log4j进行日志操作

时间:2014-12-26 14:31:34      阅读:289      评论:0      收藏:0      [点我收藏+]

标签:

使用Log4j进行日志操作

 

一、Log4j简介

 

(1)概述

 

Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接字服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。

最令人感兴趣的就是,这些只需要通过一个属性配置文件来灵活地进行配置,而不需要修改应用的代码。因为目前在 Java 中最有名的 Log 方式, 首推是 Log4j, 另外 JDK 1.4 中也提供了Logging API。Log4j是在jakarta apache 项目下开发的一个开源的日志记录工具。

 

(2)应用的目的

 

当你在开发程序的时候, 调试(debugging)和日志(logging)都是非常重要的工作。在应用中使用日志主要有三个目的

l 监视代码中的变量的变化情况,把数据周期性地记录到文件中供其它应用进行统计分析工作

l 跟踪代码运行的轨迹,作为日后审计的依据

l 担当集成开发环境中的调试器,向文件或者控制台打印代码的调试信息

 

而实现这些应用的常规方式是在代码中嵌入许多的打印语句,这些打印语句可以输出到控制台或文件中,比较好的做法就是构造一个日志操作类来封装此类操作,而不是让一系列的打印语句充斥了代码的主体。

 

(3)优点

l 采用Log4j进行日志操作的整个过程相当简单明了,与直接使用System.out.println语句进行日志信息输出的方式相比,基本上没有增加代码量,同时能够清楚地理解每一条日志信息的重要程度。

l 通过控制配置文件,我们还可以灵活地修改日志信息的格式,输出目的地等等方面,而单纯依靠System.out.println语句,显然需要做更多的工作。

 

(4)与System.out.println()的对比

l log4j提供分级方法在程序中嵌入日志记录语句。日志信息具有多种输出格式和多个输出级别。

程序开发环境中的日志记录是由嵌入在程序中以输出一些对开发人员有用信息的语句所组成。例如,跟踪语句(trace),结构转储和常见的System.out.println或printf调试语句。

l 使用一个专门的日志记录包,可以减轻对成千上万的System.out.println语句的维护成本

因为日志记录可以通过配置脚本在运行时得以控制。log4j维护嵌入在程序代码中的日志记录语句,通过属性配置文件可以快速地规范日志记录的处理过程。

 

(5)log4j的其它特性

l log4j已经被移植到C, C++, C#, Perl, Python, Ruby, Eiffel 几种语言。

l log4j有三种主要的组件:记录器(Loggers),存放器(Appenders),布局(Layouts)

这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出。综合使用这三个组件可以轻松的记录信息的类型和级别,并可以在运行时控制日志输出的样式和位置。

 

记录器(记录器可不关心log数据存放的事,应该是存放器的事)。

l log4j允许程序员定义多个记录器,每个记录器有自己的名字。有一个记录器叫根记录器,它永远存在并且是类别等级的起始,且不能通过名字检索或引用,可以通过Logger.getRootLogger()方法取得它,而一般记录器通过Logger.getLogger(String name)方法。记录器使用点式标记来进行命名并且也具有继承的特性。

l 记录器还有一个重要的属性,就是级别。(这好理解,就象一个家庭中,成员间存在辈份关系,但不同的成员的身高可能不一样,且身高与辈份无关)程序员可以给不同的记录器赋以不同的级别,如果某个成员没有被明确级别,就自动继承最近的一个有级别长辈的级别值。

 

二、下载并安置Log4j的*.jar包

 

(1)http://jakarta.apache.org/log4j/docs/download.html下载log4j发行版并将该*.jar包添加到CLASSPATH 环境变量中。

 

(2)Logger类的基本方法

package org.apache.log4j; 

public class Logger 

{

// Creation & retrieval methods:

public static Logger getRootLogger();

public static Logger getLogger(String name);

 

// printing methods:

public void debug(Object message);

public void info(Object message);

public void warn(Object message);

public void error(Object message);

public void fatal(Object message);

 

// generic printing method:

public void log(Level l, Object message);

}

 

三、Apache 的Log4j的编程实现

 

下面看一下在JCreator中实现log4j的例子。

 

1、打开或者新建一个Java程序

 

1

 

2)内容如下,详细代码请见源程序

 

public class UserLog4jWithJCreate 

{

  public UserLog4jWithJCreate() 

  {  

  }  

  public static void main(String[] args) 

  {

    UserLog4jWithJCreate mainObj=new UserLog4jWithJCreate();

  }

}

 

2、在程序所在的目录下新建一个配置文件log4j.properties

 

1

 

 

2)文件的内容如下

# config root logger

log4j.rootLogger = INFO,system.out

log4j.appender.system.out = org.apache.log4j.ConsoleAppender

log4j.appender.system.out.layout = org.apache.log4j.PatternLayout

log4j.appender.system.out.layout.ConversionPattern =this4j-->%5p {%F:%L} - %m%n

 

# config thisProject.file logger

log4j.logger.thisProject.file = INFO, thisProject.file.out

log4j.appender.thisProject.file.out = org.apache.log4j.DailyRollingFileAppender

log4j.appender.thisProject.file.out.File = logContentFile.log

log4j.appender.thisProject.file.out.layout = org.apache.log4j.PatternLayout

 

3、在JCreator中引入Log4j的apache Jar包log4j-1.2.8.jar到本程序中

 

 

 

4、编程该程序以使用Log4j

 

1)引入与 log4j相关的包

 

import org.apache.log4j.PropertyConfigurator;

import org.apache.log4j.Logger;

2)读其配置文件

PropertyConfigurator.configure("log4j.properties");

3)获得总的输出对象并向控制台输出信息

Logger loggerConsole = Logger.getRootLogger();

    loggerConsole.info("这是在JCreator中向控制台输出的一般信息文字");

    loggerConsole.warn("这是在JCreator中向控制台输出的警告类别的信息文字");

4)获得文件输出对象并向文件中输出信息

    Logger loggerFile= Logger.getLogger("thisProject.file");

loggerFile.warn("这是在JCreator中向指定的log文件中输出的警告类别的信息文字");

 

5)最后总的程序为

import org.apache.log4j.PropertyConfigurator;

import org.apache.log4j.Logger;

public class UserLog4jWithJCreate 

{

  public UserLog4jWithJCreate() 

  {

   PropertyConfigurator.configure("log4j.properties");

  

   Logger loggerConsole = Logger.getRootLogger();

    loggerConsole.info("这是在JCreator中向控制台输出的一般信息文字");

    loggerConsole.warn("这是在JCreator中向控制台输出的警告类别的信息文字");

 

Logger loggerFile= Logger.getLogger("thisProject.file");

loggerFile.warn("这是在JCreator中向指定的log文件中输出的警告类别的信息文字");

  }

  public static void main(String[] args) 

  {

    UserLog4jWithJCreate mainObj=new UserLog4jWithJCreate();

  }

}

 

5、执行该Java程序

 

1)观看其控制台上的输出,并注意其输出的信息格式

 

 

 

2)观看其磁盘文件的输出

 

 

 

 

有了这样一个直观的例子感受,我们就可以进一步的讨论。

 

四、log信息的级别

 

(1)五个log信息的级别

 

Loggers组件在此系统中被分为五个级别:DEBUG、INFO、WARN、ERROR和FATAL。这五个级别是有顺序的,DEBUG < INFO < WARN < ERROR < FATAL。如果一条log信息的级别,大于等于记录器的级别值,那么记录器就会记录它,否则则不记录。

static Level DEBUG:DEBUG Level指出细粒度信息事件对调试应用程序是非常有帮助的。

static Level INFO:INFO level表明 消息在粗粒度级别上突出强调应用程序的运行过程。

static Level WARN:WARN level表明会出现潜在错误的情形。

static Level ERROR:ERROR level指出虽然发生错误事件,但仍然不影响系统的继续运行。

static Level FATAL:FATAL level指出每个严重的错误事件将会导致应用程序的退出。

另外,还有两个可用的特别的日志记录级别: 

(以下描述来自log4j API http://jakarta.apache.org/log4j/docs/api/index.html): 

static Level ALL:ALL Level是最低等级的,用于打开所有日志记录。 

static Level OFF:OFF Level是最高等级的,用于关闭所有日志记录。

 

(2)下面给出参考示例来说明级别的应用 

  

 // 获得一个名称为“thisProject.file的parentlogger实例

   Logger  parentlogger = Logger.getLogger("thisProject.file "); 

  // 设置其级别为Level.INFO ,一般并不需要在代码中设置,可以在属性配置文件中进行设置

   parentlogger.setLevel(Level.INFO);

   // 再获得一个名称为“thisProject.file.Son的sonlogger实例

Logger sonlogger= Logger.getLogger("thisProject.file.Son");

 

   // 由于warn级别大于Info级别,因此可以产生出log 信息

   parentlogger.warn("由于warn级别大于Info级别,因此可以产生出log 信息");

   // 下面的输出将被禁止,因为parentlogger实例的级别在前面已经设置为Level.INFO ,但由于DEBUG < INFO,因此通过parentlogger.debug()方法将不会产生出log 信息

   parentlogger.debug("下面的输出将被禁止,因为parentlogger实例的级别在前面已经设置为Level.INFO ");

  

//命名为“thisProject.file.Son的实例sonlogger会继承命名为“thisProject.file实例parentlogger的级别。因此,下面这个请求可用,因为INFO >= INFO

sonlogger.info("下面这个请求可用,因为INFO >= INFO ");

//下面这个请求不可用,因为DEBUG < INFO

sonlogger.debug("下面这个请求不可用,因为DEBUG < INFO "); 

 

(3)日志记录器(Logger)的级别继承关系

 

日志记录器(Logger)将只输出那些级别高于或等于它的级别的信息。如果没有设置日志记录器(Logger)的级别,那么它将会继承最近的祖先的级别。因此,如果在包thisProject.file.Son中创建一个日志记录器(Logger)并且没有设置级别,那它将会继承在包thisProject.file中创建的日志记录器(Logger)的级别。

如果在thisProject.file中没有创建日志记录器(Logger)的话,那么在thisProject.file.Son中创建的日志记录器(Logger)将继承root 日志记录器(Logger)的级别,root日志记录器(Logger)经常被实例化而可用,它的级别为DEBUG。

 

五、Log4j组件构成

 

Log4j由三个重要的组件构成:日志信息的产生器、日志信息的输出目的地、日志信息的输出格式。

l 日志信息的的产生器Logger:它主要负责生成日志并能够按照优先级进行输出(级别从高到低有ERROR、WARN、INFO、DEBUG,分别用来指定这条日志信息的重要程度);

l 日志信息的输出目的地Appender:它指定了日志将打印到控制台还是文件中等不同的目的地;

l 而日志信息的输出格式Layout:它控制了日志信息的显示内容的格式。

 

 

六、通过定义属性配置文件来定义log4j的产生方式

 

其实也可以完全不使用属性配置文件,而是在代码中配置Log4j环境。但是,使用配置文件将使应用程序更加灵活。

Log4j支持两种配置文件格式,一种是XML格式的文件,一种是Java属性文件(键=值)。

Log4J的配置文件(Configuration File)就是用来设置记录器的级别、存放器和布局的,它可按key=value格式的设置或xml格式的设置信息。通过配置,可以创建出Log4J的运行环境。

在配置文件中主要指定Root logger的级别并且和一个appender相绑定,同时再指定appender的属性,最后再为appender指定一个layout。下面我们介绍使用Java特性文件做为配置文件的方法:

 

(1)配置根Logger或者其它Logger,其语法为:

 

log4j.rootLogger = [ level ] , appenderName, appenderName, …

其中,level 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者自定义的级别。

Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。

appenderName就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。

如输出目的地为控制台:

log4j.rootLogger = INFO,system.out

如果为log4j.rootLogger=WARN, 则意味着只有WARN,ERROR,FATAL被输出,而DEBUG,INFO将被屏蔽掉。

如输出目的地为文件:

log4j.logger.thisProject.file = INFO, thisProject.file.out
也可以为某个日志记录器同时指定多个目的地

log4j.rootLogger = INFO,system.out, thisProject.file.out

 

 

(2)再配置该日志记录器的日志信息输出目的地Appender

 

Log4j日志系统允许把日志信息输出到不同的目的地,如控制台(Console)、文件(Files)、根据天数或者文件大小产生新的文件、以流的形式发送到其它地方等等。

l Log4j中定义的日志信息输出目的地,有下面的各种形式

ü ConsoleAppender:使用用户指定的布局(layout) 输出日志事件到System.out或者 System.err。默认的目标是System.out。

ü DailyRollingFileAppender 扩展FileAppender,每天产生一个日志文件,因此多个日志文件可以以一个用户选定的频率进行循环日志记录。

ü FileAppender 把日志事件写入一个文件

ü RollingFileAppender 扩展FileAppender备份容量达到一定大小的日志文件。

ü WriterAppender根据用户的选择把日志事件写入到Writer或者OutputStream。 

ü SMTPAppender 当特定的日志事件发生时,一般是指发生错误或者重大错误时,发送一封邮件。 

ü SocketAppender 给远程日志服务器(通常是网络套接字节点)发送日志事件(LoggingEvent)对象。 

ü SocketHubAppender 给远程日志服务器群组(通常是网络套接字节点)发送日志事件(LoggingEvent)对象。

ü SyslogAppender给远程异步日志记录的后台精灵程序(daemon)发送消息。 

ü TelnetAppender 一个专用于向只读网络套接字发送消息的log4j appender。

l 其语法为

log4j.appender.appenderName = fully.qualified.name.of.appender.class

如:log4j.appender.system.out = org.apache.log4j.ConsoleAppender

如:log4j.appender.thisProject.file.out = org.apache.log4j.DailyRollingFileAppender

 

(3)配置日志信息的格式(布局)

 

有时用户希望根据自己的喜好格式化自己的日志输出。Log4j可以在Appenders的后面附加Layouts来完成这个功能。Layouts提供了四种日志输出样式,如根据HTML样式、自由指定样式、包含日志级别与信息的样式和包含日志时间、线程、类别等信息的样式等等。

其语法为:

log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class

布局负责格式化输出的log信息。log4j的PatternLayout可以让程序以类似C语言printf的格式化模板来定义格式。其中,Log4j提供的layout可以为下面的几种:

org.apache.log4j.HTMLLayout(以HTML表格形式布局),

org.apache.log4j.PatternLayout(可以灵活地指定布局模式),

org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),

org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

如:

log4j.appender.system.out.layout = org.apache.log4j.PatternLayout

log4j.appender.system.out.layout.ConversionPattern =this4j-->%5p {%F:%L} - %m%n

如:

log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n

 

七、在程序中使用Log4j

 

(1)第一步:配置Log4j环境

 

其语法为:

l BasicConfigurator.configure ()

自动快速地使用缺省Log4j环境。

l PropertyConfigurator.configure ( String configFilename) 

读取使用Java的属性文件编写的配置文件,该参数是一个完整的路径名称,指向一个包含Log4J配置信息的属性文件。

l DOMConfigurator.configure ( String filename ) 

读取XML形式的配置文件。

如:

PropertyConfigurator.configure("log4j.properties");

 注意:

也可以不用调用PropertyConfigurator.configure(),而是让Log4J自己在模块的CLASSPATH中寻找一个叫Log4J.properties的属性文件。查找属性文件的操作在Logger.getLogger()函数第一次被调用时执行。

(2)第二步:就是获取日志记录器,这个记录器将负责控制日志信息。

 

其语法为:

public static Logger getLogger( String name),

通过指定的名字获得记录器,如果必要的话,则为这个名字创建一个新的记录器。在对Logger实例进行命名时,没有限制,可以取任意自己感兴趣的名字。但一般取本类的名字作为Name。

比如:

Logger loggerConsole = Logger.getRootLogger();

如:

Logger loggerFile= Logger.getLogger("thisProject.file");

 

(3)第三步:插入记录信息(格式化日志信息)

 

当上面的两个必要步骤执行完毕,您就可以轻松地使用不同优先级别的日志记录语句插入到您想记录日志的任何地方,其语法如下:

Logger.debug ( Object message ) ;

Logger.info ( Object message ) ;

Logger.warn ( Object message ) ;

Logger.error ( Object message ) ;

 

八、一个属性配置文件的示例

 

(1)这里需要说明的就是日志信息格式中几个符号所代表的含义:

%r:自程序开始后所耗费的毫秒数

%t:表示日志记录请求生成的线程

    %p:在日志信息中显示出日志信息级别的文字

    %d{}:显示出日志信息产生时间

    %c:显示出日志信息所在的类名

    %m:显示出产生的日志具体信息

%n:显示出日志信息时,每行进行换行

%F:显示出程序的文件名称

 

(2)配置文件的示例

# config root logger

log4j.rootLogger = WARN,system.out

log4j.appender.system.out = org.apache.log4j.ConsoleAppender

log4j.appender.system.out.layout = org.apache.log4j.PatternLayout

log4j.appender.system.out.layout.ConversionPattern = lpw4j-->%5p {%F:%L} - %m%n

 

# config lpw4j.database logger

log4j.logger.lpw4j.database = WARN,database.file.out

log4j.appender.database.file.out = org.apache.log4j.DailyRollingFileAppender

log4j.appender.database.file.out.File = E:/lpw/shi-jie/source/shi-jie/WEB-INF/log-files/database.log

log4j.appender.database.file.out.layout = org.apache.log4j.PatternLayout

log4j.appender.database.file.out.layout.ConversionPattern = lpw4j-->%5p {%F:%L} - %m%n

 

 

九、在JBuilder中实现Log4j

 

1、新建一个Project

 

项目的名称为ApacheLog4j

 

 

 

2、在该项目中新建一个应用程序

 

包名称为apachelog4j。类名称为UserLog4j

 

 

窗口类为MainFrame

 

 

 

3、在项目中新建一个配置文件log4j.properties

 

1)目录位置如下

 

 

 

2)其内的内容为

 

# config root logger

log4j.rootLogger = INFO,system.out

log4j.appender.system.out = org.apache.log4j.ConsoleAppender

log4j.appender.system.out.layout = org.apache.log4j.PatternLayout

log4j.appender.system.out.layout.ConversionPattern =this4j-->%5p {%F:%L} - %m%n

 

# config thisProject.file logger

log4j.logger.thisProject.file = INFO, thisProject.file.out

log4j.appender.thisProject.file.out = org.apache.log4j.DailyRollingFileAppender

log4j.appender.thisProject.file.out.File = logContentFile.log

log4j.appender.thisProject.file.out.layout = org.apache.log4j.PatternLayout

4、在本项目中引入 Log4j的apache Jar包log4j-1.2.8.jar到本项目中

1)选择Tools菜单下的Configure Libraries菜单

 

2)在对话框内点击“New”按钮,然后在新的对话框内的名称栏:log4jJar,在 Location中:JBuilder

,然后点击“Add”按钮将Log4j的apache Jar包log4j-1.2.8.jar文件到本项目中

 

最后为

 

点击“OK”将添加到本项目中

 

3)在本项目中引入前面所配置的库

 

点击上面的“OK”按钮

 

 

 

5、在程序中使用log4j

 

1)引入与 log4j相关的包

import org.apache.log4j.PropertyConfigurator;

import org.apache.log4j.Logger;

 

2)读其配置文件

PropertyConfigurator.configure("log4j.properties");

 

3)获得总的输出对象并向控制台输出信息

Logger loggerConsole = Logger.getRootLogger();

    loggerConsole.info("这是在JBuilder中向控制台输出的一般信息文字");

    loggerConsole.warn("这是在JBuilder中向控制台输出的警告类别的信息文字");

 

4)获得文件输出对象并向文件中输出信息

    Logger loggerFile= Logger.getLogger("thisProject.file");

loggerFile.warn("这是在JBuilder中向指定的log文件中输出的警告类别的信息文字");

 

6、执行该程序

 

1

 

2)将在JBuilder的控制台上显示出 Log 信息

 

3)同时在磁盘中也有Log 信息

 

 

 

 

 

 

 

 

 

 

 

 

 

十、在 Servlet中实现log4j

 

1、环境设置:将log4j-1.2.8.jar复制到$TOMCAT_HOME/common/lib目录下。

 

 

 

2、在某一个Web应用程序(本例为WebMis)所在的目录下的web.xml文件加入以后代码

 

  <servlet>

    <servlet-name>userregisterservlet</servlet-name>

     <servlet-class>webmisservlet.UserRegisterServlet</servlet-class>

 <init-param>

      <param-name>log4j</param-name>

      <param-value>/WEB-INF/log4j/log4j.properties</param-value>

    </init-param>

 

  </servlet>

  <servlet-mapping>

    <servlet-name>userregisterservlet</servlet-name>

    <url-pattern>/userregisterservlet</url-pattern>

  </servlet-mapping>

这样在该Servlet被加载的时候,可以在Servlet中获得初始参数。该初始参数主要是指定log4j的属性配置文件的存放的目录位置。

 

3、将log4j的属性配置文件log4j.properties放在/WEB-INF

 

 

该属性配置文件的内容如下:

# config root logger

log4j.rootLogger = INFO,system.out

log4j.appender.system.out = org.apache.log4j.ConsoleAppender

log4j.appender.system.out.layout = org.apache.log4j.PatternLayout

log4j.appender.system.out.layout.ConversionPattern =this4j-->%5p {%F:%L} - %m%n

 

# config thisProject.file logger

log4j.logger.thisProject.file = INFO, thisProject.file.out

log4j.appender.thisProject.file.out = org.apache.log4j.DailyRollingFileAppender

log4j.appender.thisProject.file.out.File =

 C:/jakarta-tomcat-5.0.19/webapps/WebMis/WEB-INF/logContentFile.log

log4j.appender.thisProject.file.out.layout = org.apache.log4j.PatternLayout

log4j.appender.thisProject.file.out.layout.ConversionPattern =this4j-->%5p {%F:%L} - %m%n

 

4、在Servlet程序的代码中使用log4j

 

编程该UserRegisterServlet程序

package webmisservlet;

import java.io.*;

import java.sql.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

import org.apache.log4j.PropertyConfigurator;

import org.apache.log4j.Logger;

 

public class UserRegisterServlet extends HttpServlet

{

   public void init(ServletConfig config)    throws ServletException

    {

       super.init(config);

/*

以下是从Web.xml文件中获得数据库的初始配置的参数

*/

String logFilePrefix = getServletContext().getRealPath("/");

String propertyFileName = getInitParameter("log4j");

if(propertyFileName != null) 

{

PropertyConfigurator.configure(logFilePrefix + propertyFileName);

}

    }

    public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException

    {

Logger loggerConsole = Logger.getRootLogger();

loggerConsole.info("这是在JCreator中向控制台输出的一般信息文字");

loggerConsole.warn("这是在JCreator中向控制台输出的警告类别的信息文字");

 

Logger loggerFile= Logger.getLogger("thisProject.file");

loggerFile.warn("这是在JCreator中向指定的log文件中输出的警告类别的信息文字");

    }

}

在Servlet被加载的过程中,系统会读取/WEB-INF/log4j.properties这个log4j的属性配置文件。

 

 

5、执行该Servlet程序

 

由于本Servlet是针对用户注册的,因此浏览该Web页面以触发它。

 

此时在Tomcat的服务器的控制台上将产生如下的输出信息

 

同时在磁盘中将产生如下的log信息文件

 

 

使用Log4j进行日志操作

标签:

原文地址:http://www.cnblogs.com/from/p/4186551.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!