0
# Browser Logging
1
2
Browser console log collection, filtering, and event stream management with level conversion and timestamp handling through the v115Log class.
3
4
## Capabilities
5
6
### Log Domain
7
8
Comprehensive browser console log management with event streaming and level conversion.
9
10
```java { .api }
11
/**
12
* Browser log domain for console log collection and management
13
* Implements the idealized Log interface for version independence
14
*/
15
public class v115Log implements Log {
16
/**
17
* Enable log domain for console log collection
18
* @return Command to enable log domain
19
*/
20
public Command<Void> enable();
21
22
/**
23
* Clear all browser console logs
24
* @return Command to clear browser logs
25
*/
26
public Command<Void> clear();
27
28
/**
29
* Get log entry added event stream
30
* @return Event stream for new log entries
31
*/
32
public Event<LogEntry> entryAdded();
33
}
34
```
35
36
### Log Collection
37
38
Enable browser log collection and receive log entries as they are created.
39
40
**Usage Examples:**
41
42
```java
43
import org.openqa.selenium.devtools.v115.v115Log;
44
import org.openqa.selenium.devtools.idealized.log.model.LogEntry;
45
import java.util.logging.Level;
46
47
// Create log domain
48
v115Log log = new v115Log();
49
50
// Enable log collection
51
devTools.send(log.enable());
52
53
// Listen for log entries
54
devTools.addListener(log.entryAdded(), logEntry -> {
55
System.out.println("Browser Log Entry:");
56
System.out.println(" Kind: " + logEntry.getKind());
57
58
org.openqa.selenium.logging.LogEntry entry = logEntry.getEntry();
59
System.out.println(" Level: " + entry.getLevel());
60
System.out.println(" Timestamp: " + new Date(entry.getTimestamp()));
61
System.out.println(" Message: " + entry.getMessage());
62
System.out.println();
63
});
64
65
// Navigate and generate logs
66
driver.get("https://example.com");
67
68
// Generate console logs from browser
69
driver.executeScript("console.log('Information message');");
70
driver.executeScript("console.warn('Warning message');");
71
driver.executeScript("console.error('Error message');");
72
73
// JavaScript error
74
driver.executeScript("throw new Error('Test error');");
75
```
76
77
### Log Level Conversion
78
79
The v115Log class automatically converts CDP log levels to standard Java logging levels.
80
81
**Supported Level Mappings:**
82
83
```java { .api }
84
/**
85
* Convert CDP log level to Java logging level
86
* @param level CDP LogEntry.Level enum
87
* @return Java logging Level
88
*/
89
private Level fromCdpLevel(LogEntry.Level level);
90
```
91
92
**Level Conversion Table:**
93
94
| CDP Level | Java Level | Description |
95
|-----------|------------|-------------|
96
| `verbose` | `FINEST` | Detailed debug information |
97
| `info` | `INFO` | General information messages |
98
| `warning` | `WARNING` | Warning conditions |
99
| `error` | `SEVERE` | Error conditions |
100
| (default) | `INFO` | Fallback for unknown levels |
101
102
**Usage Examples:**
103
104
```java
105
// The level conversion happens automatically in log event processing
106
devTools.addListener(log.entryAdded(), logEntry -> {
107
org.openqa.selenium.logging.LogEntry entry = logEntry.getEntry();
108
Level javaLevel = entry.getLevel();
109
110
// Handle different log levels
111
switch (javaLevel.getName()) {
112
case "SEVERE" -> System.err.println("ERROR: " + entry.getMessage());
113
case "WARNING" -> System.out.println("WARN: " + entry.getMessage());
114
case "INFO" -> System.out.println("INFO: " + entry.getMessage());
115
case "FINEST" -> System.out.println("DEBUG: " + entry.getMessage());
116
default -> System.out.println("LOG: " + entry.getMessage());
117
}
118
});
119
```
120
121
### Log Management
122
123
Clear browser logs and manage log collection lifecycle.
124
125
**Usage Examples:**
126
127
```java
128
// Clear existing logs before starting test
129
devTools.send(log.clear());
130
131
// Run test operations
132
driver.get("https://example.com");
133
performTestOperations();
134
135
// Clear logs after test
136
devTools.send(log.clear());
137
138
// Disable log collection when done
139
// Note: Log domain doesn't have explicit disable - use DevTools session lifecycle
140
```
141
142
### Advanced Log Filtering
143
144
Filter and categorize log entries based on content and level.
145
146
**Usage Examples:**
147
148
```java
149
import java.util.concurrent.ConcurrentHashMap;
150
import java.util.concurrent.atomic.AtomicInteger;
151
152
// Set up log categorization
153
Map<String, AtomicInteger> logCounts = new ConcurrentHashMap<>();
154
List<String> errorMessages = Collections.synchronizedList(new ArrayList<>());
155
List<String> networkLogs = Collections.synchronizedList(new ArrayList<>());
156
157
devTools.addListener(log.entryAdded(), logEntry -> {
158
org.openqa.selenium.logging.LogEntry entry = logEntry.getEntry();
159
String message = entry.getMessage();
160
Level level = entry.getLevel();
161
162
// Count logs by level
163
String levelName = level.getName();
164
logCounts.computeIfAbsent(levelName, k -> new AtomicInteger(0)).incrementAndGet();
165
166
// Collect error messages
167
if (level == Level.SEVERE) {
168
errorMessages.add(message);
169
}
170
171
// Filter network-related logs
172
if (message.contains("Failed to load resource") ||
173
message.contains("XMLHttpRequest") ||
174
message.contains("fetch")) {
175
networkLogs.add(message);
176
}
177
178
// Filter security warnings
179
if (message.contains("Mixed Content") ||
180
message.contains("Insecure") ||
181
message.contains("HTTPS")) {
182
System.out.println("SECURITY WARNING: " + message);
183
}
184
});
185
186
// Generate logs and analyze
187
driver.get("https://example.com");
188
performComplexOperations();
189
190
// Print analysis
191
System.out.println("\nLog Analysis:");
192
logCounts.forEach((level, count) ->
193
System.out.println(level + ": " + count.get() + " entries"));
194
195
System.out.println("\nErrors found: " + errorMessages.size());
196
errorMessages.forEach(error -> System.out.println(" - " + error));
197
198
System.out.println("\nNetwork issues: " + networkLogs.size());
199
networkLogs.forEach(networkLog -> System.out.println(" - " + networkLog));
200
```
201
202
### Log Pattern Matching
203
204
Identify specific log patterns for automated testing and monitoring.
205
206
**Usage Examples:**
207
208
```java
209
import java.util.regex.Pattern;
210
import java.util.concurrent.CompletableFuture;
211
212
// Set up pattern-based log monitoring
213
Pattern errorPattern = Pattern.compile("Error:.*|Uncaught.*|TypeError:.*", Pattern.CASE_INSENSITIVE);
214
Pattern apiErrorPattern = Pattern.compile("HTTP.*[45]\\d\\d|API.*error|Request failed", Pattern.CASE_INSENSITIVE);
215
Pattern performancePattern = Pattern.compile("Performance.*|Slow.*|Timeout.*", Pattern.CASE_INSENSITIVE);
216
217
CompletableFuture<String> firstErrorFuture = new CompletableFuture<>();
218
List<String> apiErrors = Collections.synchronizedList(new ArrayList<>());
219
List<String> performanceIssues = Collections.synchronizedList(new ArrayList<>());
220
221
devTools.addListener(log.entryAdded(), logEntry -> {
222
String message = logEntry.getEntry().getMessage();
223
224
// Detect first JavaScript error
225
if (errorPattern.matcher(message).find() && !firstErrorFuture.isDone()) {
226
firstErrorFuture.complete(message);
227
}
228
229
// Collect API errors
230
if (apiErrorPattern.matcher(message).find()) {
231
apiErrors.add(message);
232
}
233
234
// Collect performance issues
235
if (performancePattern.matcher(message).find()) {
236
performanceIssues.add(message);
237
}
238
});
239
240
// Run operations and wait for specific conditions
241
driver.get("https://app.example.com");
242
243
try {
244
// Wait for first error (with timeout)
245
String firstError = firstErrorFuture.get(10, TimeUnit.SECONDS);
246
System.out.println("First error detected: " + firstError);
247
} catch (TimeoutException e) {
248
System.out.println("No errors detected within timeout");
249
} catch (Exception e) {
250
System.err.println("Error waiting for log: " + e.getMessage());
251
}
252
253
// Analyze collected issues
254
System.out.println("API errors detected: " + apiErrors.size());
255
System.out.println("Performance issues detected: " + performanceIssues.size());
256
```
257
258
### Integration with WebDriver Logs
259
260
Combine DevTools logs with WebDriver's built-in logging capabilities.
261
262
**Usage Examples:**
263
264
```java
265
import org.openqa.selenium.logging.LogType;
266
import org.openqa.selenium.logging.LoggingPreferences;
267
import org.openqa.selenium.chrome.ChromeOptions;
268
import org.openqa.selenium.logging.LogEntries;
269
270
// Set up WebDriver logging (complementary to DevTools logging)
271
ChromeOptions options = new ChromeOptions();
272
LoggingPreferences logPrefs = new LoggingPreferences();
273
logPrefs.enable(LogType.BROWSER, Level.ALL);
274
logPrefs.enable(LogType.PERFORMANCE, Level.INFO);
275
options.setCapability(CapabilityType.LOGGING_PREFS, logPrefs);
276
277
ChromeDriver driver = new ChromeDriver(options);
278
DevTools devTools = driver.getDevTools();
279
devTools.createSession();
280
281
// Enable DevTools logging
282
v115Log devToolsLog = new v115Log();
283
devTools.send(devToolsLog.enable());
284
285
// Collect logs from both sources
286
List<String> devToolsLogs = Collections.synchronizedList(new ArrayList<>());
287
List<String> webDriverLogs = Collections.synchronizedList(new ArrayList<>());
288
289
// DevTools log collection
290
devTools.addListener(devToolsLog.entryAdded(), logEntry -> {
291
devToolsLogs.add("DevTools: " + logEntry.getEntry().getMessage());
292
});
293
294
// Perform operations
295
driver.get("https://example.com");
296
performTestOperations();
297
298
// Collect WebDriver logs
299
LogEntries browserLogs = driver.manage().logs().get(LogType.BROWSER);
300
browserLogs.forEach(entry -> {
301
webDriverLogs.add("WebDriver: " + entry.getMessage());
302
});
303
304
// Compare and analyze both log sources
305
System.out.println("DevTools logs: " + devToolsLogs.size());
306
System.out.println("WebDriver logs: " + webDriverLogs.size());
307
308
// Find overlapping entries
309
Set<String> uniqueMessages = new HashSet<>();
310
devToolsLogs.forEach(log -> uniqueMessages.add(log.substring(log.indexOf(":") + 2)));
311
webDriverLogs.forEach(log -> uniqueMessages.add(log.substring(log.indexOf(":") + 2)));
312
313
System.out.println("Unique log messages: " + uniqueMessages.size());
314
```
315
316
## Timestamp Handling
317
318
### CDP Timestamp Conversion
319
320
The v115Log class handles CDP timestamp conversion with error recovery.
321
322
```java { .api }
323
/**
324
* Convert CDP timestamp to milliseconds since epoch
325
* @param timestamp CDP Timestamp object
326
* @return Long timestamp in milliseconds, or current time if conversion fails
327
*/
328
private long fromCdpTimestamp(Timestamp timestamp);
329
```
330
331
**Usage Examples:**
332
333
```java
334
// Timestamp conversion happens automatically, but you can access it
335
devTools.addListener(log.entryAdded(), logEntry -> {
336
org.openqa.selenium.logging.LogEntry entry = logEntry.getEntry();
337
long timestamp = entry.getTimestamp();
338
339
// Convert to various time formats
340
Instant instant = Instant.ofEpochMilli(timestamp);
341
LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
342
343
System.out.println("Log timestamp: " + dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
344
System.out.println("Relative time: " + Duration.between(Instant.now(), instant).toMillis() + "ms ago");
345
});
346
```
347
348
## Error Handling
349
350
### Malformed Timestamps
351
352
The system gracefully handles malformed CDP timestamps:
353
354
```java
355
// Automatic fallback to current system time for invalid timestamps
356
private long fromCdpTimestamp(Timestamp timestamp) {
357
try {
358
return Long.parseLong(timestamp.toString());
359
} catch (NumberFormatException e) {
360
// Return current time as fallback
361
return System.currentTimeMillis();
362
}
363
}
364
```
365
366
### Log Collection Failures
367
368
Handle cases where log collection fails or is interrupted:
369
370
```java
371
try {
372
devTools.send(log.enable());
373
System.out.println("Log collection enabled");
374
} catch (Exception e) {
375
System.err.println("Failed to enable log collection: " + e.getMessage());
376
// Continue without DevTools logging, rely on WebDriver logs
377
}
378
379
// Safe log clearing
380
try {
381
devTools.send(log.clear());
382
System.out.println("Browser logs cleared");
383
} catch (Exception e) {
384
System.err.println("Failed to clear logs: " + e.getMessage());
385
// Not critical - continue operation
386
}
387
```
388
389
### Memory Management
390
391
Prevent memory leaks when collecting large numbers of log entries:
392
393
```java
394
// Use bounded collections for log storage
395
private final Queue<String> recentLogs = new ArrayDeque<String>() {
396
@Override
397
public boolean add(String item) {
398
if (size() >= 1000) { // Keep only last 1000 logs
399
poll();
400
}
401
return super.add(item);
402
}
403
};
404
405
devTools.addListener(log.entryAdded(), logEntry -> {
406
String message = logEntry.getEntry().getMessage();
407
408
// Store with size limit
409
synchronized (recentLogs) {
410
recentLogs.add(message);
411
}
412
});
413
```