mirror of https://github.com/grafana/grafana
Pyroscope: Add standalone build (#80222)
* Pyroscope standalone build * Fix for tests * Add missing packages * Remove import * Update trace to profiles * Update testpull/81063/head^2
parent
96010eb21e
commit
6796e66fb8
@ -0,0 +1,51 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend" |
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" |
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" |
||||||
|
pyroscope "github.com/grafana/grafana/pkg/tsdb/grafana-pyroscope-datasource" |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
_ backend.QueryDataHandler = (*Datasource)(nil) |
||||||
|
_ backend.CheckHealthHandler = (*Datasource)(nil) |
||||||
|
_ backend.CallResourceHandler = (*Datasource)(nil) |
||||||
|
_ backend.StreamHandler = (*Datasource)(nil) |
||||||
|
) |
||||||
|
|
||||||
|
func NewDatasource(context.Context, backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { |
||||||
|
return &Datasource{ |
||||||
|
Service: pyroscope.ProvideService(httpclient.NewProvider()), |
||||||
|
}, nil |
||||||
|
} |
||||||
|
|
||||||
|
type Datasource struct { |
||||||
|
Service *pyroscope.Service |
||||||
|
} |
||||||
|
|
||||||
|
func (d *Datasource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { |
||||||
|
return d.Service.QueryData(ctx, req) |
||||||
|
} |
||||||
|
|
||||||
|
func (d *Datasource) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { |
||||||
|
return d.Service.CallResource(ctx, req, sender) |
||||||
|
} |
||||||
|
|
||||||
|
func (d *Datasource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) { |
||||||
|
return d.Service.CheckHealth(ctx, req) |
||||||
|
} |
||||||
|
|
||||||
|
func (d *Datasource) SubscribeStream(ctx context.Context, req *backend.SubscribeStreamRequest) (*backend.SubscribeStreamResponse, error) { |
||||||
|
return d.Service.SubscribeStream(ctx, req) |
||||||
|
} |
||||||
|
|
||||||
|
func (d *Datasource) PublishStream(ctx context.Context, req *backend.PublishStreamRequest) (*backend.PublishStreamResponse, error) { |
||||||
|
return d.Service.PublishStream(ctx, req) |
||||||
|
} |
||||||
|
|
||||||
|
func (d *Datasource) RunStream(ctx context.Context, req *backend.RunStreamRequest, sender *backend.StreamSender) error { |
||||||
|
return d.Service.RunStream(ctx, req, sender) |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"os" |
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource" |
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/log" |
||||||
|
) |
||||||
|
|
||||||
|
func main() { |
||||||
|
// Start listening to requests sent from Grafana. This call is blocking so
|
||||||
|
// it won't finish until Grafana shuts down the process or the plugin choose
|
||||||
|
// to exit by itself using os.Exit. Manage automatically manages life cycle
|
||||||
|
// of datasource instances. It accepts datasource instance factory as first
|
||||||
|
// argument. This factory will be automatically called on incoming request
|
||||||
|
// from Grafana to create different instances of SampleDatasource (per datasource
|
||||||
|
// ID). When datasource configuration changed Dispose method will be called and
|
||||||
|
// new datasource instance created using NewSampleDatasource factory.
|
||||||
|
if err := datasource.Manage("grafana-pyroscope-datasource", NewDatasource, datasource.ManageOpts{}); err != nil { |
||||||
|
log.DefaultLogger.Error(err.Error()) |
||||||
|
os.Exit(1) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
# Changelog |
@ -0,0 +1,49 @@ |
|||||||
|
{ |
||||||
|
"name": "@grafana-plugins/grafana-pyroscope-datasource", |
||||||
|
"description": "Continuous profiling for analysis of CPU and memory usage, down to the line number and throughout time. Saving infrastructure cost, improving performance, and increasing reliability.", |
||||||
|
"private": true, |
||||||
|
"version": "10.4.0-pre", |
||||||
|
"dependencies": { |
||||||
|
"@emotion/css": "11.11.2", |
||||||
|
"@grafana/data": "10.4.0-pre", |
||||||
|
"@grafana/runtime": "10.4.0-pre", |
||||||
|
"@grafana/schema": "10.4.0-pre", |
||||||
|
"@grafana/ui": "10.4.0-pre", |
||||||
|
"fast-deep-equal": "^3.1.3", |
||||||
|
"lodash": "4.17.21", |
||||||
|
"monaco-editor": "0.34.0", |
||||||
|
"prismjs": "1.29.0", |
||||||
|
"react": "18.2.0", |
||||||
|
"react-dom": "18.2.0", |
||||||
|
"react-use": "17.4.0", |
||||||
|
"rxjs": "7.8.1", |
||||||
|
"tslib": "2.6.0" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"@grafana/plugin-configs": "10.4.0-pre", |
||||||
|
"@testing-library/jest-dom": "6.1.4", |
||||||
|
"@testing-library/react": "14.0.0", |
||||||
|
"@testing-library/user-event": "14.5.1", |
||||||
|
"@types/jest": "29.5.4", |
||||||
|
"@types/lodash": "4.14.195", |
||||||
|
"@types/prismjs": "1.26.0", |
||||||
|
"@types/react": "18.2.15", |
||||||
|
"@types/react-dom": "18.2.7", |
||||||
|
"@types/testing-library__jest-dom": "5.14.8", |
||||||
|
"css-loader": "6.8.1", |
||||||
|
"jest": "29.7.0", |
||||||
|
"style-loader": "3.3.3", |
||||||
|
"ts-node": "10.9.1", |
||||||
|
"typescript": "5.2.2", |
||||||
|
"webpack": "5.89.0" |
||||||
|
}, |
||||||
|
"peerDependencies": { |
||||||
|
"@grafana/runtime": "*" |
||||||
|
}, |
||||||
|
"scripts": { |
||||||
|
"build": "webpack -c ./webpack.config.ts --env production", |
||||||
|
"build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", |
||||||
|
"dev": "webpack -w -c ./webpack.config.ts --env development" |
||||||
|
}, |
||||||
|
"packageManager": "yarn@3.6.0" |
||||||
|
} |
@ -0,0 +1,4 @@ |
|||||||
|
{ |
||||||
|
"extends": "@grafana/plugin-configs/tsconfig.json", |
||||||
|
"include": ["."] |
||||||
|
} |
@ -0,0 +1,84 @@ |
|||||||
|
import { invert } from 'lodash'; |
||||||
|
import { Token } from 'prismjs'; |
||||||
|
|
||||||
|
import { AbstractLabelMatcher, AbstractLabelOperator, AbstractQuery } from '@grafana/data'; |
||||||
|
|
||||||
|
export function extractLabelMatchers(tokens: Array<string | Token>): AbstractLabelMatcher[] { |
||||||
|
const labelMatchers: AbstractLabelMatcher[] = []; |
||||||
|
|
||||||
|
for (const token of tokens) { |
||||||
|
if (!(token instanceof Token)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
if (token.type === 'context-labels') { |
||||||
|
let labelKey = ''; |
||||||
|
let labelValue = ''; |
||||||
|
let labelOperator = ''; |
||||||
|
|
||||||
|
const contentTokens = Array.isArray(token.content) ? token.content : [token.content]; |
||||||
|
|
||||||
|
for (let currentToken of contentTokens) { |
||||||
|
if (typeof currentToken === 'string') { |
||||||
|
let currentStr: string; |
||||||
|
currentStr = currentToken; |
||||||
|
if (currentStr === '=' || currentStr === '!=' || currentStr === '=~' || currentStr === '!~') { |
||||||
|
labelOperator = currentStr; |
||||||
|
} |
||||||
|
} else if (currentToken instanceof Token) { |
||||||
|
switch (currentToken.type) { |
||||||
|
case 'label-key': |
||||||
|
labelKey = getMaybeTokenStringContent(currentToken); |
||||||
|
break; |
||||||
|
case 'label-value': |
||||||
|
labelValue = getMaybeTokenStringContent(currentToken); |
||||||
|
labelValue = labelValue.substring(1, labelValue.length - 1); |
||||||
|
const labelComparator = FromPromLikeMap[labelOperator]; |
||||||
|
if (labelComparator) { |
||||||
|
labelMatchers.push({ name: labelKey, operator: labelComparator, value: labelValue }); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return labelMatchers; |
||||||
|
} |
||||||
|
|
||||||
|
export function toPromLikeExpr(labelBasedQuery: AbstractQuery): string { |
||||||
|
const expr = labelBasedQuery.labelMatchers |
||||||
|
.map((selector: AbstractLabelMatcher) => { |
||||||
|
const operator = ToPromLikeMap[selector.operator]; |
||||||
|
if (operator) { |
||||||
|
return `${selector.name}${operator}"${selector.value}"`; |
||||||
|
} else { |
||||||
|
return ''; |
||||||
|
} |
||||||
|
}) |
||||||
|
.filter((e: string) => e !== '') |
||||||
|
.join(', '); |
||||||
|
|
||||||
|
return expr ? `{${expr}}` : ''; |
||||||
|
} |
||||||
|
|
||||||
|
function getMaybeTokenStringContent(token: Token): string { |
||||||
|
if (typeof token.content === 'string') { |
||||||
|
return token.content; |
||||||
|
} |
||||||
|
|
||||||
|
return ''; |
||||||
|
} |
||||||
|
|
||||||
|
const FromPromLikeMap: Record<string, AbstractLabelOperator> = { |
||||||
|
'=': AbstractLabelOperator.Equal, |
||||||
|
'!=': AbstractLabelOperator.NotEqual, |
||||||
|
'=~': AbstractLabelOperator.EqualRegEx, |
||||||
|
'!~': AbstractLabelOperator.NotEqualRegEx, |
||||||
|
}; |
||||||
|
|
||||||
|
const ToPromLikeMap: Record<AbstractLabelOperator, string> = invert(FromPromLikeMap) as Record< |
||||||
|
AbstractLabelOperator, |
||||||
|
string |
||||||
|
>; |
@ -0,0 +1,15 @@ |
|||||||
|
import config from '@grafana/plugin-configs/webpack.config'; |
||||||
|
|
||||||
|
const configWithFallback = async (env: Record<string, unknown>) => { |
||||||
|
const response = await config(env); |
||||||
|
if (response !== undefined && response.resolve !== undefined) { |
||||||
|
response.resolve.fallback = { |
||||||
|
...response.resolve.fallback, |
||||||
|
stream: false, |
||||||
|
string_decoder: false, |
||||||
|
}; |
||||||
|
} |
||||||
|
return response; |
||||||
|
}; |
||||||
|
|
||||||
|
export default configWithFallback; |
Loading…
Reference in new issue