Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pinecone-mixin/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../Makefile_mixin
126 changes: 126 additions & 0 deletions pinecone-mixin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Pinecone Mixin

The Pinecone mixin is a set of configurable Grafana dashboards and alerts based on the metrics exported by the [Pinecone Prometheus exporter](https://docs.pinecone.io/guides/production/monitoring#monitor-with-prometheus).

## Dashboards

- **Pinecone Overview** - Provides details on index capacity, operation metrics (upsert, query, fetch, delete), operation durations, and resource usage (read/write units).

## Alerts

| Alert | Summary |
| ----- | ------- |
| PineconeHighQueryLatency | Query latency exceeds baseline thresholds, indicating performance degradation in query operations. |
| PineconeHighUpsertLatency | Upsert latency exceeds baseline thresholds, indicating performance degradation in upsert operations. |
| PineconeHighErrorRate | Error rate exceeds configured thresholds, indicating increased request failures. |
| PineconeHighStorageUsage | Index storage usage is high, risking degraded performance. |
| PineconeHighUnitConsumption | Read or write unit consumption is increasing rapidly or nearing allocated limits. |

Alert thresholds can be configured in `config.libsonnet`. See the generated `prometheus_alerts.yaml` for default values.

## Configuration

This mixin is designed to work with Pinecone's built-in Prometheus exporter, which is available on Standard and Enterprise plans.

### Alloy

To monitor all serverless indexes in a project using Alloy, add the following to your Alloy configuration:

```alloy
prometheus.scrape "pinecone" {
targets = discovery.http "pinecone" {
url = "https://api.pinecone.io/prometheus/projects/PROJECT_ID/metrics/discovery"
refresh_interval = "1m"
authorization {
type = "Bearer"
credentials = "API_KEY"
}
}.targets
forward_to = [prometheus.remote_write.metrics.receiver]
}

prometheus.remote_write "metrics" {
endpoint {
url = "YOUR_PROMETHEUS_REMOTE_WRITE_ENDPOINT"
}
}
```

Replace `PROJECT_ID` and `API_KEY` with your Pinecone project ID and API key. For more details, see the [Pinecone monitoring documentation](https://docs.pinecone.io/guides/production/monitoring#monitor-with-prometheus).

**Note:** If you have more than one Pinecone project, you need to add separate scrape configurations for each project with different project IDs and targets. It is recommended to add a `project_id` label via relabeling to distinguish metrics from different projects.

#### Alloy (Multiple Projects)

```alloy
discovery.http "pinecone_project_1" {
url = "https://api.pinecone.io/prometheus/projects/PROJECT_ID_1/metrics/discovery"
refresh_interval = "1m"
authorization {
type = "Bearer"
credentials = "API_KEY_1"
}
}

prometheus.scrape "pinecone_project_1" {
targets = discovery.http.pinecone_project_1.targets
forward_to = [prometheus.remote_write.metrics.receiver]

relabel {
source_labels = ["__meta_http_sd_url"]
regex = ".*/projects/([^/]+)/.*"
target_label = "project_id"
replacement = "${1}"
}
}

discovery.http "pinecone_project_2" {
url = "https://api.pinecone.io/prometheus/projects/PROJECT_ID_2/metrics/discovery"
refresh_interval = "1m"
authorization {
type = "Bearer"
credentials = "API_KEY_2"
}
}

prometheus.scrape "pinecone_project_2" {
targets = discovery.http.pinecone_project_2.targets
forward_to = [prometheus.remote_write.metrics.receiver]

relabel {
source_labels = ["__meta_http_sd_url"]
regex = ".*/projects/([^/]+)/.*"
target_label = "project_id"
replacement = "${1}"
}
}

prometheus.remote_write "metrics" {
endpoint {
url = "YOUR_PROMETHEUS_REMOTE_WRITE_ENDPOINT"
}
}
```

## Install Tools

To use this mixin, a working Golang toolchain is required, alongside having `mixtool` and `jsonnetfmt` installed.
To do so, run the following:

```bash
go install github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb@latest
go install github.com/monitoring-mixins/mixtool/cmd/mixtool@latest
go install github.com/google/go-jsonnet/cmd/jsonnetfmt@latest
```

## Generate Dashboards and Alerts

Edit `config.libsonnet` if required and then build JSON dashboard files for Grafana:

```bash
make
```

The files in `dashboards_out` need to be imported into your Grafana server. The `prometheus_alerts.yaml` file needs to be imported into Prometheus.

For more advanced uses of mixins, see [Prometheus Monitoring Mixins docs](https://github.com/monitoring-mixins/docs).
14 changes: 14 additions & 0 deletions pinecone-mixin/alerts/alerts.libsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
new(this): {
prometheusAlerts+:: {
groups+: [
{
name: 'pinecone',
rules: [
// Add your alert rules here
],
},
],
},
},
}
26 changes: 26 additions & 0 deletions pinecone-mixin/config.libsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
local this = self,
dashboardTags: ['pinecone'],
dashboardPeriod: 'now-1h',
dashboardTimezone: 'default',
dashboardRefresh: '1m',
dashboardNamePrefix: 'Pinecone',
uid: 'pinecone',

// Filtering and labels
filteringSelector: 'job=~"$job"',
groupLabels: ['job'], // Job label for filtering
instanceLabels: ['instance', 'index_name'], // Instance and index_name labels

// Metrics source
metricsSource: ['prometheus'],

// Signals
signals: {
operations: (import './signals/operations.libsonnet')(this),
overview: (import './signals/overview.libsonnet')(this),
},

// Feature flags
enableLokiLogs: false,
}
25 changes: 25 additions & 0 deletions pinecone-mixin/dashboards.libsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
local g = import '../g.libsonnet';

{
new(this):
{
'pinecone-overview.json':
g.dashboard.new(this.config.dashboardNamePrefix + ' overview')
+ g.dashboard.withUid(this.config.uid + '-overview')
+ g.dashboard.withTags(this.config.dashboardTags)
+ g.dashboard.withTimezone(this.config.dashboardTimezone)
+ g.dashboard.withRefresh(this.config.dashboardRefresh)
+ g.dashboard.time.withFrom(this.config.dashboardPeriod)
+ g.dashboard.withVariables(
this.signals.operations.getVariablesMultiChoice()
)
+ g.dashboard.withPanels(
g.util.grid.wrapPanels(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation issue here, and could you wrap wrapPanels in resolveCollapsedFlagOnRow as well to account for any future collapsed rows we may have?

this.grafana.rows.overview
+ this.grafana.rows.writeOperations
+ this.grafana.rows.readOperations
+ this.grafana.rows.resourceUsage
)
),
},
}
1 change: 1 addition & 0 deletions pinecone-mixin/g.libsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import 'github.com/grafana/grafonnet/gen/grafonnet-v11.4.0/main.libsonnet'
26 changes: 26 additions & 0 deletions pinecone-mixin/jsonnetfile.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"version": 1,
"dependencies": [
{
"source": {
"git": {
"remote": "https://github.com/grafana/grafonnet.git",
"subdir": "gen/grafonnet-v11.4.0"
}
},
"version": "main"
},
{
"source": {
"git": {
"remote": "https://github.com/grafana/jsonnet-libs.git",
"subdir": "common-lib"
}
},
"version": "master"
}
],
"legacyImports": true
}


56 changes: 56 additions & 0 deletions pinecone-mixin/main.libsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
local alerts = import './alerts/alerts.libsonnet';
local config = import './config.libsonnet';
local dashboards = import './dashboards.libsonnet';
local panels = import './panels.libsonnet';
local rows = import './rows.libsonnet';
local commonlib = import 'common-lib/common/main.libsonnet';

{
new(): {
local this = self,
config: config,

signals:
{
operations: commonlib.signals.unmarshallJsonMulti(
this.config.signals.operations,
type=this.config.metricsSource
),
overview: commonlib.signals.unmarshallJsonMulti(
this.config.signals.overview,
type=this.config.metricsSource
),
},

grafana: {
variables: commonlib.variables.new(
filteringSelector=this.config.filteringSelector,
groupLabels=this.config.groupLabels,
instanceLabels=this.config.instanceLabels,
varMetric='pinecone_db_record_total',
customAllValue='.+',
enableLokiLogs=this.config.enableLokiLogs,
),
annotations: {},
links: {},
panels: panels.new(this),
dashboards: dashboards.new(this),
rows: rows.new(this),
},

prometheus: {
alerts: alerts.new(this),
recordingRules: {},
},

asMonitoringMixin(): {
grafanaDashboards+:: this.grafana.dashboards,
prometheusAlerts+:: this.prometheus.alerts,
prometheusRules+:: this.prometheus.recordingRules,
},
},

withConfigMixin(config): {
config+: config,
},
}
1 change: 1 addition & 0 deletions pinecone-mixin/mixin.libsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(import './main.libsonnet').new().asMonitoringMixin()
Loading
Loading