关于网站全量访问日志,含session信息、用户请求发出的url信息记录功能,web请求的处理异步。尽量减少空间消耗和时间消耗。
配置方式:web.xml中配置listener
<listener>
<listener-class>com.zgl.listener.VistLogListener</listener-class>
</listener>
实现代码如下
package com.zgl.listener;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.regex.Pattern;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import com.zgl.util.FileUtil;
import com.zgl.util.SystemConfig;
/**
* @author 张光磊
* @version V1.0 创建时间:2010-1-29 下午04:56:31
* 类说明:对所有请求记录日志
* 需要在systemconfig.properties 中配置以下参数
* 过滤url的正则表达式,不配时过滤所有
* logurlpattern=(.jsp$)|(.action$)|(.html$)|(.htm$)|(/$)
* logreqpath=D:/project/xxt_mes/visitlog/ 记录日志文件存放地方
*/
public class VistLogListener implements ServletContextListener,ServletRequestListener{
protected static Thread thread =null;
protected static StringBuffer logMsg=new StringBuffer();
private static boolean RUNFLAG=true;
private static Pattern urlPattern=null;
private static String LogPath=null;
private final static String [] LogKey=new String []{"sessionid","ip","user","url","preurl"};
protected static Queue<String []> container = new ConcurrentLinkedQueue<String []>();
/**
* ServletRequestListener.requestDestroyed
*/
public void requestDestroyed(ServletRequestEvent event) {
// TODO Auto-generated method stub
}
/**
* ServletRequestListener.requestInitialized
*/
public void requestInitialized(ServletRequestEvent event) {
// TODO Auto-generated method stub
ServletRequest request=event.getServletRequest();
if(request instanceof HttpServletRequest){
HttpServletRequest req=(HttpServletRequest)request;
String URI=req.getRequestURI();
if(needLog(URI)){
//Map<String,Object> logMap=new HashMap<String,Object>();
String tmp=null;
try {
tmp = req.getQueryString()!=null?new String(req.getQueryString().getBytes("ISO8859_1"),"gbk"):null;
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
add(new String []{
req.getSession().getId(),
req.getRemoteAddr(),
new MySession(req.getSession()).toString(),
tmp!=null ? URI+"?"+tmp: URI,
req.getHeader("Referer")
});
}
}
}
/**
* ServletContextListener.contextDestroyed
*/
public void contextDestroyed(ServletContextEvent event) {
//thread.stop();
RUNFLAG=false;
FormartTime.stop();
event.getServletContext().log("日志容器关闭");
}
/**
* ServletContextListener.contextInitialized
*/
public void contextInitialized(ServletContextEvent event) {
String urlpattern=null;
urlpattern=SystemConfig.getCfgValue("logurlpattern");
LogPath=SystemConfig.getCfgValue("logreqpath");
if(urlpattern!=null&&urlpattern.length()>0){
urlPattern= Pattern.compile(urlpattern);
}
FormartTime.begin();
logToFile();
event.getServletContext().log("日志容器启动成功!");
}
/**
* 启动记录日志监听工作
*/
private static void logToFile(){
thread=new Thread(){
private String[] row=null;
private StringBuffer log=new StringBuffer();
private int count=0;
public void run(){
while (RUNFLAG){
if(container.size()==0){
try {
Thread.sleep(1000);
//Logger.getLogger(this.getClass().getName()).info("无访问,休息1s");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
while(RUNFLAG&&container.size()>0){
//TODO Log
row=container.poll();
logMsg.delete(0, logMsg.length());
logMsg.append(FormartTime.hhmmss);
for(int i=0;i<LogKey.length;i++){
logMsg.append(LogKey[i]+":"+row[i]+",");
}
//JSON模式
//Logger.getLogger(this.getClass().getName()).info("{"+logMsg.substring(0, logMsg.length()-1)+"}");
//普通模式
if(count >2000&&log.length()>0){
FileUtil.appendAsFile(log.toString(), LogPath+FormartTime.yyyyMMdd+"visit.log");
count=0;
log.delete(0, log.length());
}
log.append(container.size()+"|"+logMsg.toString()+"\n");
count++;
//Logger.getLogger(this.getClass().getName()).info(container.size()+"|"+logMsg.toString());
}
if(log.length()>0){
FileUtil.appendAsFile(log.toString(), LogPath+FormartTime.yyyyMMdd+"visit.log");
count=0;
log.delete(0, log.length());
}
}
}
};
thread.setName("VistLogToFileThread");
thread.start();
}
/**
* 日志队列添加元素
*/
private static void add(String [] row){
container.offer(row);// queue.offer("Hello");
}
/**
* 判断传入URL是否需要记录
*/
private static boolean needLog(String url){
if(urlPattern==null){
return true;
}else{
return urlPattern.matcher(url).find();
}
}
/**
* 读取 Session
* @author 张光磊
* @since 2010-2-22 下午02:50:01
*/
private class MySession{
StringBuffer sb=new StringBuffer();
public MySession(HttpSession session){
Enumeration enu=session.getAttributeNames();
while(enu!=null&&enu.hasMoreElements()){
String name=enu.nextElement().toString();
sb.append(name+":{"+session.getAttribute(name)+"}");
}
}
public String toString(){
return sb.toString();
}
}
/**
* 每秒生成一个时间串
* @author 张光磊
*
*/
static class FormartTime{
private static SimpleDateFormat sdf1=new SimpleDateFormat("yyyyMMdd");
private static SimpleDateFormat sdf2=new SimpleDateFormat("[HH:mm:ss]");
protected static String yyyyMMdd= getFormat1(new Date());
protected static String hhmmss= getFormat2(new Date());
private static final Timer timer = new Timer();
public static void begin(){
TimerTask tt=new TimerTask() {
@Override
public void run() {
Date tmp=new Date();
yyyyMMdd= getFormat1(tmp);
hhmmss= getFormat2(tmp);
}
};
timer.schedule(tt, 1000, 1000);
}
public static void stop(){
timer.cancel();
}
private static String getFormat1(Date date){
return sdf1.format(date);
}
private static String getFormat2(Date date){
return sdf2.format(date);
}
}
}
类图传不上来,就不传了。呵呵。
想了解原理的同学们可以看下 ServletContextListener,ServletRequestListener 的调用方式就行了。个人认为处理思路还是比较简单的。关于队列、StringBuilder 对空间的消耗情况可以跟踪下,呵呵。原则上是最小的消耗。输入日志的循环间隔时间大家就根据访问频度调整下吧,慢的情况1秒就行,访问较快的话可以设成1毫秒,一般的应用设置为100毫秒应该就可以满足需求了。
实现中使用到的Systemconfig类,其功能就是读取配置文件,相信大家都知道怎么写吧,呵呵。
如有其它问题,可以联系我。呵呵,转载请注明出处![](/images/smiles/icon_biggrin.gif)
分享到:
相关推荐
标题中的"ASP基于WEB的房屋出租管理系统的设计与实现(源代码+LW)"指的是一个使用ASP(Active Server Pages)技术构建的在线房屋出租管理系统的项目。ASP是微软开发的一种服务器端脚本语言,用于创建动态网页。这个...
通过《MySQL实用教程(第2版)》的源代码实践,读者可以更直观地看到这些知识点在实际操作中的应用,从而加深理解,提升技能。在阅读源代码的过程中,建议结合书中的讲解,逐步实现每个示例,遇到问题时,可以通过...
"存储备份代码"指的是用于创建、管理和恢复web应用数据备份的源代码。这样的代码可以帮助开发者确保在系统故障、数据丢失或恶意攻击时,能够迅速恢复服务,保障业务的连续性和数据的安全性。 在web备份代码中,通常...
- 日志查看:记录详细的执行日志,便于排查问题。 - 多用户管理:支持多团队协作,权限控制确保数据安全。 3. **前端与后端配合** - 前端部分负责用户交互界面的设计,包括任务创建、修改、删除以及任务执行状态...
通过研究这个源代码,开发者可以深入了解数据库同步的实现细节,以及如何在实际项目中应用这些技术。 总之,"mysql2sqlite异构数据转.rar"提供的源代码是学习和实践数据库异构同步的一个宝贵资源,特别是对于涉及...
这三个框架的结合提供了强大的功能,能够帮助开发者高效地构建数据驱动的Web应用。 首先,Spring框架是Java领域的一个核心框架,它为依赖注入(Dependency Injection, DI)和面向切面编程(Aspect-Oriented ...
1. **C#编程语言**: C#是微软公司推出的一种面向对象的编程语言,它支持.NET Framework,具有丰富的类库和强大的功能,适用于开发Windows桌面应用、Web应用以及移动应用等。在这个项目中,C#将作为主要的开发工具,...
5. 实时日志:支持通过web页面实时查看执行器输出的完整的执行日志; 6. 唯一搜索:支持通过web界面根据jobname或jobgroup进行全局唯一查询 7. 强自定义:支持在线配置定时任务请求类型、请求路径、请求参数、Cron...
它涉及将一个数据源中的数据更新复制到另一个目标位置,确保在多个位置的数据库或应用程序间的数据一致性和完整性。在IT行业中,数据同步是关键的业务流程,尤其是在分布式系统、云计算和大数据环境中。 "Mvc...
该工具可能包含了扫描PHP源代码、分析日志、模拟攻击场景等功能,帮助用户快速定位并修复安全问题。 使用PHP漏洞查找工具时,通常需要按照以下步骤进行: 1. 安装和配置工具:根据工具的文档,正确安装并设置相应...
数据库课程设计是IT教育...在压缩包"Attendance1.20"中,可能包含了该项目的源代码、数据库脚本、用户手册或其他相关资源。通过分析和学习这些文件,学生可以深入了解项目的实现细节,提升自己的数据库设计和开发技能。
MySQL是一款开源、免费的关系型数据库管理系统,它在Web应用中被广泛应用。对于MySQL的备份,常见的方法有全量备份、增量备份和差异备份。全量备份是备份所有数据库或选定的数据库,包括所有的表、索引和数据。增量...
`Laravel开发-twitterstreaming-laravel`项目是专为实现这一目标而设计的,它包含了一个名为`twitterstreaming-laravel-master`的压缩包文件,这是一份完整的源代码资源。 Laravel是一个流行的开源PHP框架,它为...
7. **错误处理与日志记录**:系统应能捕获并处理异常,同时记录操作日志,以便于故障排查和性能优化。 在“LMS.rar”中,LMS文件很可能是系统的核心部分,可能是Python、Java、C#或其他编程语言编写的应用程序。...
`mysqlphpbak.0.1.1.php3` 文件可能是`mysqlphpbak` 工具的源代码或执行文件,版本号为0.1.1,这表明它可能还处于早期开发阶段,但已经具备基本功能。在使用这个工具之前,你需要确保你的服务器环境支持PHP运行,...
1. **下载源码**:从官方网站或者可靠的镜像站点获取Redis 4.0.2的源代码包。 2. **编译与安装**:解压源码,运行配置脚本并进行编译,然后将编译后的二进制文件安装到系统指定目录。 3. **配置文件**:编辑`redis....
PHP,全称Hypertext Preprocessor(超文本预处理器),是一种开放源代码的脚本语言,常用于Web开发,可以嵌入到HTML中运行。利用PHP,开发者可以编写出与服务器端交互的程序,例如这里的数据库备份和恢复工具。 ...
MySQL数据库是世界上最受欢迎的开源关系型数据库管理系统之一,它以其高效、可靠和易于维护的特点深受开发者喜爱。在日常运维中,数据库备份是非常重要的环节,它能够保护数据免受意外丢失,确保业务连续性。本PHP版...
6. **日志记录**:记录每次备份的操作详情,便于跟踪和问题排查。 7. **邮件通知**:备份完成后,通过电子邮件发送通知,让用户及时了解备份状态。 在部署和使用时,用户需要注意以下几点: - 确保服务器环境支持...