Skip to content
This repository has been archived by the owner on Mar 21, 2024. It is now read-only.

Commit

Permalink
Metrics API — Introduce a /metrics route for observability / monito…
Browse files Browse the repository at this point in the history
…ring purposes (#174)

* init spec for /metrics

* Rename spec filename and add description for metrics

* update metrics name and type col in the metrics table; add auth errors

* Add --enable-metrics-route to instance-options.md specification

* Precise metrics

* update open-api.yml

* Add telemetry instance property

* Mention metrics route on stats.get action

* Add  action

* Precise  action description

* Rephrase future possibility

* Add MEILI_ENABLE_METRICS_ROUTE

* rename all the cli parameter to the experimental variant

* Update text/0174-metrics-api.md

Co-authored-by: Guillaume Mourier <guillaume@meilisearch.com>

* Update open-api.yaml

Co-authored-by: Guillaume Mourier <guillaume@meilisearch.com>

* Update text/0085-api-keys.md

Co-authored-by: Guillaume Mourier <guillaume@meilisearch.com>

* Apply suggestions from code review

Co-authored-by: Tamo <tamo@meilisearch.com>

---------

Co-authored-by: Tamo <tamo@meilisearch.com>
  • Loading branch information
gmourier and irevoire authored Apr 3, 2023
1 parent 4caad7a commit 6d9a5fd
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 1 deletion.
52 changes: 52 additions & 0 deletions open-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@ components:
- settings.get
- settings.update
- stats.get
- metrics.get
- dumps.create
- version
- keys.get
Expand Down Expand Up @@ -3702,4 +3703,55 @@ paths:
$ref: '#/components/examples/202_indexSwap'
'401':
$ref: '#/components/responses/401'
parameters:
- $ref: '#/components/parameters/taskUid'
/metrics:
get:
summary: (EXPERIMENTAL) Get prometheus format metrics for observability and monitoring
description: 'See [technical specification](https://github.com/meilisearch/specifications/blob/main/text/0174-metrics-api.md)'
tags:
- stats
responses:
'200':
description: OK
content:
text/plain:
type: string
examples:
sampleResponse: '
# HELP http_requests_total HTTP requests total
# TYPE http_requests_total counter
http_requests_total{method="GET",path="/metrics"} 3
# HELP http_response_time_seconds HTTP response times
# TYPE http_response_time_seconds histogram
http_response_time_seconds_bucket{method="GET",path="/metrics",le="0.0005"} 0
http_response_time_seconds_bucket{method="GET",path="/metrics",le="0.0008"} 1
http_response_time_seconds_bucket{method="GET",path="/metrics",le="0.00085"} 1
http_response_time_seconds_bucket{method="GET",path="/metrics",le="0.0009"} 1
http_response_time_seconds_bucket{method="GET",path="/metrics",le="0.00095"} 1
http_response_time_seconds_bucket{method="GET",path="/metrics",le="0.001"} 1
http_response_time_seconds_bucket{method="GET",path="/metrics",le="0.00105"} 1
http_response_time_seconds_bucket{method="GET",path="/metrics",le="0.0011"} 1
http_response_time_seconds_bucket{method="GET",path="/metrics",le="0.00115"} 1
http_response_time_seconds_bucket{method="GET",path="/metrics",le="0.0012"} 1
http_response_time_seconds_bucket{method="GET",path="/metrics",le="0.0015"} 1
http_response_time_seconds_bucket{method="GET",path="/metrics",le="0.002"} 1
http_response_time_seconds_bucket{method="GET",path="/metrics",le="0.003"} 1
http_response_time_seconds_bucket{method="GET",path="/metrics",le="1"} 2
http_response_time_seconds_bucket{method="GET",path="/metrics",le="+Inf"} 2
http_response_time_seconds_sum{method="GET",path="/metrics"} 0.0056515409999999995
http_response_time_seconds_count{method="GET",path="/metrics"} 2
# HELP meilisearch_db_size_bytes Meilisearch Db Size In Bytes
# TYPE meilisearch_db_size_bytes gauge
meilisearch_db_size_bytes 155648
# HELP meilisearch_index_count Meilisearch Index Count
# TYPE meilisearch_index_count gauge
meilisearch_index_count 1
# HELP meilisearch_index_docs_count Meilisearch Index Docs Count
# TYPE meilisearch_index_docs_count gauge
meilisearch_index_docs_count{index="movies"} 0'
operationId: metrics.get
parameters: []
security:
- apiKey: []
security: []
2 changes: 2 additions & 0 deletions text/0034-telemetry-policies.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ The collected data is sent to [Segment](https://segment.com/). Segment is a plat
| `infos.ssl_resumption` | `true` if `--ssl-resumption`/`MEILI_SSL_RESUMPTION` is specified, otherwise `false` | false | Every Hour |
| `infos.ssl_tickets` | `true` if `--ssl-tickets`/`MEILI_SSL_TICKETS` is specified, otherwise `false` | false | Every Hour |
| `infos.with_configuration_file` | `true` if the instance is launched with a configuration file, otherwise `false` | false | Every Hour |
| `infos.experimental_enable_metrics` | `true` if `--experimental-enable-metrics`/`MEILI_EXPERIMENTAL_ENABLE_METRICS` is specified at launch, otherwise `false` | `false` | Every Hour |
| `system.distribution` | Distribution on which MeiliSearch is launched | Arch Linux | Every hour |
| `system.kernel_version` | Kernel version on which MeiliSearch is launched | 5.14.10 | Every hour |
| `system.cores` | Number of cores | 24 | Every hour |
Expand Down Expand Up @@ -221,6 +222,7 @@ This property allows us to gather essential information to better understand on
| infos.ssl_resumption | `true` if `--ssl-resumption`/`MEILI_SSL_RESUMPTION` is specified, otherwise `false` | false |
| infos.ssl_tickets | `true` if `--ssl-tickets`/`MEILI_SSL_TICKETS` is specified, otherwise `false` | false |
| infos.with_configuration_file | `true` if the instance is launched with a configuration file, otherwise `false` | `false` |
| infos.experimental_enable_metrics | `true` if `--experimental-enable-metrics`/`MEILI_EXPERIMENTAL_ENABLE_METRICS` is specified at launch, otherwise `false` | `false` |

##### MeiliSearch Statistics `stats`

Expand Down
3 changes: 2 additions & 1 deletion text/0085-api-keys.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,8 @@ Create an API key.
| tasks.delete | Provides access to `DELETE` `/tasks` route. |
| settings.get | Provides access to `GET` `/indexes/:authorizedIndexes/settings` and `/indexes/:authorizedIndexes/settings/*` routes. |
| settings.update | Provides access to `POST / DELETE` `/indexes/:authorizedIndexes/settings` and `/indexes/:authorizedIndexes/settings/*` routes. |
| stats.get | Provides access to `GET` `/stats/`. **⚠️Non-authorized `indexes` are omitted from the response on `/stats`**. Also add access to `GET` `/indexes/:authorizedIndexes/stats`. |
| stats.get | Provides access to `GET` `/stats`. **⚠️Non-authorized `indexes` are omitted from the response on `/stats`**. Also add access to `GET` `/indexes/:authorizedIndexes/stats`. |
| metrics.get | Provides access to `GET` `/metrics` route. **A restriction on `indexes` stops you from calling the route.** |
| dumps.create | Provides access to `POST` `/dumps` route. **As dumps are not scoped by indexes, a restriction on `indexes` does not affect this action.** |
| version | Provides access to `GET` `/version` route. |
| keys.get | Provides access to `GET` `/keys` route. |
Expand Down
11 changes: 11 additions & 0 deletions text/0119-instance-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ The expected behavior of each flag is described in the list above.
- [SSL resumption](#3324-ssl-resumption)
- [SSL tickets](#3325-ssl-tickets)
- [Config file path](#3326-config-file-path)
- [Experimental enable Metrics](#3327-experimental-enable-metrics)

#### 3.3.1. Database path

Expand Down Expand Up @@ -476,6 +477,16 @@ Define the config file to load at Meilisearch launch.

See [Configuration File](0185-configuration-file.md) specification details.

#### 3.3.27. Experimental enable Metrics

**Environment variable**: `MEILI_EXPERIMENTAL_ENABLE_METRICS`
**CLI option**: `--experimental-enable-metrics`
**Default**: Disabled

⚠️ This command-line option does not take any values. Assigning a value will throw an error.

Activate the `/metrics` endpoint to collect Meilisearch metrics for monitoring purposes. See [0174-metrics-api.md](0174-metrics-api.md).

## 4. Technical Aspects

N/A
Expand Down
148 changes: 148 additions & 0 deletions text/0174-metrics-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Metrics API

This endpoint is currently experimental.

This means that it can break at any time between two minor versions as long as it is not stabilized.

## 1. Summary

This specification describes the metrics API endpoint with the exhaustive list of returned metrics.

The endpoint returns observability data to monitor a Meilisearch instance using [prometheus](https://prometheus.io/).

## 2. Motivation

Improve the capabilities of a Meilisearch instance regarding observability and ease its integration into monitoring stacks.

## 3. Functionnal Specification

### 3.1. Activating the feature

By default, the `/metrics` endpoint is not accessible. To activate it, the `--experimental-enable-metrics` CLI option or `MEILI_EXPERIMENTAL_ENABLE_METRICS` env var must be specified at launch. See [Instance Options](0119-instance-options.md)

### 3.2. `metrics` API resource definition

Prometheus metrics format is text-based and line-oriented. Lines are separated by a line feed character (n).

A metric is composed by several fields:

- `# HELP` metadata
- `# TYPE` metadata
- Metric name
- Current metric value

Meilisearch returns the metrics specified in the table below.

| Name | Type |
|---------------------------------------------------------------------------|-----------|
| [`http_requests_total`](#321-http_requests_total) | counter |
| [`http_response_time_seconds`](#322-http_response_time_seconds) | histogram |
| [`meilisearch_database_size_bytes`](#323-meilisearch_database_size_bytes) | gauge |
| [`meilisearch_index_docs_count`](#324-meilisearch_index_docs_count) | gauge |
| [`meilisearch_index_count`](#325-meilisearch_index_count) | gauge |

#### 3.2.1 `http_requests_total`

Returns the number of times an API resource is accessed.

```
# HELP http_requests_total HTTP requests total
# TYPE http_requests_total counter
http_requests_total{method=":httpMethod",path=":resourcePath"} :numberOfRequest
```

#### 3.2.2. `http_responses_time_seconds`

Returns a time histogram showing the number of times an API resource call goes into a time bucket (expressed in second).

```
# HELP http_response_time_seconds HTTP response times
# TYPE http_response_time_seconds histogram
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="0.0005"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="0.0008"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="0.00085"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="0.0009"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="0.00095"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="0.001"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="0.00105"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="0.0011"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="0.00115"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="0.0012"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="0.0015"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="0.002"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="0.003"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="1"} :numberOfRequest
http_response_time_seconds_bucket{method=":httpMethod",path=":resourcePath",le="+Inf"} :numberOfRequest
http_response_time_seconds_sum{method=":httpMethod",path=":resourcePath"} :numberOfRequest
http_response_time_seconds_count{method=":httpMethod",path=":resourcePath"} :numberOfRequest
```

#### 3.2.3. `meilisearch_database_size_bytes`

Returns the size of the database in bytes.

```
# HELP meilisearch_db_size_bytes Meilisearch Db Size In Bytes
# TYPE meilisearch_db_size_bytes gauge
meilisearch_db_size_bytes :databaseSizeInBytes
```

#### 3.2.4. `meilisearch_index_docs_count`

Returns the number of documents for an index.

```
# HELP meilisearch_index_docs_count Meilisearch Index Docs Count
# TYPE meilisearch_index_docs_count gauge
meilisearch_index_docs_count{index=":indexUid"} :numberOfDocuments
```

#### 3.2.5. `meilisearch_index_count`

Returns the total number of index for the Meilisearch instance.

```
# HELP meilisearch_index_count Meilisearch Index Count
# TYPE meilisearch_index_count gauge
meilisearch_index_count :numberOfIndex
````
### 3.3. API Endpoints Definition
#### 3.3.1. `GET` - `/metrics`
Fetch the metrics of the Meilisearch instance.
`200` - Response body example
```
# HELP meilisearch_database_size MeiliSearch Stats DbSize
# TYPE meilisearch_database_size gauge
meilisearch_database_size 1097728
# HELP meilisearch_docs_count MeiliSearch Stats Docs Count
# TYPE meilisearch_docs_count gauge
meilisearch_docs_count{index="movies"} 807
meilisearch_docs_count{index="movies_2"} 0
# HELP meilisearch_total_index MeiliSearch Stats Index Count
# TYPE meilisearch_total_index gauge
meilisearch_total_index 2
```
#### 3.3.2. Errors
- 🔴 If `--experimental-enable-metrics` CLI option / `MEILI_EXPERIMENTAL_ENABLE_METRICS` env var is not specified at launch, the API returns a `404 Not Found` HTTP response.
##### 3.3.2.1 Auth Errors
If a master key is used to secure a Meilisearch instance, the auth layer returns the following errors:
- 🔴 Accessing this route without the `Authorization` header returns a [missing_authorization_header](0061-error-format-and-definitions.md#missing_authorization_header) error.
- 🔴 Accessing this route with a key that does not have the permission `metrics.get` (i.e. other than the master key) returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error.
- 🔴 Accessing this route with a key that have a restriction on the indexes returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error.
## 4. Technical Details
N/A
## 5. Future Possibilities
- Merge `/stats` with `/metrics`. A header could specify the prefered format. e.g `application/json` (similar to actual `stats` resource) or `text/plain` (prometheus)

0 comments on commit 6d9a5fd

Please sign in to comment.