Appender of Log4j [4]

和网络有关的Appender有:

  • JDBCAppender
  • TelnetAppender
  • JMSAppender
  • SMTPAppender
  • SocketAppender
  • SocketHubAppender
  • SyslogAppender

org.apache.log4j.net包下主要是一些网络相关的类:



netetc

8.JDBCAppender

JDBCAppender继承自AppenderSkeleton,提供了将日志信息记录到数据库的功能,JDBCAppender需要配合Layout使用,即requiresLayout返回true。JDBCAppender提供的标准log4j属性配置有BufferSize、URL、User、Password、Driver、layout(注意数据库sql语法),分别表示缓冲区大小、数据库访问连接串、数据库访问用户名、数据库访问密码、数据库驱动类名、日志插入数据库SQL本质上为PatternLayout的模式字符串。

JDBCAppender提供了缓冲区,LoggingEvent会首先放入ArrayList的缓冲区,当缓冲区满时再将LoggingEvent刷出到数据库持久化。JDBCAppender在刷出LoggingEvent时,使用的是Statement而非PreparedStatement,即每次LoggingEvent作为一个独立的数据库Statement执行;log4j提供的数据库连接为简单的DriverManager.getConnection调用,而非数据库连接池。可重写JDBCAppender函数execute、getConnection以优化数据库插入性能、数据库连接复用性能等。

  // override 使用数据库连接池
  protected Connection getConnection() throws SQLException {
    if (!DriverManager.getDrivers().hasMoreElements())
      setDriver("sun.jdbc.odbc.JdbcOdbcDriver");
      if (connection == null) {
        connection = DriverManager.getConnection(databaseURL, databaseUser, databasePassword);
      }
      return connection;
  }

  // override 使用PreparedStatement等优化性能
  protected void execute(String sql) throws SQLException {
    Connection con = null;
    Statement stmt = null;
    try {
      con = getConnection();
      stmt = con.createStatement();
      stmt.executeUpdate(sql);
    } finally {
      if(stmt != null) {
        stmt.close();
      }
      closeConnection(con);
    }
    //System.out.println("Execute: " + sql);
  }

建议:将log4j提供的JDBCAppender作为一个父类,重写成员函数(在log4j JDBCAppender实现中,访问控制为protected)

  • getConnection() 获取一个数据库连接,可使用连接池
  • closeConnection(Connection con) 关闭一个连接,在使用连接池时可不实际关闭连接,仅将连接释放到连接池
  • getLogStatement(LoggingEvent event) 根据LoggingEvent生成一个具体的数据库插入sql语句(getLayout().format(event);),子类可根据需要生成动态sql等

demo

demo log4j config:

log4j.rootLogger=INFO,jdbc
#使用的Appender类,这里为JDBCAppender
log4j.appender.jdbc=org.apache.log4j.jdbc.JDBCAppender
#缓冲区大小
log4j.appender.jdbc.BufferSize=2
#数据库连接地址,不同数据库的jdbc url格式有区别,这里为mysql
log4j.appender.jdbc.URL=jdbc:mysql://127.0.0.1/luohw
#数据库访问用户名
log4j.appender.jdbc.User=root
#数据库访问密码
log4j.appender.jdbc.Password=root
#数据库驱动
log4j.appender.jdbc.Driver=com.mysql.jdbc.Driver
#JDBCAppender这里使用的layout,这里为PatternLayout,默认也为PatternLayout
log4j.appender.jdbc.layout=org.apache.log4j.PatternLayout
#实际数据持久化到数据库的sql语句,经过layout渲染后为合法的数据库sql语句
log4j.appender.jdbc.sql=insert into log4j (thread, message) values ('%t', '%m’)
#当前配置JDBCAppender的名字,每个appender都有一个关联的名字
log4j.appender.jdbc.name=jdbcdemo

日志持久化到数据库效果如下:

JDBCAppender

9.TelnetAppender

TelnetAppender同样继承自AppenderSkeleton,由AppenderSkeleton提供了日志输出目的地的通用功能。TelnetAppender的主要应用情景是将LoggingEvent输出到一个只读的套接字Socket中,输出的LoggingEvent有良好的telnet协议格式,可被telnet客户端监听到,这里TelnetAppender作为Socket编程的服务端。

TelnetAppender的主要目的即是日志监控,比如servlet的监控。TelnetAppender在AppenderSkeleton的基础上提供的配置属性有Port,即输出日志信息的端口,telnet客户端监听此端口,默认为23。

TelnetAppender的函数requiresLayout返回为true,即TelnetAppender需要关联一个Layout。TelnetAppender重写了OptionHandler接口的activateOptions方法,在激活配置逻辑中创建了SocketHandler,用于接收客户端建立连接请求和断开连接。SocketHandler为TelnetAppender的内部类,其实现为标准的Socket服务端编程,等待客户端主动发起连接到来,并维护客户端的socket连接请求,即:

Socket newClient = serverSocket.accept();

将获取的连接维护到内部的容器中,SocketHandler支持最多20个客户端telnet监听。SocketHandler同时继承Thread类,在activateOptions方法中,会启动线程开始监听。

TelnetAppender重写了AppenderSkeleton的append函数,在append逻辑中,将LoggingEvent信息输出到SocketHandler维护的客户端socket中。

  /** Handles a log event.  For this appender, that means writing the
    message to each connected client.  */
  protected void append(LoggingEvent event) {
      if(sh != null) {
          sh.send(layout.format(event));
          if(layout.ignoresThrowable()) {
              String[] s = event.getThrowableStrRep();
              if (s != null) {
                  StringBuffer buf = new StringBuffer();
                  for(int i = 0; i < s.length; i++) {
                      buf.append(s[i]);
                      buf.append("\r\n");
                  }
                  sh.send(buf.toString());
              }
          }
      }
  }

demo

demo log4j config:

log4j.rootLogger=INFO,telnet
#使用的Appender为TelnetAppender
log4j.appender.telnet=org.apache.log4j.net.TelnetAppender
#TelnetAppender使用的端口,注意端口占用权限
log4j.appender.telnet.port=8000
#TelnetAppender关联的Layout
log4j.appender.telnet.layout=org.apache.log4j.PatternLayout
log4j.appender.telnet.layout.ConversionPattern=%t %m%n
#Appender的名字
log4j.appender.telnet.name=telnetdemo

telnet客户端监控效果:

TelnetAppender

10.JMSAppender

什么是JMS,体味概念:

The Java Message Service (JMS) API is a messaging standard that allows application components based on the Java Platform Enterprise Edition (Java EE) to create, send, receive, and read messages. It enables distributed communication that is loosely coupled, reliable, and asynchronous.

JMS(JAVA Message Service,java消息服务)API是一个消息服务的标准或者说是规范,允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息。它使分布式通信耦合度更低,消息服务更加可靠以及异步性。JMS支持2种消息模型,点对点Point-to-Point(P2P)以及发布订阅Publish/Subscribe(Pub/Sub)

P2P模型概念有,消息队列Queue、发送者Sender、接受者Receiver。消息发送者将消息Message发送到指定的队列中,消息接受者可从队列种获取消息,每个消息仅有一个接收者。消息有超时时间,超过生命周期的Message从队列种移除。消息接受后接受者Receiver会返回一个确认Acknowledge。通过JMS P2P模式,可以将消息生产、消费解耦,便于构建分布式系统。模型图如下:
JMSAppender1

Pub/Sub模型概念有:主题(Topic)、发布者(Publisher)、订阅者(Subscriber)。发布者将消息发送到主题,多个发布者将消息发送到主题Topic,系统将这些消息传递给多个订阅者。这里每个消息可以有多个订阅者、发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息,而且为了消费消息,订阅者必须保持运行的状态。模型图如下:

JMSAppender2

推荐2个开源的消息服务,即Kafka、Apache ActiveMQ。JMSAppender即是将LoggingEvent发布到主题Topic,LoggingEvent被序列化并作为JMS编程模型中的ObjectMessage发送(不是Layout方式渲染)。还是不介绍具体细节了,没有具体的使用过...

11.SMTPAppender

SMTPAppender用于将日志消息发送到邮箱,主要用于监控告警某些系统级严重错误或故障(ERROR、FATAL),毕竟你也不希望你的邮箱塞爆吧。每次邮件发送包含日志数量受到缓冲大小BufferSize影响。SMTPAppender使用javax.mail包下的邮件API完成邮件发送。
SMTPAppender支持配置项属性有:

  • From 邮件发件人
  • ReplyTo 邮件回复地址
  • To 邮件收件人,支持多人,英文逗号分隔
  • Cc 邮件抄送人,支持多人,英文逗号分隔
  • Bcc 邮件密送人,支持多人,英文逗号分隔
  • Subject 邮件主题
  • BufferSize 日志循环缓冲区大小,默认512个日志LoggingEvent。缓冲区满时时间最
  • LoggingEvent被替换掉
  • LocationInfo 默认为false,表示是否包含日志位置信息
  • SMTPPassword 邮件发送者密码
  • SMTPUsername 邮件发送者用户名
  • SMTPDebug true表示将邮件客户端和服务端的交互smtp协议命令打印到标准输出,用
  • 错误排查。生产环境不建议开启,会有明文邮箱密码
  • EvaluatorClass 实现TriggeringEventEvaluator接口的类名,TriggeringEventEvaluator有方法public boolean isTriggeringEvent(LoggingEvent event);用于控制邮件发送的时机,由log4j反射创建相应类实例
  • Evaluator 用于控制邮件发送的时机,可EvaluatorClass不同是,这里设置一个类实例。
  • SMTPProtocol 底层传输协议,如果需要使用SSL,需要配置为smtps
  • SMTPHost SMTP服务器地址,如smtp.163.com
  • SMTPPort SMTP服务端口
  • SendOnClose true表示SMTPAppender关闭时触发一次邮件发送,将缓冲中的日志LoggingEvent邮件发送

对于TriggeringEventEvaluator,log4j提供的默认实现是DefaultEvaluator ,具体判断日志LoggingEvent级别是否大于等于ERROR。

class DefaultEvaluator implements TriggeringEventEvaluator {
  public boolean isTriggeringEvent(LoggingEvent event) {
    return event.getLevel().isGreaterOrEqual(Level.ERROR);
  }
}

SMTPAppender的append实现如下:

  public void append(LoggingEvent event) {
    if(!checkEntryConditions()) {
      return;
    }
    event.getThreadName();
    event.getNDC();
    event.getMDCCopy();
    if(locationInfo) {
      event.getLocationInformation();
    }
    event.getRenderedMessage();
    event.getThrowableStrRep();
    cb.add(event); //加入循环缓冲
    // 判断是否触发日志邮件发送,邮件内容包括循环缓冲中的LoggingEvent序列化
    if(evaluator.isTriggeringEvent(event)) {
      sendBuffer();
    }
  }

注意,SMTPAppender邮件的发送以来java mail工具,需要将javax.mail.jar加入到class path中,具体下载地址和使用wiki可见: https://java.net/projects/javamail/pages/Home

demo

demo log4j config:

log4j.rootLogger=INFO,smtp
log4j.appender.smtp=org.apache.log4j.net.SMTPAppender
log4j.appender.smtp.From=
log4j.appender.smtp.ReplyTo=
log4j.appender.smtp.To=
log4j.appender.smtp.Cc=
log4j.appender.smtp.Bcc=
log4j.appender.smtp.Subject=log4j SMTPAppender
log4j.appender.smtp.BufferSize=512
log4j.appender.smtp.LocationInfo=true
log4j.appender.smtp.SMTPUsername=
log4j.appender.smtp.SMTPPassword=
log4j.appender.smtp.SMTPDebug=true
#log4j.appender.smtp.EvaluatorClass=
log4j.appender.smtp.SMTPProtocol=smtp
log4j.appender.smtp.SMTPHost=smtp.163.com
log4j.appender.smtp.SMTPPort=25
log4j.appender.smtp.SendOnClose=true

log4j.appender.smtp.layout=org.apache.log4j.PatternLayout
log4j.appender.smtp.layout.ConversionPattern=log4j.appender.WriterAppender.layout.ConversionPattern=%d %-5p [%t] [%F:%L] [%X{traceId}] - %m%n
log4j.appender.smtp.Name=smtpdemo

日志效果:

SMTPAppender

开启SMTPDebug后部分标准输出:

DEBUG: setDebug: JavaMail version 1.5.5
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
DEBUG SMTP: need username and password for authentication
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "smtp.163.com", port 25, isSSL false
220 163.com Anti-spam GT for Coremail System (163com[20141201])
DEBUG SMTP: connected to host "smtp.163.com", port: 25

EHLO 192.168.0.103
250-mail
250-PIPELINING
250-AUTH LOGIN PLAIN

后面继续~

标签: none
评论列表
  1. 你好,请问你的图片放在哪里呢
    ca88亚洲城官网 http://xxgk.hbust.com.cn

添加新评论