Skip to content

Commit 8f3e389

Browse files
committed
Implemented localized logging of HTTP Exchange operations
1 parent aa0e922 commit 8f3e389

File tree

11 files changed

+340
-5
lines changed

11 files changed

+340
-5
lines changed

src/main/java/aquality/selenium/browser/devtools/DevToolsHandling.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,12 @@ HasDevTools getDevToolsProvider() {
4343
}
4444

4545
private DevTools getDevTools() {
46+
return getDevTools("default");
47+
}
48+
49+
private DevTools getDevTools(String handleToLog) {
4650
if (session == null) {
51+
logger.info("loc.browser.devtools.session.get", handleToLog);
4752
session = devToolsProvider.getDevTools();
4853
}
4954
return session;
@@ -74,7 +79,6 @@ private void logCommandResult(Object result) {
7479
* @return The active session to use to communicate with the Chromium Developer Tools debugging protocol.
7580
*/
7681
public DevTools getDevToolsSession() {
77-
logger.info("loc.browser.devtools.session.get", "default");
7882
getDevTools().createSessionIfThereIsNotOne();
7983
return session;
8084
}
@@ -89,8 +93,7 @@ public DevTools getDevToolsSession() {
8993
* @return The active session to use to communicate with the Chromium Developer Tools debugging protocol.
9094
*/
9195
public DevTools getDevToolsSession(String windowHandle) {
92-
logger.info("loc.browser.devtools.session.get", windowHandle);
93-
getDevTools().createSessionIfThereIsNotOne(windowHandle);
96+
getDevTools(windowHandle).createSessionIfThereIsNotOne(windowHandle);
9497
return session;
9598
}
9699

src/main/java/aquality/selenium/browser/devtools/NetworkHandling.java

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,26 @@
22

33
import aquality.selenium.browser.AqualityServices;
44
import aquality.selenium.core.localization.ILocalizedLogger;
5+
import aquality.selenium.logging.HttpExchangeLoggingOptions;
6+
import org.apache.commons.lang3.StringUtils;
57
import org.openqa.selenium.Credentials;
68
import org.openqa.selenium.UsernameAndPassword;
79
import org.openqa.selenium.devtools.NetworkInterceptor;
810
import org.openqa.selenium.devtools.idealized.Network;
9-
import org.openqa.selenium.devtools.v85.network.model.RequestWillBeSent;
10-
import org.openqa.selenium.devtools.v85.network.model.ResponseReceived;
11+
import org.openqa.selenium.devtools.v85.network.model.*;
1112
import org.openqa.selenium.remote.http.*;
1213

1314
import java.net.URI;
15+
import java.util.ArrayList;
16+
import java.util.List;
1417
import java.util.Optional;
1518
import java.util.function.Consumer;
1619
import java.util.function.Function;
1720
import java.util.function.Predicate;
1821
import java.util.function.Supplier;
1922

2023
import static aquality.selenium.browser.AqualityServices.getBrowser;
24+
import static aquality.selenium.logging.LocalizedLoggerUtility.logByLevel;
2125
import static org.openqa.selenium.devtools.v85.network.Network.*;
2226

2327
/**
@@ -145,6 +149,74 @@ public void clearListeners() {
145149
tools.clearListeners();
146150
}
147151

152+
/**
153+
* Enables HTTP Request/Response logging with default {@link HttpExchangeLoggingOptions}.
154+
*/
155+
public void enableHttpExchangeLogging() {
156+
enableHttpExchangeLogging(new HttpExchangeLoggingOptions());
157+
}
158+
159+
private String formatHeaders(Headers headers) {
160+
List<String> formattedHeaders = new ArrayList<>();
161+
headers.forEach((key, value) -> formattedHeaders.add(String.format("%s\t%s: %s", System.lineSeparator(), key, value)));
162+
return String.join(",", formattedHeaders);
163+
}
164+
165+
private Consumer<RequestWillBeSent> getRequestLogger(HttpExchangeLoggingOptions loggingOptions) {
166+
return requestWillBeSent -> {
167+
Request request = requestWillBeSent.getRequest();
168+
if (loggingOptions.getRequestInfo().isEnabled()) {
169+
logByLevel(loggingOptions.getRequestInfo().getLogLevel(),
170+
"loc.browser.network.event.requestsent.log.info",
171+
request.getMethod(), request.getUrl() + request.getUrlFragment().orElse(""), requestWillBeSent.getRequestId());
172+
}
173+
if (loggingOptions.getRequestHeaders().isEnabled() && !request.getHeaders().isEmpty()) {
174+
logByLevel(loggingOptions.getRequestHeaders().getLogLevel(),
175+
"loc.browser.network.event.requestsent.log.headers",
176+
formatHeaders(request.getHeaders()));
177+
}
178+
if (loggingOptions.getRequestPostData().isEnabled() && request.getHasPostData().orElse(false)) {
179+
logByLevel(loggingOptions.getRequestPostData().getLogLevel(),
180+
"loc.browser.network.event.requestsent.log.data",
181+
request.getPostData().orElse(null));
182+
}
183+
};
184+
}
185+
186+
private Consumer<ResponseReceived> getResponseLogger(HttpExchangeLoggingOptions loggingOptions) {
187+
return responseReceived -> {
188+
Response response = responseReceived.getResponse();
189+
RequestId requestId = responseReceived.getRequestId();
190+
if (loggingOptions.getResponseInfo().isEnabled()) {
191+
logByLevel(loggingOptions.getResponseInfo().getLogLevel(),
192+
"loc.browser.network.event.responsereceived.log.info",
193+
response.getStatus(), response.getUrl(), responseReceived.getType().toString(), requestId);
194+
}
195+
if (loggingOptions.getResponseHeaders().isEnabled() && !response.getHeaders().isEmpty()) {
196+
logByLevel(loggingOptions.getResponseHeaders().getLogLevel(),
197+
"loc.browser.network.event.responsereceived.log.headers",
198+
formatHeaders(response.getHeaders()));
199+
}
200+
if (loggingOptions.getResponseBody().isEnabled()) {
201+
String responseBody = tools.sendCommand(org.openqa.selenium.devtools.v85.network.Network.getResponseBody(requestId)).getBody();
202+
if (StringUtils.isNotEmpty(responseBody)) {
203+
logByLevel(loggingOptions.getResponseBody().getLogLevel(),
204+
"loc.browser.network.event.responsereceived.log.body",
205+
responseBody);
206+
}
207+
}
208+
};
209+
}
210+
211+
/**
212+
* Enables HTTP Request/Response logging.
213+
* @param loggingOptions logging parameters {@link HttpExchangeLoggingOptions}.
214+
*/
215+
public void enableHttpExchangeLogging(HttpExchangeLoggingOptions loggingOptions) {
216+
addRequestListener(getRequestLogger(loggingOptions));
217+
addResponseListener(getResponseLogger(loggingOptions));
218+
}
219+
148220
/**
149221
* Starts network interceptor.
150222
* @param httpHandler HTTP handler.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package aquality.selenium.logging;
2+
3+
/**
4+
* HTTP Request/Response logging options.
5+
*/
6+
public class HttpExchangeLoggingOptions {
7+
private LoggingParameters requestInfo = new LoggingParameters(true, LogLevel.INFO);
8+
private LoggingParameters requestHeaders = new LoggingParameters(true, LogLevel.DEBUG);
9+
private LoggingParameters requestPostData = new LoggingParameters(false, LogLevel.DEBUG);
10+
private LoggingParameters responseInfo = new LoggingParameters(true, LogLevel.INFO);
11+
private LoggingParameters responseHeaders = new LoggingParameters(true, LogLevel.DEBUG);
12+
private LoggingParameters responseBody = new LoggingParameters(false, LogLevel.DEBUG);
13+
14+
/**
15+
* Gets logging parameters of general request info: Method, URL, Request ID.
16+
* @return request info logging parameters.
17+
*/
18+
public LoggingParameters getRequestInfo() {
19+
return requestInfo;
20+
}
21+
22+
/**
23+
* Sets logging parameters of general request info: Method, URL, Request ID.
24+
*/
25+
public void setRequestInfo(LoggingParameters requestInfo) {
26+
this.requestInfo = requestInfo;
27+
}
28+
29+
/**
30+
* Gets logging parameters of request headers.
31+
* @return logging parameters of request headers.
32+
*/
33+
public LoggingParameters getRequestHeaders() {
34+
return requestHeaders;
35+
}
36+
37+
/**
38+
* Sets logging parameters of request headers.
39+
*/
40+
public void setRequestHeaders(LoggingParameters requestHeaders) {
41+
this.requestHeaders = requestHeaders;
42+
}
43+
44+
/**
45+
* Gets logging parameters of request POST data.
46+
* @return logging parameters of request POST data.
47+
*/
48+
public LoggingParameters getRequestPostData() {
49+
return requestPostData;
50+
}
51+
52+
/**
53+
* Sets logging parameters of request POST data.
54+
*/
55+
public void setRequestPostData(LoggingParameters requestPostData) {
56+
this.requestPostData = requestPostData;
57+
}
58+
59+
/**
60+
* Gets logging parameters of general response info: Status code, URL, Resource type, Request ID.
61+
* @return logging parameters of general response info.
62+
*/
63+
public LoggingParameters getResponseInfo() {
64+
return responseInfo;
65+
}
66+
67+
/**
68+
* Sets logging parameters of general response info: Status code, URL, Resource type, Request ID.
69+
*/
70+
public void setResponseInfo(LoggingParameters responseInfo) {
71+
this.responseInfo = responseInfo;
72+
}
73+
74+
/**
75+
* Gets logging parameters of response headers.
76+
* @return logging parameters of response headers.
77+
*/
78+
public LoggingParameters getResponseHeaders() {
79+
return responseHeaders;
80+
}
81+
82+
/**
83+
* Sets logging parameters of response headers.
84+
*/
85+
public void setResponseHeaders(LoggingParameters responseHeaders) {
86+
this.responseHeaders = responseHeaders;
87+
}
88+
89+
/**
90+
* Gets logging parameters of response body.
91+
* @return logging parameters of response body.
92+
*/
93+
public LoggingParameters getResponseBody() {
94+
return responseBody;
95+
}
96+
97+
/**
98+
* Sets logging parameters of response body.
99+
*/
100+
public void setResponseBody(LoggingParameters responseBody) {
101+
this.responseBody = responseBody;
102+
}
103+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package aquality.selenium.logging;
2+
3+
import static aquality.selenium.browser.AqualityServices.getLocalizedLogger;
4+
5+
/**
6+
* Wrapper over the {@link aquality.selenium.core.localization.ILocalizedLogger}.
7+
*/
8+
public class LocalizedLoggerUtility {
9+
private LocalizedLoggerUtility() throws InstantiationException {
10+
throw new InstantiationException("Utility class");
11+
}
12+
13+
/**
14+
* Logging of localized messages with a specific log level.
15+
* @param logLevel logging level.
16+
* @param messageKey localized message key.
17+
* @param args arguments for the localized message.
18+
*/
19+
public static void logByLevel(LogLevel logLevel, String messageKey, Object... args) {
20+
switch (logLevel) {
21+
case DEBUG: {
22+
getLocalizedLogger().debug(messageKey, args);
23+
break;
24+
}
25+
case INFO: {
26+
getLocalizedLogger().info(messageKey, args);
27+
break;
28+
}
29+
case WARN: {
30+
getLocalizedLogger().warn(messageKey, args);
31+
break;
32+
}
33+
case ERROR: {
34+
getLocalizedLogger().error(messageKey, args);
35+
break;
36+
}
37+
case FATAL: {
38+
getLocalizedLogger().fatal(messageKey, new Throwable(), args);
39+
break;
40+
}
41+
default:
42+
throw new IllegalArgumentException(String.format("Localized logging at level [ %s] is not supported.", logLevel));
43+
}
44+
}
45+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package aquality.selenium.logging;
2+
3+
/**
4+
* Logging level for specific features, such as HTTP Exchange.
5+
*/
6+
public enum LogLevel {
7+
DEBUG,
8+
INFO,
9+
WARN,
10+
ERROR,
11+
FATAL
12+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package aquality.selenium.logging;
2+
3+
/**
4+
* Logging parameters for specific features, such as HTTP Exchange.
5+
*/
6+
public class LoggingParameters {
7+
private final boolean enabled;
8+
private final LogLevel logLevel;
9+
10+
/**
11+
* Initializes logging parameters.
12+
*/
13+
public LoggingParameters(boolean enabled, LogLevel logLevel) {
14+
15+
this.enabled = enabled;
16+
this.logLevel = logLevel;
17+
}
18+
19+
/**
20+
* Logging level for the specific feature.
21+
* @return logging level for the specific feature.
22+
*/
23+
public LogLevel getLogLevel() {
24+
return logLevel;
25+
}
26+
27+
/**
28+
* Whether feature logging should be enabled or not.
29+
* @return true if the feature is enabled, false otherwise.
30+
*/
31+
public boolean isEnabled() {
32+
return enabled;
33+
}
34+
}

src/main/resources/localization/be.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@
9494
"loc.browser.network.filter.clear": "Ачышчаем фільтр сеткавых падзеяў",
9595
"loc.browser.network.filter.set": "Задаем фільтр сеткавых падзеяў",
9696
"loc.browser.network.event.requestsent.add": "Падпісваемся на падзею адпраўкі сеткавага запыта",
97+
"loc.browser.network.event.requestsent.log.info": "Адпраўлены HTTP запыт:\r\nМетад: \t\t%1$s, \r\nURL: \t\t\t%2$s, \r\nID запыта: \t%3$s",
98+
"loc.browser.network.event.requestsent.log.headers": "Загалоўкі запыта:\r\n{{%s\r\n}}",
99+
"loc.browser.network.event.requestsent.log.data": "POST дадзеныя запыта:\r\n{%s}",
100+
"loc.browser.network.event.responsereceived.log.info": "Атрыманы HTTP адказ:\r\nСтатус-код: \t%1$s, \r\nURL: \t\t\t%2$s, \r\nТып рэсурса: \t%3$s, \r\nID запыта: \t%4$s",
101+
"loc.browser.network.event.responsereceived.log.headers": "Загалоўкі адказа:\r\n{{%s\r\n}}",
102+
"loc.browser.network.event.responsereceived.log.body": "Цела адказа:\r\n{%s}",
97103
"loc.browser.network.event.responsereceived.add": "Падпісваемся на падзею атрымання сеткавага адказа",
98104
"loc.browser.network.interceptor.start": "Пачынаем перахоп сеткавых падзеяў",
99105
"loc.browser.javascript.initializationscripts.get": "Атрымліваем ініцыялізацыйныя скрыпты",

src/main/resources/localization/en.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@
9494
"loc.browser.network.filter.clear": "Clearing the network events filter",
9595
"loc.browser.network.filter.set": "Setting the network events filter",
9696
"loc.browser.network.event.requestsent.add": "Subscribing to Network Request Sent event",
97+
"loc.browser.network.event.requestsent.log.info": "Send HTTP Request:\r\nMethod: \t\t%1$s, \r\nURL: \t\t\t%2$s, \r\nRequest ID: \t%3$s",
98+
"loc.browser.network.event.requestsent.log.headers": "Request headers:\r\n{{%s\r\n}}",
99+
"loc.browser.network.event.requestsent.log.data": "Request POST data:\r\n{%s}",
100+
"loc.browser.network.event.responsereceived.log.info": "Received HTTP Response:\r\nStatus code: \t%1$s, \r\nURL: \t\t\t%2$s, \r\nResource type: \t%3$s, \r\nRequest ID: \t%4$s",
101+
"loc.browser.network.event.responsereceived.log.headers": "Response headers:\r\n{{%s\r\n}}",
102+
"loc.browser.network.event.responsereceived.log.body": "Response body:\r\n{%s}",
97103
"loc.browser.network.event.responsereceived.add": "Subscribing to Network Response Received event",
98104
"loc.browser.network.interceptor.start": "Starting network events interception",
99105
"loc.browser.javascript.initializationscripts.get": "Getting initialization JavaScripts",

src/main/resources/localization/ru.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@
9494
"loc.browser.network.filter.clear": "Очистка фильтра сетевый событий",
9595
"loc.browser.network.filter.set": "Задание фильтра сетевых событий",
9696
"loc.browser.network.event.requestsent.add": "Подписываемся на событие отправки сетевого запроса",
97+
"loc.browser.network.event.requestsent.log.info": "Отправлен HTTP запрос:\r\nМетод: \t\t%1$s, \r\nURL: \t\t\t%2$s, \r\nID запроса: \t%3$s",
98+
"loc.browser.network.event.requestsent.log.headers": "Заголовки запроса:\r\n{{%s\r\n}}",
99+
"loc.browser.network.event.requestsent.log.data": "POST данные запроса:\r\n{%s}",
100+
"loc.browser.network.event.responsereceived.log.info": "Получен HTTP ответ:\r\nСтатус-код: \t%1$s, \r\nURL: \t\t\t%2$s, \r\nТип ресурса: \t%3$s, \r\nID запроса: \t%4$s",
101+
"loc.browser.network.event.responsereceived.log.headers": "Заголовки ответа:\r\n{{%s\r\n}}",
102+
"loc.browser.network.event.responsereceived.log.body": "Тело ответа:\r\n{%s}",
97103
"loc.browser.network.event.responsereceived.add": "Подписываемся на событие получения сетевого ответа",
98104
"loc.browser.network.event.listeners.clear": "Очистка списка отслеживаемых событий",
99105
"loc.browser.network.interceptor.start": "Начинаем перехват сетевых событий",

0 commit comments

Comments
 (0)