A Servlet filter to add basic but very useful Prometheus metrics for your app.
The only exposed metrics are the following:
request_seconds_bucket{type, status, isError, errorMessage, method, addr, le}
request_seconds_count{type, status, isError, errorMessage, method, addr}
request_seconds_sum{type, status, isError, errorMessage, method, addr}
response_size_bytes{type, status, isError, errorMessage, method, addr}
dependency_up{name}
dependency_request_seconds_bucket{name, type, status, isError, errorMessage, method, addr, le}
dependency_request_seconds_count{name, type, status, isError, errorMessage, method, add}
dependency_request_seconds_sum{name, type, status, isError, errorMessage, method, add}
application_info{version}
Attention, Buckets/Histogram only work if It was defined in web.xml file
Details:
-
The
request_seconds_bucket
metric defines the histogram of how many requests are falling into the well-defined buckets represented by the labelle
; -
The
request_seconds_count
is a counter that counts the overall number of requests with those exact label occurrences; -
The
request_seconds_sum
is a counter that counts the overall sum of how long the requests with those exact label occurrences are taking; -
The
response_size_bytes
is a counter that computes how much data is being sent back to the user for a given request type. It captures the response size from thecontent-length
response header. If there is no such header, the value exposed as metric will be zero; -
The
dependency_up
is a metric to register whether a specific dependency is up (1) or down (0). The labelname
registers the dependency name; -
The
dependency_request_seconds_bucket
is a metric that defines the histogram of how many requests to a specific dependency are falling into the well defined buckets represented by the label le; -
The
dependency_request_seconds_count
is a counter that counts the overall number of requests to a specific dependency; -
The
dependency_request_seconds_sum
is a counter that counts the overall sum of how long requests to a specific dependency are taking; -
The
application_info
holds static info of an application, such as it's semantic version number;
Labels:
-
type
tells which request protocol was used (e.g.grpc
orhttp
); -
status
registers the response status (e.g. HTTP status code); -
method
registers the request method; -
addr
registers the requested endpoint address; -
version
tells which version of your app handled the request; -
isError
lets us know if the status code reported is an error or not; -
errorMessage
registers the error message; -
name
registers the name of the dependency;
Import the following dependency to your project:
<dependency>
<groupId>br.com.labbs</groupId>
<artifactId>servlet-monitor</artifactId>
<version>${servlet-monitor-version}</version>
</dependency>
Please use the latest version:
The collector filter can be programmatically added to javax.servlet.ServletContext
or initialized by web.xml
file.
You just need to place the code below in your web.xml
file.
<filter>
<filter-name>metricsFilter</filter-name>
<filter-class>br.com.labbs.monitor.filter.MetricsCollectorFilter</filter-class>
</filter>
<!-- This must be the first <filter-mapping> in the web.xml file so that you can get
the most accurate measurement of latency and response size. -->
<filter-mapping>
<filter-name>metricsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
⚠️ NOTE: This must be the first<filter-mapping>
in theweb.xml
file so that you can get the most accurate measurement of latency and response size.
It is possible to use the following properties to configure the Metrics Collector Filter by init parameters on the web.xml file.
The number of buckets is only available and can be configured by passing a comma-separated string of doubles as the buckets
init parameter.
e.g.
<init-param>
<param-name>buckets</param-name>
<param-value>0.1,0.3,2,10</param-value>
</init-param>
The max depth of the URI path(that is the value of addr
label) can be configured by passing an integer value as the path-depth
init parameter.
By default, the filter will provide the full path granularity. Any number provided that is less than one will provide the full path granularity.
e.g.
<init-param>
<param-name>path-depth</param-name>
<param-value>1</param-value>
</init-param>
⚠️ NOTE: Using full path granularity may affect performance
Exclusions of paths from collect can be configured by passing a comma-separated string of paths as the exclusions
init parameter.
e.g. exclude paths starting with '/metrics' or '/static'
<init-param>
<param-name>exclusions</param-name>
<param-value>/metrics,/static</param-value>
</init-param>
It is possible to enable/disable the JVM metrics export. The export is enabled by default.
e.g. disabling
<init-param>
<param-name>export-jvm-metrics</param-name>
<param-value>false</param-value>
</init-param>
It is possible to capture error messages that were saved using HttpServletRequest.setAttribute
. The error-message
init param must be configured to get the name of the attribute.
e.g capture error messages from requests with attribute name equals to 'error-info'
<init-param>
<param-name>error-message</param-name>
<param-value>error-info</param-value>
</init-param>
Your java code should look like this:
req.setAttribute("error-info", "Page not found");
It is possible to filter the error message to avoid long messages or personal info exposed in the metrics. To do it, two params may be used: error-info-regex
and error-info-max-size
. The first will set the regex to apply in the message, with [^A-zÀ-ú .,]+
as the default value. The second, error-info-max-size
, defines the max size of the message to be truncated and has 50
as the default value.
To provide the application version to the metrics collector, the application.properties
file must exist in the project at the project resources path(Maven projects default path src/main/resources
) with the application version set to application.version
property.
e.g. src/main/resources/application.properties
application.version=1.0.2
Make sure the file classes/application.properties
exist into your jar or war package.
The process to automatically set application version retrieving the project version from the pom.xml file is using Maven resource filtering.
To have Maven filter resources when copying, simply set filtering
to true for the resource directory in your pom.xml
.
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
Create the file application.propeties
at the application resources path(most commonly src/main/resources
) and add the application.version=${project.version}
property whose value ${project.version}
will be supplied when the resource is filtered.
e.g. src/main/resources/application.properties
application.version=${project.version}
Make sure the file classes/application.properties
exist into your jar or war package and the property value is the same of the pom.xml file.
It's also possible to provide application version sending parameter:
<init-param>
<param-name>application-version</param-name>
<param-value>x.x.x</param-value>
</init-param>
or programmatically:
setInitParameter("application-version", "x.x.x");
As well as the metrics filter, the class MetricsServlet
can also be programmatically added to javax.servlet.ServletContext
or initialized via web.xml
file.
Place the code below in your web.xml
file to expose the metrics at the /metrics
path.
<servlet>
<servlet-name>Metrics</servlet-name>
<servlet-class>br.com.labbs.monitor.exporter.MetricsServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Metrics</servlet-name>
<url-pattern>/metrics</url-pattern>
</servlet-mapping>
To add a dependency state metrics to the Monitor, you would implement the interface DependencyChecker
and add an instance to the MonitorMetrics
with the period interval that the dependency must be checked.
DependencyChecker fakeChecker = new DependencyChecker() {
@Override
public DependencyState run() {
// checking the database state
return DependencyState.UP;
}
@Override
public String getDependencyName() {
return "fake-database-checker";
}
};
long periodIntervalInMillis = 15000;
MonitorMetrics.INSTANCE.addDependencyChecker(fakeChecker, periodIntervalInMillis);
⚠️ NOTE: The dependency checkers will run on a new thread, to prevent memory leak, make sure to call the methodMonitorMetrics.INSTANCE.cancelAllDependencyCheckers()
on undeploying/terminating the web app.
You also can monitore a dependency event. Just call addDependencyEvent
and pass the right params.
MonitorMetrics.INSTANCE.addDependencyEvent(name, type, status, method, address, isError, errorMessage, elapsedSeconds);
This project is part of a more large application called Big Brother.