Skip to content

Commit 2dcd1cf

Browse files
mp911dechristophstrobl
authored andcommitted
DATAES-504 - Add configuration options for logging and timeouts to ReactiveElasticsearchClient.
We now log HTTP requests and responses with the org.springframework.data.elasticsearch.client.WIRE logger for both, the HighLevelRestClient and our reactive client and associate a logging Id for improved traceability. Configuration of connection/socket timeouts is now available via the ClientConfiguration. Along the lines we also aligned entity handling to EntityOperations already common in other modules. EntityOperations centralizes how aspects of entities (versioning, retrieval of index name/index type) are handled. Original Pull Request: spring-projects#229
1 parent ba890cb commit 2dcd1cf

File tree

15 files changed

+1158
-266
lines changed

15 files changed

+1158
-266
lines changed

src/main/java/org/springframework/data/elasticsearch/client/ClientConfiguration.java

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package org.springframework.data.elasticsearch.client;
1717

1818
import java.net.InetSocketAddress;
19+
import java.net.SocketAddress;
20+
import java.time.Duration;
1921
import java.util.List;
2022
import java.util.Optional;
2123

@@ -99,6 +101,23 @@ static ClientConfiguration create(InetSocketAddress socketAddress) {
99101
*/
100102
Optional<SSLContext> getSslContext();
101103

104+
/**
105+
* Returns the {@link java.time.Duration connect timeout}.
106+
*
107+
* @see java.net.Socket#connect(SocketAddress, int)
108+
* @see io.netty.channel.ChannelOption#CONNECT_TIMEOUT_MILLIS
109+
*/
110+
Duration getConnectTimeout();
111+
112+
/**
113+
* Returns the {@link java.time.Duration socket timeout} which is typically applied as SO-timeout/read timeout.
114+
*
115+
* @see java.net.Socket#setSoTimeout(int)
116+
* @see io.netty.handler.timeout.ReadTimeoutHandler
117+
* @see io.netty.handler.timeout.WriteTimeoutHandler
118+
*/
119+
Duration getSocketTimeout();
120+
102121
/**
103122
* @author Christoph Strobl
104123
*/
@@ -146,38 +165,59 @@ default MaybeSecureClientConfigurationBuilder connectedToLocalhost() {
146165
/**
147166
* @author Christoph Strobl
148167
*/
149-
interface MaybeSecureClientConfigurationBuilder extends ClientConfigurationBuilderWithOptionalDefaultHeaders {
168+
interface MaybeSecureClientConfigurationBuilder extends TerminalClientConfigurationBuilder {
150169

151170
/**
152171
* Connect via {@literal https} <br />
153172
* <strong>NOTE</strong> You need to leave out the protocol in
154173
* {@link ClientConfigurationBuilderWithRequiredEndpoint#connectedTo(String)}.
155174
*
156-
* @return the {@link ClientConfigurationBuilderWithOptionalDefaultHeaders}.
175+
* @return the {@link TerminalClientConfigurationBuilder}.
157176
*/
158-
ClientConfigurationBuilderWithOptionalDefaultHeaders usingSsl();
177+
TerminalClientConfigurationBuilder usingSsl();
159178

160179
/**
161180
* Connect via {@literal https} using the given {@link SSLContext}.<br />
162181
* <strong>NOTE</strong> You need to leave out the protocol in
163182
* {@link ClientConfigurationBuilderWithRequiredEndpoint#connectedTo(String)}.
164183
*
165-
* @return the {@link ClientConfigurationBuilderWithOptionalDefaultHeaders}.
184+
* @return the {@link TerminalClientConfigurationBuilder}.
166185
*/
167-
ClientConfigurationBuilderWithOptionalDefaultHeaders usingSsl(SSLContext sslContext);
186+
TerminalClientConfigurationBuilder usingSsl(SSLContext sslContext);
168187
}
169188

170189
/**
171190
* @author Christoph Strobl
172191
* @author Mark Paluch
173192
*/
174-
interface ClientConfigurationBuilderWithOptionalDefaultHeaders {
193+
interface TerminalClientConfigurationBuilder {
175194

176195
/**
177196
* @param defaultHeaders must not be {@literal null}.
178-
* @return the {@link ClientConfigurationBuilderWithOptionalDefaultHeaders}
197+
* @return the {@link TerminalClientConfigurationBuilder}
198+
*/
199+
TerminalClientConfigurationBuilder withDefaultHeaders(HttpHeaders defaultHeaders);
200+
201+
/**
202+
* Configure a {@link java.time.Duration} connect timeout.
203+
*
204+
* @param connectTimeout the timeout to use.
205+
* @return the {@link TerminalClientConfigurationBuilder}
206+
* @see java.net.Socket#connect(SocketAddress, int)
207+
* @see io.netty.channel.ChannelOption#CONNECT_TIMEOUT_MILLIS
208+
*/
209+
TerminalClientConfigurationBuilder withConnectTimeout(Duration connectTimeout);
210+
211+
/**
212+
* Configure a {@link java.time.Duration socket timeout} which is typically applied as SO-timeout/read timeout.
213+
*
214+
* @param soTimeout the timeout to use.
215+
* @return the {@link TerminalClientConfigurationBuilder}
216+
* @see java.net.Socket#setSoTimeout(int)
217+
* @see io.netty.handler.timeout.ReadTimeoutHandler
218+
* @see io.netty.handler.timeout.WriteTimeoutHandler
179219
*/
180-
ClientConfigurationBuilderWithOptionalDefaultHeaders withDefaultHeaders(HttpHeaders defaultHeaders);
220+
TerminalClientConfigurationBuilder withSocketTimeout(Duration soTimeout);
181221

182222
/**
183223
* Build the {@link ClientConfiguration} object.

src/main/java/org/springframework/data/elasticsearch/client/ClientConfigurationBuilder.java

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,17 @@
1616
package org.springframework.data.elasticsearch.client;
1717

1818
import java.net.InetSocketAddress;
19+
import java.time.Duration;
1920
import java.util.ArrayList;
2021
import java.util.Arrays;
2122
import java.util.List;
2223
import java.util.stream.Collectors;
2324

2425
import javax.net.ssl.SSLContext;
2526

26-
import org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationBuilderWithOptionalDefaultHeaders;
2727
import org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationBuilderWithRequiredEndpoint;
2828
import org.springframework.data.elasticsearch.client.ClientConfiguration.MaybeSecureClientConfigurationBuilder;
29+
import org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder;
2930
import org.springframework.http.HttpHeaders;
3031
import org.springframework.lang.Nullable;
3132
import org.springframework.util.Assert;
@@ -44,8 +45,10 @@ class ClientConfigurationBuilder
4445
private HttpHeaders headers = HttpHeaders.EMPTY;
4546
private boolean useSsl;
4647
private @Nullable SSLContext sslContext;
48+
private Duration connectTimeout = Duration.ofSeconds(10);
49+
private Duration soTimeout = Duration.ofSeconds(5);
4750

48-
/*
51+
/*
4952
* (non-Javadoc)
5053
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationBuilderWithRequiredEndpoint#connectedTo(java.lang.String[])
5154
*/
@@ -58,7 +61,7 @@ public MaybeSecureClientConfigurationBuilder connectedTo(String... hostAndPorts)
5861
return this;
5962
}
6063

61-
/*
64+
/*
6265
* (non-Javadoc)
6366
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationBuilderWithRequiredEndpoint#connectedTo(java.net.InetSocketAddress[])
6467
*/
@@ -72,23 +75,23 @@ public MaybeSecureClientConfigurationBuilder connectedTo(InetSocketAddress... en
7275
return this;
7376
}
7477

75-
/*
78+
/*
7679
* (non-Javadoc)
7780
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.MaybeSecureClientConfigurationBuilder#usingSsl()
7881
*/
7982
@Override
80-
public ClientConfigurationBuilderWithOptionalDefaultHeaders usingSsl() {
83+
public TerminalClientConfigurationBuilder usingSsl() {
8184

8285
this.useSsl = true;
8386
return this;
8487
}
8588

86-
/*
89+
/*
8790
* (non-Javadoc)
8891
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.MaybeSecureClientConfigurationBuilder#usingSsl(javax.net.ssl.SSLContext)
8992
*/
9093
@Override
91-
public ClientConfigurationBuilderWithOptionalDefaultHeaders usingSsl(SSLContext sslContext) {
94+
public TerminalClientConfigurationBuilder usingSsl(SSLContext sslContext) {
9295

9396
Assert.notNull(sslContext, "SSL Context must not be null");
9497

@@ -97,26 +100,53 @@ public ClientConfigurationBuilderWithOptionalDefaultHeaders usingSsl(SSLContext
97100
return this;
98101
}
99102

100-
/*
103+
/*
101104
* (non-Javadoc)
102-
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationBuilderWithOptionalDefaultHeaders#withDefaultHeaders(org.springframework.http.HttpHeaders)
105+
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder#withDefaultHeaders(org.springframework.http.HttpHeaders)
103106
*/
104107
@Override
105-
public ClientConfigurationBuilderWithOptionalDefaultHeaders withDefaultHeaders(HttpHeaders defaultHeaders) {
108+
public TerminalClientConfigurationBuilder withDefaultHeaders(HttpHeaders defaultHeaders) {
106109

107110
Assert.notNull(defaultHeaders, "Default HTTP headers must not be null");
108111

109112
this.headers = defaultHeaders;
110113
return this;
111114
}
112115

113-
/*
116+
/*
117+
* (non-Javadoc)
118+
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder#withConnectTimeout(java.time.Duration)
119+
*/
120+
@Override
121+
public TerminalClientConfigurationBuilder withConnectTimeout(Duration connectTimeout) {
122+
123+
Assert.notNull(connectTimeout, "I/O timeout must not be null!");
124+
125+
this.connectTimeout = connectTimeout;
126+
return this;
127+
}
128+
129+
/*
130+
* (non-Javadoc)
131+
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder#withTimeout(java.time.Duration)
132+
*/
133+
@Override
134+
public TerminalClientConfigurationBuilder withSocketTimeout(Duration soTimeout) {
135+
136+
Assert.notNull(soTimeout, "Socket timeout must not be null!");
137+
138+
this.soTimeout = soTimeout;
139+
return this;
140+
}
141+
142+
/*
114143
* (non-Javadoc)
115144
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationBuilderWithOptionalDefaultHeaders#build()
116145
*/
117146
@Override
118147
public ClientConfiguration build() {
119-
return new DefaultClientConfiguration(this.hosts, this.headers, this.useSsl, this.sslContext);
148+
return new DefaultClientConfiguration(this.hosts, this.headers, this.useSsl, this.sslContext, this.soTimeout,
149+
this.connectTimeout);
120150
}
121151

122152
private static InetSocketAddress parse(String hostAndPort) {
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.client;
17+
18+
import java.util.function.Supplier;
19+
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
22+
import org.springframework.http.HttpStatus;
23+
import org.springframework.util.ObjectUtils;
24+
25+
/**
26+
* Logging Utility to log client requests and responses. Logs client requests and responses to Elasticsearch to a
27+
* dedicated logger: {@code org.springframework.data.elasticsearch.client.WIRE} on {@link org.slf4j.event.Level#TRACE}
28+
* level.
29+
*
30+
* @author Mark Paluch
31+
* @since 4.0
32+
*/
33+
public abstract class ClientLogger {
34+
35+
private static final String lineSeparator = System.getProperty("line.separator");
36+
private static final Logger WIRE_LOGGER = LoggerFactory
37+
.getLogger("org.springframework.data.elasticsearch.client.WIRE");
38+
39+
private ClientLogger() {}
40+
41+
/**
42+
* Returns {@literal true} if the logger is enabled.
43+
*
44+
* @return {@literal true} if the logger is enabled.
45+
*/
46+
public static boolean isEnabled() {
47+
return WIRE_LOGGER.isTraceEnabled();
48+
}
49+
50+
/**
51+
* Log an outgoing HTTP request.
52+
*
53+
* @param logId the correlation Id, see {@link #newLogId()}.
54+
* @param method HTTP method
55+
* @param endpoint URI
56+
* @param parameters optional parameters.
57+
*/
58+
public static void logRequest(String logId, String method, String endpoint, Object parameters) {
59+
60+
if (WIRE_LOGGER.isTraceEnabled()) {
61+
WIRE_LOGGER.trace("[{}] Sending request {} {} with parameters: {}", logId, method.toUpperCase(), endpoint,
62+
parameters);
63+
}
64+
}
65+
66+
/**
67+
* Log an outgoing HTTP request with a request body.
68+
*
69+
* @param logId the correlation Id, see {@link #newLogId()}.
70+
* @param method HTTP method
71+
* @param endpoint URI
72+
* @param parameters optional parameters.
73+
* @param body body content supplier.
74+
*/
75+
public static void logRequest(String logId, String method, String endpoint, Object parameters,
76+
Supplier<Object> body) {
77+
78+
if (WIRE_LOGGER.isTraceEnabled()) {
79+
WIRE_LOGGER.trace("[{}] Sending request {} {} with parameters: {}{}Request body: {}", logId, method.toUpperCase(),
80+
endpoint, parameters, lineSeparator, body.get());
81+
}
82+
}
83+
84+
/**
85+
* Log a raw HTTP response without logging the body.
86+
*
87+
* @param logId the correlation Id, see {@link #newLogId()}.
88+
* @param statusCode the HTTP status code.
89+
*/
90+
public static void logRawResponse(String logId, HttpStatus statusCode) {
91+
92+
if (WIRE_LOGGER.isTraceEnabled()) {
93+
WIRE_LOGGER.trace("[{}] Received raw response: ", logId, statusCode);
94+
}
95+
}
96+
97+
/**
98+
* Log a raw HTTP response along with the body.
99+
*
100+
* @param logId the correlation Id, see {@link #newLogId()}.
101+
* @param statusCode the HTTP status code.
102+
* @param body body content.
103+
*/
104+
public static void logResponse(String logId, HttpStatus statusCode, String body) {
105+
106+
if (WIRE_LOGGER.isTraceEnabled()) {
107+
WIRE_LOGGER.trace("[{}] Received response: {}{}Response body: {}", logId, statusCode, lineSeparator, body);
108+
}
109+
}
110+
111+
/**
112+
* Creates a new, unique correlation Id to improve tracing across log events.
113+
*
114+
* @return a new, unique correlation Id.
115+
*/
116+
public static String newLogId() {
117+
return ObjectUtils.getIdentityHexString(new Object());
118+
}
119+
}

0 commit comments

Comments
 (0)