source: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/web/WeblogParser.java @ 200

Last change on this file since 200 was 177, checked in by sherbold, 13 years ago
  • Changed handling of invalid URIs when parsing web usage logs. Before, the parsing was aborted, now, the entry with the invalid URI is ignored.
  • Property svn:mime-type set to text/plain
File size: 7.4 KB
Line 
1package de.ugoe.cs.eventbench.web;
2
3import java.io.FileNotFoundException;
4import java.io.IOException;
5import java.net.URI;
6import java.net.URISyntaxException;
7import java.text.ParseException;
8import java.text.SimpleDateFormat;
9import java.util.ArrayList;
10import java.util.HashMap;
11import java.util.LinkedList;
12import java.util.List;
13import java.util.Map;
14
15import de.ugoe.cs.eventbench.web.data.WebEvent;
16import de.ugoe.cs.util.FileTools;
17import de.ugoe.cs.util.console.Console;
18
19/**
20 * <p>
21 * Provides functionality to parse log files with web request.
22 * </p>
23 *
24 * @author Steffen Herbold
25 * @version 1.0
26 */
27public class WeblogParser {
28
29        /**
30         * <p>
31         * Timeout between two sessions in milliseconds.
32         * </p>
33         */
34        private long timeout;
35
36        /**
37         * <p>
38         * Minimal length of a session. All shorter sessions will be pruned.
39         * Default: 2
40         * </p>
41         */
42        private int minLength = 2;
43
44        /**
45         * <p>
46         * Collection of generated sequences.
47         * </p>
48         */
49        private List<List<WebEvent>> sequences;
50
51        /**
52         * <p>
53         * Name and path of the robot filter.
54         * </p>
55         */
56        private static final String ROBOTFILTERFILE = "misc/robotfilter.txt";
57
58        /**
59         * <p>
60         * Field that contains a regular expression that matches all robots
61         * contained in {@link #ROBOTFILTERFILE}.
62         * </p>
63         */
64        private String robotRegex = null;
65
66        /**
67         * <p>
68         * Constructor. Creates a new WeblogParser with a default timeout of
69         * 3,600,000 milliseconds (1 hour).
70         * </p>
71         */
72        public WeblogParser() {
73                this(3600000);
74        }
75
76        /**
77         * <p>
78         * Constructor. Creates a new WeblogParser.
79         * </p>
80         *
81         * @param timeout
82         *            session timeout
83         */
84        public WeblogParser(long timeout) {
85                this.timeout = timeout;
86        }
87
88        /**
89         * <p>
90         * Returns the generated event sequences.
91         * </p>
92         *
93         * @return generated event sequences
94         */
95        public List<List<WebEvent>> getSequences() {
96                return sequences;
97        }
98
99        /**
100         * <p>
101         * Sets the session timeout.
102         * </p>
103         *
104         * @param timeout
105         *            new session timeout
106         */
107        public void setTimeout(long timeout) {
108                this.timeout = timeout;
109        }
110
111        /**
112         * <p>
113         * Sets the minimal length of a session. All sessions that contain less
114         * events will be pruned.
115         * </p>
116         *
117         * @param minLength
118         *            new minimal length
119         */
120        public void setMinLength(int minLength) {
121                this.minLength = minLength;
122        }
123
124        /**
125         * <p>
126         * Parses a web log file.
127         * </p>
128         *
129         * @param filename
130         *            name and path of the log file
131         * @throws IOException
132         *             thrown if there is a problem with reading the log file
133         * @throws FileNotFoundException
134         *             thrown if the log file is not found
135         * @throws ParseException
136         *             thrown the date format is invalid
137         */
138        public void parseFile(String filename) throws IOException,
139                        FileNotFoundException, ParseException {
140                String[] lines = FileTools.getLinesFromFile(filename);
141
142                Map<String, List<Integer>> cookieSessionMap = new HashMap<String, List<Integer>>();
143                int lastId = -1;
144
145                SimpleDateFormat dateFormat = new SimpleDateFormat(
146                                "yyyy-MM-dd HH:mm:ss");
147                loadRobotRegex();
148
149                sequences = new ArrayList<List<WebEvent>>();
150
151                int lineCounter = 0;
152                for (String line : lines) {
153                        lineCounter++;
154                        String[] values = line.substring(1, line.length() - 1).split(
155                                        "\" \"");
156
157                        // use cookie as session identifier
158                        int cookieStart = values[0].lastIndexOf('.');
159                        String cookie = values[0].substring(cookieStart + 1);
160                        String dateString = values[1];
161                        long timestamp = dateFormat.parse(dateString).getTime();
162                        String uriString = values[2];
163                        // String ref = values[3]; // referer is not yet used!
164                        String agent;
165                        if (values.length > 4) {
166                                agent = values[4];
167                        } else {
168                                agent = "noagent";
169                        }
170
171                        List<String> postedVars = new ArrayList<String>();
172                        if (values.length == 6) { // post vars found
173                                for (String postVar : values[5].trim().split(" ")) {
174                                        postedVars.add(postVar);
175                                }
176                        }
177                        if (!isRobot(agent)) {
178                                try {
179                                        URI uri = new URI(uriString);
180                                        String path = uri.getPath();
181                                        List<String> getVars = extractGetVarsFromUri(uri);
182       
183                                        WebEvent event = new WebEvent(path, timestamp, postedVars,
184                                                        getVars);
185       
186                                        // find session and add event
187                                        List<Integer> sessionIds = cookieSessionMap.get(cookie);
188                                        if (sessionIds == null) {
189                                                sessionIds = new ArrayList<Integer>();
190                                                // start new session
191                                                sessionIds.add(++lastId);
192                                                cookieSessionMap.put(cookie, sessionIds);
193                                                sequences.add(new LinkedList<WebEvent>());
194                                        }
195                                        Integer lastSessionIndex = sessionIds
196                                                        .get(sessionIds.size() - 1);
197                                        List<WebEvent> lastSession = sequences.get(lastSessionIndex);
198                                        long lastEventTime = timestamp;
199                                        if (!lastSession.isEmpty()) {
200                                                lastEventTime = lastSession.get(lastSession.size() - 1)
201                                                                .getTimestamp();
202                                        }
203                                        if (timestamp - lastEventTime > timeout) {
204                                                sessionIds.add(++lastId);
205                                                List<WebEvent> newSession = new LinkedList<WebEvent>();
206                                                newSession.add(event);
207                                                sequences.add(newSession);
208                                        } else {
209                                                lastSession.add(event);
210                                        }
211                                } catch (URISyntaxException e) {
212                                        Console.traceln("Ignored line " + lineCounter + ": " + e.getMessage());
213                                }
214                        }
215                }
216                pruneShortSequences();
217        }
218
219        /**
220         * <p>
221         * Prunes sequences shorter than {@link #minLength}.
222         * </p>
223         */
224        private void pruneShortSequences() {
225                Console.traceln("" + sequences.size() + " user sequences found");
226                // prune sequences shorter than min-length
227                int i = 0;
228                while (i < sequences.size()) {
229                        if (sequences.get(i).size() < minLength) {
230                                sequences.remove(i);
231                        } else {
232                                i++;
233                        }
234                }
235                Console.traceln("" + sequences.size()
236                                + " remaining after pruning of sequences shorter than "
237                                + minLength);
238        }
239
240        /**
241         * <p>
242         * Reads {@link #ROBOTFILTERFILE} and creates a regular expression that
243         * matches all the robots defined in the file. The regular expression is
244         * stored in the field {@link #robotRegex}.
245         * </p>
246         *
247         * @throws IOException
248         *             thrown if there is a problem reading the robot filter
249         * @throws FileNotFoundException
250         *             thrown if the robot filter is not found
251         */
252        private void loadRobotRegex() throws IOException, FileNotFoundException {
253                String[] lines = FileTools.getLinesFromFile(ROBOTFILTERFILE);
254                StringBuilder regex = new StringBuilder();
255                for (int i = 0; i < lines.length; i++) {
256                        regex.append("(.*" + lines[i] + ".*)");
257                        if (i != lines.length - 1) {
258                                regex.append('|');
259                        }
260                }
261                robotRegex = regex.toString();
262        }
263
264        /**
265         * <p>
266         * Checks whether an agent is a robot.
267         * </p>
268         *
269         * @param agent
270         *            agent that is checked
271         * @return true, if the agent is a robot; false otherwise
272         */
273        private boolean isRobot(String agent) {
274                return agent.matches(robotRegex);
275        }
276
277        /**
278         * <p>
279         * Parses the URI and extracts the GET variables that have been passed.
280         * </p>
281         *
282         * @param uri
283         *            URI that is parsed
284         * @return a list with all GET variables
285         */
286        private List<String> extractGetVarsFromUri(URI uri) {
287                List<String> getVars = new ArrayList<String>();
288                String query = uri.getQuery();
289                if (query != null) {
290                        String[] paramPairs = query.split("&");
291                        for (String paramPair : paramPairs) {
292                                String[] paramSplit = paramPair.split("=");
293                                getVars.add(paramSplit[0]);
294                        }
295                }
296                return getVars;
297        }
298}
Note: See TracBrowser for help on using the repository browser.