Merge pull request #23990 from bono007

* gh-23990:
  Polish "Auto-configure Mongo metrics"
  Auto-configure Mongo metrics

Closes gh-23990
This commit is contained in:
Andy Wilkinson 2021-04-06 18:16:13 +01:00
commit 87dd329eba
10 changed files with 537 additions and 0 deletions

View File

@ -0,0 +1,110 @@
/*
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.metrics.mongo;
import com.mongodb.MongoClientSettings;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.mongodb.DefaultMongoMetricsCommandTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.DefaultMongoMetricsConnectionPoolTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsCommandListener;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsCommandTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsConnectionPoolListener;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsConnectionPoolTagsProvider;
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoClientSettingsBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Mongo metrics.
*
* @author Chris Bono
* @author Jonatan Ivanov
* @since 2.5.0
*/
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(MongoAutoConfiguration.class)
@AutoConfigureAfter({ MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class })
@ConditionalOnClass(MongoClientSettings.class)
@ConditionalOnBean(MeterRegistry.class)
public class MongoMetricsAutoConfiguration {
@ConditionalOnClass(MongoMetricsCommandListener.class)
@ConditionalOnProperty(name = "management.metrics.mongo.command.enabled", havingValue = "true",
matchIfMissing = true)
static class MongoCommandMetricsConfiguration {
@Bean
@ConditionalOnMissingBean
MongoMetricsCommandListener mongoMetricsCommandListener(MeterRegistry meterRegistry,
MongoMetricsCommandTagsProvider mongoMetricsCommandTagsProvider) {
return new MongoMetricsCommandListener(meterRegistry, mongoMetricsCommandTagsProvider);
}
@Bean
@ConditionalOnMissingBean
MongoMetricsCommandTagsProvider mongoMetricsCommandTagsProvider() {
return new DefaultMongoMetricsCommandTagsProvider();
}
@Bean
MongoClientSettingsBuilderCustomizer mongoMetricsCommandListenerClientSettingsBuilderCustomizer(
MongoMetricsCommandListener mongoMetricsCommandListener) {
return (clientSettingsBuilder) -> clientSettingsBuilder.addCommandListener(mongoMetricsCommandListener);
}
}
@ConditionalOnClass(MongoMetricsConnectionPoolListener.class)
@ConditionalOnProperty(name = "management.metrics.mongo.connectionpool.enabled", havingValue = "true",
matchIfMissing = true)
static class MongoConnectionPoolMetricsConfiguration {
@Bean
@ConditionalOnMissingBean
MongoMetricsConnectionPoolListener mongoMetricsConnectionPoolListener(MeterRegistry meterRegistry,
MongoMetricsConnectionPoolTagsProvider mongoMetricsConnectionPoolTagsProvider) {
return new MongoMetricsConnectionPoolListener(meterRegistry, mongoMetricsConnectionPoolTagsProvider);
}
@Bean
@ConditionalOnMissingBean
MongoMetricsConnectionPoolTagsProvider mongoMetricsConnectionPoolTagsProvider() {
return new DefaultMongoMetricsConnectionPoolTagsProvider();
}
@Bean
MongoClientSettingsBuilderCustomizer mongoMetricsConnectionPoolListenerClientSettingsBuilderCustomizer(
MongoMetricsConnectionPoolListener mongoMetricsConnectionPoolListener) {
return (clientSettingsBuilder) -> clientSettingsBuilder
.applyToConnectionPoolSettings((connectionPoolSettingsBuilder) -> connectionPoolSettingsBuilder
.addConnectionPoolListener(mongoMetricsConnectionPoolListener));
}
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Auto-configuration for Mongo metrics.
*/
package org.springframework.boot.actuate.autoconfigure.metrics.mongo;

View File

@ -521,6 +521,16 @@
"level": "error"
}
},
{
"name": "management.metrics.mongo.command.enabled",
"description": "Whether to enable Mongo client command metrics.",
"defaultValue": true
},
{
"name": "management.metrics.mongo.connectionpool.enabled",
"description": "Whether to enable Mongo connection pool metrics.",
"defaultValue": true
},
{
"name": "management.metrics.web.client.request.autotime.enabled",
"description": "Whether to automatically time web client requests.",

View File

@ -70,6 +70,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront.Wavefron
org.springframework.boot.actuate.autoconfigure.metrics.integration.IntegrationMetricsAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.jersey.JerseyServerMetricsAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.mongo.MongoMetricsAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.r2dbc.ConnectionPoolMetricsAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.web.client.HttpClientMetricsAutoConfiguration,\

View File

@ -0,0 +1,200 @@
/*
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.metrics.mongo;
import java.util.List;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.connection.ConnectionPoolSettings;
import com.mongodb.event.ConnectionPoolListener;
import io.micrometer.core.instrument.binder.mongodb.DefaultMongoMetricsCommandTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.DefaultMongoMetricsConnectionPoolTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsCommandListener;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsCommandTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsConnectionPoolListener;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsConnectionPoolTagsProvider;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link MongoMetricsAutoConfiguration}.
*
* @author Chris Bono
*/
class MongoMetricsAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(MongoMetricsAutoConfiguration.class));
@Test
void whenThereIsAMeterRegistryThenMetricsCommandListenerIsAdded() {
this.contextRunner.with(MetricsRun.simple())
.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class)).run((context) -> {
assertThat(context).hasSingleBean(MongoMetricsCommandListener.class);
assertThat(getActualMongoClientSettingsUsedToConstructClient(context)).isNotNull()
.extracting(MongoClientSettings::getCommandListeners).asList()
.containsExactly(context.getBean(MongoMetricsCommandListener.class));
assertThat(getMongoMetricsCommandTagsProviderUsedToConstructListener(context))
.isInstanceOf(DefaultMongoMetricsCommandTagsProvider.class);
});
}
@Test
void whenThereIsAMeterRegistryThenMetricsConnectionPoolListenerIsAdded() {
this.contextRunner.with(MetricsRun.simple())
.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class)).run((context) -> {
assertThat(context).hasSingleBean(MongoMetricsConnectionPoolListener.class);
assertThat(getConnectionPoolListenersFromClient(context))
.containsExactly(context.getBean(MongoMetricsConnectionPoolListener.class));
assertThat(getMongoMetricsConnectionPoolTagsProviderUsedToConstructListener(context))
.isInstanceOf(DefaultMongoMetricsConnectionPoolTagsProvider.class);
});
}
@Test
void whenThereIsNoMeterRegistryThenNoMetricsCommandListenerIsAdded() {
this.contextRunner.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))
.run((context) -> assertThatMetricsCommandListenerNotAdded());
}
@Test
void whenThereIsNoMeterRegistryThenNoMetricsConnectionPoolListenerIsAdded() {
this.contextRunner.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))
.run((context) -> assertThatMetricsConnectionPoolListenerNotAdded());
}
@Test
void whenThereIsACustomMetricsCommandTagsProviderItIsUsed() {
final MongoMetricsCommandTagsProvider customTagsProvider = mock(MongoMetricsCommandTagsProvider.class);
this.contextRunner.with(MetricsRun.simple())
.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))
.withBean("customMongoMetricsCommandTagsProvider", MongoMetricsCommandTagsProvider.class,
() -> customTagsProvider)
.run((context) -> assertThat(getMongoMetricsCommandTagsProviderUsedToConstructListener(context))
.isSameAs(customTagsProvider));
}
@Test
void whenThereIsACustomMetricsConnectionPoolTagsProviderItIsUsed() {
final MongoMetricsConnectionPoolTagsProvider customTagsProvider = mock(
MongoMetricsConnectionPoolTagsProvider.class);
this.contextRunner.with(MetricsRun.simple())
.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))
.withBean("customMongoMetricsConnectionPoolTagsProvider", MongoMetricsConnectionPoolTagsProvider.class,
() -> customTagsProvider)
.run((context) -> assertThat(getMongoMetricsConnectionPoolTagsProviderUsedToConstructListener(context))
.isSameAs(customTagsProvider));
}
@Test
void whenThereIsNoMongoClientSettingsOnClasspathThenNoMetricsCommandListenerIsAdded() {
this.contextRunner.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(MongoClientSettings.class))
.run((context) -> assertThatMetricsCommandListenerNotAdded());
}
@Test
void whenThereIsNoMongoClientSettingsOnClasspathThenNoMetricsConnectionPoolListenerIsAdded() {
this.contextRunner.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(MongoClientSettings.class))
.run((context) -> assertThatMetricsConnectionPoolListenerNotAdded());
}
@Test
void whenThereIsNoMongoMetricsCommandListenerOnClasspathThenNoMetricsCommandListenerIsAdded() {
this.contextRunner.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(MongoMetricsCommandListener.class))
.run((context) -> assertThatMetricsCommandListenerNotAdded());
}
@Test
void whenThereIsNoMongoMetricsConnectionPoolListenerOnClasspathThenNoMetricsConnectionPoolListenerIsAdded() {
this.contextRunner.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(MongoMetricsConnectionPoolListener.class))
.run((context) -> assertThatMetricsConnectionPoolListenerNotAdded());
}
@Test
void whenMetricsCommandListenerEnabledPropertyFalseThenNoMetricsCommandListenerIsAdded() {
this.contextRunner.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))
.withPropertyValues("management.metrics.mongo.command.enabled:false")
.run((context) -> assertThatMetricsCommandListenerNotAdded());
}
@Test
void whenMetricsConnectionPoolListenerEnabledPropertyFalseThenNoMetricsConnectionPoolListenerIsAdded() {
this.contextRunner.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))
.withPropertyValues("management.metrics.mongo.connectionpool.enabled:false")
.run((context) -> assertThatMetricsConnectionPoolListenerNotAdded());
}
private ContextConsumer<AssertableApplicationContext> assertThatMetricsCommandListenerNotAdded() {
return (context) -> {
assertThat(context).doesNotHaveBean(MongoMetricsCommandListener.class);
assertThat(getActualMongoClientSettingsUsedToConstructClient(context)).isNotNull()
.extracting(MongoClientSettings::getCommandListeners).asList().isEmpty();
};
}
private ContextConsumer<AssertableApplicationContext> assertThatMetricsConnectionPoolListenerNotAdded() {
return (context) -> {
assertThat(context).doesNotHaveBean(MongoMetricsConnectionPoolListener.class);
assertThat(getConnectionPoolListenersFromClient(context)).isEmpty();
};
}
private MongoClientSettings getActualMongoClientSettingsUsedToConstructClient(
final AssertableApplicationContext context) {
final MongoClient mongoClient = context.getBean(MongoClient.class);
return (MongoClientSettings) ReflectionTestUtils.getField(mongoClient, "settings");
}
private List<ConnectionPoolListener> getConnectionPoolListenersFromClient(
final AssertableApplicationContext context) {
MongoClientSettings mongoClientSettings = getActualMongoClientSettingsUsedToConstructClient(context);
ConnectionPoolSettings connectionPoolSettings = mongoClientSettings.getConnectionPoolSettings();
@SuppressWarnings("unchecked")
List<ConnectionPoolListener> listeners = (List<ConnectionPoolListener>) ReflectionTestUtils
.getField(connectionPoolSettings, "connectionPoolListeners");
return listeners;
}
private MongoMetricsCommandTagsProvider getMongoMetricsCommandTagsProviderUsedToConstructListener(
final AssertableApplicationContext context) {
MongoMetricsCommandListener listener = context.getBean(MongoMetricsCommandListener.class);
return (MongoMetricsCommandTagsProvider) ReflectionTestUtils.getField(listener, "tagsProvider");
}
private MongoMetricsConnectionPoolTagsProvider getMongoMetricsConnectionPoolTagsProviderUsedToConstructListener(
final AssertableApplicationContext context) {
MongoMetricsConnectionPoolListener listener = context.getBean(MongoMetricsConnectionPoolListener.class);
return (MongoMetricsConnectionPoolTagsProvider) ReflectionTestUtils.getField(listener, "tagsProvider");
}
}

View File

@ -80,6 +80,7 @@ dependencies {
implementation("org.glassfish.jersey.core:jersey-server")
implementation("org.hibernate:hibernate-jcache")
implementation("org.jooq:jooq")
implementation("org.mongodb:mongodb-driver-sync")
implementation("org.slf4j:jul-to-slf4j")
implementation("org.springframework:spring-jdbc")
implementation("org.springframework:spring-test")

View File

@ -2135,6 +2135,7 @@ Spring Boot registers the following core metrics when applicable:
* Kafka consumer, producer, and streams metrics
* Log4j2 metrics: record the number of events logged to Log4j2 at each level
* Logback metrics: record the number of events logged to Logback at each level
* MongoDB metrics for all commands issued from the client and for client connection pool information
* Uptime metrics: report a gauge for uptime and a fixed gauge representing the application's absolute start time
* Tomcat metrics (`server.tomcat.mbeanregistry.enabled` must be set to `true` for all Tomcat metrics to be registered)
* {spring-integration-docs}system-management.html#micrometer-integration[Spring Integration] metrics
@ -2396,6 +2397,90 @@ For more details refer to {spring-kafka-docs}#micrometer-native[Micrometer Nativ
[[production-ready-metrics-mongodb]]
==== MongoDB Metrics
[[production-ready-metrics-mongodb-command]]
===== Command Metrics
Auto-configuration will register a `MongoMetricsCommandListener` with the auto-configured `MongoClient`.
A timer metric with the name `mongodb.driver.commands` is created for each command issued to the underlying MongoDB driver.
Each metric is tagged with the following information by default:
|===
| Tag | Description
| `command`
| Name of the command issued
| `cluster.id`
| Identifier of the cluster the command was sent to
| `server.address`
| Address of the server the command was sent to
| `status`
| Outcome of the command - one of (`SUCCESS`, `FAILED`)
|===
To replace the default metric tags, define a `MongoMetricsCommandTagsProvider` bean, as shown in the following example:
[source,java,indent=0]
----
include::{include-productionreadyfeatures}/metrics/mongo/SampleCommandTagsProviderConfiguration.java[tag=*]
----
To disable the auto-configured command metrics, set the following property:
[source,yaml,indent=0,configprops,configblocks]
----
management:
metrics:
mongo:
command:
enabled: false
----
===== Connection Pool Metrics
Auto-configuration will register a `MongoMetricsConnectionPoolListener` with the auto-configured `MongoClient`.
The following gauge metrics are created for the connection pool:
* `mongodb.driver.pool.size` that reports the current size of the connection pool, including idle and and in-use members
* `mongodb.driver.pool.checkedout` that reports the count of connections that are currently in use
* `mongodb.driver.pool.waitqueuesize` that reports the current size of the wait queue for a connection from the pool
Each metric is tagged with the following information by default:
|===
| Tag | Description
| `cluster.id`
| Identifier of the cluster the connection pool corresponds to
| `server.address`
| Address of the server the connection pool corresponds to
|===
To replace the default metric tags, define a `MongoMetricsConnectionPoolTagsProvider` bean, as shown in the following example:
[source,java,indent=0]
----
include::{include-productionreadyfeatures}/metrics/mongo/SampleConnectionPoolTagsProviderConfiguration.java[tag=*]
----
To disable the auto-configured connection pool metrics, set the following property:
[source,yaml,indent=0,configprops,configblocks]
----
management:
metrics:
mongo:
connectionpool:
enabled: false
----
[[production-ready-metrics-custom]]
=== Registering custom metrics
To register custom metrics, inject `MeterRegistry` into your component, as shown in the following example:

View File

@ -0,0 +1,45 @@
/*
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.docs.productionreadyfeatures.metrics.mongo;
// tag::code[]
import com.mongodb.event.CommandEvent;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsCommandTagsProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class SampleCommandTagsProviderConfiguration {
@Bean
MongoMetricsCommandTagsProvider customCommandTagsProvider() {
return new CustomCommandTagsProvider();
}
}
// end::code[]
class CustomCommandTagsProvider implements MongoMetricsCommandTagsProvider {
@Override
public Iterable<Tag> commandTags(CommandEvent commandEvent) {
return java.util.Collections.emptyList();
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.docs.productionreadyfeatures.metrics.mongo;
// tag::code[]
import com.mongodb.event.ConnectionPoolCreatedEvent;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsConnectionPoolTagsProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class SampleConnectionPoolTagsProviderConfiguration {
@Bean
MongoMetricsConnectionPoolTagsProvider customConnectionPoolTagsProvider() {
return new CustomConnectionPoolTagsProvider();
}
}
// end::code[]
class CustomConnectionPoolTagsProvider implements MongoMetricsConnectionPoolTagsProvider {
@Override
public Iterable<Tag> connectionPoolTags(ConnectionPoolCreatedEvent event) {
return java.util.Collections.emptyList();
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Examples for the "Production Ready Features - Metrics - MongoDB" section.
*/
package org.springframework.boot.docs.productionreadyfeatures.metrics.mongo;