技术标签: filter java线程 web 平台 servlet 多线程 log4j
随着 Web 应用的复杂化,用户在网站上的操作过程日益复杂。网站功能的多样化和交互性的提高为用户提供了多种可能的浏览路径。对于一个复杂的站点,用户在网站上操作的行为模式和操作习惯的分析,会给网站的优化提供基础的数据支持。而从技术上要为这种分析提供支持,就需要记录下每个用户在网站上的操作过程。另一方面,这种数据的记录也有助于解决用户在使用中出现的问题。我们只要知道用户遇到问题的时间和一些基本信息,就可以从日志中查出此用户遇到问题时的操作过程,从而有助于再现用户的出错场景,进而帮助用户解决问题。此外,网站用户的安全审计和分析用户特征的数据挖掘等工作也需要提供一个方法能对用户的网站操作进行跟踪和纪录。
通常 Web 应用的开发者会在开发过程中设置很多的跟踪点,在这些跟踪点向日志系统输出一些应用程序运行的信息,如果这些信息足够全面的话,开发者就可以利用他们猜测出程序如何处理的用户请求,以及可能遇到了什么问题。但不幸的是,如果一个站点在设计阶段没有把用户跟踪作为系统必须解决的一个问题提出的话,这些日志很可能就只是开发者为满足系统调试的需要而设置的一些信息。当用户访问量急剧增加的的时候,就会出现下面的问题。
在一个高访问量的 Web 应用中,经常要在同一时刻处理大量的用户请求。Web 服务器会为每一个请求分配一个线程,每一个线程都会向日志系统输入一些信息,通常日志系统都是按照时间顺序而不是用户顺序排列这些信息的,这些线程的交替运行会让所有用户的处理信息交错在一起,让人很难分辨出那些记录是同一个用户产生的。另外,高可用性的网站经常会使用负载均衡系统平衡网络流量,这样一个用户的操作记录很可能会分布在多个 Web 服务器上,如果我们没有一种方法来标示一条记录是哪个用户产生的,从这众多的日志信息中筛选出对我们有用的东西将是一项艰巨的工作。
本文试图探讨的解决方案是建立在 Log4J 的基础上的,如果你的 Web 站点已经使用了 Log4J 作为日志系统的 API 接口,根据本文所介绍的方法,就可以很容易的在每一条日志上保存用户上下文信息,为用户跟踪保存基本的访问数据。为了更清晰地介绍这种方法,我们先对 Log4J 以及 NDC/MDC 做个简单的介绍。
Log4J 是 Apache 组织提供的一个日志组件, 它设计了灵活的配置文件,利用它可以在不更改程序的情况下,通过修改配置文件来调控日志的输出。下面是 Log4J 最主要的三大基本构件:
对日志信息进行分类筛选。通过指定优先级,控制程序中日志信息的输出:高于优先级的日志可以被输出,低于优先级的日志则被忽略。
指定日志信息的输出设备。Log4J 目前支持的输出设备有以下几种:
程序员也可以根据自己的需要定制 Appenders,实现更复杂和更为方便实用的日志管理,比如把日志输入数据库,或者传输到统一的日志服务器,等等。
指定日志输出的格式。Log4J 提供的 Layout 有以下几种:
软件开发人员可以通过这三大构件,根据日志的类型和优先级进行记录,并且可以在程序运行时去控制日志信息输出的格式和往什么地方输出(控制台、日志文件)。
下面是一个在 Web 应用中使用 Log4J 的简单例子。
第 1 步:修改 Web 应用的 web.xml 文件
在 Web 应用的 web.xml 中指明 Log4J 的配置文件名称。
第 2 步:对 Log4J 进行配置
我们看到,在上面的配置中指定了 Log4J 的配置文件名为 log4j.properties。在这个文件中,我们可以通过对前文所述的 Log4J 的三大控件进行配置:
第 3 步:在 Web 应用的 Java 代码中使用 Log4J
进行完上面两步的配置,我们就可以在 Java 程序中使用 Log4J 进行日志的输出。
首先读取 Log4J 配置信息,初始化 Logger。
运行该 Web 应用后,当有客户机访问该 Web 应用时,就会得到应用程序输出的日志信息。下面是以三个并发用户访问该 Web 应用的情况下,从打印出的日志中挑选出的上述相关日志信息:
在上面的例子中,我们看到,利用 Log4J 提供的功能,我们很方便地输出了程序的日志,但是同时也看到,这样的日志在多用户并发访问的情况下,特别是应用程序复杂且拥有大量并发访问用户的情况下,根本无法区分哪些日志是属于哪个用户的,这样就使得进行日志分析和用户跟踪变成一件非常困难的事情。
NDC(Nested Diagnostic Context)是 Neil Harrison 在名为《Patterns for Logging Diagnostic Messages》的书中提出的嵌套诊断环境的机制。这种机制的提出,主要为了减少多线程的系统为每个客户单独记录日志的系统开销。在过去,区分两个客户的日志输出的常用方法是单独为每个客户机实例化新类别,但该方法会增加类别数量,并增加日志记录的管理开销。Neil Harrison 提出的方法就是把用户的上下文信息放到嵌套式诊断环境 (NDC) 中。
NDC 为每一个线程管理一个堆栈。开发人员可以在代码中合适的位置嵌入简单的 push 和 pop 方法,用来维护堆栈。通常 push 进堆栈的是可以唯一标示客户的上下文信息,如 SessionID 或者客户名称,IP 地址等。因为每个客户请求都会有单独的 NDC 堆栈,因此日志系统在输出的时候会根据每个线程找到对应的堆栈,并在输出日志的时候附加上堆栈内的信息。开发人员就可以很容易的在日志中区分出各个不同客户所产生的日志条目。
Log4J 从 1.2 起开始支持 NDC,org.apache.log4j.NDC 声明如下:
要注意的是,org.apache.log4j.NDC 类中所有的方法都是静态的。假设 NDC 日志输出功能被打开,每一次的日志请求,Log4J 组件都会把当前线程的整个 NDC 堆栈内容输出在日志条目中。这样的过程不需要开发人员写过多的代码,程序员只需要在代码中合适的地方通过 push 和 pop 方法将正确的信息放到 NDC 的堆栈中,然后通过修改 Log4J 的配置文件,指定用户标志信息输出的位置和格式,而原来 Java 代码中输出日志的代码不需要任何修改,就能够输出带有用户标志信息的日志。
在前面的 Log4J 使用示例 部分,我们曾经讲过 Log4J 配置文件中相应的配置信息,其中 PatternLayout 的 ConversionPattern 用于程序员指定日志输出的格式。要使用 NDC 的方式输出用户标志信息,只需要在 PatternLayout 的格式定义 ConversionPattern 中使用 %x,就能在相应的位置上输出 NDC 存储的上下文信息。具体的使用方法我们将在后面的 在 Web 应用中添加用户跟踪 部分进行介绍。
MDC 和 NDC 相似,也可以减少多线程的系统为每个客户单独记录日志的系统开销。它同样是为每个线程建立一个独立的存储空间,开发人员可以根据需要把信息存入其中。不同的是 MDC 使用 Map 的机制来存储信息,信息以 key/value 对的形式存储在 Map 中。
Log4J 从 1.3 alpha 版本开始提供对 MDC 的支持,org.apache.log4j.MDC 声明如下:
MDC 和 NDC 的使用方法也类似,区别只是在 Log4J配置文件中,在通过 PatternLayout 的 ConversionPattern 来配置日志的格式的时候,需要使用 %x{key} 来输出相应的用户标志信息对象。
下面,我们通过具体的例子来说明如何在使用 Log4J 的 Web 应用中增加用户标志信息,达到进行用户跟踪的目的。在开发中,对于使用 NDC 还是 MDC 的机制,要看具体的应用在处理上下文信息的时候,是采用堆栈式的还是 Map 式的方便。下面我们以 NDC 为例进行说明。
通常,开发人员会在系统的很多地方设置输出点,输出日志。如果要全面的修改这些输出点使日志条目附加上所需的信息,是一件繁重的工作。我们可以利用 Servlet 的 filter 来简化这项工作。Servlets Filter 是 Servlet 2.3 规范中出现的,它能截取用户从客户端提交的请求,并在请求没有到达真正需要访问的资源前运行一个指定的类。如果我们在这个类中实现 NDC 或 MDC 的功能,就可以大量简化日志修改的工作。下面的清单显示了实现这种修改所需的三个步骤。在这里,我们使用的是 NDC,您也可以使用 MDC 实现相同的功能。
在下面的例子中,介绍如何在前面已有的 Log4J 使用示例 的 Web 应用代码的基础上,通过为 Web 应用的 Servlet 增加一个 filter 的方法,将用户标志信息在 filter 中压入/弹出 NDC 堆栈,而不需要修改任何原来的 Java 程序中的输出日志的代码,使用起来非常简便。
第 1 步:增加一个处理 NDC 堆栈信息的 filter 类
本例通过在 filter 中取得访问该 Web 应用的客户机的IP地址,用以唯一地标识客户。您也可以和实际的应用程序代码相配合,使用更加人性化的方式来唯一标识客户,如取得 Session 中存储的客户名称等。
代码 7. 在 filter 中增加将用户标志信息放入 NDC 堆栈
第 2 步:修改 Web 应用的 web.xml 文件
我们需要修改 Web 应用的 web.xml 文件,对 filter 进行设置。在 <web-app< 元素下面增加下列的代码行:
上述 XML 中的 url-pattern 元素与这个 Web 应用中的所有 URL 匹配。如果只想应用于部分 URL,可以相应地调整模式。
第 3 步:修改 Log4J 的配置文件
需要对 Log4J.properties 文件的配置做一些改变,以便看到 NDC 上下文。在 NDC 简介部分,我们曾经说过,%x 表示会在每个日志行上打印当前 NDC 上下文。我们对 Log4J使用示例 中的 Log4J.properties配置文件 进行如下修改,在 PatternLayout 的格式定义 ConversionPattern 中增加 %x, 将 NDC 堆栈中的信息在 %x 指定的位置上进行输出。如下:
完成以上修改之后,每一条记录都会把我们在 Filter 中 push 进 NDC 堆栈的内容打印出来。仍然以 Log4J 使用示例 中的三个并发用户访问为例,我们可以得到如下的日志信息,和前面不使用 NDC 的方式下 打印的日志信息相比较,可以看到在原来日志的基础上增加了客户机 IP 地址,这样可以很容易地区分不同的用户的信息,为我们进行日志分析和用户跟踪打下了很好的基础。
图 2. 应用 NDC 之后,运行 Web 应用后输出的日志
或许以上的描述已经让你了解到如何利用 NDC 和 MDC 的机制来记录某个用户的唯一标示,或者跟踪其他特定于应用的数据。一旦这些用户标示的数据记入日志,则能很容易地利用其他工具将他们抽取出来,如 grep。如果我们自定义一个数据库的 Appenders,把日志信息插入数据库的话,还能很容易的对这些数据进行统计和分析。
Log4J 提供了对 NDC 和 MDC 机制的支持,开发人员可以利用此机制为每条日志记录增加我们需要的内容。本文通过在 servlet 的 filter 中合适的位置应用很少的代码,就可以修改整个应用的日志策略。合理的善用本文所提到的机制,可以节省我们的工作量,也简化程序中日志的维护。最终,客户可以获得更好的网络应用程序,遇到问题也能从技术支持团队得到迅速有效的响应。
值得注意的是,我们并不能保证本文所提出的用户跟踪方案可以完美地解决所有的问题。如果读者希望采用本方案,请参考 Apache Log4J 的文档以了解更多的信息。
文章浏览阅读3.6k次,点赞2次,收藏2次。DELL7080台式机两块硬盘。_没有u盘怎么装ubuntu
文章浏览阅读32次。题面Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape of an N x N grid (1 <= N <= 500). The grid contains K asteroids (1 <= K <= 10,000), which are conv...
文章浏览阅读2.6w次,点赞21次,收藏112次。机器视觉则主要是指工业领域视觉的应用研究,例如自主机器人的视觉,用于检测和测量的视觉系统等。它通过在工业领域将图像感知、图像处理、控制理论与软件、硬件紧密结合,并研究解决图像处理和计算机视觉理论在实际应用过程中的问题,以实现高效的运动控制或各种实时操作。_工业机器视觉系统的构成与开发过程(理论篇—1
文章浏览阅读5.9w次,点赞32次,收藏58次。legend 传奇、图例。plt.legend()的作用:在plt.plot() 定义后plt.legend() 会显示该 label 的内容,否则会报error: No handles with labels found to put in legend.plt.plot(result_price, color = 'red', label = 'Training Loss') legend作用位置:下图红圈处。..._plt.legend
文章浏览阅读2.2k次,点赞3次,收藏11次。深入理解 C# .NET Core 中 async await 异步编程思想引言一、什么是异步?1.1 简单实例(WatchTV并行CookCoffee)二、深入理解(异步)2.1 当我需要异步返回值时,怎么处理?2.2 充分利用异步并行的高效性async await的秘密引言很久没来CSDN了,快小半年了一直在闲置,也写不出一些带有思想和深度的文章;之前就写过一篇关于async await 的异步理解 ,现在回顾,真的不要太浅和太陋,让人不忍直视!好了,废话不再啰嗦,直入主题:一、什么是异步?_netcore async await
文章浏览阅读6.5w次,点赞166次,收藏309次。当我看到别人的类上面的多行注释是是这样的:这样的:这样的:好装X啊!我也想要!怎么办呢?往下瞅:跟着我左手右手一个慢动作~~~File--->Settings---->Editor---->File and Code Templates --->Includes--->File Header:之后点applay--..._idea作者和日期等注释
文章浏览阅读175次。Netperf是一种网络性能的测量工具,主要针对基于TCP或UDP的传输。Netperf根据应用的不同,可以进行不同模式的网络性能测试,即批量数据传输(bulk data transfer)模式和请求/应答(request/reponse)模式。工作原理Netperf工具以client/server方式工作。server端是netserver,用来侦听来自client端的连接,c..._netperf 麒麟
文章浏览阅读1.1k次,点赞2次,收藏3次。作者| qcrao责编 | 屠敏出品 | 程序员宅基地刚开始写这篇文章的时候,目标非常大,想要探索 Go 程序的一生:编码、编译、汇编、链接、运行、退出。它的每一步具体如何进行,力图弄清 Go 程序的这一生。在这个过程中,我又复习了一遍《程序员的自我修养》。这是一本讲编译、链接的书,非常详细,值得一看!数年前,我第一次看到这本书的书名,就非常喜欢。因为它模仿了周星驰喜剧..._go run 每次都要编译吗
文章浏览阅读1.4k次,点赞4次,收藏2次。0、C++的输入输出分为三种:(1)基于控制台的I/O (2)基于文件的I/O (3)基于字符串的I/O 1、头文件[cpp] view plaincopyprint?#include 2、作用istringstream类用于执行C++风格的字符串流的输入操作。 ostringstream类用_c++ istringstream a >> string
文章浏览阅读2k次,点赞3次,收藏14次。我们在每个修改的地方都记录一条对应的 redo 日志显然是不现实的,因此实现方式是用时间换空间,我们在数据库崩了之后用日志还原数据时,在执行这条日志之前,数据库应该是一个一致性状态,我们用对应的参数,执行固定的步骤,修改对应的数据。1,MySQL 就是通过 undolog 回滚日志来保证事务原子性的,在异常发生时,对已经执行的操作进行回滚,回滚日志会先于数据持久化到磁盘上(因为它记录的数据比较少,所以持久化的速度快),当用户再次启动数据库的时候,数据库能够通过查询回滚日志来回滚将之前未完成的事务。_binglog
文章浏览阅读3k次。概述之前介绍过 移动Web开发基础-flex弹性布局(兼容写法) 里面有提到过想做一个Chrome插件,来生成flexbox布局的css代码直接拷贝出来用。最近把这个想法实现了,给大家分享下。play-flexbox插件介绍play-flexbox一秒搞定flexbox布局,可直接预览效果,拷贝CSS代码快速用于页面重构。 你也可以通过点击以下链接(codepen示例)查_chrome css布局插件
文章浏览阅读308次。我自己的配置是GeForce GTX 1660 +CUDA10.0+CUDNN7.6.0 + TensorFlow-GPU 1.14.0Win10系统安装tensorflow-gpu(按照步骤一次成功)https://blog.csdn.net/zqxdsy/article/details/103152190环境配置——win10下TensorFlow-GPU安装(GTX1660 SUPER+CUDA10+CUDNN7.4)https://blog.csdn.net/jiDxiaohuo/arti