发表于: 2017-11-16 22:27:17
0 742
一.今日完成
1.参考师兄代码,在本地运行两个service,然后配置nginx负载均衡,使用tomcat部署web组件,实现RMI调用;其中一个service挂掉后,另一个继续提供服务.
2.任务过程中,主要遇到空指针.类加载初始化失败以及方法调用嵌套异常,通过查找CSDN,Stack Overflow,Info Q以及开源中国等论坛资源,一般都提醒是在Spring框架i配置无误的前提下,一般问题都出在jar上,要么是jarJava未成功加载或者是选用的依赖jar包版本冲突.根据控制台输出信息,找到相应jar包配置不正确的地方,解决了问题.
3.抽空整理了Java日志管理知识点
因为在生产环境中,日志是查找问题来源的重要依据。以前习惯于使用 System.out.println、System.err.println 以及异常对象的 printStrackTrace 方法来输出相关信息。这些使用方式虽然简便,但是所产生的信息在出现问题时并不能提供有效的帮助。学习整理过log4j1.2 log4j2以及slf4j等,但是使用较少;在bug定位和排除方面,往往不知如何处置.下面整理了Java日志管理的知识,对于slf4j+log4j2的具体配置已经在前面的日报里有详细说明了.
(1)记录日志只是有效地利用日志的第一步,更重要的是如何对程序运行时产生的日志进行处理和分析。典型的情景包括当日志中包含满足特定条件的记录时,触发相应的通知机制,比如邮件或短信通知;还可以在程序运行出现错误时,快速地定位潜在的问题源。这样的处理和分析的能力对于实际系统的维护尤其重要。当运行系统中包含的组件过多时,日志对于错误的诊断就显得格外重要。
(2)从功能上来说,日志 API 本身所需求的功能非常简单,只需要能够记录一段文本即可。API 的使用者在需要进行记录时,根据当前的上下文信息构造出相应的文本信息,调用 API 完成记录。一般来说,日志 API 由下面几个部分组成:
记录器(Logger):日志 API 的使用者通过记录器来发出日志记录请求,并提供日志的内容。在记录日志时,需要指定日志的严重性级别。
格式化器(Formatter):对记录器所记录的文本进行格式化,并添加额外的元数据。
处理器(Handler):把经过格式化之后的日志记录输出到不同的地方。常见的日志输出目标包括控制台、文件和数据库等。
日志记录封装 API 也会定义自己的级别并映射到底层实现中相对应的实际级别。
比如 JDK 标准的日志 API 使用的级别包括 OFF、SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST 和 ALL 等,Log4j 使用的级别则包括 OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE 和 ALL 等。一般情况下,使用得比较多的级别是 FATAL、ERROR、WARN、INFO、DEBUG 和 TRACE 等。
通过记录器对象来记录日志时,只是发出一个日志记录请求。该请求是否会完成取决于请求和记录器对象的严重性级别。记录器使用者产生的低于记录器对象严重性级别的日志消息不会被记录下来。这样的记录请求会被忽略。
日志处理器也可以配置所处理日志信息的最低严重性级别。低于该级别的日志不会被处理。这样可以控制所处理的日志记录数量。比如控制台处理器的级别一般设置为 INFO,而文件处理器则一般设置为 DEBUG。
(3)日志记录实践
1)当日志记录器收到一个日志记录请求时,如果请求的严重性级别低于记录器对象的实际有效级别,则该请求会被忽略。在日志记录方法的实现中会首先进行这样的检查。一般是在调用 API 进行记录之前,首先进行相应的检查,这样可以避免不必要的性能问题.
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("This is a message.");
}
这种做法的作用在于避免了构造日志记录消息所带来的开销。日志消息中通常包含与当前上下文相关的信息。为了获取这些信息并构造相应的消息文本,不可避免会产生额外的开销。尤其对于 DEBUG 和 TRACE 级别的日志消息来说,它们所出现的频率很高,累加起来的开销比较大。因此在记录 INFO、DEBUG 和 TRACE 级别的日志时,首先进行相应的检查是一个好的实践。而 WARN 及其以上级别的日志则一般不需要进行检查。
但是,也有观点提出:应该避免在代码里加入is*Enabled这个乱哄哄的东西。性能看起来没有什么提升(尤其是用了slf4j之后),更像是过早的优化。这么做有点多余么,很少有时候是明确需要这种显式的判断语句的,除非证明构造日志消息本身开销太大。不然的话,该怎么记就怎么记,让日志框架去操心这个。
2)日志中所包含的信息应该是充分的。在记录日志消息时应该尽可能多的包含当前上下文中的各种信息,以方便在遇到问题时可以快速的获取到所需的信息。比如在网上支付功能中,与支付相关的日志应该完整的包含当前用户、订单以及支付方式等全部信息。一种比较常见的做法是把相关的日志记录分散在由不同日志记录器所记录的日志中。
3)一般的日志记录实践是使用当前 Java 类的全名作为其使用的日志记录器的名称。这样做可以得到一个与 Java 类和包的层次结构相对应的日志记录器的层次结构。可以很方便的按照不同的模块来设置相应的日志记录级别。不过对于某些全局的或是横切的功能,如安全和性能等,则推荐使用功能相关的名称。
4)日志记录中除了基本的日志消息之外,还包括由日志框架提供的其他元数据。这些数据按照给定的格式出现在日志记录中。这些半结构化的格式使得可以通过工具提取日志记录中的相关信息进行分析。在使用日志 API 进行记录时,对于日志消息本身,也推荐使用半结构化的方式来组织。
比如一个电子商务的网站,当用户登录之后,该用户所产生的不同操作所对应的日志记录中都可以包含该用户的用户名,并以固定的格式出现在日志记录中.
[user1] 用户登录成功。
[user1] 用户成功购买产品 A。
[user2] 订单 003 付款失败。
当需要通过日志记录来排查某个用户所遇到的问题时,只需要通过正则表达就可以很快地查询到用户相关的日志记录。
5)善于使用slf4j
slf4j支持一个很棒的模式注入的方式:
log.debug("Found {} records matching filter: '{}'", records, filter);
单独使用log4j只能这样:
log.debug("Found " + records + " recordsmatching filter: '" + filter + "'");
这样写不仅更啰嗦和可读性差,更严重的是字符串拼接影响效率(当这个级别并不需要输出的时候)。slf4j引入了一个{}的注入特性。并且由于避免了每次都进行字符串拼接,toString方法不会被调用,也不再需要加上isDebugEnabled了。
6)记录方法的参数和返回值
如果在开发阶段发现了一个BUG,通常会用调试器来跟踪具体的原因。现在假设不让用调试器了,比如,因为这个BUG几天前在用户的环境里出现了,能拿到的只有一些日志。能从中发现些什么?
参考以下这个格式:
public String printDocument(Document doc, Mode mode) {
log.debug("Entering printDocument(doc={}, mode={})", doc, mode);
String id = //Lengthy printing operation log.debug("Leaving printDocument(): {}", id);
return id;
}
由于在方法的开始和结束都记录了日志,所以可以人工找出效率不高的代码,甚至还可以检测到可能会引起死锁和饥饿的诱因——你只需看一下“Entering”后面是不是没有”Leaving“就明白了。如果方法名的含义很清晰,打日志和分析异常也更得更简单了,因为知道每一步都在干些什么。代码里要记录的方法很多的话,可以用AOP切面来完成。这样减少了重复的代码,不过使用它得特别小心,不注意的话可能会导致输出大量的日志。
参考资料:https://my.oschina.net/u/1182234/blog/599298
https://www.ibm.com/developerworks/cn/java/j-lo-practicelog/
http://www.infoq.com/cn/news/2014/08/apache-log4j2
二.明日计划
学习tuscany相关知识点,在任务8的基础上完成任务9
三.遇到问题
下午有一个师弟在使用Spring MVC模型绑定时候,遇到数据没传递到隐含模型对象的问题,当时拿过来问我,一时间忘记ModelAndView,Map和Model的区别,查了资料才确定使用哪种对象的方法比较好,尴尬.
四.收获
以上.
进度:今天提交了任务8,开始任务9.
因为tuscany相关技术在去年5月已经"退休了",师兄建议不需要在这个上面花太多精力,计划一天完成相关任务.
评论