Skip to content

Commit e0ddcc4

Browse files
committed
Merge branch 'add-content-type' into 'main'
Add content type See merge request weblogic-cloud/weblogic-monitoring-exporter!299
2 parents f76e00d + 83999b6 commit e0ddcc4

File tree

10 files changed

+293
-52
lines changed

10 files changed

+293
-52
lines changed

wls-exporter-core/src/main/java/com/oracle/wls/exporter/AuthenticatedCall.java

+44-8
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
1-
// Copyright (c) 2017, 2023, Oracle and/or its affiliates.
1+
// Copyright (c) 2017, 2025, Oracle and/or its affiliates.
22
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
33

44
package com.oracle.wls.exporter;
55

66
import java.io.IOException;
77
import java.io.PrintStream;
8+
import java.time.Duration;
89
import java.time.OffsetDateTime;
910
import java.util.ArrayList;
11+
import java.util.Collection;
1012
import java.util.Collections;
1113
import java.util.HashMap;
1214
import java.util.List;
1315
import java.util.Map;
1416
import java.util.Optional;
17+
import java.util.Set;
1518
import java.util.stream.Collectors;
1619

1720
import com.oracle.wls.exporter.domain.MBeanSelector;
@@ -38,11 +41,12 @@ public abstract class AuthenticatedCall {
3841
* A map of authentication credentials to lists of cookies. The cookies will be sent on any request with
3942
* the specified credentials.
4043
*/
41-
private static final Map<String,List<Cookie>> COOKIES = new HashMap<>();
44+
private static final Map<String,Map<String,Cookie>> COOKIES = new HashMap<>();
4245

4346
private final WebClientFactory webClientFactory;
4447
private final InvocationContext context;
4548
private final UrlBuilder urlBuilder;
49+
private static final List<Retry> callRetries = new ArrayList<>();
4650

4751
// For unit testing only
4852
static void clearCookies() {
@@ -55,6 +59,10 @@ protected AuthenticatedCall(WebClientFactory webClientFactory, InvocationContext
5559
this.urlBuilder = context.createUrlBuilder();
5660
}
5761

62+
public static int getRecentRetries() {
63+
return callRetries.size();
64+
}
65+
5866
public String getAuthenticationUrl() {
5967
return urlBuilder.createUrl(QueryType.RUNTIME_URL_PATTERN);
6068
}
@@ -86,23 +94,25 @@ private void manageCookies(WebClient webClient) {
8694

8795
public List<String> getCookies(String credentials) {
8896
final OffsetDateTime now = SystemClock.now();
89-
final List<Cookie> cookieList = getCookieList(credentials);
97+
final Collection<Cookie> cookieList = getCookieList(credentials);
9098
cookieList.removeIf(c -> c.isExpiredAt(now));
9199

92100
return cookieList.stream().map(Cookie::getValue).collect(Collectors.toList());
93101
}
94102

95-
private List<Cookie> getCookieList(String credentials) {
96-
return Optional.ofNullable(COOKIES.get(credentials)).orElse(Collections.emptyList());
103+
private Collection<Cookie> getCookieList(String credentials) {
104+
return Optional.ofNullable(COOKIES.get(credentials))
105+
.map(Map::values)
106+
.orElse(Collections.emptySet());
97107
}
98108

99109
void handleNewCookie(String cookieHeader) {
100110
if (context.getAuthenticationHeader() == null) return;
101111

102112
final Cookie cookie = new Cookie(cookieHeader);
103113
COOKIES
104-
.computeIfAbsent(context.getAuthenticationHeader(), h -> new ArrayList<>())
105-
.add(cookie);
114+
.computeIfAbsent(context.getAuthenticationHeader(), h -> new HashMap<>())
115+
.put(cookie.getCookieName(), cookie);
106116
}
107117

108118
private static class Cookie {
@@ -117,6 +127,13 @@ String getValue() {
117127
return value;
118128
}
119129

130+
String getCookieName() {
131+
if (!value.contains("="))
132+
return value;
133+
else
134+
return value.substring(0, value.indexOf('='));
135+
}
136+
120137
boolean isExpiredAt(OffsetDateTime now) {
121138
return now.isAfter(expirationTime);
122139
}
@@ -184,9 +201,12 @@ public String getRequestContentType() {
184201

185202

186203
private void performRequest(WebClient webClient) throws IOException {
204+
boolean retryNeeded;
187205
do {
188206
invoke(webClient, context);
189-
} while (webClient.isRetryNeeded());
207+
retryNeeded = webClient.isRetryNeeded();
208+
if (retryNeeded) addRetry();
209+
} while (retryNeeded);
190210
}
191211

192212
private void reportUnableToContactRestApiPort(String uri) throws IOException {
@@ -211,4 +231,20 @@ private void reportUnableToContactRestApiPort(String uri) throws IOException {
211231
*/
212232
protected abstract void invoke(WebClient webClient, InvocationContext context) throws IOException;
213233

234+
private void addRetry() {
235+
callRetries.removeIf(Retry::isObsolete);
236+
callRetries.add(new Retry());
237+
}
238+
239+
private static class Retry {
240+
private final OffsetDateTime time;
241+
242+
Retry() {
243+
this.time = SystemClock.now();
244+
}
245+
246+
private boolean isObsolete() {
247+
return Duration.between(time, SystemClock.now()).toMinutes() > 10;
248+
}
249+
}
214250
}

wls-exporter-core/src/main/java/com/oracle/wls/exporter/ExporterCall.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2021, 2023, Oracle and/or its affiliates.
1+
// Copyright (c) 2021, 2025, Oracle and/or its affiliates.
22
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
33

44
package com.oracle.wls.exporter;
@@ -25,6 +25,7 @@ public ExporterCall(WebClientFactory webClientFactory, InvocationContext context
2525
@Override
2626
protected void invoke(WebClient webClient, InvocationContext context) throws IOException {
2727
LiveConfiguration.updateConfiguration();
28+
context.setResponseHeader("Content-Type", "text/plain");
2829
try (OutputStream responseStream = context.getResponseStream();
2930
MetricsStream metricsStream = new MetricsStream(getInstanceName(), responseStream)) {
3031
if (!LiveConfiguration.hasQueries())

wls-exporter-core/src/main/java/com/oracle/wls/exporter/MetricsStream.java

+19-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2017, 2022, Oracle and/or its affiliates.
1+
// Copyright (c) 2017, 2025, Oracle and/or its affiliates.
22
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
33

44
package com.oracle.wls.exporter;
@@ -21,6 +21,14 @@
2121
class MetricsStream extends PrintStream {
2222
private static final String PROMETHEUS_LINE_SEPARATOR = "\n"; // This is not dependent on the platform running the exporter.
2323
private static final double NANOSEC_PER_SECONDS = 1000000000;
24+
static final String CPU_USAGE_METRIC = "wls_scrape_cpu_seconds";
25+
static final String NUM_MBEANS_SCRAPED_METRIC = "wls_scrape_mbeans_count_total";
26+
static final String SCRAPE_DURATION_SECONDS_METRIC = "wls_scrape_duration_seconds";
27+
static final String FREE_MEMORY_METRIC = "exporter_free_memory_bytes";
28+
static final String MESSAGES_DIAGNOSTIC_SIZE = "exporter_messages_diagnostics_bytes";
29+
static final String MAXIMUM_EXCHANGE_SIZE = "exporter_messages_maximum_exchange_bytes";
30+
static final String RECENT_MESSAGES_DIAGNOSTIC_SIZE = "exporter_messages_recent_bytes";
31+
static final String RECENT_RETRIES = "exporter_recent_retries";
2432

2533
private final PerformanceProbe performanceProbe;
2634
private final long startTime;
@@ -67,14 +75,19 @@ void printMetric(String name, Object value) {
6775
* Prints the summary performance metrics
6876
*/
6977
void printPlatformMetrics() {
70-
printMetric(getCountName(), scrapeCount);
71-
printMetric(getDurationName(), toSecondsString(getElapsedTime()));
72-
printMetric(getCpuUsageName(), toSecondsString(getCpuUsed()));
78+
printPlatformMetric(NUM_MBEANS_SCRAPED_METRIC, scrapeCount);
79+
printPlatformMetric(SCRAPE_DURATION_SECONDS_METRIC, toSecondsString(getElapsedTime()));
80+
printPlatformMetric(CPU_USAGE_METRIC, toSecondsString(getCpuUsed()));
81+
printPlatformMetric(FREE_MEMORY_METRIC, Runtime.getRuntime().freeMemory());
82+
printPlatformMetric(MESSAGES_DIAGNOSTIC_SIZE, WlsRestExchanges.getMessageAllocation());
83+
printPlatformMetric(MAXIMUM_EXCHANGE_SIZE, WlsRestExchanges.getMaximumExchangeLength());
84+
printPlatformMetric(RECENT_MESSAGES_DIAGNOSTIC_SIZE, WlsRestExchanges.getTotalExchangeLengthOverPastTenMinutes());
85+
printPlatformMetric(RECENT_RETRIES, AuthenticatedCall.getRecentRetries());
7386
printMetric(getExporterVersionName(), 1);
7487
}
7588

76-
private String getDurationName() {
77-
return "wls_scrape_duration_seconds" + getPlatformQualifier();
89+
private void printPlatformMetric(String metricName, Object value) {
90+
printMetric(metricName + getPlatformQualifier(), value);
7891
}
7992

8093
/**
@@ -85,14 +98,6 @@ private String getPlatformQualifier() {
8598
return String.format("{instance=\"%s\"}", instance);
8699
}
87100

88-
private String getCpuUsageName() {
89-
return "wls_scrape_cpu_seconds" + getPlatformQualifier();
90-
}
91-
92-
private String getCountName() {
93-
return "wls_scrape_mbeans_count_total" + getPlatformQualifier();
94-
}
95-
96101
private String getExporterVersionName() {
97102
return "exporter_version" + getExporterVersionQualifier();
98103
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
// Copyright (c) 2021, 2023, Oracle and/or its affiliates.
1+
// Copyright (c) 2021, 2025, Oracle and/or its affiliates.
22
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
33

44
package com.oracle.wls.exporter;
55

6-
import java.util.ArrayList;
6+
import java.nio.charset.Charset;
7+
import java.time.Duration;
8+
import java.time.OffsetDateTime;
79
import java.util.List;
810
import java.util.Queue;
911
import java.util.concurrent.ConcurrentLinkedDeque;
12+
import java.util.stream.Collectors;
1013

1114
import static java.time.format.DateTimeFormatter.ISO_LOCAL_TIME;
1215

@@ -18,7 +21,34 @@ public class WlsRestExchanges {
1821
public static final int MAX_EXCHANGES = 5;
1922
private static final String TEMPLATE = "At %s, REQUEST to %s:%n%s%nREPLY:%n%s%n";
2023

21-
private static final Queue<String> exchanges = new ConcurrentLinkedDeque<>();
24+
private static final Queue<Exchange> exchanges = new ConcurrentLinkedDeque<>();
25+
static final int TEN_MINUTES = 10;
26+
27+
private static class Exchange {
28+
private final OffsetDateTime time;
29+
private final String url;
30+
private final String request;
31+
private final String response;
32+
33+
Exchange(String url, String request, String response) {
34+
this.time = SystemClock.now();
35+
this.url = url;
36+
this.request = request;
37+
this.response = response;
38+
}
39+
40+
private String getContent() {
41+
return String.format(TEMPLATE, ISO_LOCAL_TIME.format(time), url, request, response);
42+
}
43+
44+
private int getContentLength() {
45+
return getContent().getBytes(Charset.defaultCharset()).length;
46+
}
47+
48+
private boolean isWithinTenMinutes() {
49+
return Duration.between(time, SystemClock.now()).toMinutes() <= TEN_MINUTES;
50+
}
51+
}
2252

2353
private WlsRestExchanges() {
2454
}
@@ -27,7 +57,7 @@ private WlsRestExchanges() {
2757
* Returns a list of the most recent exchanges.
2858
*/
2959
public static List<String> getExchanges() {
30-
return new ArrayList<>(exchanges);
60+
return exchanges.stream().map(Exchange::getContent).collect(Collectors.toList());
3161
}
3262

3363
/**
@@ -37,18 +67,26 @@ public static List<String> getExchanges() {
3767
* @param response the returned JSON string
3868
*/
3969
public static void addExchange(String url, String request, String response) {
40-
exchanges.add(String.format(TEMPLATE, getCurrentTime(), url, request, response));
70+
exchanges.add(new Exchange(url, request, response));
4171
if (exchanges.size() > MAX_EXCHANGES) exchanges.remove();
4272
}
4373

44-
private static String getCurrentTime() {
45-
return ISO_LOCAL_TIME.format(SystemClock.now());
46-
}
47-
4874
/**
4975
* Clears the set of recorded exchanges. Intended for unit testing.
5076
*/
5177
public static void clear() {
5278
exchanges.clear();
5379
}
80+
81+
public static int getMessageAllocation() {
82+
return exchanges.stream().map(Exchange::getContentLength).reduce(Integer::sum).orElse(0);
83+
}
84+
85+
public static int getMaximumExchangeLength() {
86+
return exchanges.stream().map(Exchange::getContentLength).reduce(Math::max).orElse(0);
87+
}
88+
89+
public static int getTotalExchangeLengthOverPastTenMinutes() {
90+
return exchanges.stream().filter(Exchange::isWithinTenMinutes).map(Exchange::getContentLength).reduce(Integer::sum).orElse(0);
91+
}
5492
}

wls-exporter-core/src/test/java/com/oracle/wls/exporter/AuthenticatedCallTest.java

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2023, Oracle and/or its affiliates.
1+
// Copyright (c) 2023, 2025, Oracle and/or its affiliates.
22
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
33

44
package com.oracle.wls.exporter;
@@ -64,7 +64,7 @@ private void configureResponseWithSetCookieHeaders() {
6464
.addResponse();
6565
}
6666

67-
@Test
67+
@Test
6868
void whenResponseFromRestApiContainsSetCookieHeaders_cacheThem() throws IOException {
6969
configureResponseWithSetCookieHeaders();
7070

@@ -73,6 +73,21 @@ void whenResponseFromRestApiContainsSetCookieHeaders_cacheThem() throws IOExcept
7373
assertThat(callStub.getCookies(CREDENTIALS), containsInAnyOrder("cookie1=value1", "cookie2=value2"));
7474
}
7575

76+
@Test
77+
void whenMultipleResponsesContainsSetCookieHeadersWithTheSameName_keepOnlyTheLast() throws IOException {
78+
handleServerCookieWithValue("value1");
79+
handleServerCookieWithValue("value2");
80+
81+
assertThat(callStub.getCookies(CREDENTIALS), containsInAnyOrder("cookie1=value2"));
82+
}
83+
84+
private void handleServerCookieWithValue(String cookieValue) throws IOException {
85+
webClientFactory.forJson("{}")
86+
.withResponseHeader(SET_COOKIE_HEADER, "cookie1=" + cookieValue)
87+
.addResponse();
88+
callStub.doWithAuthentication();
89+
}
90+
7691
@Test
7792
void whenResponseFromRestApiContainsSetCookieHeaders_ignoreForDifferentCredentials() throws IOException {
7893
configureResponseWithSetCookieHeaders();

wls-exporter-core/src/test/java/com/oracle/wls/exporter/ExporterServletTest.java

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2017, 2023, Oracle and/or its affiliates.
1+
// Copyright (c) 2017, 2025, Oracle and/or its affiliates.
22
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
33

44
package com.oracle.wls.exporter;
@@ -21,6 +21,11 @@
2121

2222
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
2323
import static com.oracle.wls.exporter.InMemoryFileSystem.withNoParams;
24+
import static com.oracle.wls.exporter.MetricsStream.FREE_MEMORY_METRIC;
25+
import static com.oracle.wls.exporter.MetricsStream.MAXIMUM_EXCHANGE_SIZE;
26+
import static com.oracle.wls.exporter.MetricsStream.MESSAGES_DIAGNOSTIC_SIZE;
27+
import static com.oracle.wls.exporter.MetricsStream.NUM_MBEANS_SCRAPED_METRIC;
28+
import static com.oracle.wls.exporter.MetricsStream.RECENT_MESSAGES_DIAGNOSTIC_SIZE;
2429
import static com.oracle.wls.exporter.WebAppConstants.AUTHENTICATION_CHALLENGE_HEADER;
2530
import static com.oracle.wls.exporter.WebAppConstants.AUTHENTICATION_HEADER;
2631
import static com.oracle.wls.exporter.matchers.CommentsOnlyMatcher.containsOnlyComments;
@@ -322,7 +327,11 @@ void onGet_producePerformanceMetrics() throws Exception {
322327

323328
servlet.doGet(request, response);
324329

325-
assertThat(toHtml(response), containsString("wls_scrape_mbeans_count_total"));
330+
assertThat(toHtml(response), containsString(NUM_MBEANS_SCRAPED_METRIC + "{instance="));
331+
assertThat(toHtml(response), containsString(FREE_MEMORY_METRIC));
332+
assertThat(toHtml(response), containsString(MESSAGES_DIAGNOSTIC_SIZE));
333+
assertThat(toHtml(response), containsString(MAXIMUM_EXCHANGE_SIZE));
334+
assertThat(toHtml(response), containsString(RECENT_MESSAGES_DIAGNOSTIC_SIZE));
326335
}
327336

328337
@Test

0 commit comments

Comments
 (0)