Compare commits

..

2 Commits

Author SHA1 Message Date
Wesley van Tilburg
7bb1b38c06 datasource: add testing error to make sure its the right place
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled
2026-01-14 09:12:19 +00:00
Wesley van Tilburg
3711fdd990 fix built for newer versions 2026-01-14 09:11:59 +00:00
48 changed files with 688 additions and 1767 deletions

View File

@@ -3,7 +3,7 @@
# see https://github.com/unknwon/bra/blob/master/templates/default.bra.toml for more configuration options. # see https://github.com/unknwon/bra/blob/master/templates/default.bra.toml for more configuration options.
[run] [run]
init_cmds = [ init_cmds = [
["mage", "-v", "build:debug"], ["mage", "-v", "build:backend"],
["mage", "-v" , "reloadPlugin"] ["mage", "-v" , "reloadPlugin"]
] ]
watch_all = true watch_all = true
@@ -17,6 +17,6 @@ watch_dirs = [
watch_exts = [".go", ".json"] watch_exts = [".go", ".json"]
build_delay = 2000 build_delay = 2000
cmds = [ cmds = [
["mage", "-v", "build:debug"], ["mage", "-v", "build:backend"],
["mage", "-v" , "reloadPlugin"] ["mage", "-v" , "reloadPlugin"]
] ]

View File

@@ -7,8 +7,7 @@ ARG anonymous_auth_enabled=true
ARG development=false ARG development=false
ARG TARGETARCH ARG TARGETARCH
ARG GO_VERSION=1.25.6
ARG GO_ARCH=${TARGETARCH:-amd64}
ENV DEV "${development}" ENV DEV "${development}"
# Make it as simple as possible to access the grafana instance for development purposes # Make it as simple as possible to access the grafana instance for development purposes
@@ -44,27 +43,7 @@ RUN if [ "${development}" = "true" ]; then \
COPY supervisord/supervisord.conf /etc/supervisor.d/supervisord.ini COPY supervisord/supervisord.conf /etc/supervisor.d/supervisord.ini
COPY supervisord/supervisord.conf /etc/supervisor/conf.d/supervisord.conf COPY supervisord/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Installing Go
RUN if [ "${development}" = "true" ]; then \
curl -O -L https://golang.org/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && \
rm -rf /usr/local/go && \
tar -C /usr/local -xzf go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && \
echo "export PATH=$PATH:/usr/local/go/bin:~/go/bin" >> ~/.bashrc && \
rm -f go${GO_VERSION}.linux-${GO_ARCH}.tar.gz; \
fi
# Installing delve for debugging
RUN if [ "${development}" = "true" ]; then \
/usr/local/go/bin/go install github.com/go-delve/delve/cmd/dlv@latest; \
fi
# Installing mage for plugin (re)building
RUN if [ "${development}" = "true" ]; then \
git clone https://github.com/magefile/mage; \
cd mage; \
export PATH=$PATH:/usr/local/go/bin; \
go run bootstrap.go; \
fi
# Inject livereload script into grafana index.html # Inject livereload script into grafana index.html
RUN sed -i 's|</body>|<script src="http://localhost:35729/livereload.js"></script></body>|g' /usr/share/grafana/public/views/index.html RUN sed -i 's|</body>|<script src="http://localhost:35729/livereload.js"></script></body>|g' /usr/share/grafana/public/views/index.html

View File

@@ -7,17 +7,11 @@ services:
context: . context: .
args: args:
grafana_image: ${GRAFANA_IMAGE:-grafana-enterprise} grafana_image: ${GRAFANA_IMAGE:-grafana-enterprise}
grafana_version: ${GRAFANA_VERSION:-12.3.1} grafana_version: ${GRAFANA_VERSION:-12.2.0}
development: ${DEVELOPMENT:-false} development: ${DEVELOPMENT:-false}
anonymous_auth_enabled: ${ANONYMOUS_AUTH_ENABLED:-true} anonymous_auth_enabled: ${ANONYMOUS_AUTH_ENABLED:-true}
ports: ports:
- 3000:3000/tcp - 3000:3000/tcp
- 2345:2345/tcp # delve
security_opt:
- 'apparmor:unconfined'
- 'seccomp:unconfined'
cap_add:
- SYS_PTRACE
volumes: volumes:
- ../dist:/var/lib/grafana/plugins/alexanderzobnin-zabbix-app - ../dist:/var/lib/grafana/plugins/alexanderzobnin-zabbix-app
- ../provisioning:/etc/grafana/provisioning - ../provisioning:/etc/grafana/provisioning

View File

@@ -5,7 +5,7 @@ user=root
[program:grafana] [program:grafana]
user=root user=root
directory=/var/lib/grafana directory=/var/lib/grafana
command=bash -c 'while [ ! -f /root/alexanderzobnin-zabbix-app/dist/datasource/gpx_zabbix-datasource* ]; do sleep 1; done; /run.sh' command=/run.sh
stdout_logfile=/dev/fd/1 stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0 stdout_logfile_maxbytes=0
redirect_stderr=true redirect_stderr=true
@@ -13,35 +13,3 @@ killasgroup=true
stopasgroup=true stopasgroup=true
autostart=true autostart=true
[program:delve]
user=root
command=/bin/bash -c 'pid=""; while [ -z "$pid" ]; do pid=$(pgrep -f gpx_zabbix-datasource); done; /root/go/bin/dlv attach --api-version=2 --headless --continue --accept-multiclient --listen=:2345 $pid'
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
killasgroup=false
stopasgroup=false
autostart=true
autorestart=true
[program:build-watcher]
user=root
command=/bin/bash -c 'while inotifywait -e modify,create,delete -r /var/lib/grafana/plugins/alexanderzobnin-zabbix-app; do echo "Change detected, restarting delve...";supervisorctl restart delve; done'
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
killasgroup=true
stopasgroup=true
autostart=true
[program:mage-watcher]
user=root
environment=PATH="/usr/local/go/bin:/root/go/bin:%(ENV_PATH)s"
directory=/root/alexanderzobnin-zabbix-app
command=/bin/bash -c 'git config --global --add safe.directory /root/alexanderzobnin-zabbix-app && mage -v watch'
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
killasgroup=true
stopasgroup=true
autostart=true

View File

@@ -14,11 +14,11 @@ jobs:
compatibility-check: compatibility-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with: with:
go-version: '1.25' go-version: '1.25'

View File

@@ -14,11 +14,11 @@ jobs:
compatibility-check: compatibility-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with: with:
go-version: '1.25' go-version: '1.25'

View File

@@ -14,11 +14,11 @@ jobs:
compatibility-check: compatibility-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with: with:
go-version: '1.25' go-version: '1.25'

View File

@@ -14,11 +14,11 @@ jobs:
compatibility-check: compatibility-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with: with:
go-version: '1.25' go-version: '1.25'

View File

@@ -14,11 +14,11 @@ jobs:
compatibility-check: compatibility-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with: with:
go-version: '1.25' go-version: '1.25'

View File

@@ -3,7 +3,6 @@ run-name: Deploy ${{ inputs.branch }} to ${{ inputs.environment }} by @${{ githu
permissions: permissions:
attestations: write attestations: write
contents: write contents: write
pull-requests: read
id-token: write id-token: write
on: on:
@@ -28,7 +27,7 @@ on:
jobs: jobs:
cd: cd:
name: CD name: CD
uses: grafana/plugin-ci-workflows/.github/workflows/cd.yml@ci-cd-workflows/v6.1.0 uses: grafana/plugin-ci-workflows/.github/workflows/cd.yml@ci-cd-workflows/v5.1.0
with: with:
golangci-lint-version: '2.7.2' golangci-lint-version: '2.7.2'
go-version: '1.25.5' go-version: '1.25.5'
@@ -37,4 +36,3 @@ jobs:
docs-only: ${{ fromJSON(github.event.inputs.docs-only) }} docs-only: ${{ fromJSON(github.event.inputs.docs-only) }}
run-playwright: true run-playwright: true
github-draft-release: false github-draft-release: false
run-playwright-with-skip-grafana-react-19-preview-image: true

View File

@@ -12,10 +12,9 @@ on:
jobs: jobs:
ci: ci:
name: CI name: CI
uses: grafana/plugin-ci-workflows/.github/workflows/ci.yml@ci-cd-workflows/v6.1.0 uses: grafana/plugin-ci-workflows/.github/workflows/ci.yml@ci-cd-workflows/v5.1.0
with: with:
go-version: '1.25.5' go-version: '1.25.5'
golangci-lint-version: '2.7.2' golangci-lint-version: '2.7.2'
plugin-version-suffix: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || '' }} plugin-version-suffix: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || '' }}
run-playwright: true run-playwright: true
run-playwright-with-skip-grafana-react-19-preview-image: true

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@
*.sublime-project *.sublime-project
.idea/ .idea/
.vscode
*.bat *.bat
.DS_Store .DS_Store

36
.vscode/launch.json vendored
View File

@@ -1,36 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Standalone debug mode",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/pkg",
"env": {},
"args": [
"-standalone"
]
},
{
"name": "Attach to plugin backend in docker",
"type": "go",
"request": "attach",
"mode": "remote",
"port": 2345,
"host": "127.0.0.1",
"showLog": true,
"trace": "log",
"logOutput": "rpc",
"substitutePath": [
{
"from": "${workspaceFolder}",
"to": "/root/alexanderzobnin-zabbix-app"
}
]
}
]
}

View File

@@ -1,17 +1,5 @@
# Change Log # Change Log
## 6.1.2
🐛 Fix silent removal of itemTagFilter when no tags match regex
🐛 Enhance the problems panel with the ability to convert specific tags to columns. Single or multiple tags supported.
🐛 Fix column visibility toggles for problems panel
## 6.1.1
🐛 Fix moment value rendering issue
🐛 Fix proxies dropdown in ProblemsQueryEditor
## 6.1.0 ## 6.1.0
🎉 Migrates use of DatasourceApi to DatasourceWithBackend 🎉 Migrates use of DatasourceApi to DatasourceWithBackend

104
CLAUDE.md
View File

@@ -1,104 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Grafana-Zabbix is a hybrid Grafana plugin connecting Grafana to Zabbix monitoring infrastructure. It consists of three components:
- **Zabbix App** (`/src`) - Container app plugin
- **Zabbix Data Source** (`/src/datasource`) - TypeScript frontend + Go backend for querying Zabbix
- **Problems Panel** (`/src/panel-triggers`) - React panel for displaying Zabbix problems/triggers
## Build Commands
```bash
# Install all dependencies
make install # or: yarn install && go install -v ./pkg/
# Development
yarn dev # Watch mode for frontend
make run-backend # Watch mode for backend (uses bra)
# Production build
make build # or: yarn build && mage -v build:backend
# Distribution (all platforms)
make dist
# After building, restart Grafana to reload the plugin
podman container stop grafana && podman container start grafana
```
## Testing
```bash
# Frontend tests (Jest)
yarn test # Watch mode
yarn test:ci # CI mode, all tests
# Run specific test file
yarn test datasource.test.ts
yarn test Problems.test.tsx
# Backend tests (Go)
go test ./pkg/...
```
Test files are located alongside source code with `.test.ts` or `.test.tsx` extensions:
- `src/datasource/specs/*.test.ts`
- `src/datasource/components/**/*.test.tsx`
- `src/datasource/zabbix/**/*.test.ts`
- `src/panel-triggers/components/**/*.test.tsx`
## Linting and Type Checking
```bash
yarn lint # Check for linting errors
yarn lint:fix # Auto-fix lint and formatting issues
yarn typecheck # TypeScript type checking
```
## Development Environment
```bash
yarn server # Start Grafana + Zabbix via Docker Compose
yarn server:down # Stop and remove containers
```
Docker setup in `/devenv/` includes multiple Zabbix versions (5.0, 6.0, 7.0, 7.2, 7.4) for compatibility testing.
## Architecture
**Frontend-Backend Communication**: Frontend queries go through Grafana's backend proxy to the plugin backend executable (`gpx_zabbix-datasource`), which handles Zabbix API calls. Uses gRPC via Grafana Plugin SDK.
**Key Frontend Packages**:
- `/src/datasource/datasource.ts` - Main ZabbixDatasource class
- `/src/datasource/zabbix/` - Zabbix API client logic
- `/src/datasource/components/` - Query editor, config editor components
- `/src/panel-triggers/components/` - Problems panel components
**Key Backend Packages** (`/pkg/`):
- `datasource/` - Main backend logic
- `zabbix/` - Zabbix API interactions
- `zabbixapi/` - Low-level API connector
- `cache/` - Caching layer
## Requirements
- Node.js: v24 (see `.nvmrc`)
- Yarn: v4.12.0
- Go: 1.25
- Grafana: >=11.6.0
## PR Workflow
Run `yarn changeset` to create a changeset file for your PR. This is required for version bumping and changelog generation.
## Debugging Backend
```bash
make build-debug # Build with debug flags
./debug-backend.sh # Attach delve debugger (after starting Grafana)
```
VS Code debug config connects to delve on port 3222.

View File

@@ -4,11 +4,11 @@
```sh ```sh
# install frontend deps # install frontend deps
yarn install yarn install --pure-lockfile
# build frontend # build frontend
yarn build yarn build
#build backend #build backend for current platform
mage -v mage -v build:backend
``` ```
## Rebuild backend on changes ## Rebuild backend on changes
@@ -19,31 +19,31 @@ mage watch
## Debugging backend plugin ## Debugging backend plugin
The plugin supports two debugging modes for the Go backend: For debugging backend part written on Go, you should go through a few steps. First, build a plugin with special flags for debugging:
### Standalone Debug Mode
This mode allows you to run and debug the plugin locally:
1. Use the **"Standalone debug mode"** configuration in VS Code (already configured in `.vscode/launch.json`)
2. Set breakpoints in your Go code
3. The plugin will start in standalone mode with the `-standalone` flag
4. Run your local grafana instance
### Debugging with Docker (Recommended for Grafana Integration)
For debugging the backend plugin while it's running inside Grafana in Docker:
1. Run the docker compose file with the following command in any of the devenv folders:
```sh ```sh
DEVELOPMENT=true docker compose up --build -d make build-debug
``` ```
1. Attach VS Code debugger: Then, configure your editor to connect to [delve](https://github.com/go-delve/delve) debugger running in headless mode. This is an example for VS Code:
- Use the **"Attach to plugin backend in docker"** configuration in VS Code (already configured in `.vscode/launch.json`)
- Set breakpoints in your Go code ```json
- The debugger will connect to delve running in the Docker container {
"version": "0.2.0",
"configurations": [
{
"name": "Debug backend plugin",
"type": "go",
"request": "attach",
"mode": "remote",
"port": 3222,
"host": "127.0.0.1"
}
]
}
```
Finally, run grafana-server and then execute `./debug-backend.sh` from grafana-zabbix root folder. This script will attach delve to running plugin. Now you can go to the VS Code and run _Debug backend plugin_ debug config.
## Submitting PR ## Submitting PR

View File

@@ -29,11 +29,7 @@
"src/**", "src/**",
"pkg/**" "pkg/**"
], ],
"ignoreRegExpList": [ "ignoreRegExpList": ["import\\s*\\((.|[\r\n])*?\\)", "import\\s*.*\".*?\"", "\\[@.+\\]"],
"import\\s*\\((.|[\r\n])*?\\)",
"import\\s*.*\".*?\"",
"\\[@.+\\]"
],
"words": [ "words": [
"alexanderzobnin", "alexanderzobnin",
"applicationids", "applicationids",
@@ -41,7 +37,6 @@
"datapoints", "datapoints",
"datasource", "datasource",
"datasources", "datasources",
"devenv",
"dompurify", "dompurify",
"eventid", "eventid",
"eventids", "eventids",

View File

@@ -1,4 +1,4 @@
FROM python:3@sha256:17bc9f1d032a760546802cc4e406401eb5fe99dbcb4602c91628e73672fa749c FROM python:3@sha256:6d58c1a9444bc2664f0fa20c43a592fcdb2698eb9a9c32257516538a2746c19a
ENV ZBX_API_URL=http://zabbix-web ENV ZBX_API_URL=http://zabbix-web
ENV ZBX_API_USER="Admin" ENV ZBX_API_USER="Admin"

View File

@@ -19,6 +19,7 @@ services:
file: ../../.config/docker-compose-base.yaml file: ../../.config/docker-compose-base.yaml
service: grafana service: grafana
volumes: volumes:
- ../..:/grafana-zabbix
- ../dashboards:/devenv/dashboards - ../dashboards:/devenv/dashboards
- '../datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml' - '../datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml'
- '../dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml' - '../dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml'
@@ -64,7 +65,7 @@ services:
- ../nginx/.htpasswd:/etc/nginx/.htpasswd:ro - ../nginx/.htpasswd:/etc/nginx/.htpasswd:ro
database: database:
image: postgres:18@sha256:5773fe724c49c42a7a9ca70202e11e1dff21fb7235b335a73f39297d200b73a2 image: postgres:18@sha256:bfe50b2b0ddd9b55eadedd066fe24c7c6fe06626185b73358c480ea37868024d
ports: ports:
- '15432:5432' - '15432:5432'
environment: environment:

View File

@@ -19,13 +19,14 @@ services:
file: ../../.config/docker-compose-base.yaml file: ../../.config/docker-compose-base.yaml
service: grafana service: grafana
volumes: volumes:
- ../..:/grafana-zabbix
- ../dashboards:/devenv/dashboards - ../dashboards:/devenv/dashboards
- '../datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml' - '../datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml'
- '../dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml' - '../dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml'
# Zabbix # Zabbix
zabbix-server: zabbix-server:
image: zabbix/zabbix-server-pgsql:alpine-6.0-latest@sha256:b34303498b75e4a13d76211f250d5a831f746fc13d441d89d1dcea04b64adf4c image: zabbix/zabbix-server-pgsql:alpine-6.0-latest@sha256:dbc5a2a27b1163f450b86d5633a8a878c67fb895d435d49fb0f2f6461e43138f
ports: ports:
- '10051:10051' - '10051:10051'
depends_on: depends_on:
@@ -42,7 +43,7 @@ services:
ZBX_DEBUGLEVEL: 3 ZBX_DEBUGLEVEL: 3
zabbix-web: zabbix-web:
image: zabbix/zabbix-web-nginx-pgsql:alpine-6.0-latest@sha256:b38d7ae7c073a8f4d0488315cd2c2131ab08294076bba4650f7b3ab065d9c07d image: zabbix/zabbix-web-nginx-pgsql:alpine-6.0-latest@sha256:e034dd99e711ebb3c28ae87750b818279b857504cdac9be521743ecfbc9711e0
ports: ports:
- '443:443' - '443:443'
- '8188:8080' - '8188:8080'
@@ -63,7 +64,7 @@ services:
POSTGRES_DB: zabbix POSTGRES_DB: zabbix
database: database:
image: postgres:18@sha256:5773fe724c49c42a7a9ca70202e11e1dff21fb7235b335a73f39297d200b73a2 image: postgres:18@sha256:bfe50b2b0ddd9b55eadedd066fe24c7c6fe06626185b73358c480ea37868024d
ports: ports:
- '15432:5432' - '15432:5432'
command: postgres -c 'max_connections=1000' command: postgres -c 'max_connections=1000'
@@ -72,7 +73,7 @@ services:
POSTGRES_PASSWORD: zabbix POSTGRES_PASSWORD: zabbix
zabbix-agent: zabbix-agent:
image: zabbix/zabbix-agent:alpine-6.0-latest@sha256:4686ff4dd5c7e3ea43e9653e35019039e567c544495f55fcb949c2cdd0a6cf50 image: zabbix/zabbix-agent:alpine-6.0-latest@sha256:9eab77e4f23e68746f935ab71f3c828a6bfc73b2e2783c5453d61a24f996bb6b
environment: environment:
ZBX_SERVER_HOST: zabbix-server ZBX_SERVER_HOST: zabbix-server
ZBX_SERVER_PORT: 10051 ZBX_SERVER_PORT: 10051

View File

@@ -19,13 +19,14 @@ services:
file: ../../.config/docker-compose-base.yaml file: ../../.config/docker-compose-base.yaml
service: grafana service: grafana
volumes: volumes:
- ../..:/grafana-zabbix
- ../dashboards:/devenv/dashboards - ../dashboards:/devenv/dashboards
- '../datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml' - '../datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml'
- '../dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml' - '../dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml'
# Zabbix # Zabbix
zabbix-server: zabbix-server:
image: zabbix/zabbix-server-pgsql:alpine-7.0-latest@sha256:2cec4dde78b1ea1ad483ea823f91dff45abd013779909db004f3568a596c3bde image: zabbix/zabbix-server-pgsql:alpine-7.0-latest@sha256:b3c1451adf27e28741fe3b2b3b614c52b0ac68f749b2515224536ef2c1474473
ports: ports:
- '10051:10051' - '10051:10051'
depends_on: depends_on:
@@ -42,7 +43,7 @@ services:
ZBX_DEBUGLEVEL: 3 ZBX_DEBUGLEVEL: 3
zabbix-web: zabbix-web:
image: zabbix/zabbix-web-nginx-pgsql:alpine-7.0-latest@sha256:927b9a2836ee0ae6f44c4c749e50042931e87c7d9866b7d3bbd3901318ae63eb image: zabbix/zabbix-web-nginx-pgsql:alpine-7.0-latest@sha256:08b2b13e1c92f8cdce81238cdbbb89d1fbc5863e5e7ba0310406212d87988d53
ports: ports:
- '443:443' - '443:443'
- '8188:8080' - '8188:8080'
@@ -63,7 +64,7 @@ services:
POSTGRES_DB: zabbix POSTGRES_DB: zabbix
database: database:
image: postgres:18@sha256:5773fe724c49c42a7a9ca70202e11e1dff21fb7235b335a73f39297d200b73a2 image: postgres:18@sha256:bfe50b2b0ddd9b55eadedd066fe24c7c6fe06626185b73358c480ea37868024d
ports: ports:
- '15432:5432' - '15432:5432'
command: postgres -c 'max_connections=1000' command: postgres -c 'max_connections=1000'
@@ -72,7 +73,7 @@ services:
POSTGRES_PASSWORD: zabbix POSTGRES_PASSWORD: zabbix
zabbix-agent: zabbix-agent:
image: zabbix/zabbix-agent:alpine-7.0-latest@sha256:52865010468af7f6dc3e3dbd45b645c32b8d133f4a230301cea26ffa679d5cc4 image: zabbix/zabbix-agent:alpine-7.0-latest@sha256:71f1f22b3828f47b714a1bbef39b456453e0e552461d138f36e18a35732302ba
environment: environment:
ZBX_SERVER_HOST: zabbix-server ZBX_SERVER_HOST: zabbix-server
ZBX_SERVER_PORT: 10051 ZBX_SERVER_PORT: 10051

View File

@@ -5,6 +5,7 @@ services:
file: ../../.config/docker-compose-base.yaml file: ../../.config/docker-compose-base.yaml
service: grafana service: grafana
volumes: volumes:
- ../..:/grafana-zabbix
- ../dashboards:/devenv/dashboards - ../dashboards:/devenv/dashboards
- '../datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml' - '../datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml'
- '../dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml' - '../dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml'
@@ -44,7 +45,7 @@ services:
POSTGRES_DB: zabbix POSTGRES_DB: zabbix
database: database:
image: postgres:18@sha256:5773fe724c49c42a7a9ca70202e11e1dff21fb7235b335a73f39297d200b73a2 image: postgres:18@sha256:bfe50b2b0ddd9b55eadedd066fe24c7c6fe06626185b73358c480ea37868024d
ports: ports:
- '15432:5432' - '15432:5432'
command: postgres -c 'max_connections=1000' command: postgres -c 'max_connections=1000'

View File

@@ -1,4 +1,4 @@
FROM python:3.13-slim-bookworm@sha256:97e9392d12279f8c180eb80f0c7c0f3dfe5650f0f2573f7ad770aea58f75ed12 FROM python:3.13-slim-bookworm@sha256:0c5171fd1e80d3133604e1006aa5f788c5f020631537dd1e09edcbe874bb8192
ENV ZBX_API_URL=http://zabbix-web:8080 ENV ZBX_API_URL=http://zabbix-web:8080
ENV ZBX_API_USER="Admin" ENV ZBX_API_USER="Admin"

View File

@@ -5,13 +5,14 @@ services:
file: ../../.config/docker-compose-base.yaml file: ../../.config/docker-compose-base.yaml
service: grafana service: grafana
volumes: volumes:
- ../..:/grafana-zabbix
- ../dashboards:/devenv/dashboards - ../dashboards:/devenv/dashboards
- '../datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml' - '../datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml'
- '../dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml' - '../dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml'
# Zabbix # Zabbix
zabbix-server: zabbix-server:
image: zabbix/zabbix-server-pgsql:alpine-7.4-latest@sha256:033791214ab8146a4663c56dd6b46f742f03363e441d928216202136d094e154 image: zabbix/zabbix-server-pgsql:alpine-7.4-latest@sha256:a6f748d96bfa4d361df5e9284eba041c475e7ff26c1358f8f189969437ebdb9b
ports: ports:
- '10051:10051' - '10051:10051'
depends_on: depends_on:
@@ -28,7 +29,7 @@ services:
ZBX_DEBUGLEVEL: 3 ZBX_DEBUGLEVEL: 3
zabbix-web: zabbix-web:
image: zabbix/zabbix-web-apache-pgsql:alpine-7.4-latest@sha256:f7357956bb66ac1c18db0b93a2af1c60ecea9f2ce6366f55bfb5cd6000415441 image: zabbix/zabbix-web-apache-pgsql:alpine-7.4-latest@sha256:9b5ad53c684c9f5d7b15c626e22e3d2c97c2b0b2b05ce811d1a8fe42416cd01b
ports: ports:
- '8188:8080' - '8188:8080'
depends_on: depends_on:
@@ -44,7 +45,7 @@ services:
POSTGRES_DB: zabbix POSTGRES_DB: zabbix
database: database:
image: postgres:18@sha256:5773fe724c49c42a7a9ca70202e11e1dff21fb7235b335a73f39297d200b73a2 image: postgres:18@sha256:bfe50b2b0ddd9b55eadedd066fe24c7c6fe06626185b73358c480ea37868024d
ports: ports:
- '15432:5432' - '15432:5432'
command: postgres -c 'max_connections=1000' command: postgres -c 'max_connections=1000'
@@ -53,7 +54,7 @@ services:
POSTGRES_PASSWORD: zabbix POSTGRES_PASSWORD: zabbix
zabbix-agent: zabbix-agent:
image: zabbix/zabbix-agent:alpine-7.4-latest@sha256:cfc45062ace0e7d0a12e2e043026c1df53b5eceb91ea66dced9fbcad40ae6cc0 image: zabbix/zabbix-agent:alpine-7.4-latest@sha256:2a5989f552e70c1a7d48870ff6002ebbcda1a907e42046851aeae9feba614ac4
environment: environment:
ZBX_SERVER_HOST: zabbix-server ZBX_SERVER_HOST: zabbix-server
ZBX_SERVER_PORT: 10051 ZBX_SERVER_PORT: 10051

60
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/alexanderzobnin/grafana-zabbix module github.com/alexanderzobnin/grafana-zabbix
go 1.25.5 go 1.25
// Go 1.24 enabled the post-quantum key exchange mechanism // Go 1.24 enabled the post-quantum key exchange mechanism
// X25519MLKEM768 by default. It can cause issues with some TLS servers // X25519MLKEM768 by default. It can cause issues with some TLS servers
@@ -11,17 +11,17 @@ godebug tlsmlkem=0
require ( require (
github.com/bitly/go-simplejson v0.5.1 github.com/bitly/go-simplejson v0.5.1
github.com/dlclark/regexp2 v1.11.5 github.com/dlclark/regexp2 v1.11.5
github.com/grafana/grafana-plugin-sdk-go v0.286.0 github.com/grafana/grafana-plugin-sdk-go v0.284.0
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/prometheus/client_golang v1.23.2 github.com/prometheus/client_golang v1.23.2
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.11.1
golang.org/x/net v0.49.0 golang.org/x/net v0.48.0
gotest.tools v2.2.0+incompatible gotest.tools v2.2.0+incompatible
) )
require ( require (
github.com/BurntSushi/toml v1.5.0 // indirect github.com/BurntSushi/toml v1.5.0 // indirect
github.com/apache/arrow-go/v18 v18.5.0 // indirect github.com/apache/arrow-go/v18 v18.4.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
@@ -35,20 +35,20 @@ require (
github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/google/flatbuffers v25.9.23+incompatible // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect
github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/grafana/otel-profiling-go v0.5.1 // indirect github.com/grafana/otel-profiling-go v0.5.1 // indirect
github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-plugin v1.7.0 // indirect github.com/hashicorp/go-plugin v1.7.0 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect github.com/hashicorp/yamux v0.1.2 // indirect
github.com/jaegertracing/jaeger-idl v0.6.0 // indirect github.com/jaegertracing/jaeger-idl v0.5.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.18.2 // indirect github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/magefile/mage v1.15.0 // indirect github.com/magefile/mage v1.15.0 // indirect
github.com/mattetti/filebuffer v1.0.1 // indirect github.com/mattetti/filebuffer v1.0.1 // indirect
@@ -64,7 +64,7 @@ require (
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.4 // indirect github.com/prometheus/common v0.67.2 // indirect
github.com/prometheus/procfs v0.16.1 // indirect github.com/prometheus/procfs v0.16.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
@@ -73,31 +73,31 @@ require (
github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect
github.com/urfave/cli v1.22.17 // indirect github.com/urfave/cli v1.22.17 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.64.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0 // indirect
go.opentelemetry.io/contrib/propagators/jaeger v1.39.0 // indirect go.opentelemetry.io/contrib/propagators/jaeger v1.38.0 // indirect
go.opentelemetry.io/contrib/samplers/jaegerremote v0.33.0 // indirect go.opentelemetry.io/contrib/samplers/jaegerremote v0.32.0 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect
go.opentelemetry.io/otel/metric v1.39.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/otel/sdk v1.39.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect
golang.org/x/mod v0.31.0 // indirect golang.org/x/mod v0.30.0 // indirect
golang.org/x/sync v0.19.0 // indirect golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.40.0 // indirect golang.org/x/sys v0.39.0 // indirect
golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect
golang.org/x/text v0.33.0 // indirect golang.org/x/text v0.32.0 // indirect
golang.org/x/tools v0.40.0 // indirect golang.org/x/tools v0.39.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect
google.golang.org/grpc v1.78.0 // indirect google.golang.org/grpc v1.76.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect google.golang.org/protobuf v1.36.10 // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

128
go.sum
View File

@@ -3,8 +3,8 @@ github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/apache/arrow-go/v18 v18.5.0 h1:rmhKjVA+MKVnQIMi/qnM0OxeY4tmHlN3/Pvu+Itmd6s= github.com/apache/arrow-go/v18 v18.4.1 h1:q/jVkBWCJOB9reDgaIZIdruLQUb1kbkvOnOFezVH1C4=
github.com/apache/arrow-go/v18 v18.5.0/go.mod h1:F1/wPb3bUy6ZdP4kEPWC7GUZm+yDmxXFERK6uDSkhr8= github.com/apache/arrow-go/v18 v18.4.1/go.mod h1:tLyFubsAl17bvFdUAy24bsSvA/6ww95Iqi67fTpGu3E=
github.com/apache/thrift v0.22.0 h1:r7mTJdj51TMDe6RtcmNdQxgn9XcyfGDOzegMDRg47uc= github.com/apache/thrift v0.22.0 h1:r7mTJdj51TMDe6RtcmNdQxgn9XcyfGDOzegMDRg47uc=
github.com/apache/thrift v0.22.0/go.mod h1:1e7J/O1Ae6ZQMTYdy9xa3w9k+XHWPfRvdPyJeynQ+/g= github.com/apache/thrift v0.22.0/go.mod h1:1e7J/O1Ae6ZQMTYdy9xa3w9k+XHWPfRvdPyJeynQ+/g=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -51,8 +51,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/flatbuffers v25.9.23+incompatible h1:rGZKv+wOb6QPzIdkM2KxhBZCDrA0DeN6DNmRDrqIsQU= github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q=
github.com/google/flatbuffers v25.9.23+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
@@ -61,8 +61,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/grafana/grafana-plugin-sdk-go v0.286.0 h1:nrG/XLDpYuUONVpVVGIUxPJdWeXGHM/47qIAnuDkdjg= github.com/grafana/grafana-plugin-sdk-go v0.284.0 h1:1bK7eWsnPBLUWDcWJWe218Ik5ad0a5JpEL4mH9ry7Ws=
github.com/grafana/grafana-plugin-sdk-go v0.286.0/go.mod h1:cNFa2EpURNF5Hy15kH7HfVdprNu+UEmNZx7TMWVdctY= github.com/grafana/grafana-plugin-sdk-go v0.284.0/go.mod h1:lHPniaSxq3SL5MxDIPy04TYB1jnTp/ivkYO+xn5Rz3E=
github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8=
github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls= github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls=
github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og=
@@ -71,16 +71,16 @@ github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 h1:B+8ClL/kCQkRiU82d9xajRPKYMrB7E0MbtzWVi1K4ns= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 h1:B+8ClL/kCQkRiU82d9xajRPKYMrB7E0MbtzWVi1K4ns=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3/go.mod h1:NbCUVmiS4foBGBHOYlCT25+YmGpJ32dZPi75pGEUpj4= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3/go.mod h1:NbCUVmiS4foBGBHOYlCT25+YmGpJ32dZPi75pGEUpj4=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA= github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA=
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
github.com/jaegertracing/jaeger-idl v0.6.0 h1:LOVQfVby9ywdMPI9n3hMwKbyLVV3BL1XH2QqsP5KTMk= github.com/jaegertracing/jaeger-idl v0.5.0 h1:zFXR5NL3Utu7MhPg8ZorxtCBjHrL3ReM1VoB65FOFGE=
github.com/jaegertracing/jaeger-idl v0.6.0/go.mod h1:mpW0lZfG907/+o5w5OlnNnig7nHJGT3SfKmRqC42HGQ= github.com/jaegertracing/jaeger-idl v0.5.0/go.mod h1:ON90zFo9eoyXrt9F/KN8YeF3zxcnujaisMweFY/rg5k=
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=
github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -91,8 +91,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4=
github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -147,15 +147,15 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= github.com/prometheus/common v0.67.2 h1:PcBAckGFTIHt2+L3I33uNRTlKTplNzFctXcWhPyAEN8=
github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko=
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -192,38 +192,38 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.64.0 h1:OXSUzgmIFkcC4An+mv+lqqZSndTffXpjAyoR+1f8k/A= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0 h1:2pn7OzMewmYRiNtv1doZnLo3gONcnMHlFnmOR8Vgt+8=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.64.0/go.mod h1:1A4GVLFIm54HFqVdOpWmukap7rgb0frrE3zWXohLPdM= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0/go.mod h1:rjbQTDEPQymPE0YnRQp9/NuPwwtL0sesz/fnqRW/v84=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
go.opentelemetry.io/contrib/propagators/jaeger v1.39.0 h1:Gz3yKzfMSEFzF0Vy5eIpu9ndpo4DhXMCxsLMF0OOApo= go.opentelemetry.io/contrib/propagators/jaeger v1.38.0 h1:nXGeLvT1QtCAhkASkP/ksjkTKZALIaQBIW+JSIw1KIc=
go.opentelemetry.io/contrib/propagators/jaeger v1.39.0/go.mod h1:2D/cxxCqTlrday0rZrPujjg5aoAdqk1NaNyoXn8FJn8= go.opentelemetry.io/contrib/propagators/jaeger v1.38.0/go.mod h1:oMvOXk78ZR3KEuPMBgp/ThAMDy9ku/eyUVztr+3G6Wo=
go.opentelemetry.io/contrib/samplers/jaegerremote v0.33.0 h1:RcFp4UxGTE2VQQ0M7s24YRUShEJ5D5JDnd5g2EaTh6E= go.opentelemetry.io/contrib/samplers/jaegerremote v0.32.0 h1:oPW/SRFyHgIgxrvNhSBzqvZER2N5kRlci3/rGTOuyWo=
go.opentelemetry.io/contrib/samplers/jaegerremote v0.33.0/go.mod h1:y6oMwgsv+yWYCLRigU6Pp07/x4KZUEh8LIPTSUnQKbQ= go.opentelemetry.io/contrib/samplers/jaegerremote v0.32.0/go.mod h1:B9Oka5QVD0bnmZNO6gBbBta6nohD/1Z+f9waH2oXyBs=
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
@@ -235,14 +235,14 @@ golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 h1:TQwNpfvNkxAVlItJf6Cr5JTsV
golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -260,20 +260,20 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA= golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo=
golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -282,14 +282,14 @@ golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhS
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls= google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ=
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@@ -1,8 +1,6 @@
{ {
"name": "grafana-zabbix", "name": "grafana-zabbix",
"version": "6.2-rit", "version": "6.1.1",
"description": "Zabbix plugin for Grafana", "description": "Zabbix plugin for Grafana",
"homepage": "http://grafana-zabbix.org", "homepage": "http://grafana-zabbix.org",
"bugs": { "bugs": {
@@ -44,37 +42,37 @@
"tslib": "2.8.1" "tslib": "2.8.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.28.6", "@babel/core": "7.28.5",
"@changesets/cli": "2.29.8", "@changesets/cli": "2.29.8",
"@grafana/e2e-selectors": "12.3.1", "@grafana/e2e-selectors": "12.3.1",
"@grafana/eslint-config": "9.0.0", "@grafana/eslint-config": "9.0.0",
"@grafana/plugin-e2e": "3.1.4", "@grafana/plugin-e2e": "3.1.1",
"@grafana/tsconfig": "2.0.1", "@grafana/tsconfig": "2.0.1",
"@playwright/test": "1.57.0", "@playwright/test": "1.57.0",
"@stylistic/eslint-plugin-ts": "4.4.1", "@stylistic/eslint-plugin-ts": "4.4.1",
"@swc/core": "1.15.10", "@swc/core": "1.15.8",
"@swc/helpers": "0.5.18", "@swc/helpers": "0.5.18",
"@swc/jest": "0.2.39", "@swc/jest": "0.2.39",
"@tanstack/react-table": "8.21.3", "@tanstack/react-table": "8.21.3",
"@testing-library/dom": "10.4.1", "@testing-library/dom": "10.4.1",
"@testing-library/jest-dom": "6.9.1", "@testing-library/jest-dom": "6.9.1",
"@testing-library/react": "16.3.2", "@testing-library/react": "16.3.1",
"@types/grafana": "github:CorpGlory/types-grafana", "@types/grafana": "github:CorpGlory/types-grafana",
"@types/jest": "30.0.0", "@types/jest": "30.0.0",
"@types/lodash": "4.17.23", "@types/lodash": "4.17.22",
"@types/node": "25.0.10", "@types/node": "25.0.5",
"@types/react": "18.3.27", "@types/react": "18.3.27",
"@types/react-dom": "18.3.7", "@types/react-dom": "18.3.7",
"@typescript-eslint/eslint-plugin": "8.53.1", "@typescript-eslint/eslint-plugin": "8.52.0",
"@typescript-eslint/parser": "8.53.1", "@typescript-eslint/parser": "8.52.0",
"autoprefixer": "10.4.23", "autoprefixer": "10.4.23",
"copy-webpack-plugin": "13.0.1", "copy-webpack-plugin": "13.0.1",
"cspell": "9.6.0", "cspell": "9.4.0",
"css-loader": "7.1.2", "css-loader": "7.1.2",
"eslint": "9.39.2", "eslint": "9.39.2",
"eslint-config-prettier": "10.1.8", "eslint-config-prettier": "10.1.8",
"eslint-plugin-jsdoc": "62.3.1", "eslint-plugin-jsdoc": "62.0.0",
"eslint-plugin-prettier": "5.5.5", "eslint-plugin-prettier": "5.5.4",
"eslint-plugin-react": "7.37.5", "eslint-plugin-react": "7.37.5",
"eslint-plugin-react-hooks": "7.0.1", "eslint-plugin-react-hooks": "7.0.1",
"eslint-webpack-plugin": "5.0.2", "eslint-webpack-plugin": "5.0.2",
@@ -84,20 +82,20 @@
"imports-loader": "5.0.0", "imports-loader": "5.0.0",
"jest": "30.2.0", "jest": "30.2.0",
"jest-environment-jsdom": "30.2.0", "jest-environment-jsdom": "30.2.0",
"lodash": "4.17.23", "lodash": "4.17.21",
"mini-css-extract-plugin": "2.10.0", "mini-css-extract-plugin": "2.9.4",
"moment": "2.30.1", "moment": "2.30.1",
"postcss": "8.5.6", "postcss": "8.5.6",
"postcss-loader": "8.2.0", "postcss-loader": "8.2.0",
"postcss-reporter": "7.1.0", "postcss-reporter": "7.1.0",
"postcss-scss": "4.0.9", "postcss-scss": "4.0.9",
"prettier": "3.8.1", "prettier": "3.7.4",
"replace-in-file-webpack-plugin": "1.0.6", "replace-in-file-webpack-plugin": "1.0.6",
"sass": "1.97.3", "sass": "1.97.2",
"sass-loader": "16.0.6", "sass-loader": "16.0.6",
"semver": "7.7.3", "semver": "7.7.3",
"style-loader": "4.0.0", "style-loader": "4.0.0",
"swc-loader": "0.2.7", "swc-loader": "0.2.6",
"terser-webpack-plugin": "5.3.16", "terser-webpack-plugin": "5.3.16",
"ts-node": "10.9.2", "ts-node": "10.9.2",
"tsconfig-paths": "4.2.0", "tsconfig-paths": "4.2.0",

View File

@@ -150,8 +150,6 @@ func (ds *ZabbixDatasource) QueryData(ctx context.Context, req *backend.QueryDat
frames, queryErr = zabbixDS.queryItemIdData(queryCtx, &query) frames, queryErr = zabbixDS.queryItemIdData(queryCtx, &query)
case MODE_PROBLEMS: case MODE_PROBLEMS:
queryErr = backend.DownstreamError(test) //send a test error queryErr = backend.DownstreamError(test) //send a test error
case MODE_PROBLEMS_ALERTING:
frames, queryErr = zabbixDS.queryProblemsAlerting(queryCtx, &query)
default: default:
queryErr = backend.DownstreamError(ErrNonMetricQueryNotSupported) queryErr = backend.DownstreamError(ErrNonMetricQueryNotSupported)
} }

View File

@@ -20,7 +20,6 @@ const (
MODE_ITEMID = "3" MODE_ITEMID = "3"
MODE_TRIGGERS = "4" MODE_TRIGGERS = "4"
MODE_PROBLEMS = "5" MODE_PROBLEMS = "5"
MODE_PROBLEMS_ALERTING = "7"
) )
type DBConnectionPostProcessingRequest struct { type DBConnectionPostProcessingRequest struct {
@@ -128,15 +127,13 @@ func ReadQuery(query backend.DataQuery) (QueryModel, error) {
return model, backend.DownstreamError(fmt.Errorf("could not read query JSON: %w", err)) return model, backend.DownstreamError(fmt.Errorf("could not read query JSON: %w", err))
} }
// Try reading queryType as string first, then as int64 queryType, err := queryJSON.Get("queryType").Int64()
if queryTypeStr, err := queryJSON.Get("queryType").String(); err == nil && queryTypeStr != "" { if err != nil {
model.QueryType = queryTypeStr
} else if queryType, err := queryJSON.Get("queryType").Int64(); err == nil {
model.QueryType = strconv.FormatInt(queryType, 10)
} else {
log.DefaultLogger.Warn("could not read query type", "error", err) log.DefaultLogger.Warn("could not read query type", "error", err)
log.DefaultLogger.Debug("setting query type to default value") log.DefaultLogger.Debug("setting query type to default value")
model.QueryType = "0" model.QueryType = "0"
} else {
model.QueryType = strconv.FormatInt(queryType, 10)
} }
} }

View File

@@ -1,125 +0,0 @@
package datasource
import (
"context"
"fmt"
"strings"
"time"
"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbix"
"github.com/grafana/grafana-plugin-sdk-go/data"
)
func (ds *ZabbixDatasourceInstance) queryProblemsAlerting(ctx context.Context, query *QueryModel) ([]*data.Frame, error) {
ds.logger.Info("queryProblemsAlerting called", "groupFilter", query.Group.Filter, "hostFilter", query.Host.Filter)
triggers, err := ds.zabbix.GetTriggers(ctx, query.Group.Filter, query.Host.Filter)
if err != nil {
ds.logger.Error("GetTriggers failed", "error", err)
return nil, err
}
ds.logger.Info("GetTriggers returned", "count", len(triggers))
if len(triggers) == 0 {
frame := data.NewFrame("No triggers found")
frame.RefID = query.RefID
return []*data.Frame{frame}, nil
}
triggerIDs := make([]string, len(triggers))
for i, t := range triggers {
triggerIDs[i] = t.ID
}
problems, err := ds.zabbix.GetProblems(ctx, triggerIDs)
if err != nil {
return nil, err
}
// Map trigger ID to problem (includes opdata captured at problem creation)
problemMap := buildProblemMap(problems)
currentTime := time.Now()
frames := make([]*data.Frame, 0)
for _, trigger := range triggers {
for _, host := range trigger.Hosts {
value := 0.0
problemName := ""
opdata := ""
if problem, hasProblem := problemMap[trigger.ID]; hasProblem {
value = 1.0
problemName = problem.Name // Expanded trigger description at problem creation
opdata = problem.Opdata // Operational data if configured
}
frame := createAlertingFrame(trigger, host, value, problemName, opdata, currentTime, query.RefID)
frames = append(frames, frame)
}
}
return frames, nil
}
// buildProblemMap returns a map of trigger ID to Problem object
func buildProblemMap(problems []zabbix.Problem) map[string]zabbix.Problem {
problemMap := make(map[string]zabbix.Problem)
for _, p := range problems {
problemMap[p.ObjectID] = p
}
return problemMap
}
func createAlertingFrame(trigger zabbix.Trigger, host zabbix.ItemHost, value float64, problemName string, opdata string, ts time.Time, refID string) *data.Frame {
labels := data.Labels{
"host": host.Name,
"trigger": trigger.Description,
"trigger_id": trigger.ID,
"severity": mapSeverity(trigger.Priority),
"tags": formatTags(trigger.Tags),
"problem_name": problemName, // Expanded trigger description at problem creation
"opdata": opdata, // Operational data if configured on trigger
}
timeField := data.NewField("time", nil, []time.Time{ts})
valueField := data.NewField("value", labels, []float64{value})
frameName := fmt.Sprintf("%s: %s", host.Name, trigger.Description)
frame := data.NewFrame(frameName, timeField, valueField)
frame.RefID = refID
return frame
}
func mapSeverity(priority string) string {
switch priority {
case "0":
return "Not classified"
case "1":
return "Information"
case "2":
return "Warning"
case "3":
return "Average"
case "4":
return "High"
case "5":
return "Disaster"
default:
return priority
}
}
func formatTags(tags []zabbix.Tag) string {
if len(tags) == 0 {
return ""
}
parts := make([]string, len(tags))
for i, t := range tags {
if t.Value != "" {
parts[i] = fmt.Sprintf("%s:%s", t.Tag, t.Value)
} else {
parts[i] = t.Tag
}
}
return strings.Join(parts, ",")
}

View File

@@ -5,7 +5,6 @@ import (
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
) )
@@ -106,24 +105,16 @@ func (ds *Zabbix) GetItems(
} }
if isRegex(itemTagFilter) { if isRegex(itemTagFilter) {
ds.logger.Debug("Processing regex item tag filter", "filterPattern", itemTagFilter, "hostCount", len(hostids))
tags, err := ds.GetItemTags(ctx, groupFilter, hostFilter, itemTagFilter) tags, err := ds.GetItemTags(ctx, groupFilter, hostFilter, itemTagFilter)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ds.logger.Debug("GetItemTags completed", "matchedTagCount", len(tags), "filterPattern", itemTagFilter)
// If regex filter doesn't match any tags, return empty items list
// to prevent silently removing the filter and returning all items
if len(tags) == 0 {
return []*Item{}, nil
}
var tagStrs []string var tagStrs []string
for _, t := range tags { for _, t := range tags {
tagStrs = append(tagStrs, itemTagToString(t)) tagStrs = append(tagStrs, itemTagToString(t))
} }
itemTagFilter = strings.Join(tagStrs, ",") itemTagFilter = strings.Join(tagStrs, ",")
} }
ds.logger.Debug("Fetching items with filters", "hostCount", len(hostids), "itemType", itemType, "showDisabled", showDisabled, "hasItemTagFilter", len(itemTagFilter) > 0)
allItems, err = ds.GetAllItems(ctx, hostids, nil, itemType, showDisabled, itemTagFilter) allItems, err = ds.GetAllItems(ctx, hostids, nil, itemType, showDisabled, itemTagFilter)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -320,10 +311,6 @@ func (ds *Zabbix) GetHosts(ctx context.Context, groupFilter string, hostFilter s
} }
func filterHostsByQuery(items []Host, filter string) ([]Host, error) { func filterHostsByQuery(items []Host, filter string) ([]Host, error) {
if filter == "" {
return items, nil
}
re, err := parseFilter(filter) re, err := parseFilter(filter)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -359,10 +346,6 @@ func (ds *Zabbix) GetGroups(ctx context.Context, groupFilter string) ([]Group, e
} }
func filterGroupsByQuery(items []Group, filter string) ([]Group, error) { func filterGroupsByQuery(items []Group, filter string) ([]Group, error) {
if filter == "" {
return items, nil
}
re, err := parseFilter(filter) re, err := parseFilter(filter)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -566,113 +549,3 @@ func (ds *Zabbix) GetVersion(ctx context.Context) (int, error) {
versionNum, err := strconv.Atoi(version) versionNum, err := strconv.Atoi(version)
return versionNum, err return versionNum, err
} }
func (ds *Zabbix) GetTriggers(ctx context.Context, groupFilter string, hostFilter string) ([]Trigger, error) {
ds.logger.Info("GetTriggers called", "groupFilter", groupFilter, "hostFilter", hostFilter)
hosts, err := ds.GetHosts(ctx, groupFilter, hostFilter)
if err != nil {
ds.logger.Error("GetHosts failed", "error", err)
return nil, err
}
ds.logger.Info("GetHosts returned", "count", len(hosts))
if len(hosts) == 0 {
return []Trigger{}, nil
}
hostids := make([]string, 0)
for _, host := range hosts {
hostids = append(hostids, host.ID)
}
// Get triggers currently in PROBLEM state (always include these)
problemParams := ZabbixAPIParams{
"output": []string{"triggerid", "description", "priority", "value"},
"hostids": hostids,
"selectHosts": []string{"hostid", "name"},
"selectTags": "extend",
"monitored": true,
"expandDescription": true,
"skipDependent": true, // Only show root cause triggers, not dependent ones
"filter": map[string]interface{}{
"value": "1",
},
}
problemResult, err := ds.Request(ctx, &ZabbixAPIRequest{Method: "trigger.get", Params: problemParams})
if err != nil {
return nil, err
}
var problemTriggers []Trigger
err = convertTo(problemResult, &problemTriggers)
if err != nil {
return nil, err
}
// Get triggers that changed state in the last 24 hours (for alert resolution)
oneDayAgo := time.Now().Add(-24 * time.Hour).Unix()
recentParams := ZabbixAPIParams{
"output": []string{"triggerid", "description", "priority", "value"},
"hostids": hostids,
"selectHosts": []string{"hostid", "name"},
"selectTags": "extend",
"monitored": true,
"expandDescription": true,
"skipDependent": true, // Only show root cause triggers, not dependent ones
"lastChangeSince": oneDayAgo,
}
recentResult, err := ds.Request(ctx, &ZabbixAPIRequest{Method: "trigger.get", Params: recentParams})
if err != nil {
return nil, err
}
var recentTriggers []Trigger
err = convertTo(recentResult, &recentTriggers)
if err != nil {
return nil, err
}
// Merge and deduplicate
triggerMap := make(map[string]Trigger)
for _, t := range problemTriggers {
triggerMap[t.ID] = t
}
for _, t := range recentTriggers {
triggerMap[t.ID] = t
}
triggers := make([]Trigger, 0, len(triggerMap))
for _, t := range triggerMap {
triggers = append(triggers, t)
}
ds.logger.Info("GetTriggers returning", "problemCount", len(problemTriggers), "recentCount", len(recentTriggers), "totalCount", len(triggers))
return triggers, nil
}
func (ds *Zabbix) GetProblems(ctx context.Context, triggerIDs []string) ([]Problem, error) {
if len(triggerIDs) == 0 {
return []Problem{}, nil
}
params := ZabbixAPIParams{
"output": []string{"eventid", "objectid", "severity", "name", "opdata"},
"objectids": triggerIDs,
"source": "0",
"object": "0",
"recent": true,
"selectTags": "extend",
}
result, err := ds.Request(ctx, &ZabbixAPIRequest{Method: "problem.get", Params: params})
if err != nil {
return nil, err
}
var problems []Problem
err = convertTo(result, &problems)
return problems, err
}

View File

@@ -122,76 +122,6 @@ func TestGetItems(t *testing.T) {
} }
} }
func TestGetItemsWithRegexItemTagFilterNoMatch(t *testing.T) {
// Test that when a regex itemTagFilter doesn't match any tags,
// GetItems returns an empty list instead of all items.
//
// This test verifies the fix for the bug where an empty tag filter result
// would cause itemTagFilter to become empty string, silently removing the filter.
//
// Bug scenario (without fix):
// 1. Regex itemTagFilter "/^NonExistentTag/" doesn't match any tags
// 2. GetItemTags returns empty list
// 3. itemTagFilter becomes "" (empty string)
// 4. GetAllItems is called with empty itemTagFilter → returns ALL items (no tag filtering)
// 5. filterItemsByQuery filters by itemFilter "/.*/" → returns all 2 items
//
// Fixed scenario (with fix):
// 1. Regex itemTagFilter "/^NonExistentTag/" doesn't match any tags
// 2. GetItemTags returns empty list
// 3. Early return with empty items list → returns 0 items
itemGetCalls := []map[string]interface{}{}
client := NewZabbixClientWithHandler(t, func(payload ApiRequestPayload) string {
if payload.Method == "item.get" {
// Track all item.get calls to verify behavior
paramsCopy := make(map[string]interface{})
for k, v := range payload.Params {
paramsCopy[k] = v
}
itemGetCalls = append(itemGetCalls, paramsCopy)
// Return items that would be returned if no tag filter is applied
return `{
"result":[
{"itemid":"100","name":"CPU usage","tags":[{"tag":"Env","value":"prod"}]},
{"itemid":"200","name":"Memory usage","tags":[{"tag":"Application","value":"api"}]}
]
}`
}
if payload.Method == "hostgroup.get" {
return `{"result":[{"groupid":"1","name":"Servers"}]}`
}
if payload.Method == "host.get" {
return `{"result":[{"hostid":"10","name":"web01"}]}`
}
if payload.Method == "apiinfo.version" {
return `{"result":"6.4.0"}`
}
return `{"result":null}`
})
// Use a regex itemTagFilter that won't match any tags
// Use itemFilter "/.*/" which matches all items, so we can detect if bug returns all items
items, err := client.GetItems(context.Background(), "Servers", "web01", "/^NonExistentTag/", "/.*/", "num", false)
require.NoError(t, err)
// With fix: Should return empty list (0 items) because no tags matched
// Without fix: Would return 2 items because itemTagFilter becomes empty and GetAllItems returns all items
if len(items) != 0 {
t.Errorf("Expected empty list when regex itemTagFilter matches no tags, but got %d items. This indicates the bug: itemTagFilter was silently removed and all items were returned.", len(items))
t.Logf("Item.get was called %d times", len(itemGetCalls))
for i, call := range itemGetCalls {
tags, hasTags := call["tags"]
if hasTags {
t.Logf("Call %d: has tags filter: %v", i+1, tags)
} else {
t.Logf("Call %d: NO tags filter (this is the bug - should not call GetAllItems with empty filter)", i+1)
}
}
}
assert.Len(t, items, 0, "Expected empty list when regex itemTagFilter matches no tags. Without fix, this would return 2 items.")
}
func TestGetItemsBefore54(t *testing.T) { func TestGetItemsBefore54(t *testing.T) {
client := NewZabbixClientWithResponses(t, map[string]string{ client := NewZabbixClientWithResponses(t, map[string]string{
"hostgroup.get": `{"result":[{"groupid":"1","name":"Servers"}]}`, "hostgroup.get": `{"result":[{"groupid":"1","name":"Servers"}]}`,

View File

@@ -111,21 +111,3 @@ type ValueMapping struct {
Value string `json:"value"` Value string `json:"value"`
NewValue string `json:"newvalue"` NewValue string `json:"newvalue"`
} }
type Trigger struct {
ID string `json:"triggerid"`
Description string `json:"description"`
Priority string `json:"priority"`
Value string `json:"value"`
Hosts []ItemHost `json:"hosts,omitempty"`
Tags []Tag `json:"tags,omitempty"`
}
type Problem struct {
EventID string `json:"eventid"`
ObjectID string `json:"objectid"`
Severity string `json:"severity"`
Name string `json:"name"`
Opdata string `json:"opdata"`
Tags []Tag `json:"tags,omitempty"`
}

View File

@@ -55,11 +55,6 @@ const zabbixQueryTypeOptions: Array<ComboboxOption<QueryType>> = [
label: 'User macros', label: 'User macros',
description: 'User Macros', description: 'User Macros',
}, },
{
value: c.MODE_PROBLEMS_ALERTING,
label: 'Problems (Alerting)',
description: 'Query problems for alerting (returns 0/1 time series)',
},
]; ];
const getDefaultQuery: () => Partial<ZabbixMetricsQuery> = () => ({ const getDefaultQuery: () => Partial<ZabbixMetricsQuery> = () => ({
@@ -231,7 +226,6 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery, range }:
{queryType === c.MODE_TEXT && renderTextMetricsEditor()} {queryType === c.MODE_TEXT && renderTextMetricsEditor()}
{queryType === c.MODE_ITSERVICE && renderITServicesEditor()} {queryType === c.MODE_ITSERVICE && renderITServicesEditor()}
{queryType === c.MODE_PROBLEMS && renderProblemsEditor()} {queryType === c.MODE_PROBLEMS && renderProblemsEditor()}
{queryType === c.MODE_PROBLEMS_ALERTING && renderProblemsEditor()}
{queryType === c.MODE_TRIGGERS && renderTriggersEditor()} {queryType === c.MODE_TRIGGERS && renderTriggersEditor()}
{queryType === c.MODE_MACROS && renderUserMacrosEditor()} {queryType === c.MODE_MACROS && renderUserMacrosEditor()}
<QueryOptionsEditor queryType={queryType} queryOptions={query.options} onChange={onOptionsChange} /> <QueryOptionsEditor queryType={queryType} queryOptions={query.options} onChange={onOptionsChange} />

View File

@@ -1,132 +0,0 @@
import React from 'react';
import { render, waitFor } from '@testing-library/react';
import { ProblemsQueryEditor } from './ProblemsQueryEditor';
import { ShowProblemTypes, ZabbixTagEvalType } from '../../types/query';
const metricPickerSpy = jest.fn();
jest.mock('../../../components', () => ({
MetricPicker: (props: any) => {
metricPickerSpy(props);
return null;
},
}));
jest.mock('@grafana/runtime', () => ({
getTemplateSrv: jest.fn(() => ({
getVariables: jest.fn(() => []),
})),
}));
jest.mock('@grafana/ui', () => ({
Combobox: (props: any) => <div {...props} />,
InlineField: ({ children }: any) => <div>{children}</div>,
InlineFieldRow: ({ children }: any) => <div>{children}</div>,
InlineFormLabel: ({ children }: any) => <div>{children}</div>,
Input: (props: any) => <input {...props} />,
MultiSelect: (props: any) => <div {...props} />,
}));
const baseQuery: any = {
group: { filter: '' },
host: { filter: '' },
proxy: { filter: '' },
application: { filter: '' },
trigger: { filter: '' },
tags: { filter: '' },
evaltype: ZabbixTagEvalType.AndOr,
showProblems: ShowProblemTypes.Problems,
options: { severities: [] },
};
const buildDatasource = (overrides: Partial<any> = {}) => {
const zabbix = {
getAllGroups: jest.fn().mockResolvedValue([]),
getAllHosts: jest.fn().mockResolvedValue([]),
getAllApps: jest.fn().mockResolvedValue([]),
getProxies: jest.fn().mockResolvedValue([]),
supportsApplications: jest.fn(() => true),
...overrides,
};
return {
zabbix,
interpolateVariablesInQueries: jest.fn((queries: any[]) => queries),
};
};
describe('ProblemsQueryEditor', () => {
beforeEach(() => {
metricPickerSpy.mockClear();
});
it('uses proxy name when host is missing', async () => {
const datasource = buildDatasource({
getProxies: jest.fn().mockResolvedValue([{ name: 'proxy-a' }]),
});
render(<ProblemsQueryEditor query={baseQuery} datasource={datasource as any} onChange={jest.fn()} />);
await waitFor(() => {
const proxyCall = metricPickerSpy.mock.calls
.map((call) => call[0])
.find((props) => props?.placeholder === 'Proxy name' && props?.options);
expect(proxyCall).toBeTruthy();
expect(proxyCall.options).toEqual([{ value: 'proxy-a', label: 'proxy-a' }]);
});
});
it('uses proxy host when present', async () => {
const datasource = buildDatasource({
getProxies: jest.fn().mockResolvedValue([{ host: 'legacy-proxy' }]),
});
render(<ProblemsQueryEditor query={baseQuery} datasource={datasource as any} onChange={jest.fn()} />);
await waitFor(() => {
const proxyCall = metricPickerSpy.mock.calls
.map((call) => call[0])
.find((props) => props?.placeholder === 'Proxy name' && props?.options);
expect(proxyCall).toBeTruthy();
expect(proxyCall.options).toEqual([{ value: 'legacy-proxy', label: 'legacy-proxy' }]);
});
});
it('defaults missing option values to empty strings', async () => {
const datasource = buildDatasource({
getAllGroups: jest.fn().mockResolvedValue([{ name: 'group-a' }, { name: '' }, {}]),
getAllHosts: jest.fn().mockResolvedValue([{ name: 'host-a' }, { name: '' }, {}]),
getAllApps: jest.fn().mockResolvedValue([{ name: 'app-a' }, { name: '' }, {}]),
getProxies: jest.fn().mockResolvedValue([{ name: '' }, { host: '' }, { name: 'proxy-a' }]),
});
render(<ProblemsQueryEditor query={baseQuery} datasource={datasource as any} onChange={jest.fn()} />);
await waitFor(() => {
const groupCall = metricPickerSpy.mock.calls
.map((call) => call[0])
.find((props) => props?.placeholder === 'Group name' && props?.options);
const hostCall = metricPickerSpy.mock.calls
.map((call) => call[0])
.find((props) => props?.placeholder === 'Host name' && props?.options);
const appCall = metricPickerSpy.mock.calls
.map((call) => call[0])
.find((props) => props?.placeholder === 'Application name' && props?.options);
const proxyCall = metricPickerSpy.mock.calls
.map((call) => call[0])
.find((props) => props?.placeholder === 'Proxy name' && props?.options);
const hasValidValues = (options: any[]) =>
options.every(
(option) => option.value !== undefined && (option.label !== undefined || option.value === '/.*/')
);
expect(hasValidValues(groupCall.options)).toBe(true);
expect(hasValidValues(hostCall.options)).toBe(true);
expect(hasValidValues(appCall.options)).toBe(true);
expect(hasValidValues(proxyCall.options)).toBe(true);
});
});
});

View File

@@ -43,8 +43,8 @@ export const ProblemsQueryEditor = ({ query, datasource, onChange }: Props) => {
const loadGroupOptions = async () => { const loadGroupOptions = async () => {
const groups = await datasource.zabbix.getAllGroups(); const groups = await datasource.zabbix.getAllGroups();
const options = groups?.map((group) => ({ const options = groups?.map((group) => ({
value: group.name ?? '', value: group.name,
label: group.name ?? '', label: group.name,
})); }));
options.unshift(...getVariableOptions()); options.unshift(...getVariableOptions());
return options; return options;
@@ -58,8 +58,8 @@ export const ProblemsQueryEditor = ({ query, datasource, onChange }: Props) => {
const loadHostOptions = async (group: string) => { const loadHostOptions = async (group: string) => {
const hosts = await datasource.zabbix.getAllHosts(group); const hosts = await datasource.zabbix.getAllHosts(group);
let options: Array<ComboboxOption<string>> = hosts?.map((host) => ({ let options: Array<ComboboxOption<string>> = hosts?.map((host) => ({
value: host.name ?? '', value: host.name,
label: host.name ?? '', label: host.name,
})); }));
options = _.uniqBy(options, (o) => o.value); options = _.uniqBy(options, (o) => o.value);
options.unshift({ value: '/.*/' }); options.unshift({ value: '/.*/' });
@@ -75,8 +75,8 @@ export const ProblemsQueryEditor = ({ query, datasource, onChange }: Props) => {
const loadAppOptions = async (group: string, host: string) => { const loadAppOptions = async (group: string, host: string) => {
const apps = await datasource.zabbix.getAllApps(group, host); const apps = await datasource.zabbix.getAllApps(group, host);
let options: Array<ComboboxOption<string>> = apps?.map((app) => ({ let options: Array<ComboboxOption<string>> = apps?.map((app) => ({
value: app.name ?? '', value: app.name,
label: app.name ?? '', label: app.name,
})); }));
options = _.uniqBy(options, (o) => o.value); options = _.uniqBy(options, (o) => o.value);
options.unshift(...getVariableOptions()); options.unshift(...getVariableOptions());
@@ -91,8 +91,8 @@ export const ProblemsQueryEditor = ({ query, datasource, onChange }: Props) => {
const loadProxyOptions = async () => { const loadProxyOptions = async () => {
const proxies = await datasource.zabbix.getProxies(); const proxies = await datasource.zabbix.getProxies();
const options = proxies?.map((proxy) => ({ const options = proxies?.map((proxy) => ({
value: (!!proxy.host ? proxy.host : proxy.name) ?? '', value: proxy.host,
label: (!!proxy.host ? proxy.host : proxy.name) ?? '', label: proxy.host,
})); }));
options.unshift(...getVariableOptions()); options.unshift(...getVariableOptions());
return options; return options;

View File

@@ -51,7 +51,7 @@ export class ZabbixVariableQueryEditor extends PureComponent<VariableQueryProps,
} }
getSelectedQueryType(queryType: VariableQueryTypes) { getSelectedQueryType(queryType: VariableQueryTypes) {
return this.queryTypes.find((q) => q.value === queryType) ?? this.defaults.selectedQueryType; return this.queryTypes.find((q) => q.value === queryType);
} }
handleQueryUpdate = (evt: React.ChangeEvent<HTMLInputElement>, prop: string) => { handleQueryUpdate = (evt: React.ChangeEvent<HTMLInputElement>, prop: string) => {

View File

@@ -14,7 +14,6 @@ export const MODE_ITEMID = '3';
export const MODE_TRIGGERS = '4'; export const MODE_TRIGGERS = '4';
export const MODE_PROBLEMS = '5'; export const MODE_PROBLEMS = '5';
export const MODE_MACROS = '6'; export const MODE_MACROS = '6';
export const MODE_PROBLEMS_ALERTING = '7';
// Triggers severity // Triggers severity
export const SEV_NOT_CLASSIFIED = 0; export const SEV_NOT_CLASSIFIED = 0;

View File

@@ -900,7 +900,7 @@ export class ZabbixDatasource extends DataSourceWithBackend<ZabbixMetricsQuery,
return false; return false;
} }
return target.queryType === c.MODE_METRICS || target.queryType === c.MODE_ITEMID || target.queryType === c.MODE_PROBLEMS_ALERTING; return target.queryType === c.MODE_METRICS || target.queryType === c.MODE_ITEMID;
}; };
isDBConnectionTarget = (target: any): boolean => { isDBConnectionTarget = (target: any): boolean => {

View File

@@ -9,8 +9,7 @@ export type QueryType =
| typeof c.MODE_ITEMID | typeof c.MODE_ITEMID
| typeof c.MODE_TRIGGERS | typeof c.MODE_TRIGGERS
| typeof c.MODE_PROBLEMS | typeof c.MODE_PROBLEMS
| typeof c.MODE_MACROS | typeof c.MODE_MACROS;
| typeof c.MODE_PROBLEMS_ALERTING;
type BaseQuery = { queryType: QueryType; datasourceId: number } & DataQuery; type BaseQuery = { queryType: QueryType; datasourceId: number } & DataQuery;

View File

@@ -296,6 +296,7 @@ export class Zabbix implements ZabbixConnector {
} }
getAllGroups() { getAllGroups() {
console.log(this.zabbixAPI.getGroups());
return this.zabbixAPI.getGroups(); return this.zabbixAPI.getGroups();
} }

View File

@@ -1,253 +0,0 @@
import React from 'react';
import { render, screen, within } from '@testing-library/react';
import { ProblemList, ProblemListProps } from './Problems';
import { ProblemDTO, ZBXAlert, ZBXEvent } from '../../../datasource/types';
import { ProblemsPanelOptions, DEFAULT_SEVERITY } from '../../types';
import { APIExecuteScriptResponse, ZBXScript } from '../../../datasource/zabbix/connectors/zabbix_api/types';
// Mock @grafana/runtime
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
reportInteraction: jest.fn(),
config: {},
}));
describe('ProblemList', () => {
const mockGetProblemEvents = jest.fn<Promise<ZBXEvent[]>, [ProblemDTO]>();
const mockGetProblemAlerts = jest.fn<Promise<ZBXAlert[]>, [ProblemDTO]>();
const mockGetScripts = jest.fn<Promise<ZBXScript[]>, [ProblemDTO]>();
const mockOnExecuteScript = jest.fn<Promise<APIExecuteScriptResponse>, [ProblemDTO, string, string]>();
const mockOnProblemAck = jest.fn();
const mockOnTagClick = jest.fn();
const mockOnPageSizeChange = jest.fn();
const mockOnColumnResize = jest.fn();
const defaultPanelOptions: ProblemsPanelOptions = {
datasources: [],
fontSize: '100%',
layout: 'table',
schemaVersion: 1,
targets: [],
hostField: true,
hostTechNameField: false,
hostGroups: false,
hostProxy: false,
severityField: true,
statusField: true,
statusIcon: true,
opdataField: false,
ackField: true,
showTags: true,
showDatasourceName: false,
ageField: true,
customLastChangeFormat: false,
lastChangeFormat: '',
highlightNewEvents: false,
highlightNewerThan: '',
markAckEvents: false,
ackEventColor: 'rgb(56, 219, 156)',
okEventColor: 'rgb(56, 189, 113)',
triggerSeverity: DEFAULT_SEVERITY,
problemTimeline: false,
allowDangerousHTML: false,
resizedColumns: [],
};
const createMockProblem = (id: string, timestamp: number): ProblemDTO => ({
eventid: id,
name: `Test Problem ${id}`,
acknowledged: '0',
value: '1',
severity: '3',
priority: '3',
host: `Test Host ${id}`,
hostTechName: `host-${id}`,
hostInMaintenance: false,
groups: [],
proxy: '',
tags: [],
url: '',
opdata: '',
datasource: { type: 'alexanderzobnin-zabbix-datasource', uid: 'test-ds' },
timestamp,
acknowledges: [],
suppressed: '0',
suppression_data: [],
comments: '',
});
const defaultProps: ProblemListProps = {
problems: [],
panelOptions: defaultPanelOptions,
loading: false,
pageSize: 10,
fontSize: 100,
panelId: 1,
getProblemEvents: mockGetProblemEvents,
getProblemAlerts: mockGetProblemAlerts,
getScripts: mockGetScripts,
onExecuteScript: mockOnExecuteScript,
onProblemAck: mockOnProblemAck,
onTagClick: mockOnTagClick,
onPageSizeChange: mockOnPageSizeChange,
onColumnResize: mockOnColumnResize,
};
beforeEach(() => {
jest.clearAllMocks();
});
describe('Age Field', () => {
it('should render the age column header when ageField is enabled', () => {
const props = {
...defaultProps,
panelOptions: { ...defaultPanelOptions, ageField: true },
problems: [createMockProblem('1', 1609459200)], // 2021-01-01 00:00:00 UTC
};
render(<ProblemList {...props} />);
const table = screen.getByRole('table');
const headers = within(table).getAllByRole('columnheader');
const ageHeader = headers.find((header) => header.textContent === 'Age');
expect(ageHeader).toBeInTheDocument();
});
it('should not render the age column header when ageField is disabled', () => {
const props = {
...defaultProps,
panelOptions: { ...defaultPanelOptions, ageField: false },
problems: [createMockProblem('1', 1609459200)],
};
render(<ProblemList {...props} />);
const table = screen.getByRole('table');
const headers = within(table).getAllByRole('columnheader');
const ageHeader = headers.find((header) => header.textContent === 'Age');
expect(ageHeader).toBeUndefined();
});
});
describe('Status Field', () => {
it('should render the status column header when statusField is enabled', () => {
const props = {
...defaultProps,
panelOptions: { ...defaultPanelOptions, statusField: true },
problems: [createMockProblem('1', 1609459200)],
};
render(<ProblemList {...props} />);
const table = screen.getByRole('table');
const headers = within(table).getAllByRole('columnheader');
const statusHeader = headers.find((header) => header.textContent === 'Status');
expect(statusHeader).toBeInTheDocument();
});
it('should not render the status column header when statusField is disabled', () => {
const props = {
...defaultProps,
panelOptions: { ...defaultPanelOptions, statusField: false },
problems: [createMockProblem('1', 1609459200)],
};
render(<ProblemList {...props} />);
const table = screen.getByRole('table');
const headers = within(table).getAllByRole('columnheader');
const statusHeader = headers.find((header) => header.textContent === 'Status');
expect(statusHeader).toBeUndefined();
});
});
describe('Severity Field', () => {
it('should render the severity column header when severityField is enabled', () => {
const props = {
...defaultProps,
panelOptions: { ...defaultPanelOptions, severityField: true },
problems: [createMockProblem('1', 1609459200)],
};
render(<ProblemList {...props} />);
const table = screen.getByRole('table');
const headers = within(table).getAllByRole('columnheader');
const severityHeader = headers.find((header) => header.textContent === 'Severity');
expect(severityHeader).toBeInTheDocument();
});
it('should not render the severity column header when severityField is disabled', () => {
const props = {
...defaultProps,
panelOptions: { ...defaultPanelOptions, severityField: false },
problems: [createMockProblem('1', 1609459200)],
};
render(<ProblemList {...props} />);
const table = screen.getByRole('table');
const headers = within(table).getAllByRole('columnheader');
const severityHeader = headers.find((header) => header.textContent === 'Severity');
expect(severityHeader).toBeUndefined();
});
});
describe('Ack Field', () => {
it('should render the ack column header when ackField is enabled', () => {
const props = {
...defaultProps,
panelOptions: { ...defaultPanelOptions, ackField: true },
problems: [createMockProblem('1', 1609459200)],
};
render(<ProblemList {...props} />);
const table = screen.getByRole('table');
const headers = within(table).getAllByRole('columnheader');
const ackHeader = headers.find((header) => header.textContent === 'Ack');
expect(ackHeader).toBeInTheDocument();
});
it('should not render the ack column header when ackField is disabled', () => {
const props = {
...defaultProps,
panelOptions: { ...defaultPanelOptions, ackField: false },
problems: [createMockProblem('1', 1609459200)],
};
render(<ProblemList {...props} />);
const table = screen.getByRole('table');
const headers = within(table).getAllByRole('columnheader');
const ackHeader = headers.find((header) => header.textContent === 'Ack');
expect(ackHeader).toBeUndefined();
});
});
describe('Datasource Field', () => {
it('should not render the datasource column header when showDatasourceName is disabled', () => {
const props = {
...defaultProps,
panelOptions: { ...defaultPanelOptions, showDatasourceName: false },
problems: [createMockProblem('1', 1609459200)],
};
render(<ProblemList {...props} />);
const table = screen.getByRole('table');
const headers = within(table).getAllByRole('columnheader');
const datasourceHeader = headers.find((header) => header.textContent === 'Datasource');
expect(datasourceHeader).toBeUndefined();
});
});
});

View File

@@ -23,9 +23,8 @@ import {
getPaginationRowModel, getPaginationRowModel,
useReactTable, useReactTable,
} from '@tanstack/react-table'; } from '@tanstack/react-table';
import { getDataSourceSrv, reportInteraction } from '@grafana/runtime'; import { reportInteraction } from '@grafana/runtime';
import { ProblemDetails } from './ProblemDetails'; import { ProblemDetails } from './ProblemDetails';
import { capitalizeFirstLetter, parseCustomTagColumns } from './utils';
export interface ProblemListProps { export interface ProblemListProps {
problems: ProblemDTO[]; problems: ProblemDTO[];
@@ -48,33 +47,6 @@ export interface ProblemListProps {
const columnHelper = createColumnHelper<ProblemDTO>(); const columnHelper = createColumnHelper<ProblemDTO>();
const buildCustomTagColumns = (customTagColumns?: string) => {
const tagNames = parseCustomTagColumns(customTagColumns);
return tagNames.map((tagName) =>
columnHelper.accessor(
(row) => {
const tags = row.tags ?? [];
const values = tags
.filter((t) => t.tag === tagName)
.map((t) => t.value)
.filter(Boolean);
return values.length ? values.join(', ') : '';
},
{
id: `problem-tag_${tagName}`,
header: capitalizeFirstLetter(tagName),
size: 150,
meta: {
className: `problem-tag_${tagName}`,
},
cell: ({ getValue }) => <span>{getValue() as string}</span>,
}
)
);
};
export const ProblemList = (props: ProblemListProps) => { export const ProblemList = (props: ProblemListProps) => {
const { const {
pageSize, pageSize,
@@ -100,8 +72,6 @@ export const ProblemList = (props: ProblemListProps) => {
const columns = useMemo(() => { const columns = useMemo(() => {
const highlightNewerThan = panelOptions.highlightNewEvents && panelOptions.highlightNewerThan; const highlightNewerThan = panelOptions.highlightNewEvents && panelOptions.highlightNewerThan;
const customTagColumns = buildCustomTagColumns(panelOptions.customTagColumns);
return [ return [
columnHelper.accessor('host', { columnHelper.accessor('host', {
header: 'Host', header: 'Host',
@@ -176,7 +146,6 @@ export const ProblemList = (props: ProblemListProps) => {
size: 70, size: 70,
cell: ({ cell }) => <AckCell acknowledges={cell.row.original.acknowledges} />, cell: ({ cell }) => <AckCell acknowledges={cell.row.original.acknowledges} />,
}), }),
...customTagColumns,
columnHelper.accessor('tags', { columnHelper.accessor('tags', {
header: 'Tags', header: 'Tags',
size: 150, size: 150,
@@ -191,19 +160,6 @@ export const ProblemList = (props: ProblemListProps) => {
/> />
), ),
}), }),
columnHelper.accessor('datasource', {
header: 'Datasource',
size: 120,
cell: ({ cell }) => {
const datasource = cell.getValue();
let dsName: string = datasource as string;
if ((datasource as DataSourceRef)?.uid) {
const dsInstance = getDataSourceSrv().getInstanceSettings((datasource as DataSourceRef).uid);
dsName = dsInstance?.name || dsName;
}
return <span>{dsName}</span>;
},
}),
columnHelper.accessor('timestamp', { columnHelper.accessor('timestamp', {
id: 'age', id: 'age',
header: 'Age', header: 'Age',
@@ -211,7 +167,7 @@ export const ProblemList = (props: ProblemListProps) => {
meta: { meta: {
className: 'problem-age', className: 'problem-age',
}, },
cell: ({ cell }) => <span>{moment.unix(cell.row.original.timestamp).fromNow(true)}</span>, cell: ({ cell }) => moment.unix(cell.row.original.timestamp),
}), }),
columnHelper.accessor('timestamp', { columnHelper.accessor('timestamp', {
id: 'lastchange', id: 'lastchange',
@@ -281,27 +237,6 @@ export const ProblemList = (props: ProblemListProps) => {
})); }));
}, [effectivePageSize]); }, [effectivePageSize]);
// Column visibility state derived from panelOptions
const columnVisibility = useMemo(
() => ({
host: panelOptions.hostField,
hostTechName: panelOptions.hostTechNameField,
groups: panelOptions.hostGroups,
proxy: panelOptions.hostProxy,
priority: panelOptions.severityField,
statusIcon: panelOptions.statusIcon,
value: panelOptions.statusField,
opdata: panelOptions.opdataField,
acknowledged: panelOptions.ackField,
tags: panelOptions.showTags,
datasource: panelOptions.showDatasourceName,
age: panelOptions.ageField,
}),
[panelOptions]
);
// https://github.com/TanStack/table/issues/6137
// eslint-disable-next-line react-hooks/incompatible-library -- TanStack Table's useReactTable returns functions that cannot be memoized
const table = useReactTable({ const table = useReactTable({
data: problems, data: problems,
columns, columns,
@@ -310,12 +245,25 @@ export const ProblemList = (props: ProblemListProps) => {
state: { state: {
columnSizing, columnSizing,
pagination, pagination,
columnVisibility,
}, },
onPaginationChange: setPagination, onPaginationChange: setPagination,
meta: { meta: {
panelOptions, panelOptions,
}, },
initialState: {
columnVisibility: {
host: panelOptions.hostField,
hostTechName: panelOptions.hostTechNameField,
groups: panelOptions.hostGroups,
proxy: panelOptions.hostProxy,
severity: panelOptions.severityField,
statusIcon: panelOptions.statusIcon,
opdata: panelOptions.opdataField,
ack: panelOptions.ackField,
tags: panelOptions.showTags,
age: panelOptions.ageField,
},
},
onColumnSizingChange: (updater) => { onColumnSizingChange: (updater) => {
const newSizing = typeof updater === 'function' ? updater(columnSizing) : updater; const newSizing = typeof updater === 'function' ? updater(columnSizing) : updater;
setColumnSizing(newSizing); setColumnSizing(newSizing);

View File

@@ -1,38 +0,0 @@
import { capitalizeFirstLetter, parseCustomTagColumns } from './utils';
describe('capitalizeFirstLetter', () => {
it('capitalizes first letter and lowercases the rest', () => {
expect(capitalizeFirstLetter('zabbixgrafana')).toBe('Zabbixgrafana');
expect(capitalizeFirstLetter('ZABBIXGRAFANA')).toBe('Zabbixgrafana');
expect(capitalizeFirstLetter('zAbBiXgRaFaNa')).toBe('Zabbixgrafana');
});
it('returns empty string for empty input', () => {
expect(capitalizeFirstLetter('')).toBe('');
});
it('handles single-character strings', () => {
expect(capitalizeFirstLetter('a')).toBe('A');
expect(capitalizeFirstLetter('A')).toBe('A');
});
});
describe('parseCustomTagColumns', () => {
it('returns empty array for undefined or empty input', () => {
expect(parseCustomTagColumns(undefined)).toEqual([]);
expect(parseCustomTagColumns('')).toEqual([]);
expect(parseCustomTagColumns(' ')).toEqual([]);
});
it('splits comma-separated values and trims whitespace', () => {
expect(parseCustomTagColumns('env, region ,service')).toEqual(['env', 'region', 'service']);
});
it('filters out empty values', () => {
expect(parseCustomTagColumns('env,, ,region,')).toEqual(['env', 'region']);
});
it('preserves order', () => {
expect(parseCustomTagColumns('a,b,c')).toEqual(['a', 'b', 'c']);
});
});

View File

@@ -1,12 +0,0 @@
export const capitalizeFirstLetter = (str: string): string => str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
export const parseCustomTagColumns = (customTagColumns?: string): string[] => {
if (!customTagColumns) {
return [];
}
return customTagColumns
.split(',')
.map((tagName) => tagName.trim())
.filter(Boolean);
};

View File

@@ -220,17 +220,6 @@ export const plugin = new PanelPlugin<ProblemsPanelOptions, {}>(ProblemsPanel)
name: 'Datasource name', name: 'Datasource name',
defaultValue: defaultPanelOptions.showDatasourceName, defaultValue: defaultPanelOptions.showDatasourceName,
category: ['Fields'], category: ['Fields'],
})
// Select tag name to display as column
.addTextInput({
path: 'customTagColumns',
name: 'Tags to columns',
defaultValue: '',
description: 'Comma-separated list of tag names to display as columns (e.g., component, scope, environment)',
settings: {
placeholder: 'component, scope, target',
},
category: ['Fields'],
}); });
}); });

View File

@@ -42,8 +42,6 @@ export interface ProblemsPanelOptions {
okEventColor: TriggerColor; okEventColor: TriggerColor;
ackEventColor: TriggerColor; ackEventColor: TriggerColor;
markAckEvents?: boolean; markAckEvents?: boolean;
// Custom tag names to display as column
customTagColumns?: string;
} }
export const DEFAULT_SEVERITY: TriggerSeverity[] = [ export const DEFAULT_SEVERITY: TriggerSeverity[] = [

962
yarn.lock

File diff suppressed because it is too large Load Diff