diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 301d8ba..6ce7e59 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,5 +1,8 @@
name: CI
+env:
+ CYPRESS_CACHE_FOLDER: cypress/cache
+
on:
pull_request:
branches:
@@ -27,38 +30,37 @@ jobs:
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
-
- name: Cache node_modules
id: cache-node-modules
uses: actions/cache@v2
with:
path: node_modules
- key: ${{ runner.os }}-${{ matrix.node-version }}-nodemodules-${{ hashFiles('**/yarn.lock') }}
+ key: ${{ runner.os }}-${{ matrix.node-version }}-node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
- ${{ runner.os }}-${{ matrix.node-version }}-nodemodules-
+ ${{ runner.os }}-${{ matrix.node-version }}-node-modules-
+ - name: Cache Cypress Binary
+ id: cache-cypress-binary
+ uses: actions/cache@v2
+ with:
+ path: cypress/cache
+ key: cypress-binary-${{ hashFiles('yarn.lock') }}
- - name: Build plugin
- run: yarn build
+ - name: Pull dependencies
+ run: yarn
- name: Sign plugin
- run: |
- # We only have a single dependency, grafana-toolkit
- # So we install next to where it's needed
- yarn
- yarn sign
+ run: yarn sign
env:
GRAFANA_API_KEY: ${{ secrets.GRAFANA_API_KEY }} # Requires a Grafana API key from Grafana.com.
- # We reuse the same tests from the other repo, after all, why not?
- # TODO: run other tests that are valid here
- # eg: checking README etc
+ # Smoke test
+ # We already tested it extensively in the other repository
- name: Run grafana server
- run: docker-compose -f pyroscope/grafana-plugin/panel/docker-compose.yml up -d
+ run: docker-compose -f docker-compose.yml up -d
- name: Run tests
- run: yarn --cwd pyroscope cy:panel:ci
+ run: yarn cy:ci
env:
CYPRESS_VIDEO: true
- CYPRESS_COMPARE_SNAPSHOTS: true
- uses: actions/upload-artifact@v2
if: always()
with:
@@ -69,12 +71,6 @@ jobs:
with:
name: cypress-videos
path: pyroscope/cypress/videos
- - uses: actions/upload-artifact@v2
- if: always()
- with:
- name: cypress-snapshots
- # TODO: scope to only store screenshots that refer to grafana
- path: pyroscope/cypress/snapshots
# Setup the go environment, since the grafana plugin linter isn't distributed as a binary
- name: Setup Go environment
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 40ea16d..b9c15a2 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -29,55 +29,28 @@ jobs:
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
-
- name: Cache node_modules
id: cache-node-modules
uses: actions/cache@v2
with:
path: node_modules
- key: ${{ runner.os }}-${{ matrix.node-version }}-nodemodules-${{ hashFiles('**/yarn.lock') }}
+ key: ${{ runner.os }}-${{ matrix.node-version }}-node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
- ${{ runner.os }}-${{ matrix.node-version }}-nodemodules-
-
- - name: Build plugin
- run: yarn build
+ ${{ runner.os }}-${{ matrix.node-version }}-node-modules-
+ - name: Cache Cypress Binary
+ id: cache-cypress-binary
+ uses: actions/cache@v2
+ with:
+ path: cypress/cache
+ key: cypress-binary-${{ hashFiles('yarn.lock') }}
+ - name: Pull dependencies
+ run: yarn
- name: Sign plugin
- run: |
- # We only have a single dependency, grafana-toolkit
- # So we install next to where it's needed
- yarn
- yarn sign
+ run: yarn sign
env:
GRAFANA_API_KEY: ${{ secrets.GRAFANA_API_KEY }} # Requires a Grafana API key from Grafana.com.
- # We reuse the same tests from the other repo, after all, why not?
- # TODO: run other tests that are valid here
- # eg: checking README etc
- - name: Run grafana server
- run: docker-compose -f pyroscope/grafana-plugin/panel/docker-compose.yml up -d
- - name: Run tests
- run: yarn --cwd pyroscope cy:panel:ci
- env:
- CYPRESS_VIDEO: true
- CYPRESS_COMPARE_SNAPSHOTS: true
- - uses: actions/upload-artifact@v2
- if: always()
- with:
- name: cypress-screenshots
- path: pyroscope/cypress/screenshots
- - uses: actions/upload-artifact@v2
- if: always()
- with:
- name: cypress-videos
- path: pyroscope/cypress/videos
- - uses: actions/upload-artifact@v2
- if: always()
- with:
- name: cypress-snapshots
- # TODO: scope to only store screenshots that refer to grafana
- path: pyroscope/cypress/snapshots
-
# Setup the go environment, since the grafana plugin linter isn't distributed as a binary
- name: Setup Go environment
if: steps.check-for-backend.outputs.has-backend == 'true'
diff --git a/.gitignore b/.gitignore
index f9f0e92..3e32de2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,7 +30,7 @@ e2e-results/
# Editors
.idea
-src/flamegraphComponent.js
-pyroscope
dist.zip
plugin-validator
+
+cypress/videos
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index 4b18ff4..0000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Changelog
-
-## 1.2.0
-* Remove broken export button
-* Improve flamegraph coloring for go
-
-## 1.1.0
-* Add context menu (triggered by right clicking the flamegraph)
-* Add toolbar
-* Allow focusing on a subtree
-* Allow searching nodes that match a specific string
-* Visual updates
-
-## 1.0.0
-
-Initial release.
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 8dada3e..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "{}"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright {yyyy} {name of copyright owner}
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/README.md b/README.md
index c685105..a5f517b 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,21 @@
# Pyroscope Grafana Panel Plugin
+# Usage
For more info see [pyroscope-panel plugin for Grafana | Grafana Labs](https://grafana.com/grafana/plugins/pyroscope-panel/)
-or [pyroscope/grafana-plugin/panel at main · pyroscope-io/pyroscope](https://github.com/pyroscope-io/pyroscope/tree/main/grafana-plugin/panel)
+or the source code [pyroscope/packages/pyroscope-panel-plugin at main · pyroscope-io/pyroscope](https://github.com/pyroscope-io/pyroscope/tree/main/packages/pyroscope-panel-plugin)
+# Raison d'etre
+The actual plugin development happens in the [main repo](https://github.com/pyroscope-io/pyroscope/tree/main/packages/pyroscope-panel-plugin).
+
+This repository is a simple wrapper around the `@pyroscope/panel-plugin` library.
+It simply packages it, signs it and make a github release.
+It does this for a couple reasons:
+* So that we control the actual plugin release (since `@pyroscope/panel-plugin` release is automated)
+* So that it's cleaner for users (The main repo releases refer to the pyroscope binary itself)
+
# Releasing new versions
-1. Update the `UPSTREAM_BRANCH` in `build-panel.sh`
-2. Update CHANGELOG.md
-3. Bump the version in `package.json`
-4. Merge to the main branch.
+1. Update the `@pyroscope/panel-plugin` dependency
+2. Open a Pull Request and merge it
+3. Submit the new plugin version in Grafana Cloud (https://grafana.com/docs/grafana/latest/developers/plugins/package-a-plugin/#maintain-your-plugin)
+
diff --git a/cypress.json b/cypress.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/cypress.json
@@ -0,0 +1 @@
+{}
diff --git a/cypress/fixtures/simple-golang-app-cpu.json b/cypress/fixtures/simple-golang-app-cpu.json
new file mode 100644
index 0000000..9fc275c
--- /dev/null
+++ b/cypress/fixtures/simple-golang-app-cpu.json
@@ -0,0 +1,35 @@
+{
+ "flamebearer": {
+ "names": [
+ "total",
+ "runtime.main",
+ "main.slowFunction",
+ "main.work",
+ "main.main",
+ "main.fastFunction"
+ ],
+ "levels": [
+ [0, 988, 0, 0],
+ [0, 988, 0, 1],
+ [0, 214, 0, 5, 0, 3, 2, 4, 0, 771, 0, 2],
+ [0, 214, 214, 3, 2, 1, 1, 5, 0, 771, 771, 3]
+ ],
+ "numTicks": 988,
+ "maxSelf": 771,
+ "spyName": "gospy",
+ "sampleRate": 100,
+ "units": "samples",
+ "format": "single"
+ },
+ "metadata": {
+ "format": "single",
+ "sampleRate": 100,
+ "spyName": "gospy",
+ "units": "samples"
+ },
+ "timeline": {
+ "startTime": 1632335270,
+ "samples": [989],
+ "durationDelta": 10
+ }
+}
diff --git a/cypress/integration/smoke.js b/cypress/integration/smoke.js
new file mode 100644
index 0000000..7a249d6
--- /dev/null
+++ b/cypress/integration/smoke.js
@@ -0,0 +1,13 @@
+// For these tests we can mock the requests
+// Since we are only testing the panel itself
+describe('smoke', () => {
+ it('renders the panel correctly', () => {
+ cy.intercept('**/render*', {
+ fixture: 'simple-golang-app-cpu.json',
+ }).as('render');
+
+ cy.visit('http://localhost:3000/d/single-panel/pyroscope-demo?orgId=1');
+
+ cy.get('[data-testid="flamegraph-canvas"]').should('exist');
+ });
+});
diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js
new file mode 100644
index 0000000..59b2bab
--- /dev/null
+++ b/cypress/plugins/index.js
@@ -0,0 +1,22 @@
+///
+// ***********************************************************
+// This example plugins/index.js can be used to load plugins
+//
+// You can change the location of this file or turn off loading
+// the plugins file with the 'pluginsFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/plugins-guide
+// ***********************************************************
+
+// This function is called when a project is opened or re-opened (e.g. due to
+// the project's config changing)
+
+/**
+ * @type {Cypress.PluginConfig}
+ */
+// eslint-disable-next-line no-unused-vars
+module.exports = (on, config) => {
+ // `on` is used to hook into various events Cypress emits
+ // `config` is the resolved Cypress config
+}
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
new file mode 100644
index 0000000..119ab03
--- /dev/null
+++ b/cypress/support/commands.js
@@ -0,0 +1,25 @@
+// ***********************************************
+// This example commands.js shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+//
+//
+// -- This is a parent command --
+// Cypress.Commands.add('login', (email, password) => { ... })
+//
+//
+// -- This is a child command --
+// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
+//
+//
+// -- This will overwrite an existing command --
+// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
diff --git a/cypress/support/index.js b/cypress/support/index.js
new file mode 100644
index 0000000..d68db96
--- /dev/null
+++ b/cypress/support/index.js
@@ -0,0 +1,20 @@
+// ***********************************************************
+// This example support/index.js is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands'
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
diff --git a/docker-compose.yml b/docker-compose.yml
index c830f3c..7d7b538 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,13 +1,11 @@
-# this allows to test plugin very quickly
-# run `./build-panel.sh` first
-# then run `docker-compose up`
----
version: "3.9"
services:
grafana:
image: grafana/grafana:8.1.1
volumes:
- ./dist:/var/lib/grafana/plugins/pyroscope-panel
+ - ./grafana.ini:/etc/grafana/grafana.ini
+ - ./grafana-provisioning:/etc/grafana/provisioning
environment:
- GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=pyroscope-panel
- GF_INSTALL_PLUGINS=pyroscope-datasource
diff --git a/grafana-provisioning/dashboards/dashboard.json b/grafana-provisioning/dashboards/dashboard.json
new file mode 100644
index 0000000..78220f5
--- /dev/null
+++ b/grafana-provisioning/dashboards/dashboard.json
@@ -0,0 +1,151 @@
+{
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "target": {
+ "limit": 100,
+ "matchAny": false,
+ "tags": [],
+ "type": "dashboard"
+ },
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "links": [],
+ "panels": [
+ {
+ "datasource": "Pyroscope",
+ "gridPos": {
+ "h": 10,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 2,
+ "options": {
+ "seriesCountSize": "sm",
+ "showSeriesCount": false,
+ "text": "Default value of text input option"
+ },
+ "targets": [
+ {
+ "format": "json",
+ "from": "now-1h",
+ "name": "pyroscope.server.cpu",
+ "queryType": "randomWalk",
+ "refId": "A",
+ "until": "now"
+ }
+ ],
+ "title": "Panel Title",
+ "type": "pyroscope-panel"
+ },
+ {
+ "datasource": "Pyroscope",
+ "gridPos": {
+ "h": 8,
+ "w": 7,
+ "x": 0,
+ "y": 10
+ },
+ "id": 3,
+ "options": {
+ "seriesCountSize": "sm",
+ "showSeriesCount": false,
+ "text": "Default value of text input option"
+ },
+ "targets": [
+ {
+ "format": "json",
+ "from": "now-1h",
+ "name": "pyroscope.server.cpu",
+ "queryType": "randomWalk",
+ "refId": "A",
+ "until": "now"
+ }
+ ],
+ "title": "Panel Title",
+ "type": "pyroscope-panel"
+ },
+ {
+ "datasource": "Pyroscope",
+ "gridPos": {
+ "h": 8,
+ "w": 11,
+ "x": 7,
+ "y": 10
+ },
+ "id": 4,
+ "options": {
+ "seriesCountSize": "sm",
+ "showSeriesCount": false,
+ "text": "Default value of text input option"
+ },
+ "targets": [
+ {
+ "format": "json",
+ "from": "now-1h",
+ "name": "pyroscope.server.cpu",
+ "queryType": "randomWalk",
+ "refId": "A",
+ "until": "now"
+ }
+ ],
+ "title": "Panel Title",
+ "type": "pyroscope-panel"
+ },
+ {
+ "datasource": "Pyroscope",
+ "gridPos": {
+ "h": 8,
+ "w": 6,
+ "x": 18,
+ "y": 10
+ },
+ "id": 5,
+ "options": {
+ "seriesCountSize": "sm",
+ "showSeriesCount": false,
+ "text": "Default value of text input option"
+ },
+ "targets": [
+ {
+ "format": "json",
+ "from": "now-1h",
+ "name": "pyroscope.server.cpu",
+ "queryType": "randomWalk",
+ "refId": "A",
+ "until": "now"
+ }
+ ],
+ "title": "Panel Title",
+ "type": "pyroscope-panel"
+ }
+ ],
+ "refresh": "",
+ "schemaVersion": 30,
+ "style": "dark",
+ "tags": [],
+ "templating": {
+ "list": []
+ },
+ "time": {
+ "from": "now-5m",
+ "to": "now"
+ },
+ "timepicker": {},
+ "timezone": "",
+ "title": "Pyroscope demo",
+ "uid": "ZNBMoutnz",
+ "version": 3
+}
diff --git a/grafana-provisioning/dashboards/main.yml b/grafana-provisioning/dashboards/main.yml
new file mode 100644
index 0000000..736aa1f
--- /dev/null
+++ b/grafana-provisioning/dashboards/main.yml
@@ -0,0 +1,8 @@
+apiVersion: 1
+
+providers:
+ - name: dashboards
+ type: file
+ updateIntervalSeconds: 5
+ options:
+ path: /etc/grafana/provisioning/dashboards
diff --git a/grafana-provisioning/dashboards/single-panel.json b/grafana-provisioning/dashboards/single-panel.json
new file mode 100644
index 0000000..cf42437
--- /dev/null
+++ b/grafana-provisioning/dashboards/single-panel.json
@@ -0,0 +1,67 @@
+{
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "target": {
+ "limit": 100,
+ "matchAny": false,
+ "tags": [],
+ "type": "dashboard"
+ },
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "links": [],
+ "panels": [
+ {
+ "datasource": "Pyroscope",
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 0
+ },
+ "id": 2,
+ "options": {
+ "showToolbar": false
+ },
+ "targets": [
+ {
+ "format": "json",
+ "from": "now-1h",
+ "name": "pyroscope.server.cpu",
+ "queryType": "randomWalk",
+ "refId": "A",
+ "until": "now"
+ }
+ ],
+ "title": "Panel Title",
+ "type": "pyroscope-panel"
+ }
+ ],
+ "schemaVersion": 30,
+ "style": "dark",
+ "tags": [],
+ "templating": {
+ "list": []
+ },
+ "time": {
+ "from": "now-5m",
+ "to": "now"
+ },
+ "timepicker": {},
+ "timezone": "",
+ "title": "Single Panel Dashboard",
+ "uid": "single-panel",
+ "version": 3
+}
diff --git a/grafana-provisioning/datasources/datasources.yml b/grafana-provisioning/datasources/datasources.yml
new file mode 100644
index 0000000..984bbd0
--- /dev/null
+++ b/grafana-provisioning/datasources/datasources.yml
@@ -0,0 +1,11 @@
+---
+apiVersion: 1
+
+datasources:
+ - name: Pyroscope
+ type: pyroscope-datasource
+ access: proxy
+ orgId: 1
+ uid: pyroscope
+ jsonData:
+ path: http://pyroscope:4040
diff --git a/grafana.ini b/grafana.ini
new file mode 100644
index 0000000..9939cbb
--- /dev/null
+++ b/grafana.ini
@@ -0,0 +1,976 @@
+##################### Grafana Configuration Example #####################
+#
+# Everything has defaults so you only need to uncomment things you want to
+# change
+
+# possible values : production, development
+;app_mode = production
+
+# instance name, defaults to HOSTNAME environment variable value or hostname if HOSTNAME var is empty
+;instance_name = ${HOSTNAME}
+
+#################################### Paths ####################################
+[paths]
+# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used)
+;data = /var/lib/grafana
+
+# Temporary files in `data` directory older than given duration will be removed
+;temp_data_lifetime = 24h
+
+# Directory where grafana can store logs
+;logs = /var/log/grafana
+
+# Directory where grafana will automatically scan and look for plugins
+;plugins = /var/lib/grafana/plugins
+
+# folder that contains provisioning config files that grafana will apply on startup and while running.
+provisioning = /etc/grafana/provisioning
+
+#################################### Server ####################################
+[server]
+# Protocol (http, https, h2, socket)
+;protocol = http
+
+# The ip address to bind to, empty will bind to all interfaces
+;http_addr =
+
+# The http port to use
+;http_port = 3000
+
+# The public facing domain name used to access grafana from a browser
+;domain = localhost
+
+# Redirect to correct domain if host header does not match domain
+# Prevents DNS rebinding attacks
+;enforce_domain = false
+
+# The full public facing url you use in browser, used for redirects and emails
+# If you use reverse proxy and sub path specify full url (with sub path)
+;root_url = %(protocol)s://%(domain)s:%(http_port)s/
+
+# Serve Grafana from subpath specified in `root_url` setting. By default it is set to `false` for compatibility reasons.
+;serve_from_sub_path = false
+
+# Log web requests
+;router_logging = false
+
+# the path relative working path
+;static_root_path = public
+
+# enable gzip
+;enable_gzip = false
+
+# https certs & key file
+;cert_file =
+;cert_key =
+
+# Unix socket path
+;socket =
+
+# CDN Url
+;cdn_url =
+
+# Sets the maximum time using a duration format (5s/5m/5ms) before timing out read of an incoming request and closing idle connections.
+# `0` means there is no timeout for reading the request.
+;read_timeout = 0
+
+#################################### Database ####################################
+[database]
+# You can configure the database connection by specifying type, host, name, user and password
+# as separate properties or as on string using the url properties.
+
+# Either "mysql", "postgres" or "sqlite3", it's your choice
+;type = sqlite3
+;host = 127.0.0.1:3306
+;name = grafana
+;user = root
+# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;"""
+;password =
+
+# Use either URL or the previous fields to configure the database
+# Example: mysql://user:secret@host:port/database
+;url =
+
+# For "postgres" only, either "disable", "require" or "verify-full"
+;ssl_mode = disable
+
+# Database drivers may support different transaction isolation levels.
+# Currently, only "mysql" driver supports isolation levels.
+# If the value is empty - driver's default isolation level is applied.
+# For "mysql" use "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ" or "SERIALIZABLE".
+;isolation_level =
+
+;ca_cert_path =
+;client_key_path =
+;client_cert_path =
+;server_cert_name =
+
+# For "sqlite3" only, path relative to data_path setting
+;path = grafana.db
+
+# Max idle conn setting default is 2
+;max_idle_conn = 2
+
+# Max conn setting default is 0 (mean not set)
+;max_open_conn =
+
+# Connection Max Lifetime default is 14400 (means 14400 seconds or 4 hours)
+;conn_max_lifetime = 14400
+
+# Set to true to log the sql calls and execution times.
+;log_queries =
+
+# For "sqlite3" only. cache mode setting used for connecting to the database. (private, shared)
+;cache_mode = private
+
+################################### Data sources #########################
+[datasources]
+# Upper limit of data sources that Grafana will return. This limit is a temporary configuration and it will be deprecated when pagination will be introduced on the list data sources API.
+;datasource_limit = 5000
+
+#################################### Cache server #############################
+[remote_cache]
+# Either "redis", "memcached" or "database" default is "database"
+;type = database
+
+# cache connectionstring options
+# database: will use Grafana primary database.
+# redis: config like redis server e.g. `addr=127.0.0.1:6379,pool_size=100,db=0,ssl=false`. Only addr is required. ssl may be 'true', 'false', or 'insecure'.
+# memcache: 127.0.0.1:11211
+;connstr =
+
+#################################### Data proxy ###########################
+[dataproxy]
+
+# This enables data proxy logging, default is false
+;logging = false
+
+# How long the data proxy waits to read the headers of the response before timing out, default is 30 seconds.
+# This setting also applies to core backend HTTP data sources where query requests use an HTTP client with timeout set.
+;timeout = 30
+
+# How long the data proxy waits to establish a TCP connection before timing out, default is 10 seconds.
+;dialTimeout = 10
+
+# How many seconds the data proxy waits before sending a keepalive probe request.
+;keep_alive_seconds = 30
+
+# How many seconds the data proxy waits for a successful TLS Handshake before timing out.
+;tls_handshake_timeout_seconds = 10
+
+# How many seconds the data proxy will wait for a server's first response headers after
+# fully writing the request headers if the request has an "Expect: 100-continue"
+# header. A value of 0 will result in the body being sent immediately, without
+# waiting for the server to approve.
+;expect_continue_timeout_seconds = 1
+
+# The maximum number of idle connections that Grafana will keep alive.
+;max_idle_connections = 100
+
+# The maximum number of idle connections per host that Grafana will keep alive.
+;max_idle_connections_per_host = 2
+
+# How many seconds the data proxy keeps an idle connection open before timing out.
+;idle_conn_timeout_seconds = 90
+
+# If enabled and user is not anonymous, data proxy will add X-Grafana-User header with username into the request, default is false.
+;send_user_header = false
+
+#################################### Analytics ####################################
+[analytics]
+# Server reporting, sends usage counters to stats.grafana.org every 24 hours.
+# No ip addresses are being tracked, only simple counters to track
+# running instances, dashboard and error counts. It is very helpful to us.
+# Change this option to false to disable reporting.
+;reporting_enabled = true
+
+# The name of the distributor of the Grafana instance. Ex hosted-grafana, grafana-labs
+;reporting_distributor = grafana-labs
+
+# Set to false to disable all checks to https://grafana.net
+# for new versions (grafana itself and plugins), check is used
+# in some UI views to notify that grafana or plugin update exists
+# This option does not cause any auto updates, nor send any information
+# only a GET request to http://grafana.com to get latest versions
+;check_for_updates = true
+
+# Google Analytics universal tracking code, only enabled if you specify an id here
+;google_analytics_ua_id =
+
+# Google Tag Manager ID, only enabled if you specify an id here
+;google_tag_manager_id =
+
+#################################### Security ####################################
+[security]
+# disable creation of admin user on first start of grafana
+;disable_initial_admin_creation = false
+
+# default admin user, created on startup
+;admin_user = admin
+
+# default admin password, can be changed before first start of grafana, or in profile settings
+;admin_password = admin
+
+# used for signing
+;secret_key = SW2YcwTIb9zpOOhoPsMm
+
+# disable gravatar profile images
+;disable_gravatar = false
+
+# data source proxy whitelist (ip_or_domain:port separated by spaces)
+;data_source_proxy_whitelist =
+
+# disable protection against brute force login attempts
+;disable_brute_force_login_protection = false
+
+# set to true if you host Grafana behind HTTPS. default is false.
+;cookie_secure = false
+
+# set cookie SameSite attribute. defaults to `lax`. can be set to "lax", "strict", "none" and "disabled"
+;cookie_samesite = lax
+
+# set to true if you want to allow browsers to render Grafana in a ,