Skip to content

Commit 05cd7bf

Browse files
committed
feat: add opensearch plugin
1 parent b6a641a commit 05cd7bf

47 files changed

Lines changed: 6664 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

opensearch/README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Plugin Module: opensearch
2+
3+
Datasource plugin for [OpenSearch](https://opensearch.org/) in Perses. Supports log queries using
4+
[PPL (Piped Processing Language)](https://opensearch.org/docs/latest/search-plugins/sql/ppl/index/).
5+
6+
This plugin is intended to display logs alongside the traces surfaced by the Tempo plugin, so a user can
7+
pivot from a trace to the related logs in OpenSearch.
8+
9+
### How to install
10+
11+
This plugin requires react and react-dom 18.
12+
13+
```bash
14+
npm install react@18 react-dom@18
15+
npm install @perses-dev/opensearch-plugin
16+
```
17+
18+
## Development
19+
20+
```bash
21+
npm install
22+
npm run dev # start the dev server
23+
npm run build # build the plugin
24+
npm test # run unit tests
25+
```
26+
27+
## Trace to logs
28+
29+
This plugin is intended to display logs alongside traces produced by the Tempo or
30+
Jaeger plugins. Use a dashboard variable (e.g. `$traceId`) to share the selected
31+
trace between the trace panel and the OpenSearch logs panel.
32+
33+
PPL example:
34+
35+
```
36+
source=otel-logs-* | where traceId='$traceId'
37+
```
38+
39+
A complete example dashboard is in `docs/examples/trace-to-logs.json`. See
40+
`docs/examples/README.md` for field-name conventions and how to swap Tempo for Jaeger.
41+
42+
## Field overrides
43+
44+
OpenSearch is schema-flexible; field names vary by exporter. The plugin tries
45+
common names by default (`@timestamp`/`timestamp`/`time` for the timestamp;
46+
`message`/`log`/`body` for the message). If your index uses different names,
47+
set `timestampField` and `messageField` on the query spec.

opensearch/cue.mod/module.cue

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module: "github.com/perses/plugins/opensearch@v0"
2+
language: {
3+
version: "v0.15.1"
4+
}
5+
source: {
6+
kind: "git"
7+
}
8+
deps: {
9+
"github.com/perses/shared/cue@v0": {
10+
v: "v0.53.1"
11+
default: true
12+
}
13+
}

opensearch/docs/examples/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# OpenSearch examples
2+
3+
## trace-to-logs.json
4+
5+
Demonstrates the trace→logs pivot:
6+
7+
1. The `traceId` dashboard variable holds the currently selected trace.
8+
2. The Tempo panel renders the trace via `TempoTraceQuery` and `TracingGanttChart`.
9+
3. The OpenSearch logs panel runs a PPL query filtered by `traceId='$traceId'`.
10+
11+
When the user picks a trace in the gantt chart (or sets the variable elsewhere),
12+
the logs panel re-runs and shows logs for that trace.
13+
14+
### Field-name conventions
15+
16+
OpenSearch indexes vary in how they name fields. Common defaults:
17+
18+
| Source | timestamp | message | trace id |
19+
| ---------------------------- | ------------ | --------- | ---------- |
20+
| OpenTelemetry / Data Prepper | `@timestamp` | `body` | `traceId` |
21+
| AWS / X-Ray exporter | `@timestamp` | `message` | `traceId` |
22+
| Legacy / custom | `time` | `message` | `trace_id` |
23+
24+
If your index uses different names, set `timestampField` and/or `messageField` on
25+
the `OpenSearchLogQuery` spec, and adjust the `where` clause to your trace_id field.
26+
27+
### Swap Tempo for Jaeger
28+
29+
Replace the Tempo panel's `plugin.kind` and `datasource.kind` with `JaegerTraceQuery`
30+
and `JaegerDatasource`. The OpenSearch panel does not change.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
{
2+
"kind": "Dashboard",
3+
"metadata": {
4+
"name": "trace-to-logs-example",
5+
"project": "examples"
6+
},
7+
"spec": {
8+
"display": {
9+
"name": "Trace to Logs (Tempo + OpenSearch)"
10+
},
11+
"duration": "1h",
12+
"variables": [
13+
{
14+
"kind": "TextVariable",
15+
"spec": {
16+
"name": "traceId",
17+
"value": ""
18+
}
19+
}
20+
],
21+
"panels": {
22+
"trace": {
23+
"kind": "Panel",
24+
"spec": {
25+
"display": { "name": "Trace" },
26+
"plugin": {
27+
"kind": "TracingGanttChart",
28+
"spec": {}
29+
},
30+
"queries": [
31+
{
32+
"kind": "TraceQuery",
33+
"spec": {
34+
"plugin": {
35+
"kind": "TempoTraceQuery",
36+
"spec": {
37+
"query": "$traceId",
38+
"datasource": { "kind": "TempoDatasource", "name": "tempo" }
39+
}
40+
}
41+
}
42+
}
43+
]
44+
}
45+
},
46+
"logs": {
47+
"kind": "Panel",
48+
"spec": {
49+
"display": { "name": "Logs for current trace" },
50+
"plugin": {
51+
"kind": "LogsTable",
52+
"spec": {}
53+
},
54+
"queries": [
55+
{
56+
"kind": "LogQuery",
57+
"spec": {
58+
"plugin": {
59+
"kind": "OpenSearchLogQuery",
60+
"spec": {
61+
"datasource": { "kind": "OpenSearchDatasource", "name": "opensearch" },
62+
"index": "otel-logs-*",
63+
"query": "source=otel-logs-* | where traceId='$traceId'"
64+
}
65+
}
66+
}
67+
}
68+
]
69+
}
70+
}
71+
},
72+
"layouts": [
73+
{
74+
"kind": "Grid",
75+
"spec": {
76+
"items": [
77+
{ "x": 0, "y": 0, "width": 24, "height": 12, "content": { "$ref": "#/spec/panels/trace" } },
78+
{ "x": 0, "y": 12, "width": 24, "height": 12, "content": { "$ref": "#/spec/panels/logs" } }
79+
]
80+
}
81+
}
82+
]
83+
}
84+
}

opensearch/go.mod

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module github.com/perses/plugins/opensearch
2+
3+
go 1.25.7
4+
5+
require github.com/perses/perses v0.53.1
6+
7+
require (
8+
github.com/beorn7/perks v1.0.1 // indirect
9+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
10+
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
11+
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
12+
github.com/google/uuid v1.6.0 // indirect
13+
github.com/jpillora/backoff v1.0.0 // indirect
14+
github.com/kr/text v0.2.0 // indirect
15+
github.com/muhlemmer/gu v0.3.1 // indirect
16+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
17+
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
18+
github.com/perses/common v0.30.2 // indirect
19+
github.com/prometheus/client_golang v1.23.2 // indirect
20+
github.com/prometheus/client_model v0.6.2 // indirect
21+
github.com/prometheus/common v0.67.5 // indirect
22+
github.com/prometheus/procfs v0.17.0 // indirect
23+
github.com/zitadel/oidc/v3 v3.45.4 // indirect
24+
github.com/zitadel/schema v1.3.2 // indirect
25+
go.yaml.in/yaml/v2 v2.4.3 // indirect
26+
golang.org/x/net v0.49.0 // indirect
27+
golang.org/x/oauth2 v0.35.0 // indirect
28+
golang.org/x/sys v0.41.0 // indirect
29+
golang.org/x/text v0.34.0 // indirect
30+
google.golang.org/protobuf v1.36.11 // indirect
31+
gopkg.in/yaml.v3 v3.0.1 // indirect
32+
)

opensearch/go.sum

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
2+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
3+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
4+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
5+
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
6+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
7+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8+
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
9+
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
10+
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
11+
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
12+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
13+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
14+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
15+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
16+
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
17+
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
18+
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
19+
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
20+
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
21+
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
22+
github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM=
23+
github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM=
24+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
25+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
26+
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
27+
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
28+
github.com/nexucis/lamenv v0.5.2 h1:tK/u3XGhCq9qIoVNcXsK9LZb8fKopm0A5weqSRvHd7M=
29+
github.com/nexucis/lamenv v0.5.2/go.mod h1:HusJm6ltmmT7FMG8A750mOLuME6SHCsr2iFYxp5fFi0=
30+
github.com/perses/common v0.30.2 h1:RAiVxUpX76lTCb4X7pfcXSvYdXQmZwKi4oDKAEO//u0=
31+
github.com/perses/common v0.30.2/go.mod h1:DFtur1QPah2/ChXbKKhw7djYdwNgz27s5fPKpiK0Xao=
32+
github.com/perses/perses v0.53.1 h1:9VY/6p9QWrZwPSV7qiwTMSOsgcB37Lb1AXKT0ORXc6I=
33+
github.com/perses/perses v0.53.1/go.mod h1:ro8fsgBkHYOdrL/MV+fdP9mflKzYCy/+gcbxiaReI/A=
34+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
35+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
36+
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
37+
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
38+
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
39+
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
40+
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
41+
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
42+
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
43+
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
44+
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
45+
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
46+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
47+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
48+
github.com/zitadel/oidc/v3 v3.45.4 h1:GKyWaPRVQ8sCu9XgJ3NgNGtG52FzwVJpzXjIUG2+YrI=
49+
github.com/zitadel/oidc/v3 v3.45.4/go.mod h1:XALmFXS9/kSom9B6uWin1yJ2WTI/E4Ti5aXJdewAVEs=
50+
github.com/zitadel/schema v1.3.2 h1:gfJvt7dOMfTmxzhscZ9KkapKo3Nei3B6cAxjav+lyjI=
51+
github.com/zitadel/schema v1.3.2/go.mod h1:IZmdfF9Wu62Zu6tJJTH3UsArevs3Y4smfJIj3L8fzxw=
52+
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
53+
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
54+
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
55+
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
56+
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
57+
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
58+
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
59+
golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
60+
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
61+
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
62+
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
63+
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
64+
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
65+
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
66+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
67+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
68+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
69+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
70+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

opensearch/jest.config.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright The Perses Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
import { readFileSync } from 'fs';
15+
import { resolve, dirname } from 'path';
16+
import { fileURLToPath } from 'url';
17+
import type { Config } from '@jest/types';
18+
19+
const here = dirname(fileURLToPath(import.meta.url));
20+
const swcrc = JSON.parse(readFileSync(resolve(here, '../.cjs.swcrc'), 'utf-8'));
21+
22+
const jestConfig: Config.InitialOptions = {
23+
testEnvironment: 'jsdom',
24+
roots: ['<rootDir>/src'],
25+
moduleNameMapper: {
26+
'^echarts/(.*)$': 'echarts',
27+
'^use-resize-observer$': 'use-resize-observer/polyfilled',
28+
'\\.(css|less)$': '<rootDir>/../stylesMock.js',
29+
'^react$': '<rootDir>/../node_modules/react',
30+
'^react-dom$': '<rootDir>/../node_modules/react-dom',
31+
'^react/jsx-runtime$': '<rootDir>/../node_modules/react/jsx-runtime',
32+
'^react-dom/(.*)$': '<rootDir>/../node_modules/react-dom/$1',
33+
},
34+
transformIgnorePatterns: ['node_modules/(?!(lodash-es|yaml))'],
35+
transform: {
36+
'^.+\\.(ts|tsx|js|jsx)$': ['@swc/jest', { ...swcrc, exclude: [], swcrc: false }],
37+
},
38+
setupFilesAfterEnv: ['<rootDir>/src/setup-tests.ts'],
39+
};
40+
41+
export default jestConfig;

0 commit comments

Comments
 (0)