Socket(五)

文章介绍了服务器日志的重要性,特别是在无人看管时用于调试。Java提供java.util.logging包进行日志记录,建议为不同目的如请求和错误创建独立的日志。日志级别包括OFF,SEVERE,WARNING,INFO等,通常审计日志使用INFO,错误日志使用WARNING或SEVERE。日志可以通过配置文件指定输出位置,如使用FileHandler将日志写入文件并进行轮换。
摘要由CSDN通过智能技术生成

1. 日志

服务器要在无人看管的情况下运行很长时间,通常需要在很久以后对服务器中发生的情况进行调试,这很重要。由于这个原因,建议在存储服务器日志,至少要存储一段时间的日志。日志中通常希望记录的主要内容是:

  • 请求
  • 服务器错误

实际上,服务器一般会为这两项内容维护两个不同的日志,审计日志中,对应与服务器建立的每一个连接会分别包含一个记录,每个连接完成多个操作的服务器可能对每个操作都有一个记录。例如,dict服务器可能会为客户端查找的每个单词建立一个日志记录。错误日志则主要包含服务器运行期间发送的意外异常,主要记录程序中发生的一些异常。

2. 如何记录日志

在java1.4之前,程序基本使用的是第三方日志库,如log4j或Aache Commons Logging,之后官方提供了java.util.logging包,它能满足绝大多数需求。尽管可以根据需要来加载日志工具,不过需要最容易的办法是为每个类创建一个日志工具,如下:

private final static Logger auditLogger=Logger.getLogger("requests");

日志工具是线程安全的,所以将它们存储在共享静态字段中没有任何问题,实际上,往往需要这么做,因为即使不用在线程之间共享Logger对象,日志文件或数据块也需要共享。这在大量使用多线程的服务器中非常重要。上面的例子输出到一个名为"requests"的日志中,这个日志是什么、放在哪里取决于外部配置。它不一定是一个文件,可能是一个数据块、一个在多个服务器上运行的SOAP服务、同一个主机上运行的另一个java程序,或者是其它形式。一旦又了一个日志工具,可以使用多个方法写入这个日志。最基本的是log()。java.util.logging.Level中命名常量定义了七个级别,按严重性从高到低依次为:

  • Level.OFF
  • Level.SERVE
  • Level.WARNING
  • Level.INFO
  • Level.CONFIG
  • Level.FINE
  • Level.FINER
  • Level.FINEST
  • Level.ALL

我们通常会对审计日志使用INFO级别,对错误日志使用WARNING级别或SERVER级别。较低级别用于调试,不要在生成系统中使用。可以对各个日志使用任何方便的格式。一般来讲,每个记录应该包含一个时间戳、一个客户端地址,以及所处理的请求的任何特定信息。如果日志消息表示为一个叫错误,则要抛出特定的异常。Java会自动填入记录这个消息所在的代码位置,所以这个方面不用操心。

下面代码展示了如何为daytime服务器增加日志记录

public class QuizCardBuilder {
    private final static Logger auditLogger=Logger.getLogger("requests");
    private final static Logger errorLogger= Logger.getLogger("errors");
    public static void main(String[] args) {
        ExecutorService pool=Executors.newFixedThreadPool(50);
        try(ServerSocket server=new ServerSocket(8080)){
            while(true){
                try {
                    Socket connection=server.accept();
                    Callable<Void> task=new DaytimeTask(connection);
                    pool.submit(task);
                }catch (IOException ex){
                    errorLogger.log(Level.SEVERE,"accept  error"+ex);
                }catch (RuntimeException ex){
                    errorLogger.log(Level.SEVERE,"unexcepted error"+ex.getMessage(),ex);
                }
            }
        }catch (IOException e) {
            errorLogger.log(Level.SEVERE,"Coundn`t start server"+e);
        }catch (RuntimeException e){
            errorLogger.log(Level.SEVERE,"Coundm`t start server"+e);
        }

    }
    private static class DaytimeTask implements Callable<Void>{
        private Socket connection;
        DaytimeTask(Socket connection){
            this.connection=connection;
        }
        @Override
        public Void call() {
            try{
                Date now=new Date();
                //先写入日志记录以防万一客户端端口连接
                auditLogger.info(now+" "+connection.getRemoteSocketAddress());
                Writer out=new OutputStreamWriter(connection.getOutputStream());
                out.write(now.toString()+"\r\n");
                out.flush();
            }catch (IOException e){
               if(connection!=null){
                   try {
                       connection.close();
                   } catch (IOException ex) {
                       throw new RuntimeException(ex);
                   }
               }
            }finally {
                if(connection!=null){
                    try {
                        connection.close();
                    } catch (IOException ex) {
                        throw new RuntimeException(ex);
                    }
                }
            }
            return null;
        }
    }

}

多次在终端使用Telnet与dayTime服务器通信

在这里插入图片描述

查看结果

在这里插入图片描述
上面的日志信息是直接在控制台打印的,如果我们希望将日志文件放到更加持久的位置,虽然我们可以在代码中指定,但是更好的是在配置文件中指定。这样就能改变日志位置而无需重新编译代码。java.util.logging.config.file系统属性采用常规的属性格式指向控制日志记录的一个文件。可以在启动虚拟机时加入vm配置-Djava.util.logging.config.file=_filename_参数来设置这个属性。

handlers=java.util.logging.FileHandler
java.util.logging.FileHandler.pattern=/var/logs/daytime/requests.log
java.util.logging.FileHandler.limit=10000000
java.util.logging.FileHandler.count=2
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.append=true
java.util.logging.FileHandler.format=%4$s: %5$s [%1$tc]%n

上面的配置指定来下面的内容:

  • 日志要写入文件
  • 请求日志应当在/var/logs/daytime/requests.log(INFO级别)
  • 错误日志应当在/var/logs/daytime/requests.log(SERVER级别)
  • 日志大小限制为10MB,然后轮换
  • 维护两个日志:当前日志和之前的日志
  • 使用基本文本格式化工具
  • 日志的每一行采用消息级别时间戳
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值