`
xian0617
  • 浏览: 8124 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
文章分类
社区版块
存档分类
最新评论

web应用中网站全量访问日志高效记录源代码

阅读更多

关于网站全量访问日志,含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类,其功能就是读取配置文件,相信大家都知道怎么写吧,呵呵。

 

 

如有其它问题,可以联系我。呵呵,转载请注明出处

 

 

 

 

1
0
分享到:
评论

相关推荐

    ASP基于WEB的房屋出租管理系统的设计与实现(源代码+LW).zip

    标题中的"ASP基于WEB的房屋出租管理系统的设计与实现(源代码+LW)"指的是一个使用ASP(Active Server Pages)技术构建的在线房屋出租管理系统的项目。ASP是微软开发的一种服务器端脚本语言,用于创建动态网页。这个...

    MySQL实用教程(第2版)源代码

    通过《MySQL实用教程(第2版)》的源代码实践,读者可以更直观地看到这些知识点在实际操作中的应用,从而加深理解,提升技能。在阅读源代码的过程中,建议结合书中的讲解,逐步实现每个示例,遇到问题时,可以通过...

    存储备份代码

    "存储备份代码"指的是用于创建、管理和恢复web应用数据备份的源代码。这样的代码可以帮助开发者确保在系统故障、数据丢失或恶意攻击时,能够迅速恢复服务,保障业务的连续性和数据的安全性。 在web备份代码中,通常...

    数据同步工具datax-web可视化工具

    - 日志查看:记录详细的执行日志,便于排查问题。 - 多用户管理:支持多团队协作,权限控制确保数据安全。 3. **前端与后端配合** - 前端部分负责用户交互界面的设计,包括任务创建、修改、删除以及任务执行状态...

    mysql2sqlite异构数据转.rar

    通过研究这个源代码,开发者可以深入了解数据库同步的实现细节,以及如何在实际项目中应用这些技术。 总之,"mysql2sqlite异构数据转.rar"提供的源代码是学习和实践数据库异构同步的一个宝贵资源,特别是对于涉及...

    SSM整合jar包

    这三个框架的结合提供了强大的功能,能够帮助开发者高效地构建数据驱动的Web应用。 首先,Spring框架是Java领域的一个核心框架,它为依赖注入(Dependency Injection, DI)和面向切面编程(Aspect-Oriented ...

    C#数据同步项目

    1. **C#编程语言**: C#是微软公司推出的一种面向对象的编程语言,它支持.NET Framework,具有丰富的类库和强大的功能,适用于开发Windows桌面应用、Web应用以及移动应用等。在这个项目中,C#将作为主要的开发工具,...

    Job Plus项目是基于SpringBoot+Vue的轻量级定时任务管理系统+源代码+文档说明

    5. 实时日志:支持通过web页面实时查看执行器输出的完整的执行日志; 6. 唯一搜索:支持通过web界面根据jobname或jobgroup进行全局唯一查询 7. 强自定义:支持在线配置定时任务请求类型、请求路径、请求参数、Cron...

    数据同步程序

    它涉及将一个数据源中的数据更新复制到另一个目标位置,确保在多个位置的数据库或应用程序间的数据一致性和完整性。在IT行业中,数据同步是关键的业务流程,尤其是在分布式系统、云计算和大数据环境中。 "Mvc...

    php 漏洞查找工具

    该工具可能包含了扫描PHP源代码、分析日志、模拟攻击场景等功能,帮助用户快速定位并修复安全问题。 使用PHP漏洞查找工具时,通常需要按照以下步骤进行: 1. 安装和配置工具:根据工具的文档,正确安装并设置相应...

    数据库课程设计 考勤管理系统

    数据库课程设计是IT教育...在压缩包"Attendance1.20"中,可能包含了该项目的源代码、数据库脚本、用户手册或其他相关资源。通过分析和学习这些文件,学生可以深入了解项目的实现细节,提升自己的数据库设计和开发技能。

    简易的数据库备份系统

    MySQL是一款开源、免费的关系型数据库管理系统,它在Web应用中被广泛应用。对于MySQL的备份,常见的方法有全量备份、增量备份和差异备份。全量备份是备份所有数据库或选定的数据库,包括所有的表、索引和数据。增量...

    Laravel开发-twitterstreaming-laravel

    `Laravel开发-twitterstreaming-laravel`项目是专为实现这一目标而设计的,它包含了一个名为`twitterstreaming-laravel-master`的压缩包文件,这是一份完整的源代码资源。 Laravel是一个流行的开源PHP框架,它为...

    LMS.rar_简单的图书管理系统

    7. **错误处理与日志记录**:系统应能捕获并处理异常,同时记录操作日志,以便于故障排查和性能优化。 在“LMS.rar”中,LMS文件很可能是系统的核心部分,可能是Python、Java、C#或其他编程语言编写的应用程序。...

    MySQl数据库备份

    `mysqlphpbak.0.1.1.php3` 文件可能是`mysqlphpbak` 工具的源代码或执行文件,版本号为0.1.1,这表明它可能还处于早期开发阶段,但已经具备基本功能。在使用这个工具之前,你需要确保你的服务器环境支持PHP运行,...

    redis4.0.2下载

    1. **下载源码**:从官方网站或者可靠的镜像站点获取Redis 4.0.2的源代码包。 2. **编译与安装**:解压源码,运行配置脚本并进行编译,然后将编译后的二进制文件安装到系统指定目录。 3. **配置文件**:编辑`redis....

    php版mysql大数据库备份和恢复工具

    PHP,全称Hypertext Preprocessor(超文本预处理器),是一种开放源代码的脚本语言,常用于Web开发,可以嵌入到HTML中运行。利用PHP,开发者可以编写出与服务器端交互的程序,例如这里的数据库备份和恢复工具。 ...

    Mysql数据库备份程序PHP版

    MySQL数据库是世界上最受欢迎的开源关系型数据库管理系统之一,它以其高效、可靠和易于维护的特点深受开发者喜爱。在日常运维中,数据库备份是非常重要的环节,它能够保护数据免受意外丢失,确保业务连续性。本PHP版...

    和其mysql备份 v1.0.rar

    6. **日志记录**:记录每次备份的操作详情,便于跟踪和问题排查。 7. **邮件通知**:备份完成后,通过电子邮件发送通知,让用户及时了解备份状态。 在部署和使用时,用户需要注意以下几点: - 确保服务器环境支持...

Global site tag (gtag.js) - Google Analytics