Apache服务器日志Log解析

    xiaoxiao2021-04-16  234

    ------------本文笔记整理自《Hadoop海量数据处理:技术详解与项目实战》范东来

    一、Apache服务器日志信息组成说明

    1. group-0 是一条初始的log日志信息;

    2. group-1 ~ group-15 是对该条日志正则解析后的结果。

    一条原始log日志: group-0 : 120.196.145.58 - - [11/Dec/2013:10:00:32 +0800] "GET /__utm.gif HTTP/1.1" 200 35 "http://easternmiles.ceair.com/flight/index.html" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36" "BIGipServermu_122.119.122.14=192575354.20480.0000;Webtrends=120.196.145.58.1386724976245806;uuid=5eb501f9-3586-4239-a15c-fe89aa14d624;userId=099;st=1" 1482 352 - easternmiles.ceair.com 794 远端主机(访客IP地址): group-1 : 120.196.145.58 远端登录名: group-2 : - 远端用户名: group-3 : - 服务器接收请求时间: group-4 : 11/Dec/2013:10:00:32 +0800 请求的第一行(请求方式、请求的URL、请求所用协议): group-5 : GET /__utm.gif HTTP/1.1 响应码(最后的请求状态): group-6 : 200 返回的数据流量(以CLF格式显示的除HTTP头以外传送的字节数): group-7 : 35 上一个访问的页面(访客来源): group-8 : http://easternmiles.ceair.com/flight/index.html 访客浏览器信息: group-9 : Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 Cookie信息(包含uuid/userId/sessiontime): group-10 : BIGipServermu_122.119.122.14=192575354.20480.0000;Webtrends=120.196.145.58.1386724976245806;uuid=5eb501f9-3586-4239-a15c-fe89aa14d624;userId=099;st=1 接收的字节数(包括请求头的数据,并且不能为零): group-11 : 1482 发送的字节数(包括请求头的数据,并且不能为零): group-12 : 352 %{X-Forwarded-For}i: group-13 : - 访问主机地址: group-14 : easternmiles.ceair.com 服务器处理本请求所用时间,以微秒为单位: group-15 : 794

    二、正则解释

    参考正则教程链接:Java 正则表达式 | 菜鸟教程

    1.用到的正则表达式解释:

    "(.+)": 字符串中用一对括号括起来的表示 一个组 "(.+)(.+)":这个就表示 两个组,因为有两对括号 "(.+)":括号中的 . 代表 匹配除 \r\n 之外的任何单个字符 括号中的 + 代表 一次或多次匹配前面的字符或子表达式,也就是多次匹配 . "\\s":代表字符串中转义"\\",最终转换成正则表达式时, 即为"\s",代表匹配任何空白字符,包括空格、制表符、换页符等,如:\f\n\r\t\v "\\(":代表字符串中转义"\\",转成正则时,代表 \( 即对"("的转义 这个"\\(\\)"与"()"不同: 前一个代表匹配一对括号,后一个代表匹配一个组 "\\[\\]":代表匹配一对方括号 "[0-9.]":代表匹配任意一位数字或者一个字符,与上一个例子不同 "[0-9.]+\\s":代表匹配任意多位数字或者多个字符,并以空白字符结尾 "[^0-9]":用"^"尖角代表除0-9的任意一个字符 "\\[([^\\[\\]]+)\\]\\s":代表匹配以"["开头,以"]"和空白字符结尾的一串字符 其中字符是除了"["、"]"方括号以外的任意多个字符

    2.将需要匹配的日志信息和浏览器信息字符串,及对应的正则匹配字符串,按组(一行一组)拆分如下:

    2.1.日志解析:

    待解析的一条日志:(Java字符串) String LOG = "120.196.145.58 " + "- " + "- " + "[11/Dec/2013:10:00:32 +0800] " + "\"GET /__utm.gif HTTP/1.1\" " + "200 " + "35 " + "\"http://easternmiles.ceair.com/flight/index.html\" " + "\"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36\" " + "\"BIGipServermu_122.119.122.14=192575354.20480.0000;Webtrends=120.196.145.58.1386724976245806;uuid=5eb501f9-3586-4239-a15c-fe89aa14d624;userId=099;st=1\" " + "1482 " + "352 " + "- " + "easternmiles.ceair.com " + "794"; 使用的正则表达式:(Java字符串) String APACHE_LOG_REGEX = "^([0-9.]+)\\s" +"([\\w.-]+)\\s" +"([\\w.-]+)\\s" +"\\[([^\\[\\]]+)\\]\\s" +"\"((?:[^\"]|\\\")+)\"\\s" +"(\\d{3})\\s" +"(\\d+|-)\\s" +"\"((?:[^\"]|\\\")+)\"\\s" +"\"((?:[^\"]|\\\")+)\"\\s" +"\"(.+)\"\\s" +"(\\d+|-)\\s" +"(\\d+|-)\\s" +"(\\d+|-)\\s" +"(.+)\\s" +"(\\d+|-)$";

    2.2.浏览器解析: 

    待解析的一条浏览器信息 String userAgentStr = "\"Mozilla/5.0 " +"(Windows NT 6.1; WOW64) " +"AppleWebKit/537.36 " +"(KHTML, like Gecko) " +"Chrome/31.0.1650.63 " +"Safari/537.36\" "; 用户浏览器信息匹配正则:(Java字符串) String USER_AGENT_REGEX = "^(.+)\\s" +"\\((.+)\\)\\s" +"(.+)\\s" +"\\((.+)\\)\\s" +"(.+)\\s" +"(.+)$";

     

    三、代码实现

    1. 将原书中的日志解析代码从Mapper类中抽离了出来,封装成独立的功能,供Mapper调用。

    2. LogParser类设计成了单例模式,以便重复使用此对象,减少由不断创建对象带来的开销。

    3. 代码中有测试用例,可直接运行。

    4. 其中的IP解析类在上篇博文:利用纯真IP数据库解析IP地址位置信息

    package com.etl.utls; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.etl.utls.IpParser; public class LogParser { //Apache服务器日志信息的正则表达式 private static final String APACHE_LOG_REGEX = "^([0-9.]+)\\s([\\w.-]+)\\s([\\w.-]+)\\s\\[([^\\[\\]]+)\\]\\s\"((?:[^" + "\"]|\\\")+)\"\\s(\\d{3})\\s(\\d+|-)\\s\"((?:[^\"]|\\\")+)\"\\s\"((?:" + "[^\"]|\\\")+)\"\\s\"(.+)\"\\s(\\d+|-)\\s(\\d+|-)\\s(\\d+|-)\\s(.+)\\" + "s(\\d+|-)$"; //用户浏览器信息的正则表达式 private static final String USER_AGENT_REGEX = "^(.+)\\s\\((.+)\\)\\s(.+)\\s\\((.+)\\)\\s(.+)\\s(.+)$"; //测试日志一条 public static final String LOG = "120.196.145.58 " + "- " + "- " + "[11/Dec/2013:10:00:32 +0800] " + "\"GET /__utm.gif HTTP/1.1\" " + "200 " + "35 " + "\"http://easternmiles.ceair.com/flight/index.html\" " + "\"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/31.0.1650.63 Safari/537.36\" " + "\"BIGipServermu_122.119.122.14=192575354.20480.0000;Webtrends=120.196.145.58.1386724976245806;" + "uuid=5eb501f9-3586-4239-a15c-fe89aa14d624;userId=099;st=1\" " + "1482 " + "352 " + "- " + "easternmiles.ceair.com " + "794"; public static final String CANNOT_GET = "can not get"; //需要解析的字段 private String ipAddress = null; //ip地址 private String uniqueId = null; //uuid private String url = null; //访问的url地址 private String sessionId = null; //会话id private String sessionTimes = null; //服务器响应时间 private String areaAddress = null; //国家 private String localAddress = null; //地区 private String browserType = null; //浏览器类型 private String operationSys = null; //操作系统 private String referUrl = null; //访问的上一个页面url private String receiveTime = null; //服务器接收请求时间 private String userId = null; //用户id //保存cookies信息的map private static Map<String, String> cookies = new HashMap<String, String>(); //实例化的LogParser计数 private static int count = 0; //LogParser唯一标识 private int index = 0; private LogParser() { count++; index = count; } //初始化Log解析器 private void init() { setIpAddress(CANNOT_GET); setUniqueId(CANNOT_GET); setUrl(CANNOT_GET); setSessionId(CANNOT_GET); setSessionTimes(CANNOT_GET); setAreaAddress(CANNOT_GET); setLocalAddress(CANNOT_GET); setBrowserType(CANNOT_GET); setOperationSys(CANNOT_GET); setReferUrl(CANNOT_GET); setReceiveTime(CANNOT_GET); setUserId(CANNOT_GET); cookies.clear(); } /* * 解析一条log日志 * * @param log 一条日志 */ public void parse(String log) { //初始化Log解析器 init(); String ipStr = null; String receiveTimeStr = null; String urlStr = null; String referUrlStr = null; String userAgentStr = null; String cookieStr = null; String hostNameStr = null; //正则解析日志 Pattern pattern = Pattern.compile(APACHE_LOG_REGEX); Matcher matcher = pattern.matcher(LOG); if (matcher.find()) { // for (int i = 0; i <= matcher.groupCount(); i++) { // System.out.println("group-" + i + " : " + matcher.group(i)); // } //根据正则表达式将日志文件断开 ipStr = matcher.group(1); //远端主机(访客IP地址) receiveTimeStr = matcher.group(4); //服务器接收请求时间 urlStr = matcher.group(5); //请求的第一行(请求方式、请求的URL、请求所用协议) referUrlStr = matcher.group(8); //上一个访问的页面(访客来源) userAgentStr = matcher.group(9); //访客浏览器信息 cookieStr = matcher.group(10); //Cookie信息(包含uuid/userId/sessiontime) hostNameStr = matcher.group(14); //访问主机地址 //保存IP地址 ipAddress = ipStr; //解析IP地址 IpParser ipParser = new IpParser(); try { //根据IP地址得出所在区域 areaAddress = ipParser.parse(ipStr).split(" ")[0]; localAddress = ipParser.parse(ipStr).split(" ")[1]; } catch (Exception e) { e.printStackTrace(); } //格式化请求接受时间 DateFormat df = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss Z",Locale.US); try { Date date = df.parse(receiveTimeStr); //将时间转换为字符串 receiveTime = Long.toString(date.getTime()); } catch (ParseException e) { e.printStackTrace(); } //将url中的无效字符串丢弃 urlStr = urlStr.substring(5); //重新拼装成url字符串 url = hostNameStr + urlStr; //解析用户浏览器信息 pattern = Pattern.compile(USER_AGENT_REGEX); matcher = pattern.matcher(userAgentStr); if (matcher.find()) { // for (int i = 0; i <= matcher.groupCount(); i++) { // System.out.println("group-" + i + " : " + matcher.group(i)); // } //获取浏览器类型 browserType = matcher.group(5); //获取操作系统类型 operationSys = matcher.group(2).split(" ")[0]; } //保存上一个页面url referUrl = referUrlStr; //HashMap保存cookie信息 String[] strs = cookieStr.split(";"); for (int i = 0; i < strs.length; i++) { String[] kv = strs[i].split("="); String keyStr = kv[0]; String valStr = kv[1]; cookies.put(keyStr, valStr); } //获取uuid信息 uniqueId = cookies.get("uuid"); //获取账号信息 userId = cookies.get("userId"); //如果没有获取成功,说明用户没有登录 if (userId == null) { userId = "unlog_in"; } //获取sessionTimes sessionTimes = cookies.get("st"); //拼装成sessionId sessionId = uniqueId + "|" + sessionTimes; } } public String getIpAddress() { return ipAddress; } public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; } public String getUniqueId() { return uniqueId; } public void setUniqueId(String uniqueId) { this.uniqueId = uniqueId; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getSessionId() { return sessionId; } public void setSessionId(String sessionId) { this.sessionId = sessionId; } public String getSessionTimes() { return sessionTimes; } public void setSessionTimes(String sessionTimes) { this.sessionTimes = sessionTimes; } public String getAreaAddress() { return areaAddress; } public void setAreaAddress(String areaAddress) { this.areaAddress = areaAddress; } public String getLocalAddress() { return localAddress; } public void setLocalAddress(String localAddress) { this.localAddress = localAddress; } public String getBrowserType() { return browserType; } public void setBrowserType(String browserType) { this.browserType = browserType; } public String getOperationSys() { return operationSys; } public void setOperationSys(String operationSys) { this.operationSys = operationSys; } public String getReferUrl() { return referUrl; } public void setReferUrl(String referUrl) { this.referUrl = referUrl; } public String getReceiveTime() { return receiveTime; } public void setReceiveTime(String receiveTime) { this.receiveTime = receiveTime; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public int getIndex() { return index; } /* * 测试 */ public static void main(String[] args) { //获取日志解析对象 LogParser logParser = new LogParser(); //解析测试用例日志 logParser.parse(LogParser.LOG); String mapOutKey = logParser.getSessionId() + "&" + logParser.getReceiveTime(); String mapOutValue = logParser.getIpAddress() + "\n" + logParser.getUniqueId() + "\n" + logParser.getUrl() + "\n" + logParser.getSessionId() + "\n" + logParser.getSessionTimes() + "\n" + logParser.getAreaAddress() + "\n" + logParser.getLocalAddress() + "\n" + logParser.getBrowserType() + "\n" + logParser.getOperationSys() + "\n" + logParser.getReferUrl() + "\n" + logParser.getReceiveTime() + "\n" + logParser.getUserId(); System.out.println("mapOutKey: " + mapOutKey + "\nmapOutValue: " + mapOutValue); } }

     


    最新回复(0)