diff --git a/docs/internal/contributing/README.md b/docs/internal/contributing/README.md index 833522748c..44b84262cd 100644 --- a/docs/internal/contributing/README.md +++ b/docs/internal/contributing/README.md @@ -35,18 +35,26 @@ Use `make lint` to ensure formatting is correct. ## Building Grafana Pyroscope -To build: +These are steps for building Pyroscope in single binary mode. See [development.md](./development.md) for more advanced methods building and running Pyroscope locally for development. + +### Building a binary + +To build a binary, run: ``` make go/bin ``` +### Building tests + To run the unit test suite: ``` make go/test ``` +### Building a docker image + To build the docker image use: ``` @@ -76,62 +84,34 @@ brew install pkg-config cairo pango libpng jpeg giflib librsvg See https://github.com/Automattic/node-canvas/issues/1662 -#### Running examples locally -replace `image: grafana/pyroscope` with the local tag name you got from docker-image/pyroscope/build (i.e): +## Running Grafana Pyroscope locally -``` - pyroscope: - image: us.gcr.io/kubernetes-dev/pyroscope:main-470125e1-WIP - ports: - - '4040:4040' -``` - -#### Run with Pyroscope with embedded Grafana + Explore Profiles +### Running examples -In order to quickly test the whole stack it is possible to run an embedded Grafana by using target parameter: +First, find the example you want to run and move to that directory. For example: ``` -go run ./cmd/pyroscope --target all,embedded-grafana +cd examples/language-sdk-instrumentation/golang-push/rideshare ``` -This will start additional to Pyroscope on `:4040`, the embedded Grafana on port `:4041`. +Then in the `docker-compose.yml` file, replace the image for the `pyroscope` service with the image built in the [Building a docker image](###building-a-docker-image) section. -#### Front end development - -**Versions for development tools**: -- Node v18 -- Yarn v1.22 - -The front end code is all located in the `public/app` directory, although its `plugin.json` -file exists at the repository root. - -To run the local front end source code: -```sh -yarn -yarn dev +```yaml +pyroscope: + image: us.gcr.io/kubernetes-dev/pyroscope:main-470125e1-WIP ``` -This will install / update front end dependencies and launch a process that will build -the front end code, launch a pyroscope web app service at `http://localhost:4041`, -and keep that web app updated any time you save the front end source code. -The resulting web app will not initially be connected to a pyroscope server, -so all attempts to fetch data will fail. +### Run with embedded Grafana + Explore Profiles -To launch a pyroscope server for development purposes: -```sh -yarn backend:dev -``` +In order to quickly test the whole stack it is possible to run an embedded Grafana by using target parameter: -This yarn script actually runs the following: -```sh -make build run 'PARAMS=--config.file ./cmd/pyroscope/pyroscope.yaml' +``` +go run ./cmd/pyroscope --target all,embedded-grafana ``` -It will take a while for this process to build and start serving pyroscope data, but -once it is fully active, the pyroscope web app service at `http://localhost:4041` -will be able to interact with it. +In addition to starting Pyroscope on `:4040`, this starts an embedded Grafana on port `:4041`. -### Dependency management +## Dependency management We use [Go modules](https://golang.org/cmd/go/#hdr-Modules__module_versions__and_more) to manage dependencies on external packages. However, we don't commit the `vendor/` folder. @@ -154,6 +134,7 @@ make go/mod Commit the changes to `go.mod` and `go.sum` before submitting your pull request. + ## Documentation The Grafana Pyroscope documentation is compiled into a website published at [grafana.com](https://grafana.com/). diff --git a/docs/internal/contributing/development.md b/docs/internal/contributing/development.md new file mode 100644 index 0000000000..8c419c9144 --- /dev/null +++ b/docs/internal/contributing/development.md @@ -0,0 +1,116 @@ +# Developing Grafana Pyroscope + +This document contains helpful tips and tricks when developing Pyroscope. + +## Run Pyroscope using a debugger + +A debugger allows you to step through the code and inspect variables and understand control flow as the program is running. + +### VSCode debugger + +To attach a debugger to Pyroscope from VSCode, perform the following steps in the root of the Pyroscope project: + +1. `mkdir .vscode` +1. `touch .vscode/tasks.json` +1. Add the following configuration. This creates a build task in VSCode which will build the Pyroscope binary with debug symbols. + ```jsonc + { + "version": "2.0.0", + "tasks": [ + { + "type": "shell", + // Name this whatever you like. + "label": "pyroscope: build debug", + "command": "make", + "args": [ + "EMBEDASSETS=\"\"", + "go/bin-pyroscope-debug" + ], + "group": "build", + "detail": "Build debug Pyroscope server" + } + ] + } + ``` +1. `touch .vscode/launch.json` +1. Add the following configuration. This will add a launch task which will launch the debug Pyroscope binary and attach a debugger. + ```jsonc + { + "version": "0.2.0", + "configurations": [ + { + // Name this whatever you like. + "name": "Launch debug Pyroscope server", + "type": "go", + "request": "launch", + "mode": "exec", + "program": "./pyroscope", + "args": [ + "-config.file", + // Point this to a Pyroscope configuration file. + "./.vscode/config.yaml", + ], + "env": { + // env vars go here. For example: + // "GITHUB_CLIENT_ID": "my_client_id" + }, + // This must match the name of the build task. + "preLaunchTask": "pyroscope: build debug", + } + ] + } + ``` +1. `touch .vscode/config.yaml` +1. Add the following configuration. These are the settings your Pyroscope instance will use. + ```yaml + server: + http_listen_port: 4040 + + # Not necessary, but this can help avoid some system limits when making + # certain queries. + limits: + max_query_length: 0 + max_query_lookback: 0 + ``` +1. You should be able to open the "Run and Debug" menu and select "Launch debug Pyroscope server" from the drop down. + +1. Now when you set breakpoints in the gutter, the debugger will break appropriately and logs will be emitted in the "DEBUG CONSOLE" terminal tab. + + +## Run a local Pyroscope frontend + +Pyroscope ships with an embedded UI. This is UI is stable and largely in maintenance mode. If you find a need to develop the UI, follow these steps to run it without embedding it into the Pyroscope binary. + +You will need these tools: + +- Node v18 +- Yarn v1.22 + +The frontend code is all located in the `public/app` directory, although its `plugin.json` +file exists at the repository root. + +To run the local frontend source code: +```sh +yarn +yarn dev +``` + +This will install/update the frontend dependencies and launch a process that will build the frontend code, launch a pyroscope web app service at `http://localhost:4041`, and keep that web app updated any time you save the frontend source code. The resulting web app will not initially be connected to a Pyroscope server, +so all attempts to fetch data will fail. + +To launch a Pyroscope server for development purposes: +```sh +yarn backend:dev +``` + +This yarn script actually runs the following: +```sh +make build run 'PARAMS=--config.file ./cmd/pyroscope/pyroscope.yaml' +``` + +> ![NOTE] +> Alternatively, you can connect to any Pyroscope instance as long as it is running on `:4040`. If you need to connect to a Pyroscope instance running on a different port, please modify the [webpack config](https://github.com/grafana/pyroscope/blob/main/scripts/webpack/webpack.dev.js#L14-L15) accordingly. + +It will take a while for this process to build and start serving pyroscope data, but +once it is fully active, the pyroscope web app service at `http://localhost:4041` +will be able to interact with it. diff --git a/docs/internal/images/pyroscope-debugger-running.png b/docs/internal/images/pyroscope-debugger-running.png new file mode 100644 index 0000000000..249e303f44 Binary files /dev/null and b/docs/internal/images/pyroscope-debugger-running.png differ diff --git a/docs/internal/images/pyroscope-launch-debugger.png b/docs/internal/images/pyroscope-launch-debugger.png new file mode 100644 index 0000000000..40f74f9d3b Binary files /dev/null and b/docs/internal/images/pyroscope-launch-debugger.png differ diff --git a/examples/README.md b/examples/README.md index defd7b08d2..6234fb2421 100644 --- a/examples/README.md +++ b/examples/README.md @@ -3,6 +3,7 @@ Choose a language folder to select an example for your language of choice. # How Pyroscope works + Pyroscope identifies performance issues in your application by continuously profiling the code. If you've never used a profiler before, then welcome! diff --git a/examples/language-sdk-instrumentation/load.js b/examples/language-sdk-instrumentation/load.js new file mode 100644 index 0000000000..ee11f8a28b --- /dev/null +++ b/examples/language-sdk-instrumentation/load.js @@ -0,0 +1,18 @@ +import { check } from 'k6'; +import http from 'k6/http'; + +export const options = { + duration: '5m', + vus: 3, +}; + +const URL = __ENV.TARGET_URL || 'http://localhost:5000'; + +export default function() { + for (const endpoint of ['car', 'scooter', 'bike']) { + const res = http.get(`${URL}/${endpoint}`); + check(res, { + 'status is 200': (r) => r.status === 200, + }); + } +} diff --git a/examples/language-sdk-instrumentation/nodejs/express-pull/.gitignore b/examples/language-sdk-instrumentation/nodejs/express-pull/.gitignore new file mode 100644 index 0000000000..febbb5c964 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-pull/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/build diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/.gitignore b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/.gitignore new file mode 100644 index 0000000000..febbb5c964 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/build diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/Dockerfile b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/Dockerfile index b8694b5bd1..82d665fef6 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/Dockerfile +++ b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/Dockerfile @@ -3,10 +3,11 @@ FROM node:latest WORKDIR /app COPY package.json yarn.lock . +RUN yarn + COPY tsconfig.json . -RUN yarn COPY *.ts . RUN yarn build -ENV DEBUG=pyroscope -CMD ["yarn", "run", "run"] +ENV DEBUG=pyroscope +CMD ["yarn", "start"] diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/index.ts b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/index.ts index d85af51fb2..88a5d0375b 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/index.ts +++ b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/index.ts @@ -6,17 +6,18 @@ const Pyroscope = require('@pyroscope/nodejs'); const SourceMapper = Pyroscope.default.SourceMapper; const port = process.env['PORT'] || 5000; - const region = process.env['REGION'] || 'default'; +const appName = process.env['APP_NAME'] || 'express-ts-inline'; +const pyroscopeUrl = process.env['PYROSCOPE_URL'] || 'http://pyroscope:4040'; const app = express(); app.use(morgan('dev')); -app.get('/', (req, res) => { +app.get('/', (_, res) => { res.send('Available routes are: /bike, /car, /scooter'); }); -const genericSearchHandler = (p: number) => (req: any, res: any) => { +const genericSearchHandler = (p: number) => (_: any, res: any) => { const time = +new Date() + p * 1000; let i = 0; while (+new Date() < time) { @@ -30,11 +31,13 @@ app.get('/bike', function bikeSearchHandler(req, res) { genericSearchHandler(0.2)(req, res) ); }); + app.get('/car', function carSearchHandler(req, res) { Pyroscope.wrapWithLabels({ vehicle: 'car' }, () => genericSearchHandler(1)(req, res) ); }); + app.get('/scooter', function scooterSearchHandler(req, res) { Pyroscope.wrapWithLabels({ vehicle: 'scooter' }, () => genericSearchHandler(0.5)(req, res) @@ -44,14 +47,14 @@ app.get('/scooter', function scooterSearchHandler(req, res) { SourceMapper.create(['.']) .then((sourceMapper) => { Pyroscope.init({ - appName: 'nodejs', - serverAddress: 'http://pyroscope:4040', + appName: appName, + serverAddress: pyroscopeUrl, sourceMapper: sourceMapper, tags: { region }, }); Pyroscope.start(); }) - .catch((e) => { + .catch((e: any) => { console.error(e); }); diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/package.json b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/package.json index 2c7a384eb3..034596f050 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/package.json +++ b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/package.json @@ -5,7 +5,10 @@ "scripts": { "build": "tsc", "test": "echo \"Error: no test specified\" && exit 1", - "run": "node build/index.js" + "start": "node build/index.js", + "start:local": "yarn build && PYROSCOPE_URL=http://localhost:4040 yarn start", + "up": "yarn down && docker compose up --build --force-recreate --no-deps", + "down": "docker compose down" }, "author": "", "license": "Apache-2.0", diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts/.gitignore b/examples/language-sdk-instrumentation/nodejs/express-ts/.gitignore new file mode 100644 index 0000000000..febbb5c964 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-ts/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/build diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts/Dockerfile b/examples/language-sdk-instrumentation/nodejs/express-ts/Dockerfile index b8694b5bd1..82d665fef6 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts/Dockerfile +++ b/examples/language-sdk-instrumentation/nodejs/express-ts/Dockerfile @@ -3,10 +3,11 @@ FROM node:latest WORKDIR /app COPY package.json yarn.lock . +RUN yarn + COPY tsconfig.json . -RUN yarn COPY *.ts . RUN yarn build -ENV DEBUG=pyroscope -CMD ["yarn", "run", "run"] +ENV DEBUG=pyroscope +CMD ["yarn", "start"] diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts/index.ts b/examples/language-sdk-instrumentation/nodejs/express-ts/index.ts index 0ac251d9d6..7619b58f50 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts/index.ts +++ b/examples/language-sdk-instrumentation/nodejs/express-ts/index.ts @@ -6,17 +6,18 @@ import Pyroscope from '@pyroscope/nodejs'; const SourceMapper = Pyroscope.SourceMapper; const port = process.env['PORT'] || 5000; - const region = process.env['REGION'] || 'default'; +const appName = process.env['APP_NAME'] || 'express-ts'; +const pyroscopeUrl = process.env['PYROSCOPE_URL'] || 'http://pyroscope:4040'; const app = express(); app.use(morgan('dev')); -app.get('/', (req, res) => { +app.get('/', (_, res) => { res.send('Available routes are: /bike, /car, /scooter'); }); -const genericSearchHandler = (p: number) => (req: any, res: any) => { +const genericSearchHandler = (p: number) => (_: any, res: any) => { const time = +new Date() + p * 1000; let i = 0; while (+new Date() < time) { @@ -30,11 +31,13 @@ app.get('/bike', function bikeSearchHandler(req, res) { genericSearchHandler(0.2)(req, res) ); }); + app.get('/car', function carSearchHandler(req, res) { Pyroscope.wrapWithLabels({ vehicle: 'car' }, () => genericSearchHandler(1)(req, res) ); }); + app.get('/scooter', function scooterSearchHandler(req, res) { Pyroscope.wrapWithLabels({ vehicle: 'scooter' }, () => genericSearchHandler(0.5)(req, res) @@ -44,8 +47,8 @@ app.get('/scooter', function scooterSearchHandler(req, res) { SourceMapper.create(['.']) .then((sourceMapper) => { Pyroscope.init({ - appName: 'nodejs', - serverAddress: 'http://pyroscope:4040', + appName: appName, + serverAddress: pyroscopeUrl, sourceMapper: sourceMapper, tags: { region }, }); diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts/package.json b/examples/language-sdk-instrumentation/nodejs/express-ts/package.json index 2c7a384eb3..034596f050 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts/package.json +++ b/examples/language-sdk-instrumentation/nodejs/express-ts/package.json @@ -5,7 +5,10 @@ "scripts": { "build": "tsc", "test": "echo \"Error: no test specified\" && exit 1", - "run": "node build/index.js" + "start": "node build/index.js", + "start:local": "yarn build && PYROSCOPE_URL=http://localhost:4040 yarn start", + "up": "yarn down && docker compose up --build --force-recreate --no-deps", + "down": "docker compose down" }, "author": "", "license": "Apache-2.0", diff --git a/examples/language-sdk-instrumentation/nodejs/express/.gitignore b/examples/language-sdk-instrumentation/nodejs/express/.gitignore new file mode 100644 index 0000000000..febbb5c964 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/build diff --git a/examples/language-sdk-instrumentation/nodejs/express/Dockerfile b/examples/language-sdk-instrumentation/nodejs/express/Dockerfile index 708be4d4c9..28c6c1ab9a 100644 --- a/examples/language-sdk-instrumentation/nodejs/express/Dockerfile +++ b/examples/language-sdk-instrumentation/nodejs/express/Dockerfile @@ -8,4 +8,4 @@ COPY index.js . ENV DEBUG=pyroscope ENV PYROSCOPE_WALL_COLLECT_CPU_TIME=true -CMD ["node", "index.js"] +CMD ["node", "index.js"] diff --git a/examples/language-sdk-instrumentation/nodejs/express/index.js b/examples/language-sdk-instrumentation/nodejs/express/index.js index ac29ee3df3..16fa648969 100644 --- a/examples/language-sdk-instrumentation/nodejs/express/index.js +++ b/examples/language-sdk-instrumentation/nodejs/express/index.js @@ -2,19 +2,20 @@ const Pyroscope = require('@pyroscope/nodejs'); const port = process.env['PORT'] || 5000; - const region = process.env['REGION'] || 'default'; +const appName = process.env['APP_NAME'] || 'express'; +const pyroscopeUrl = process.env['PYROSCOPE_URL'] || 'http://pyroscope:4040'; const express = require('express'); const morgan = require('morgan'); const app = express(); app.use(morgan('dev')); -app.get('/', (req, res) => { +app.get('/', (_, res) => { res.send('Available routes are: /bike, /car, /scooter'); }); -const genericSearchHandler = (p) => (req, res) => { +const genericSearchHandler = (p) => (_, res) => { const time = +new Date() + p * 1000; let i = 0; while (+new Date() < time) { @@ -24,11 +25,10 @@ const genericSearchHandler = (p) => (req, res) => { }; Pyroscope.init({ - appName: 'nodejs', - serverAddress: process.env['PYROSCOPE_SERVER'] || 'http://pyroscope:4040', + appName: appName, + serverAddress: pyroscopeUrl, tags: { region }, }); - Pyroscope.start(); app.get('/bike', function bikeSearchHandler(req, res) { @@ -36,11 +36,13 @@ app.get('/bike', function bikeSearchHandler(req, res) { genericSearchHandler(0.5)(req, res) ); }); + app.get('/car', function carSearchHandler(req, res) { Pyroscope.wrapWithLabels({ vehicle: 'car' }, () => genericSearchHandler(1)(req, res) ); }); + app.get('/scooter', function scooterSearchHandler(req, res) { Pyroscope.wrapWithLabels({ vehicle: 'scooter' }, () => genericSearchHandler(0.25)(req, res) diff --git a/examples/language-sdk-instrumentation/nodejs/express/package.json b/examples/language-sdk-instrumentation/nodejs/express/package.json index d97ad3668a..a391a0e12a 100644 --- a/examples/language-sdk-instrumentation/nodejs/express/package.json +++ b/examples/language-sdk-instrumentation/nodejs/express/package.json @@ -5,12 +5,15 @@ "main": "index.js", "scripts": { "start": "node index.js", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "start:local": "PYROSCOPE_URL=http://localhost:4040 yarn start", + "up": "yarn down && docker compose up --build --force-recreate --no-deps", + "down": "docker compose down" }, "author": "", "license": "Apache-2.0", "dependencies": { - "@pyroscope/nodejs": "v0.3.11", + "@pyroscope/nodejs": "v0.4.0", "express": "^4.19.2", "morgan": "^1.10.0" }, diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/.gitignore b/examples/language-sdk-instrumentation/nodejs/tinyhttp/.gitignore new file mode 100644 index 0000000000..febbb5c964 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/build diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/Dockerfile b/examples/language-sdk-instrumentation/nodejs/tinyhttp/Dockerfile new file mode 100644 index 0000000000..85b325a90f --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/Dockerfile @@ -0,0 +1,10 @@ +FROM node:latest + +WORKDIR /app + +COPY package.json yarn.lock . +RUN yarn install + +COPY index.js . + +CMD ["node", "index.js"] diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/docker-compose.yml b/examples/language-sdk-instrumentation/nodejs/tinyhttp/docker-compose.yml new file mode 100644 index 0000000000..a6d3fd6c60 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/docker-compose.yml @@ -0,0 +1,46 @@ +version: '3.9' +services: + pyroscope: + image: grafana/pyroscope + ports: + - 4040:4040 + us-east: + ports: + - 5000 + environment: + - REGION=us-east + build: + context: . + eu-north: + ports: + - 5000 + environment: + - REGION=eu-north + build: + context: . + ap-south: + ports: + - 5000 + environment: + - REGION=ap-south + build: + context: . + load-generator: + build: + context: ../ + dockerfile: Dockerfile.load-generator + depends_on: + - us-east + - eu-north + - ap-south + grafana: + image: grafana/grafana:latest + environment: + - GF_INSTALL_PLUGINS=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/nodejs/tinyhttp/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..6f04d797c8 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,14 @@ +--- +apiVersion: 1 +datasources: + - uid: local-pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [GitSession] + # Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/grafana-provisioning/plugins/explore-profiles.yml b/examples/language-sdk-instrumentation/nodejs/tinyhttp/grafana-provisioning/plugins/explore-profiles.yml new file mode 100644 index 0000000000..0d1302202e --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/grafana-provisioning/plugins/explore-profiles.yml @@ -0,0 +1,11 @@ +--- +apiVersion: 1 +apps: + - type: grafana-pyroscope-app + jsonData: + backendUrl: http://pyroscope:4040 + # uncomment this if sending data to Grafana Cloud + # basicAuthUser: '123456' + secureJsonData: + # uncomment this if sending data to Grafana Cloud + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/index.js b/examples/language-sdk-instrumentation/nodejs/tinyhttp/index.js new file mode 100644 index 0000000000..0847e03126 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/index.js @@ -0,0 +1,45 @@ +import { init, start } from '@pyroscope/nodejs'; +import { App } from '@tinyhttp/app'; +import { logger } from '@tinyhttp/logger'; + +const port = process.env['PORT'] || 5000; +const region = process.env['REGION'] || 'default'; +const appName = process.env['APP_NAME'] || 'tinyhttp'; +const pyroscopeUrl = process.env['PYROSCOPE_URL'] || 'http://pyroscope:4040'; + +init({ + appName: appName, + serverAddress: pyroscopeUrl, + tags: { region }, +}); +start(); + +const app = new App(); +app.use(logger()); + +app.get('/', (_, res) => { + res.send('Available routes are: /bike, /car, /scooter'); +}) + +const genericSearchHandler = (p) => (_, res) => { + const time = +new Date() + p * 1000; + let i = 0; + while (+new Date() < time) { + i = i + Math.random(); + } + res.send('Vehicle found'); +}; + +app.get('/bike', (req, res) => { + genericSearchHandler(0.5)(req, res); +}); + +app.get('/car', (req, res) => { + genericSearchHandler(1)(req, res); +}); + +app.get('/scooter', (req, res) => { + genericSearchHandler(0.25)(req, res); +}); + +app.listen(port, () => console.log(`Started on http://localhost:${port}`)); diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/package.json b/examples/language-sdk-instrumentation/nodejs/tinyhttp/package.json new file mode 100644 index 0000000000..1bca2b75cc --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/package.json @@ -0,0 +1,22 @@ +{ + "name": "rideshare-app-express", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "start": "node index.js", + "test": "echo \"Error: no test specified\" && exit 1", + "start:local": "PYROSCOPE_URL=http://localhost:4040 yarn start", + "up": "yarn down && docker compose up --build --force-recreate --no-deps", + "down": "docker compose down" + }, + + "author": "", + "license": "Apache-2.0", + "dependencies": { + "@pyroscope/nodejs": "^0.4.0", + "@tinyhttp/app": "^2.4.0", + "@tinyhttp/logger": "^2.0.0" + } +} diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/yarn.lock b/examples/language-sdk-instrumentation/nodejs/tinyhttp/yarn.lock new file mode 100644 index 0000000000..1a646c821f --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/yarn.lock @@ -0,0 +1,307 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@datadog/pprof@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.3.0.tgz#c2f58d328ecced7f99887f1a559d7fe3aecb9219" + integrity sha512-53z2Q3K92T6Pf4vz4Ezh8kfkVEvLzbnVqacZGgcbkP//q0joFzO8q00Etw1S6NdnCX0XmX08ULaF4rUI5r14mw== + dependencies: + delay "^5.0.0" + node-gyp-build "<4.0" + p-limit "^3.1.0" + pprof-format "^2.1.0" + source-map "^0.7.4" + +"@pyroscope/nodejs@^0.3.11": + version "0.3.11" + resolved "https://registry.yarnpkg.com/@pyroscope/nodejs/-/nodejs-0.3.11.tgz#d3ffed8423b628701d06cdc6ef97fd5943d91939" + integrity sha512-xqxUDrzgdfTic4QU3FyvPvO3iAF63zEEI+gXgBBNA6MrJVOJxaEDJkeOGnH0AT7yG/vLJVmSeo4+VyIKrCmztw== + dependencies: + "@datadog/pprof" "^5.3.0" + axios "^0.28.0" + debug "^4.3.3" + form-data "^4.0.0" + regenerator-runtime "^0.13.11" + source-map "^0.7.3" + +"@tinyhttp/accepts@2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@tinyhttp/accepts/-/accepts-2.2.3.tgz#be7601206eeda8bd8350ad82a2307808efcb7831" + integrity sha512-9pQN6pJAJOU3McmdJWTcyq7LLFW8Lj5q+DadyKcvp+sxMkEpktKX5sbfJgJuOvjk6+1xWl7pe0YL1US1vaO/1w== + dependencies: + mime "4.0.4" + negotiator "^0.6.3" + +"@tinyhttp/app@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tinyhttp/app/-/app-2.4.0.tgz#d91b3f36146d2dc63cf8b1492b94488ecea3cc6d" + integrity sha512-vOPiCemQRJq5twnl06dde6XnWiNbVMdVRFJWW/yC/9G0qgvV2TvzNNTxrdlz6YmyB7vIC7Fg3qS6m6gx8RbBNQ== + dependencies: + "@tinyhttp/cookie" "2.1.1" + "@tinyhttp/proxy-addr" "2.2.0" + "@tinyhttp/req" "2.2.4" + "@tinyhttp/res" "2.2.4" + "@tinyhttp/router" "2.2.3" + header-range-parser "1.1.3" + regexparam "^2.0.2" + +"@tinyhttp/content-disposition@2.2.2": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@tinyhttp/content-disposition/-/content-disposition-2.2.2.tgz#1207d18bdd59e1cd38ecf2493ee187f4f592ebe7" + integrity sha512-crXw1txzrS36huQOyQGYFvhTeLeG0Si1xu+/l6kXUVYpE0TjFjEZRqTbuadQLfKGZ0jaI+jJoRyqaWwxOSHW2g== + +"@tinyhttp/content-type@^0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@tinyhttp/content-type/-/content-type-0.1.4.tgz#112bce3b564213e0ed43fa76fccca4237be3a634" + integrity sha512-dl6f3SHIJPYbhsW1oXdrqOmLSQF/Ctlv3JnNfXAE22kIP7FosqJHxkz/qj2gv465prG8ODKH5KEyhBkvwrueKQ== + +"@tinyhttp/cookie-signature@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/cookie-signature/-/cookie-signature-2.1.1.tgz#ae2caad6aec4ec51d42e7d852ae34a04196d5138" + integrity sha512-VDsSMY5OJfQJIAtUgeQYhqMPSZptehFSfvEEtxr+4nldPA8IImlp3QVcOVuK985g4AFR4Hl1sCbWCXoqBnVWnw== + +"@tinyhttp/cookie@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/cookie/-/cookie-2.1.1.tgz#50ad664f732357a466a14cdc888e88e80dc3440e" + integrity sha512-h/kL9jY0e0Dvad+/QU3efKZww0aTvZJslaHj3JTPmIPC9Oan9+kYqmh3M6L5JUQRuTJYFK2nzgL2iJtH2S+6dA== + +"@tinyhttp/encode-url@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/encode-url/-/encode-url-2.1.1.tgz#a52bdbd75f541455190d1a16b0a81374c8dc587d" + integrity sha512-AhY+JqdZ56qV77tzrBm0qThXORbsVjs/IOPgGCS7x/wWnsa/Bx30zDUU/jPAUcSzNOzt860x9fhdGpzdqbUeUw== + +"@tinyhttp/etag@2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@tinyhttp/etag/-/etag-2.1.2.tgz#34fc91933bd1acce3cda3a64e5352ce5514abe4e" + integrity sha512-j80fPKimGqdmMh6962y+BtQsnYPVCzZfJw0HXjyH70VaJBHLKGF+iYhcKqzI3yef6QBNa8DKIPsbEYpuwApXTw== + +"@tinyhttp/forwarded@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/forwarded/-/forwarded-2.1.1.tgz#dbf2cae75a1737b88b71c2a2d1931e5e9ced73c3" + integrity sha512-nO3kq0R1LRl2+CAMlnggm22zE6sT8gfvGbNvSitV6F9eaUSurHP0A8YZFMihSkugHxK+uIegh1TKrqgD8+lyGQ== + +"@tinyhttp/logger@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tinyhttp/logger/-/logger-2.0.0.tgz#64c0e53497abc82765c17289a05cd75edbd4c04a" + integrity sha512-8DfLQjGDIaIJeivYamVrrpmwmsGwS8wt2DGvzlcY5HEBagdiI4QJy/veAFcUHuaJqufn4wLwmn4q5VUkW8BCpQ== + dependencies: + colorette "^2.0.20" + dayjs "^1.11.10" + http-status-emojis "^2.2.0" + +"@tinyhttp/proxy-addr@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@tinyhttp/proxy-addr/-/proxy-addr-2.2.0.tgz#82487f25af4d320d79e613bbecac17c7ad69c8f2" + integrity sha512-WM/PPL9xNvrs7/8Om5nhKbke5FHrP3EfjOOR+wBnjgESfibqn0K7wdUTnzSLp1lBmemr88os1XvzwymSgaibyA== + dependencies: + "@tinyhttp/forwarded" "2.1.1" + ipaddr.js "^2.2.0" + +"@tinyhttp/req@2.2.4": + version "2.2.4" + resolved "https://registry.yarnpkg.com/@tinyhttp/req/-/req-2.2.4.tgz#c9dfc40e3a3b3cc1eb48bdc137b5d0cd71501057" + integrity sha512-lQAZIAo0NOeghxFOZS57tQzxpHSPPLs9T68Krq2BncEBImKwqaDKUt7M9Y5Kb+rvC/GwIL3LeErhkg7f5iG4IQ== + dependencies: + "@tinyhttp/accepts" "2.2.3" + "@tinyhttp/type-is" "2.2.4" + "@tinyhttp/url" "2.1.1" + header-range-parser "^1.1.3" + +"@tinyhttp/res@2.2.4": + version "2.2.4" + resolved "https://registry.yarnpkg.com/@tinyhttp/res/-/res-2.2.4.tgz#ed79d511f21d6ef226ae907bdecc26f69c93583c" + integrity sha512-ETBRShnO19oJyIg2XQHQoofXPWeTXPAuwnIVYkU8WaftvXd/Vz4y5+WFQDHUzKlmdGOw5fAFnrEU7pIVMeFeVA== + dependencies: + "@tinyhttp/content-disposition" "2.2.2" + "@tinyhttp/cookie" "2.1.1" + "@tinyhttp/cookie-signature" "2.1.1" + "@tinyhttp/encode-url" "2.1.1" + "@tinyhttp/req" "2.2.4" + "@tinyhttp/send" "2.2.3" + "@tinyhttp/vary" "^0.1.3" + es-escape-html "^0.1.1" + mime "4.0.4" + +"@tinyhttp/router@2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@tinyhttp/router/-/router-2.2.3.tgz#a29a33da89ae7365f5897aed20f44663509273a4" + integrity sha512-O0MQqWV3Vpg/uXsMYg19XsIgOhwjyhTYWh51Qng7bxqXixxx2PEvZWnFjP7c84K7kU/nUX41KpkEBTLnznk9/Q== + +"@tinyhttp/send@2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@tinyhttp/send/-/send-2.2.3.tgz#726c400af76c62963bd71fe92e6e6838f35a7996" + integrity sha512-o4cVHHGQ8WjVBS8UT0EE/2WnjoybrfXikHwsRoNlG1pfrC/Sd01u1N4Te8cOd/9aNGLr4mGxWb5qTm2RRtEi7g== + dependencies: + "@tinyhttp/content-type" "^0.1.4" + "@tinyhttp/etag" "2.1.2" + mime "4.0.4" + +"@tinyhttp/type-is@2.2.4": + version "2.2.4" + resolved "https://registry.yarnpkg.com/@tinyhttp/type-is/-/type-is-2.2.4.tgz#8f5a30bb3cdc93dd02f399e152d88b815b0efc99" + integrity sha512-7F328NheridwjIfefBB2j1PEcKKABpADgv7aCJaE8x8EON77ZFrAkI3Rir7pGjopV7V9MBmW88xUQigBEX2rmQ== + dependencies: + "@tinyhttp/content-type" "^0.1.4" + mime "4.0.4" + +"@tinyhttp/url@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/url/-/url-2.1.1.tgz#77fa8963f5b698bacbdc6912407f946d32c793e1" + integrity sha512-POJeq2GQ5jI7Zrdmj22JqOijB5/GeX+LEX7DUdml1hUnGbJOTWDx7zf2b5cCERj7RoXL67zTgyzVblBJC+NJWg== + +"@tinyhttp/vary@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@tinyhttp/vary/-/vary-0.1.3.tgz#f5bea4769f380c43a158832a8daad8e8b186757c" + integrity sha512-SoL83sQXAGiHN1jm2VwLUWQSQeDAAl1ywOm6T0b0Cg1CZhVsjoiZadmjhxF6FHCCY7OHHVaLnTgSMxTPIDLxMg== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^0.28.0: + version "0.28.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.28.1.tgz#2a7bcd34a3837b71ee1a5ca3762214b86b703e70" + integrity sha512-iUcGA5a7p0mVb4Gm/sy+FSECNkPFT4y7wt6OM/CDpO/OnNCvSs3PoMG8ibrC9jRoGYU0gUK5pXVC4NPXq6lHRQ== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +colorette@^2.0.20: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +dayjs@^1.11.10: + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + +debug@^4.3.3: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +delay@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +es-escape-html@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/es-escape-html/-/es-escape-html-0.1.1.tgz#9a582d49754ec6204524952c76a383fe5f03c1c0" + integrity sha512-yUx1o+8RsG7UlszmYPtks+dm6Lho2m8lgHMOsLJQsFI0R8XwUJwiMhM1M4E/S8QLeGyf6MkDV/pWgjQ0tdTSyQ== + +follow-redirects@^1.15.0: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +header-range-parser@1.1.3, header-range-parser@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/header-range-parser/-/header-range-parser-1.1.3.tgz#6414b5b12e3b645d29d85225a58fd207d66d30ef" + integrity sha512-B9zCFt3jH8g09LR1vHL4pcAn8yMEtlSlOUdQemzHMRKMImNIhhszdeosYFfNW0WXKQtXIlWB+O4owHJKvEJYaA== + +http-status-emojis@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/http-status-emojis/-/http-status-emojis-2.2.0.tgz#2cf3316f0c1610c4fc94c6fccdada35aa70f992a" + integrity sha512-ompKtgwpx8ff0hsbpIB7oE4ax1LXoHmftsHHStMELX56ivG3GhofTX8ZHWlUaFKfGjcGjw6G3rPk7dJRXMmbbg== + +ipaddr.js@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" + integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-4.0.4.tgz#9f851b0fc3c289d063b20a7a8055b3014b25664b" + integrity sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ== + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +negotiator@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +node-gyp-build@<4.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.9.0.tgz#53a350187dd4d5276750da21605d1cb681d09e25" + integrity sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A== + +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +pprof-format@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pprof-format/-/pprof-format-2.1.0.tgz#acc8d7773bcf4faf0a3d3df11bceefba7ac06664" + integrity sha512-0+G5bHH0RNr8E5hoZo/zJYsL92MhkZjwrHp3O2IxmY8RJL9ooKeuZ8Tm0ZNBw5sGZ9TiM71sthTjWoR2Vf5/xw== + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + +regexparam@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-2.0.2.tgz#a0f6aa057c67b1c9c09508c45823c0755b1f6e58" + integrity sha512-A1PeDEYMrkLrfyOwv2jwihXbo9qxdGD3atBYQA9JJgreAx8/7rC6IUkWOw2NQlOxLp2wL0ifQbh1HuidDfYA6w== + +source-map@^0.7.3, source-map@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/examples/load.js b/examples/load.js new file mode 100644 index 0000000000..ee11f8a28b --- /dev/null +++ b/examples/load.js @@ -0,0 +1,18 @@ +import { check } from 'k6'; +import http from 'k6/http'; + +export const options = { + duration: '5m', + vus: 3, +}; + +const URL = __ENV.TARGET_URL || 'http://localhost:5000'; + +export default function() { + for (const endpoint of ['car', 'scooter', 'bike']) { + const res = http.get(`${URL}/${endpoint}`); + check(res, { + 'status is 200': (r) => r.status === 200, + }); + } +}