2019独角兽企业重金招聘Python工程师标准>>>

大型互联网应用的突出特点是应用本身规模大,结构复杂,用户访问量大。设计良好的日志系统,有助于分析流量趋势,帮助管理网络应用;有助于在应用出现问题时,快速查找问题,保证网络应用的可用时间。设计一套完善的日志系统,用于记录应用的内部行为,是一件很有价值的工作。

本文希望从设计和实现的角度,描述日志系统的构建。本文的描述,基于Java语言,以及使用Java语言实现的类库。读者可以根据自己的实际需求,替换成其他的实现。

日志系统介绍

最简单的日志系统其实就是在系统内添加System.out.println(“Some log”)语句。如列表1所示。

1. public void someFunction() {

2. System.out.println(“enter method”);

3. try {

4. throw new Exception(“Some exception”);

5. } catch (Exception e) {

6. System.out.println(“Failed: expcetion ” + e + ” thrown out”);

7. }

8. System.out.println(“Success”);

9. System.out.println(“exit method”);

10.}

列表1 用System.out.println实现的最简单的日志系统

这个简单的日志系统记录了两类重要信息,分别是方法调用的调用栈信息(line 1和 line 9),和方法调用的成功与否信息(line 6 和line 8)。但是因为过于简陋,这样的实现,并不能出现在实际的大型网络应用中。

对于Java开发人员来说,比较熟悉的用于实现日志系统的框架包括,Log4J和Java 类库自带的包java.util.logging。

1. Logger logger =

2. Logger.getLogger(PackageMatcher.class.getSimpleName());

3. public void someFunctionWithLogger() {

4. logger.log(Level.INFO, “enter method”);

5. try {

6. throw new Exception(“Some exception”);

7. } catch (Exception e) {

8. logger.log(Level.SEVERE,

9. “Failed: expcetion ” + e + ” thrown out”);

10. }

11. logger.log(Level.INFO, “exit method”);

12. }

列表2 使用java.util.logging实现的日志系统

首先从性能上来说,这两个框架可以满足大规模访问的需求,其次还添加了必要的基础设施,比如Level的概念(line 4, line 8 和line 11),Logger的parent/child关系等。可是这些框架的问题在于它们没有提供领域模型(domain model)。比如并没有区分列表1中表示的两类信息。这样的日志系统仍然比较粗糙,方法调用栈信息和方法调用是否成功的信息被输出在同一个日志文件中。需要额外的工作提取相应的信息。

设计完善的日志系统

对于一个大型互联网应用,很重要的一点,是可以度量网站的访问量和访问趋势,系统出现异常可以准确及时的记录问题,并使用这些数据来帮助诊断网站出现的问题。为了满足这些需求,日志系统可以分为几个模块来记录相关信息。图一给出了一个日志系统的模块图

图1 大型互联网应用的日志系统

在这个设计中,日志系统有四个子系统。分别是路径追踪系统,本地日志系统,集中式日志系统,和引用计数系统。这四个子系统,分别记录不同类别的信息,为管理和排错,提供支持。

本地日志系统

一个大型网络应用,大都部署到大量的机器集群上边。对于每一台物理机器,当运行在其上的应用模块出现问题,首先要在本机器上记录下当前的错误现象。列表3给出了记录在本机上的日志片段

2008-12-7 21:57:24 61.171.218.225 SomeClass someFunctionWithLogger

INFO: enter method

2008-12-7 21:57:24 61.171.218.225 SomeClass someFunctionWithLogger

SEVERE: Failed: expcetion java.lang.Exception: Some exception thrown out.

2008-12-7 21:57:24 61.171.218.225 SomeClass someFunctionWithLogger

INFO: exit method

列表3 记录在本机上的日志片段

因为这是一个实时的记录系统,所有系统异常都可以被准确及时的记录下来。一般来说,一个本地日志系统由四个主要部分组成,图2给出了本地日志系统的框架

图2 本地日志系统的构成

 

从图中可以看出,4个部分分别是记录条目(LogRecord)、记录器(Logger)、处理器(Handler)、过滤器(Filter)。记录器之间还可以有父子关系(比如使用Decorator 模式实现)。当子孙节点处理完日志后,可以继续交给父节点处理。列表4给出了一个本地日志系统的参考实现框架。

1. public class Logger {

// parent logger

2. private Logger parent;

// add filter

3. public void addFilter(Filter filter) {

4. }

// add handler

5. public void addHandler(Handler handler) {

6. }

// log

7. public void log(LogRecord record) {

8. }

9.}

10.public interface Handler {

11. void addFilter(Filter filter);

12.}

13.public interface Filter {

14. void filter(LogRecord record);

15.}

16.public class LogRecord {

// some fields

17.}

列表4 本地日志系统的参考实现框架

在实现本地日志系统时,可以在LogRecord类里面设计记录相关的信息。比如针对列表3给出的输出,可以在LogRecord增加Date (java.util.Date)、IP(String[])、ClassName(String)、MethodName(String)、Level(int)、Message(String)等域。其中Level用于标记日志消息的级别,高于某级别的消息才会被输出。Handler和Filter也做过滤工作,可以为日志系统提供很强的灵活性。

集中式日志系统

本地日志系统可以在某台机器上记录系统的运行情况。虽然及时、准确,但是由于在单一机器上的模块一般来说只是整个系统的一部分,所以缺点是不能全局地监测系统。需要一个日志总线,将所有的日志信息集中起来,归并相同类型的日志,记录事务信息等等。图3给出了一个集中式日志系统的架构图。

图3 集中式日志系统的架构图

如图,集中式的日志系统可以设计成一个客户端/服务器架构。在每个部署应用的服务器上,均有一个日志系统客户端,应用在一些关键点调用日志系统客户端,通过日志总线,客户端将日志信息提交到日志系统后端服务器。列表5给出了调用日志系统客户端的示例代码。

1. public void someMethodWithDistributedLogger() {

2. // Log transaction started once log client was created

3. Logger logger = CentralizedLoggerFactory.createLogger();

4. logger.setData(“key”, “value”);

5. try {

6. throw new Exception(“Some exception”);

7. } catch (Exception e) {

8. logger.setStatus(Status.FAIL,

9. new LogRecord(e.getMessage()));

10. }

11. logger.log(Level.INFO, new LogRecord(“exit method”));

12. logger.setStatus(Status.SUCCESS);

13. // Log transaction ended

14.}

列表5 集中式日志系统的客户端调用代码

当工厂方法创建日志系统客户端的时候,日志事务开始,在结束方法调用的时候,日志客户端实例的生命周期结束,日志事务也结束。这个示例代码中的一个细节是,一旦状态被设置(line 8-9),后续的状态设置将不会再起作用(line 12)。

也可以根据需要,将集中式的日志系统设计为peer-peer结构的。日志系统的后端数据库可以根据需要将数据聚合,进行数据挖掘等工作。

路径追踪系统

这个系统用于追踪已经在产品环境运行的网络系统的运行路径。它的功能可以包括记录模块和函数的调用路径、记录某一用户的身份信息、分析相应的用户数据流向等。

路径追踪系统的实现可以参考第三部分的本地日志系统地实现。列表6给出了一种使用用途——记录系统的运行路径:

1.public void doSomething(String value1, String value2) {

2. tracer.traceEnterMethod(new Object[]{value1, value2});

3. // do something

4. tracer.tranceExitMethod(new Object[]{value1, value2});

5.}

列表6记录系统的运行路径

与第四部分介绍的集中式日志系统类似,路径追踪系统也可以增加系统总线和后端服务器支持,增强系统的能力。

引用计数系统

大型网站会有很多模块,每个模块又会由更多更小的组件组成。比如用户界面模块可能会有搜索框、下拉框、用户输入条等等;后台组件比如用户权限认证、业务逻辑计算组件。统计这些组件的访问量信息可以很好地了解系统的运行情况,为维护、性能调优提供很好的帮助。

有两类引用信息是非常有价值的。一类称为静态引用记数,衡量的是一个组件在构建的时候,被其他的组件引用的次数。另外一类称为动态调用记数,衡量的是运行过程中被调用的次数。

静态引用记数

计算静态引用记数是一件颇有难度的工作,需要在每个引用到组件的代码处,递增引用计数。如果将这项工作交给组件的使用者,会发生诸如遗漏计数、错误计数等问题,也增加了使用者的负担。

解决的方法有多种。比如使用AOP技术在每次引用组件的地方增加计数。本文采用builder模式构建模块。每个component在builder里面被构建的时候,都会调用一次计数方法。

1.public static Component buildComponent(Component[] components) {

2. for(int i = 0; i < components.length; i++) {

3. addComponent(components[i]);

4. com.corp.countStaticReference(

5. components[i].getClass().getName());

6. }

7.}

列表6在Builder里计数静态引用

动态调用记数

记录模块的动态调用次数,相对来说简单一些。每一个被调用模块一般来说都会有个入口函数或是一个主控函数。记录组件的动态调用计数,只要在该函数里添加相应的计数操作即可。

1.public void handleBody() {

2. com.corp.countDynamicReference(this.getClass().getName());

3. // handleBody

4.}

列表7在模块的主控函数里添加计数操作

每次进入这个函数,静态计数函数countDynamicReference都会被调用,这个函数使用模块的类名作为键值,而相应的引用计数会被递增。

为了显示静态和动态调用计数的值,可以设计一个管理员界面,显示模块的计数值。

有了以上各个层次的日志系统,一个网络应用的内部状况基本可以一览无余的展现出来。各个不同的应用还可以根据自己不同的需求,定制不同的日志系统展示出系统的内部行为。

作者简介:沈羽是ebay中国软件工程公司的软件工程师,从事JSP应用、JSP引擎、企业级网络应用方面的开发和研究。

转载于:https://my.oschina.net/ydsakyclguozi/blog/392966

大型互联网应用中的日志系统相关推荐

  1. java中logger_Java日志系统---Logger之简单入门

    Java 中自带的日志系统,今天抽空了解了一点,算是入了门,所以将自己的一些心得记录下来,以备日后查看,有兴趣的朋友,看到此文章,觉得有错误或需要添加的地方,请在下方评论留言,大家可以共同进步,谢谢: ...

  2. PHP框架中的日志系统

    引言 接触过php框架的朋友们可能都知道,日志在项目中的重要作用了,他可以帮助我们定位错误的位置,让程序更友好(处理得当的话不会直接抛出一大堆只有程序猿才真正动的英文),调试的时候也会很方便,还可以记 ...

  3. 通用日志系统开发【转】

    1.前言 中大型软件项目中,日志系统是不可或缺的组成部分.尤其随着软件规模越来越大,内部结构越来越复杂,日志调试成为一种重要的调试方法.本文介绍了一个通用,高效,简洁的日志系统的设计思路. 文章分两部 ...

  4. 分布式框架-日志系统思路及实现

    转自:https://www.jianshu.com/p/ce30c31111ca 背景 随着互联网时代数据规模的爆发式增长,传统的单机系统在性能和可用性上已经无法胜任,分布式应用和服务化应用开始走进 ...

  5. 大型互联网分布式系统架构技术要点

    大型互联网分布式系统架构技术要点 解决问题的通用思路是将分而治之(divide-and-conquer),将大问题分为若干个小问题,各个击破.在大型互联网的架构实践中,无一不体现这种思想. 架构目标 ...

  6. 9 个技巧,解决 K8s 中的日志输出问题

    作者 | 元乙  阿里云存储服务技术专家 导读:近年来,越来越多的同学咨询如何为 Kubernetes 构建一个日志系统,或者是来求助在此过程中遇到一系列问题如何解决,授人以鱼不如授人以渔,于是作者想 ...

  7. c 语言 宏 可变 参数,利用C可变参数和宏定义来实现自己的日志系统

    在嵌入式应用的开发过程中,日志系统是非常重要的! 特别是在生产环节出现了偶发性的.与当前的执行环境相关的bug的时候, 如果没有日志系统来追踪问题,很难进行问题重现. 因此,实现一个自己的日志系统是很 ...

  8. python后台架构Django教程——日志系统

    全栈工程师开发手册 (作者:栾鹏) python教程全解 python日志的相关内容可以先参考:http://blog.csdn.net/luanpeng825485697/article/detai ...

  9. 创业公司 互联网架构方案 整体技术栈 基础设施 数据库 服务治理 消息中间件 日志系统 ELK 自动化部署

    欢迎关注博主公众号:[矿洞程序员]文章由陈晓阳原创. 本人微信:chenxiaoyangzxy. 免费提供本人大量学习资料. 从零开始搭建创业公司后台技术栈 原创: 潘锦 说到后台技术栈,脑海中是不是 ...

最新文章

  1. 跟我学Springboot开发后端管理系统2:Mybatis-Plus实战
  2. Linux平台下Eclipse的安装
  3. vector array and normal stanard array
  4. ant vue 树形菜单横向显示_Vue--组件Ant- 树形结构菜单
  5. 怎样批量调整word 图片大小?
  6. java学习教程之代码块
  7. c# hdf5 写string_Pandas系列之入门篇——HDF5
  8. python怎么存为动图_Python将视频或者动态图gif逐帧保存为图片的方法
  9. 2019.01.01洛谷 P4725/P4726 多项式对数/指数函数(牛顿迭代)
  10. [少儿数学时装街舞秀-英文版FashionMathV2] 截图展示
  11. docker安装redis【网易镜像方式】
  12. mysql 防止网络爬虫_Nginx反爬虫策略,防止UA抓取网站
  13. 分布式消我爬取豆瓣10万短评,告诉你《复仇者联盟4》在讲什么?
  14. SQL service 建数据库、表和备份还原数据库
  15. Axure RP工具介绍
  16. ACP知识域三---干系人管理
  17. 【OpenCV】-重映射
  18. 麻雀要革命2 第8节:莽撞的麻雀小姐
  19. [linux] linux sed命令删除一行/多行
  20. uniapp实现瀑布流懒加载实现和无限上拉加载更多

热门文章

  1. 虚拟机实现二层交换机_局域网SDN技术硬核内幕 5 虚拟化网络的实现
  2. mysql口令更换周期_Linux设置口令复杂度和口令定期更换策略
  3. windows不能在启动oracle,Windows不能在当地电脑启动OracleDBConsoleorcl
  4. android 自定义相册选择,Android通过手机拍照或从本地相册选取图片设置头像
  5. matlab风力机叶片仿真教程,我用matlab编写了一个风力机叶片的优化设计程序,有点问题 - 程序语言 - 小木虫 - 学术 科研 互动社区...
  6. 声音大小对于测距数值的影响
  7. python gui开发工具_深入解析Python,透析应用开发,涵盖9大应用领域的Python框架...
  8. 内网虚拟服务器怎么固定域名,如何让自己的局域网用(虚拟的)域名访问?
  9. oracle asm dd命令,ASM来用DD命令模拟数据块损坏
  10. java如何给一个链表定义和传值_如何在CUDA中为Transformer编写一个PyTorch自定义层...