---
title: Monitor services
description: The following sections describe how to set up and maintain monitoring in your deployment, to ensure appropriate performance and service availability:
component: pinggateway
version: 2023.11
page_id: pinggateway:maintenance-guide:monitoring
canonical_url: https://docs.pingidentity.com/pinggateway/2026/maintenance-guide/monitoring.html
llms_txt: https://docs.pingidentity.com/pinggateway/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
revdate: 2023-09-19T08:48:14Z
keywords: ["Maintenance", "Configuration", "JSON", "Rest", "Monitoring"]
superseded_by: https://docs.pingidentity.com/pinggateway/2026/maintenance-guide/monitoring.html
section_ids:
  monitoring-eps: Access the monitoring endpoints
  monitor-prometheus: Monitor at the Prometheus Scrape Endpoint
  proc-monitor-plat-endpoint: Monitor the Common REST Monitoring Endpoint
  monitor-vertx: Monitor Vert.x metrics
  proc-monitor-plat-protect: Protect monitoring endpoints
---

# Monitor services

The following sections describe how to set up and maintain monitoring in your deployment, to ensure appropriate performance and service availability:

## Access the monitoring endpoints

All ForgeRock products automatically expose a monitoring endpoint to expose metrics in a standard Prometheus format, and as a JSON format monitoring resource.

In IG, metrics are available for each router, subrouter, and route in the configuration. When a TimerDecorator is configured, timer metrics are also available.

For information about IG monitoring endpoints and available metrics, see [Monitoring](../reference/Monitoring.html).

### Monitor at the Prometheus Scrape Endpoint

|   |                                                                                                                                                                                                       |
| - | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Prometheus metric names are deprecated and expected to be replaced with names ending in \_total. The information provided by the metric is not deprecated. Other Prometheus metrics are not affected. |

All ForgeRock products automatically expose a monitoring endpoint where Prometheus can scrape metrics, in a standard Prometheus format.

When IG is set up as described in the [Quick install](../getting-started/preface.html), the Prometheus Scrape Endpoint is available at <http://ig.example.com:8080/openig/metrics/prometheus>.

By default, no special setup or configuration is required to access metrics at this endpoint. The following example queries the Prometheus Scrape Endpoint for a route.

Tools such as Grafana are available to create customized charts and graphs based on the information collected by Prometheus. For more information on installing and running Grafana, refer to [the Grafana website](https://grafana.com).

1. Add the following route to IG:

   * Linux

   * Windows

   ```
   $HOME/.openig/config/routes/myroute1.json
   ```

   ```
   %appdata%\OpenIG\config\routes\myroute1.json
   ```

   ```json
   {
     "name": "myroute1",
     "handler": {
       "type": "StaticResponseHandler",
       "config": {
         "status": 200,
         "headers": {
           "Content-Type": [ "text/plain; charset=UTF-8" ]
         },
         "entity": "Hello world, from myroute1!"
       }
     },
     "condition": "${find(request.uri.path, '^/myroute1')}"
   }
   ```

   The route contains a StaticResponseHandler to display a simple message.

2. Access the route a few times, on <http://ig.example.com:8080/myroute1>.

3. Query the Prometheus Scrape Endpoint:

   ```bash
   $ curl "http://ig.example.com:8080/openig/metrics/prometheus"
   ```

   Metrics for `myroute1` and `_router` are displayed:

   ```none
   # HELP ig_router_deployed_routes Generated from Dropwizard metric import (metric=gateway._router.deployed-routes, type=gauge)
   # TYPE ig_router_deployed_routes gauge
   ig_router_deployed_routes{fully_qualified_name="gateway._router",heap="gateway",name="_router",} 1.0
   # HELP ig_route_request_active Generated from Dropwizard metric import (metric=gateway._router.route.default.request.active, type=gauge)
   # TYPE ig_route_request_active gauge
   ig_route_request_active{name="default",route="default",router="gateway._router",} 0.0
   # HELP ig_route_request_active Generated from Dropwizard metric import (metric=gateway._router.route.myroute1.request.active, type=gauge)
   # TYPE ig_route_request_active gauge
   ig_route_request_active{name="myroute1",route="myroute1",router="gateway._router",} 0.0
   # HELP ig_route_request_total Generated from Dropwizard metric import (metric=gateway._router.route.default.request, type=counter)
   # TYPE ig_route_request_total counter
   ig_route_request_total{name="default",route="default",router="gateway._router",} 0.0
   # HELP ig_route_response_error Generated from Dropwizard metric import (metric=gateway._router.route.default.response.error, type=counter)
   # TYPE ig_route_response_error counter
   ig_route_response_error{name="default",route="default",router="gateway._router",} 0.0
   # HELP ig_route_response_null Generated from Dropwizard metric import (metric=gateway._router.route.default.response.null, type=counter)
   # TYPE ig_route_response_null counter
   ig_route_response_null{name="default",route="default",router="gateway._router",} 0.0
   # HELP ig_route_response_status_total Generated from Dropwizard metric import (metric=gateway._router.route.default.response.status.client_error, type=counter)
   # TYPE ig_route_response_status_total counter
   ig_route_response_status_total{family="client_error",name="default",route="default",router="gateway._router",} 0.0
   ...
   ```

   Vert.x monitoring is enabled by default to provide additional metrics for HTTP, TCP, and the internal component pool. The metrics provide low-level information about requests and responses, such as the number of bytes, duration, the number of concurrent requests, and so on.

### Monitor the Common REST Monitoring Endpoint

All ForgeRock products expose a monitoring endpoint where metrics are exposed as a JSON format monitoring resource.

When IG is set up as described in [Quick install](../getting-started/preface.html), the Common REST Monitoring Endpoint is available at <http://ig.example.com:8080/openig/metrics/api?_prettyPrint=true&_sortKeys=_id&_queryFilter=true>

By default, no special setup or configuration is required to access metrics at this endpoint. The following example queries the Common REST Monitoring Endpoint for a route, and restricts the query to specific metrics only.

Before you start, prepare IG as described in the [Quick install](../getting-started/preface.html).

1. Set up IG and some example routes, as described in the first few steps of [Monitor the Prometheus Scrape Endpoint](#proc-monitor-prometheus).

2. Query the Common REST Monitoring Endpoint:

   ```bash
   $ curl "http://ig.example.com:8080/openig/metrics/api?_prettyPrint=true&_sortKeys=_id&_queryFilter=true"
   ```

   Metrics for `myroute1` and `_router` are displayed:

   ```json
   {
     "result" : [ {
     "_id" : "gateway._router.deployed-routes",
     "value" : 1.0,
     "_type" : "gauge"
   }, {
     "_id" : "gateway._router.route.default.request",
     "count" : 204,
     "_type" : "counter"
   }, {
     "_id" : "gateway._router.route.default.request.active",
     "value" : 0.0,
     "_type" : "gauge"
   }, {

          . . .

          _id" : "gateway._router.route.myroute1.response.status.unknown",
     "count" : 0,
     "_type" : "counter"
   }, {
     "_id" : "gateway._router.route.myroute1.response.time",
     "count" : 204,
     "max" : 0.420135,
     "mean" : 0.08624678327176545,
     "min" : 0.045079999999999995,
     "p50" : 0.070241,
     "p75" : 0.096049,
     "p95" : 0.178534,
     "p98" : 0.227217,
     "p99" : 0.242554,
     "p999" : 0.420135,
     "stddev" : 0.046611762381930474,
     "m15_rate" : 0.2004491450567003,
     "m1_rate" : 2.8726563452698075,
     "m5_rate" : 0.5974045160056258,
     "mean_rate" : 0.010877725092634833,
     "duration_units" : "milliseconds",
     "rate_units" : "calls/second",
     "total" : 17.721825,
     "_type" : "timer"
   } ],
     "resultCount" : 11,
     "pagedResultsCookie" : null,
     "totalPagedResultsPolicy" : "EXACT",
     "totalPagedResults" : 11,
     "remainingPagedResults" : -1
   }
   ```

   Vert.x monitoring is enabled by default to provide additional metrics for HTTP, TCP, and the internal component pool. The metrics provide low-level information about requests and responses, such as the number of bytes, duration, the number of concurrent requests, and so on.

3. Change the query to access metrics only for `myroute1`: <http://ig.example.com:8080/openig/metrics/api?_prettyPrint=true&_sortKeys=_id&_queryFilter=_id+sw+"gateway._router.route.myroute1">;.

   Note that metric for the router, `"_id" : "gateway._router.deployed-routes"`, is no longer displayed.

### Monitor Vert.x metrics

|   |                                                                                                                                                                                                   |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Vert.x metric names are deprecated and expected to be replaced with names ending in \_total. The information provided by the metric is not deprecated. Other Prometheus metrics are not affected. |

Vert.x monitoring is enabled by default to provide metrics for HTTP, TCP, and the internal component pool. The metrics provide low-level information about requests and responses, such as the number of bytes, duration, the number of concurrent requests, and so on.

To disable Vert.x monitoring, add the following lines to `admin.json`, and restart IG:

```none
{
  "vertx": {
    "metricsEnabled": false
  }
}
```

For more information, refer to [AdminHttpApplication (admin.json)](../reference/RequiredConfiguration.html#AdminHttpApplication).

## Protect monitoring endpoints

By default, no special credentials or privileges are required for read-access to the Prometheus Scrape Endpoint and Common REST Monitoring Endpoint.

To protect the monitoring endpoints, add an `admin.json` file to your configuration, with a filter declared in the heap and named `MetricsProtectionFilter`. The following procedure gives an example of how to manage access to the monitoring endpoints.

1. Set up the procedure in [Monitor at the Prometheus Scrape Endpoint](#monitor-prometheus), query the Prometheus Scrape Endpoint, and note that metrics for `myroute1` and `_router` are displayed:

   ```bash
   $ curl -v "http://ig.example.com:8080/openig/metrics/prometheus"
   ```

2. Add the following script to the IG configuration:

   * Linux

   * Windows

   ```
   $HOME/.openig/scripts/groovy/BasicAuthResourceServerFilter.groovy
   ```

   ```
   %appdata%\OpenIG\scripts\groovy\BasicAuthResourceServerFilter.groovy
   ```

   ```groovy
   /*
    * This script is a simple implementation of HTTP basic access authentication on
    * server side.
    * It expects the following arguments:
    *  - realm: the realm to display when the user agent prompts for
    *    username and password if none were provided.
    *  - username: the expected username
    *  - passwordSecretId: the secretId to find the password
    *  - secretsProvider: the SecretsProvider to query for the password
   */
   import static org.forgerock.util.promise.Promises.newResultPromise;

   import java.nio.charset.Charset;
   import org.forgerock.util.encode.Base64;
   import org.forgerock.secrets.Purpose;
   import org.forgerock.secrets.GenericSecret;

   String authorizationHeader = request.getHeaders().getFirst("Authorization");
   if (authorizationHeader == null) {
       // No credentials provided, return 401 Unauthorized
       Response response = new Response(Status.UNAUTHORIZED);
       response.getHeaders().put("WWW-Authenticate", "Basic realm=\"" + realm + "\"");
       return newResultPromise(response);
   }

   return secretsProvider.getNamed(Purpose.PASSWORD, passwordSecretId)
           .thenAsync(password -> {
               // Build basic authentication string -> username:password
               StringBuilder basicAuthString = new StringBuilder(username).append(":");
               password.revealAsUtf8{ p -> basicAuthString.append(new String(p).trim()) };
               String expectedAuthorization = "Basic " + Base64.encode(basicAuthString.toString().getBytes(Charset.defaultCharset()));
               // Incorrect credentials provided, return 403 forbidden
               if (!expectedAuthorization.equals(authorizationHeader)) {
                   return newResultPromise(new Response(Status.FORBIDDEN));
               }
               // Correct credentials provided, continue.
               return next.handle(context, request);
           },
                   noSuchSecretException -> { throw new RuntimeException(noSuchSecretException); });
   ```

   The script is a simple implementation of the HTTP basic access authentication scheme. For information about scripting filters and handlers, refer to [Extensibility](../configure/extending.html).

3. Add the following `admin.json` configuration to IG:

   ```json
   {
     "prefix": "openig",
     "connectors": [
       { "port": 8080 }
     ],
     "heap": [
       {
         "name": "ClientHandler",
         "type": "ClientHandler"
       },
       {
         "name": "mySecretsProvider",
         "type": "Base64EncodedSecretStore",
         "config": {
           "secrets": {
             "password.secret.id": "cGFzc3dvcmQ="
           }
         }
       },
       {
         "name": "MetricsProtectionFilter",
         "type": "ScriptableFilter",
         "config": {
           "type": "application/x-groovy",
           "file": "BasicAuthResourceServerFilter.groovy",
           "args": {
             "realm": "/",
             "username": "myUsername",
             "passwordSecretId": "password.secret.id",
             "secretsProvider": "${heap['mySecretsProvider']}"
           }
         }
       }
     ]
   }
   ```

   Notice the following features of the configuration:

   * The MetricsProtectionFilter uses the script to protect the monitoring endpoint.

   * The MetricsProtectionFilter requires the username `myUsername`, and a password provided by the SecretsProvider in the heap.

4. Restart IG.

5. Query the Prometheus Scrape Endpoint without providing credentials, and note that an HTTP 401 Unauthorized is returned:

   ```bash
   $ curl -v "http://ig.example.com:8080/openig/metrics/prometheus"
   ```

6. Query the Prometheus Scrape Endpoint by providing correct credentials, and note that metrics are displayed:

   ```bash
   $ curl -v "http://ig.example.com:8080/openig/metrics/prometheus" -u myUsername:password
   ```

7. Query the Prometheus Scrape Endpoint by providing incorrect credentials\`, and note that an HTTP 403 Forbidden is returned:

   ```bash
   $ curl -v "http://ig.example.com:8080/openig/metrics/prometheus" -u myUsername:wrong-password
   ```
