55最佳实践系列:Logging最佳实践

标签: 最佳实践 系列 logging | 发表时间:2012-12-15 16:43 | 作者:旁观者
出处:http://www.cnblogs.com/zhengyun_ustc/
@郑昀汇总 创建日期:2012/10
 
#意识

ASAP (As Soon As Possible)原则

当线上出现诡异问题,
当你意识到靠现有的日志无法定位问题时,
当现象难以在你的开发环境重现时,
请不要执著于枯坐肉眼看代码,因为:一)不一定是你代码逻辑问题,可能是脏数据造成的,是老业务数据造成的,是分布式环境造成的,是其他子系统造成的;二)线上业务处于不稳定中,条件不允许问题定位无限期。
此时, 请立即在问题相关的调用链条上,一次性:
  • 在函数的入口和出口打印日志,同时 打印输入、输出参数
  • catch(){……}里打印stacktrace, 同时打印try块中关键变量的值(避免你发现某个异常是问题第一原因,却不知道是什么变量传入导致的)
  • 与其他模块交互的接口入口处打印输入参数,
即, 解决线上问题归根结底要靠log、a lot of log output!
在logging的力度上切勿犹犹豫豫,我们的工程师习惯于吝啬地找两个函数打印日志、打包部署一把、没看出来、再找几个函数打印、再部署、等着现象重现再观察、……,一来二去时间流逝,闲庭信步,从客服知道的小事故变成了全国皆知的大事故。
所以,再强调一遍: 在你的调用链条上,逐层调用的函数入口和出口都打印详细日志,不怕多只怕少,然后部署,等待现象重现,毕其功于一役!
 
我们要记录什么?
1)完成某项操作所需的时间

通过它可以跟踪为什么系统响应变慢或者太快

  • 处理完一个incoming request所耗费的时间,精确到毫秒
  • 执行数据库查询的时间
  • 从磁盘或者存储介质获取数据的时间
  • 等等
2)异常和堆栈跟踪
 
3)Sessions
知道一个问题是由谁引起的非常重要,因此在日志中使用会话标识符就变得必不可少。它可以简单到是一个 IP 地址或者是一个更复杂的 UUID,只要能区分不同的请求者就足够。
 
4)版本号
 
#工具
推荐的Java Logging框架
1)log4j:我们的配置是,log4j.appender.CONSOLE.layout.ConversionPattern=[%-d{yyyy-MM-dd HH\:mm\:ss.SSS}] [%p] [%c] [%m]%n;%p是日志优先级,%c是类目名,%m是输出信息,%n是回车换行符。
2)logback:log4j创建人Ceki Gülcü后续推出了SLF4J+logback。SLF4J(Simple Logging Facade for Java)作为commons-logging的替代,为各种logging APIs提供了一个简单的统一接口,使得最终用户能够在部署的时候配置所希望的logging APIs的实现。logback胜在性能,据称“某些关键操作,比如判定是否记录一条日志语句的操作,其性能得到了显著的提高。这个操作在logback中需要3纳秒,而在 log4j 中则需要30纳 秒。 logback 创建记录器(logger)的速度也更快:13毫秒,而在 log4j 中需要23毫秒。更重要的是,它获取已存在的记录器只需94纳秒, 而 log4j 需要2234纳秒,时间减少到了1/23。跟java.util.logging(JUL)相比性能提高也是显著的”。
 
#配置
不要随便从网上找一个log4j的配置文件,请确认你理解每一个配置项
我们既然输出日志,自然期望在面对“ 这个问题是否从过去几天开始出现?”这样的疑问时,不至于发现你的rollingPolicy错误设置导致只能看到最近几小时的日志,或者日志发生时间没有精确到毫秒。
后面会张贴主站生产环境里的log4j配置。
 
#理念
可用grep抽取的日志:独立的行!
我们总是希望能用grep处理日志文件。这意味着: 一个日志条目永远不应该跨多行,除非你是堆栈打印
我们会用grep问日志什么问题呢?如:
  • 用手机号13910******下单的顾客最近三天内都来自于哪些IP?
  • 浏览地址是****?from=kfapi的顾客,但referral却是搜索引擎域名,最近三天有多少次?
  • 最近一周内,订单中心执行的所有事务,耗时最长的一次是多长时间?
  • ××××的接口是否真的于18:00发送了一个请求,我们收到的参数是什么?
确保你的日志能回答这样的问题。
 
不同关注领域写不同的日志文件
当访问和调用极其频繁,有时候你会发现把你的工程里什么信息都打印到一个日志文件里,会让你看得头昏脑胀。
最简单的示范就是Apache的访问日志和错误日志是分开的。
同样,你也可以把更加安静的事件(偶尔出现)与更加喧闹的事件分开存储。
如,对外的开放平台可以打印三种日志文件:connection log(建立链接和关闭链接,附带接入参数),message log(内部调用链),stacktrace log(异常的堆栈打印)。
 
#具体实现
至少精确到毫秒
日志必须包含时间戳,精确到至少毫秒级。
如果只是记录到秒级,我们曾明知代码因缺乏并发控制而产生BUG,却只能郁闷地看着精确到秒级的日志。
对Java来说,最好配置为:yyyy-MM-dd/HH:mm:ss.SSS。
 
请尽可能打印明确的会话标识
日志条目里打印一个会话标识(A certain session identifier),当有许多并发请求打过来时,你就能基于此字段过滤 client 了。比如,我们司南日志会补充打印一个浏览器 cookies 里种下的 UUID 。
 
log4j的isDebugEnabled判断
如果打印信息是常量字符串或简单字符串拼接,那么不需要if ( log.isDebugEnabled() )。
如果你拼装的动作比较耗资源,请用if ( log.isDebugEnabled() )。
 
如有可能,请将性能数据标准化输出
这样更方便grep或hadoop做性能数据抽取和挖掘,从而能很轻松地转换为图形监控。
比如,订单中心的性能数据格式为: 树枝标志 当前节点起始时间 [当前节点持续时间, 当前节点自身消耗时间, 在父节点中所占的时间比例]
 
哪些位置需要部署性能检测点 
(1)访问数据库的dao层;
(2)访问外部资源的ext层;
(3)访问mq的方法;
(4)等等,一切不在你自己负责的工程掌握的部分(外部),或一切你认为自己工程的性能危险点,都需要加入性能监控日志。
 
 
#Sample
一个好的启动日志
打印了应用的版本号,客户端的会话标识,关键步骤的执行时长。
 
一个好的堆栈跟踪日志
 
 
参考资源:

2) 55最佳实践系列:Logging最佳实践 (2012-12-15 16:43)
3)

赠图1枚:
 
 
 

本文链接

相关 [最佳实践 系列 logging] 推荐:

55最佳实践系列:Logging最佳实践

- - 博客园_旁观者
@郑昀汇总 创建日期:2012/10. ASAP (As Soon As Possible)原则. 当你意识到靠现有的日志无法定位问题时,. 当现象难以在你的开发环境重现时,. 请不要执著于枯坐肉眼看代码,因为:一)不一定是你代码逻辑问题,可能是脏数据造成的,是老业务数据造成的,是分布式环境造成的,是其他子系统造成的;二)线上业务处于不稳定中,条件不允许问题定位无限期.

55最佳实践系列:MongoDB最佳实践

- - 博客园_旁观者
@郑昀汇总 创建日期:2012/9. 1) 如果发现query没使用你预期的索引,请用hint强制使用指定索引. 主站商品中心所使用的文档字段很多,各种索引建得也不少. 在沙创排查慢查询时,曾百思不得其解,为什么明明建的有联合索引,查询起来还是非常慢呢,直到显式指定使用该联合索引. 2) Design documents to be self-sufficient, 设计 自给自足的文档.

最佳实践系列:前端代码标准和最佳实践

- - 博客园_旁观者
最佳实践系列:前端代码标准. @窝窝商城前端(刘轶/李晨/徐利/穆尚)翻译于2012年 版本0.55 @郑昀校对. isobar的这个前端代码标准和最佳实践文档,涵盖了Web应用开发的方方面面,我们翻译了大部分章节,并做了注解. 渐进增强; Combo Handler; Quirks Mode; 浏览器盒子模型; 选择器特殊性; Spacer Image; CSS Sprites; PNG8;.

Write-ahead logging(WAL)

- - 掘金 后端
WAL( Write-ahead logging预写日志)是数据库用于实现事务原子性和持久性的技术. 所有的修改在提交之前,系统将其先可靠的写入到 WAL 管理的 Log 文件中,再通过 Log 文件中记录的日志执行真正的操作. 如果遵循这种过程,则无需在每个事务的提交时 等待系统落盘,因为无论何时何种情况,都可以使用日志进行数据库的恢复.

logging的使用分析

- jeff - limodou的学习生活
昨天,Lord Leatherface问我为什么使用了suds后,输出日志变成了两条. 于是我仔细地研究了logging的日志处理机制,并且再次考虑了uliweb的日志处理,最终对uliweb的日志进行了重构,并且弄清楚了为什么会有两条日志的现象,因此以本文作一个记录. 对于logging我想大家用得应该不少,那么我先提几个问题:.

Python日志库logging总结

- - IT瘾-tuicool
在部署项目时,不可能直接将所有的信息都输出到控制台中,我们可以将这些信息记录到日志文件中,这样不仅方便我们查看程序运行时的情况,也可以在项目出现故障时根据运行时产生的日志快速定位问题出现的位置. Python 标准库 logging 用作记录日志,默认分为六种日志级别(括号为级别对应的数值),NOTSET(0)、DEBUG(10)、INFO(20)、WARNING(30)、ERROR(40)、CRITICAL(50).

jQuery最佳实践

- andi - 阮一峰的网络日志
上周,我整理了《jQuery设计思想》. 那篇文章是一篇入门教程,从设计思想的角度,讲解"怎么使用jQuery". 今天的文章则是更进一步,讲解"如何用好jQuery". 我主要参考了Addy Osmani的PPT《提高jQuery性能的诀窍》(jQuery Proven Performance Tips And Tricks).

PHP最佳实践

- xiangqian - 阮一峰的网络日志
虽然名字叫《PHP最佳实践》,但是它主要谈的不是编程规则,而是PHP应用程序的合理架构. 它提供了一种逻辑和数据分离的架构模式,属于MVC模式的一种实践. 我觉得,这是很有参考价值的学习资料,类似的文章网上并不多,所以一边学习,一边就把它翻译了出来. 根据自己的理解,我总结了它的MVC模式的实现方式(详细解释见译文):.

MongoDB最佳实践

- - NoSQLFan
将 MongoDB加入到我们的服务支持列表中,是整个团队年初工作计划中的首要任务. 但我们感觉如果先添加一项对NoSQL存储的支持,而不是先升级已支持的关系型数据库,可能对用户不太好,毕竟目前的用户都使用关系型数据库. 所以我们决定将引入MongoDB这项工作放到升级MySQL和PostgreSQL之后来做.

Dockerfile 最佳实践

- - DockOne.io
在容器领域,Docker 公司提出的容器镜像已经成为目前容器打包交付的事实标准. 构建镜像需要编写 Dockerfile,如何编写一个优雅的 Dockerfile 呢. 在 Docker 公司的官方文档中给出了一篇:《 Best practices for writing Dockerfiles》.