大型互联网应用记录用户的行为是一个问题,如何在不影响用户体验的情况下,异步的追踪用户的行为,apache 的开源项目clickstream 是个不错的选择,根据session 的 建立和销毁 来记录用户的行为日志。
Clickstream 概述
一个用来跟踪正在你的站点上访问的用户所到达位置细节的工具。它允许你跟踪访问你的站点的“点击流”或者“传输路径”。请访问JIRA的更新日志 来了解Clickstream最近的发展。
特性
• 当用户会话产生时,开始跟踪点击流。(通过一个监听器 )
• 跟踪用户产生的每次点击信息。(通过一个过滤器 )
• 当用户会话终止时,将完整的点击流记录到文件或者PrintStream中。
• 设法发现用户是不是机器人,并进行适当的过滤(目前可以检测252种机器人)
下面我使用 以前的一个SSH 整合的OA 系统来做为例子,给这个系统加上 用户行为记录(先记录到控制台上),稍后我们记录到远程的日志服务器上
步骤:
1. 在web.xml 中加上 clickstream 的filter ,配置 clickstream 拦截的行为 ,注意顺序,需要配置在web.xml的 靠前部分
clickstream com.opensymphony.clickstream.ClickstreamFilter clickstream *.jsp clickstream *.html clickstream *.htm clickstream *.do com.opensymphony.clickstream.ClickstreamListener
2. session 超时以后,需要调用哪个方法来完成行为日志得记录?也就是把某个sessionID 关联的行为记录下来,需要我们实现一个clickstream 的接口 ClickstreamLogger 接口,在 session 超时的时候,它会调用 log 方法,在log方法中我们可以通过 遍历 list 的方式 拿到 clickstream 帮我们记录的 某个具体的 sessionID 的行为,然后我们根据自己的业务要求来进行 持久化--- 交给日志服务器
package com.demo.struts.util;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import com.opensymphony.clickstream.Clickstream;
import com.opensymphony.clickstream.ClickstreamRequest;
import com.opensymphony.clickstream.logger.ClickstreamLogger;
public class TouchLogger implements ClickstreamLogger{
private static final Logger log = Logger.getLogger(TouchLogger.class);
/**
* 由于行为采集将是一个比较消耗资源的操作(用户量大,点击量大),所以在优化方面
* 可以考虑以下方法:
* 1.每web服务器将日志信息记录在本地
* 2.对于用户每次登录,并不是每作一次操作都要进行一次db的数据插入,而是当该用户的session过期的时候再进行,这样避免
* 多次的数据库操作。但是考虑到数据采集的真实性需要在每次点击的时候将点击时间进行记录
*
*/
public void log(Clickstream cs) {
log.info("session超时,记录日志中~~~");
List list = cs.getStream();
HttpSession session = cs.getSession();
String userName=(String)session.getAttribute("username");
for (Iterator iter = list.iterator(); iter.hasNext();)
{
ClickstreamRequest cr = (ClickstreamRequest) iter.next();
String servletPath = null;
if(cr.getQueryString()==null){
servletPath = cr.getRequestURI();
}else{
servletPath = cr.getRequestURI()+"?"+cr.getQueryString();
}
//if(urllist.contains(servletPath)){
String ip = cr.getIp();
log.error("记录日志中:userName:"+userName+",IP:"+ip+",servletPath:"+servletPath);
}
}
}
3. 写 clickstream.xml (固定格式,网上抄一个),告诉 clickstream 单session 超时的时候 需要调用哪个方法来处理
4. 在tomcat 中配置好项目的访问路径以后启动项目,我们观察控制台,首先需要你配置下项目的 log4j.properties ,将clickstream 配置成 DEBUG 级别,方便我们观察 clickstream 的运作流程
a.首先进入主页面 ,观察控制台,返现 clickstream 已经为 我们创建了一个 clickstream 流
b.输入用户名密码之后,我们做一些页面从操作,看到控制台已经 [DEBUG][2010-02-07 17:47:04] Applying clickstream filter to request. 也就是 我们做的操作已经被拦截,并且已经加入到 clickstream 流中,帮我们缓存起来了
c. 等待session超时,在观察控制台 ,session 超时,日志被记录
5. 下面则需要我们将 clickstream 中的数据流写到 日志服务器上,而不是控制台,这样可以吧日志保存到远程日志服务器,便于以后查找和分析用户的行为,则需要我们在项目中修改log4j.properties 的 配置文件,加上远程 服务器IP和端口
log4j.logger.com.demo.struts.util.TouchLogger=ERROR,A2
#日志服务器配置
log4j.appender.A2=org.apache.log4j.net.SocketAppender
log4j.appender.A2.RemoteHost = 127.0.0.1
log4j.appender.A2.Port = 12345
log4j.appender.SOCKET.LocationInfo=true
#远程服务器日志格式
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%m%n
6. log4j 的日志服务器 其实就是启动一个socke ,监听本地的一个端口,有数据过来的时候,把数据持久化一下,比如记录在文件中,其实这个socket log4j已经给我们实现了,并且内部使用了多线程机制,高效的记录日志,使用fatjar(肥jar) 将下面的 类和 依赖的log4j 整体打一个jar包,对外暴漏一个启动的main方法,步骤可以参考我的 用Fat Jar Eclipse Plug-In打包可执行jar文件 http://8366.iteye.com/admin/blogs/480652
package cn.com.xinli.log;
import org.apache.log4j.net.SimpleSocketServer;
/**
* 日志服务器 启动的时候接受两个参数
* 第一个参数为监听端口号
* 第二个是配置文件名称,内容和log4j.properties 内容一致,就是接受到了日志流如何保存
*
* 原理:
* 使用log4j 中的 SimpleSocketServer.main 方法 在本地启动一个 socket
* 监听制定端口,当监听端口上有数据的时候,内部使用 多线程(Thread)机制完成 对数据流的 读取,
* 并且会根据你制定的配置文件来保存数据
*
*
* @author huxl
*
*/
public class LogServer
{
public LogServer()
{
}
public static void main(String args[])
throws Exception
{
if (args.length == 2)
{
String port = args[0];
String configFile = args[1];
System.out.println("日志服务监听端口:"+args[0]);
System.out.println("日志服务配置文件名字:"+args[1]);
SimpleSocketServer.main(new String[] {
port, configFile
});
}
else
{
System.out.println("日志服务器启动失败:可能是参数不正确造成,参数个数为2,第一个参数为监听端口号,第二个是配置文件名称");
System.exit(0);
}
}
}
还需要一个配置文件,就是说监听到端口上有数据了,数据该持久化到哪,是一个标准的log4j.properties文件 logServer.properties 文件内容
log4j.rootLogger=,A1
log4j.appender.console =org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%m%n
log4j.appender.A1 =org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.DatePattern='.'yyyy-MM-dd
log4j.appender.A1.File =logfiles/testlog.txt
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%m%n
启动 :将 打好的 logServer_fat.jar 和 logServer.properties 放在同级 目录下 执行启动
D:\workspace\logServer>java -jar logServer_fat.jar 12345 logServer.properties
日志服务监听端口:12345
日志服务配置文件名字:logServer.properties
当有数据到来时 它会在当前的目录下产生 logfiles/testlog.txt 并且每天都谁产生一个 日期为文件名字的日志文件,这样,我们的日志文件就可以持久化了
使用clickstream 最大的好处就是 可以异步的来 跟踪用户在网站上的行为,并且内部实现缓冲机制,对于高并发的大型互联网应用时一个不错的选择,利用 sessionID 来追踪用户的行为
备注:
1.附件中是整个项目,没有lib 文件,可以再 我的这个blog 中去下载
http://8366.iteye.com/admin/blogs/476923
2. 还需要 clickstream-1.0.3.jar 在附加中
3. 使用sql 文件来建立数据库和表结构
4. 导入到eclipse可以直接使用