diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index deedc7fa5..aa9726b45 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2cfc421b7..06737ad7a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu May 18 12:01:02 CDT 2017 +#Thu May 18 17:28:55 CDT 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-milestone-2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip diff --git a/gradlew b/gradlew index 9aa616c27..4453ccea3 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -154,16 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then cd "$(dirname "$0")" fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index ec03cf3be..afb097736 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -7,7 +7,7 @@ :imagesdir: ./images = Spring Metrics -image::https://circleci.com/gh/spring-projects/spring-metrics.svg?style=svg[Build Status, link=https://circleci.com/gh/spring-cloud/spring-metrics] +image:https://circleci.com/gh/spring-projects/spring-metrics.svg?style=svg[Build Status, link=https://circleci.com/gh/spring-cloud/spring-metrics] image:https://badges.gitter.im/Join%20Chat.svg[Gitter, link="https://gitter.im/spring-projects/spring-metrics?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge"] image:https://img.shields.io/badge/License-Apache%202.0-blue.svg[Apache License,link="http://www.apache.org/licenses/LICENSE-2.0"] @@ -258,6 +258,18 @@ groups etc. Normally all data can be refreshed in a few minutes. If the AWS services are having problems it can take much longer. A long duration timer can be used to track the overall time for refreshing the metadata. +In a Spring application, it is common for such long running processes to be implemented with `@Scheduled`. +`spring-metrics` provides a special `@Timed` annotation for instrumenting these processes with a long +task timer: + +```java +@Timed(value = "aws_scrape", longTask = true) +@Scheduled(fixedDelay = 360000) +void scrapeResources() { + // find instances, volumes, auto-scaling groups, etc... +} +``` + The charts below show max latency for the refresh using a regular timer and a long task timer. Regular timer, note that the y-axis is using a logarithmic scale: @@ -405,7 +417,7 @@ We recommend setting up alerts for production ready apps for (1) if `jvm_gc_paus is a good general purpose value) and (2) if `jvm_gc_live_data_size` exceeds 70% of the heap. 2. `LogbackMetrics` - Records counts for log event at various levels. Auto-configured in the presence of `logback-core`. -== Spring Web MVC and Spring WebFlux +== Server-side HTTP Instrumentation `spring-metrics` contains built-in instrumentation for timings of requests made to Spring MVC and Spring WebFlux server endpoints. @@ -420,6 +432,8 @@ to time. Add `@Timed` to: 1. A controller class to enable timings on every request handler in the controller. 2. A method to enable for an individual endpoint. This is not necessary if you have it on the class. +3. A method with `longTask = true` to enable a long task timer for the method. Long task timers require a +separate metric name, and can be stacked with a short task timer. ```java @RestController @@ -427,6 +441,7 @@ to time. Add `@Timed` to: public class MyController { @GetMapping("/api/people") @Timed // (2) + @Timed(value = "all_people", longTask = true) // (3) public List listPeople() { ... } ``` @@ -464,15 +479,33 @@ RouterFunction routes = RouterFunctions The filter applies to all routes defined by this router function. -=== `RestTemplate` Timing +== Client-side HTTP Instrumentation -Adding `@EnableMetrics` to your `@SpringBootApplication` class autoconfigures a `BeanPostProcessor` for `RestTemplate`, +Adding `@EnableMetrics` to your `@SpringBootApplication` class configures a `BeanPostProcessor` for `RestTemplate`, so every instance you create via the application context will be instrumented. A timer is recorded for each invocation that includes tags for URI (before parameter substitution), host, and status. The name of this timer is `http_client_requests`, and can be changed via the `spring.metrics.web.client_requests.name` property. +== Scheduling Instrumentation + +Adding `@EnableMetrics` to your `@SpringBootApplication` class plus enabling AOP configures AOP advice that times +`@Scheduled` methods. For a method to be timed, it must be marked as `@Timed("my_metric_name")` with a name. + +Depending on the duration of the scheduled task, you may want to choose to time the method with a `LongTaskTimer`, +a `Timer`, or both. Below is an example of measuring both long task and regular timings to a scheduled task: + +```java +@Timed("beep") +@Timed(value = "long_beep", longTask = true) +@Scheduled(fixedRate = 1000) +void longBeep() { + // calculate the meaning of life, then beep... + System.out.println("beep"); +} +``` + == Prometheus === Quickstart for Prometheus-based monitoring diff --git a/src/main/java/org/springframework/metrics/instrument/web/RouterFunctionMetrics.java b/src/main/java/org/springframework/metrics/instrument/web/RouterFunctionMetrics.java index b26560ce0..fe04034cb 100644 --- a/src/main/java/org/springframework/metrics/instrument/web/RouterFunctionMetrics.java +++ b/src/main/java/org/springframework/metrics/instrument/web/RouterFunctionMetrics.java @@ -26,20 +26,24 @@ public class RouterFunctionMetrics { private final MeterRegistry registry; - private String defaultTagName = "http_server_requests"; + private String defaultName = "http_server_requests"; private WebMetricsTagProvider tagProvider = new DefaultWebMetricsTagProvider(); public RouterFunctionMetrics(MeterRegistry registry) { this.registry = registry; } - public RouterFunctionMetrics setDefaultTagName(String defaultTagName) { - this.defaultTagName = defaultTagName; + public RouterFunctionMetrics setDefaultName(String defaultName) { + this.defaultName = defaultName; return this; } public HandlerFilterFunction timer() { - return timer(defaultTagName, Stream.empty()); + return timer(defaultName, Stream.empty()); + } + + public HandlerFilterFunction timer(Stream tags) { + return timer(defaultName, tags); } public HandlerFilterFunction timer(String name, Stream tags) {