Merge branch '2.0.x'
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
package org.springframework.boot.actuate.metrics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -81,15 +82,15 @@ public class MetricsEndpoint {
|
||||
public MetricResponse metric(@Selector String requiredMetricName,
|
||||
@Nullable List<String> tag) {
|
||||
List<Tag> tags = parseTags(tag);
|
||||
List<Meter> meters = new ArrayList<>();
|
||||
collectMeters(meters, this.registry, requiredMetricName, tags);
|
||||
Collection<Meter> meters = findFirstMatchingMeters(this.registry,
|
||||
requiredMetricName, tags);
|
||||
if (meters.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Map<Statistic, Double> samples = getSamples(meters);
|
||||
Map<String, Set<String>> availableTags = getAvailableTags(meters);
|
||||
tags.forEach((t) -> availableTags.remove(t.getKey()));
|
||||
Meter.Id meterId = meters.get(0).getId();
|
||||
Meter.Id meterId = meters.iterator().next().getId();
|
||||
return new MetricResponse(requiredMetricName, meterId.getDescription(),
|
||||
meterId.getBaseUnit(), asList(samples, Sample::new),
|
||||
asList(availableTags, AvailableTag::new));
|
||||
@@ -112,18 +113,23 @@ public class MetricsEndpoint {
|
||||
return Tag.of(parts[0], parts[1]);
|
||||
}
|
||||
|
||||
private void collectMeters(List<Meter> meters, MeterRegistry registry, String name,
|
||||
private Collection<Meter> findFirstMatchingMeters(MeterRegistry registry, String name,
|
||||
Iterable<Tag> tags) {
|
||||
if (registry instanceof CompositeMeterRegistry) {
|
||||
((CompositeMeterRegistry) registry).getRegistries()
|
||||
.forEach((member) -> collectMeters(meters, member, name, tags));
|
||||
}
|
||||
else {
|
||||
meters.addAll(registry.find(name).tags(tags).meters());
|
||||
return findFirstMatchingMeters((CompositeMeterRegistry) registry, name, tags);
|
||||
}
|
||||
return registry.find(name).tags(tags).meters();
|
||||
}
|
||||
|
||||
private Map<Statistic, Double> getSamples(List<Meter> meters) {
|
||||
private Collection<Meter> findFirstMatchingMeters(CompositeMeterRegistry composite,
|
||||
String name, Iterable<Tag> tags) {
|
||||
return composite.getRegistries().stream()
|
||||
.map((registry) -> findFirstMatchingMeters(registry, name, tags))
|
||||
.filter((matching) -> !matching.isEmpty()).findFirst()
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Map<Statistic, Double> getSamples(Collection<Meter> meters) {
|
||||
Map<Statistic, Double> samples = new LinkedHashMap<>();
|
||||
meters.forEach((meter) -> mergeMeasurements(samples, meter));
|
||||
return samples;
|
||||
@@ -138,7 +144,7 @@ public class MetricsEndpoint {
|
||||
return Statistic.MAX.equals(statistic) ? Double::max : Double::sum;
|
||||
}
|
||||
|
||||
private Map<String, Set<String>> getAvailableTags(List<Meter> meters) {
|
||||
private Map<String, Set<String>> getAvailableTags(Collection<Meter> meters) {
|
||||
Map<String, Set<String>> availableTags = new HashMap<>();
|
||||
meters.forEach((meter) -> mergeAvailableTags(availableTags, meter));
|
||||
return availableTags;
|
||||
|
||||
@@ -91,6 +91,42 @@ public class MetricsEndpointTests {
|
||||
assertThat(getCount(response)).hasValue(4.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFirstMatchingMetersFromNestedRegistries() {
|
||||
CompositeMeterRegistry composite = new CompositeMeterRegistry();
|
||||
SimpleMeterRegistry firstLevel0 = new SimpleMeterRegistry();
|
||||
CompositeMeterRegistry firstLevel1 = new CompositeMeterRegistry();
|
||||
SimpleMeterRegistry secondLevel = new SimpleMeterRegistry();
|
||||
composite.add(firstLevel0);
|
||||
composite.add(firstLevel1);
|
||||
firstLevel1.add(secondLevel);
|
||||
secondLevel.counter("cache", "result", "hit", "host", "1").increment(2);
|
||||
secondLevel.counter("cache", "result", "miss", "host", "1").increment(2);
|
||||
secondLevel.counter("cache", "result", "hit", "host", "2").increment(2);
|
||||
MetricsEndpoint endpoint = new MetricsEndpoint(composite);
|
||||
MetricsEndpoint.MetricResponse response = endpoint.metric("cache",
|
||||
Collections.emptyList());
|
||||
assertThat(response.getName()).isEqualTo("cache");
|
||||
assertThat(availableTagKeys(response)).containsExactly("result", "host");
|
||||
assertThat(getCount(response)).hasValue(6.0);
|
||||
response = endpoint.metric("cache", Collections.singletonList("result:hit"));
|
||||
assertThat(availableTagKeys(response)).containsExactly("host");
|
||||
assertThat(getCount(response)).hasValue(4.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchingMeterNotFoundInNestedRegistries() {
|
||||
CompositeMeterRegistry composite = new CompositeMeterRegistry();
|
||||
CompositeMeterRegistry firstLevel = new CompositeMeterRegistry();
|
||||
SimpleMeterRegistry secondLevel = new SimpleMeterRegistry();
|
||||
composite.add(firstLevel);
|
||||
firstLevel.add(secondLevel);
|
||||
MetricsEndpoint endpoint = new MetricsEndpoint(composite);
|
||||
MetricsEndpoint.MetricResponse response = endpoint.metric("invalid.metric.name",
|
||||
Collections.emptyList());
|
||||
assertThat(response).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metricTagValuesAreDeduplicated() {
|
||||
this.registry.counter("cache", "host", "1", "region", "east", "result", "hit");
|
||||
|
||||
@@ -652,6 +652,21 @@ details.
|
||||
|
||||
|
||||
|
||||
[[boot-features-encrypting-properties]]
|
||||
=== Encrypting Properties
|
||||
Spring Boot does not provide any built in support for encrypting property values, however,
|
||||
it does provide the hook points necessary to modify values contained in the Spring
|
||||
`Environment`. The `EnvironmentPostProcessor` interface allows you to manipulate the
|
||||
`Environment` before the application starts. See <<howto-customize-the-environment-or-application-context>>
|
||||
for details.
|
||||
|
||||
If you're looking for a secure way to store credentials and passwords, the
|
||||
https://cloud.spring.io/spring-cloud-vault/[Spring Cloud Vault] project provides
|
||||
support for storing externalized configuration in
|
||||
https://www.vaultproject.io/[HashiCorp Vault].
|
||||
|
||||
|
||||
|
||||
[[boot-features-external-config-yaml]]
|
||||
=== Using YAML Instead of Properties
|
||||
http://yaml.org[YAML] is a superset of JSON and, as such, is a convenient format for
|
||||
@@ -6959,6 +6974,10 @@ that the driver exits after each test and that a new instance is injected. If yo
|
||||
not want this behavior, you can add `@Scope("singleton")` to your `WebDriver` `@Bean`
|
||||
definition.
|
||||
|
||||
WARNING: The `webDriver` scope created by Spring Boot will replace any user defined scope
|
||||
of the same name. If you define your own `webDriver` scope you may find it stops working
|
||||
when you use `@WebMvcTest`.
|
||||
|
||||
If you have Spring Security on the classpath, `@WebMvcTest` will also scan `WebSecurityConfigurer`
|
||||
beans. Instead of disabling security completely for such tests, you can use Spring Security's test support.
|
||||
More details on how to use Spring Security's `MockMvc` support can be found in
|
||||
|
||||
@@ -749,16 +749,23 @@ listings for Maven and Gradle:
|
||||
.Gradle
|
||||
[source,groovy,indent=0,subs="attributes"]
|
||||
----
|
||||
configurations {
|
||||
developmentOnly
|
||||
runtimeClasspath {
|
||||
extendsFrom developmentOnly
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
compile("org.springframework.boot:spring-boot-devtools")
|
||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||
}
|
||||
----
|
||||
|
||||
NOTE: Developer tools are automatically disabled when running a fully packaged
|
||||
application. If your application is launched from `java -jar` or if it is started from a
|
||||
special classloader, then it is considered a "`production application`". Flagging the
|
||||
dependency as optional in Maven or using `compileOnly` in Gradle is a best practice that
|
||||
prevents devtools from being transitively applied to other modules that use your project.
|
||||
dependency as optional in Maven or using a custom`developmentOnly` configuration in
|
||||
Gradle (as shown above) is a best practice that prevents devtools from being transitively
|
||||
applied to other modules that use your project.
|
||||
|
||||
TIP: Repackaged archives do not contain devtools by default. If you want to use a
|
||||
<<using-boot-devtools-remote,certain remote devtools feature>>, you need to disable the
|
||||
|
||||
Reference in New Issue
Block a user