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

Last change on this file since 229 was 225, checked in by sherbold, 13 years ago

+ implemented replay generation for de.ugoe.cs.eventbench.web.data.WebRequest?

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