-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added script switch button to the query panel. #41
Changes from 4 commits
94949e0
43672a8
d6c902c
faaa071
3dd1c40
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* Copyright 2018- The Pixie Authors. | ||
* | ||
* 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. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
const customQuery = require('./pxl_scripts/custom-query.json'); | ||
const exampleQuery = require('pxl_scripts/example-query.json'); | ||
const httpDataFiltered = require('pxl_scripts/http-data-filtered.json'); | ||
const httpErrorsPerService = require('pxl_scripts/http-errors-per-service.json'); | ||
|
||
interface Script { | ||
name: string; | ||
description: string; | ||
script: string; | ||
} | ||
|
||
// Load predefined scripts | ||
const scriptsRaw: Script[] = [customQuery, exampleQuery, httpDataFiltered, httpErrorsPerService]; | ||
|
||
// Make a map for easier access of scripts | ||
export const scripts = new Map( | ||
scriptsRaw.map((script) => { | ||
return [script.name, script]; | ||
}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: this is a good candidate for shorthand syntax.
|
||
); | ||
|
||
// Construct options list which is injested by Select component in | ||
export const options = scriptsRaw.map((script: Script) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
return { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: shorthand syntax also works for objects if you wrap them in parentheses, like this: export const scriptOptions: Array<{ label: string, description: string }> = scriptsRaw.map((script) => ({
label: script.name,
description: script.description,
})); |
||
label: script.name, | ||
description: script.description, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe a nice, small follow-up PR is to figure out how to incorporate/show this description when you're looking through scripts in the dropdown. This is just a UI improvement thing though, so just a nice-to-have (and shouldn't be done in this PR). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is already done through Grafana UI component. Additionally it can display images near the selections, but I don't think we need that. |
||
}; | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"name": "Custom Query", | ||
"description": "Write your own pxl query.", | ||
"script": "" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"name": "Example Query", | ||
"description": "Example query from Pixie documentation.", | ||
"script": "# Import Pixie's module for querying data.\nimport px\n# Load data from Pixie's \\`http_events\\` table into a Dataframe.\ndf = px.DataFrame(table='http_events', start_time=__time_from)\n# Add K8s metadata context.\ndf.service = df.ctx['service']\ndf.namespace = df.ctx['namespace']\n# Bin the 'time_' column using the interval provided by Grafana.\ndf.timestamp = px.bin(df.time_, __interval)\n# Group data by unique pairings of 'timestamp' and 'service'\n# and count the total number of requests per unique pairing.\nper_ns_df = df.groupby(['timestamp', 'service']).agg(\n throughput_total=('latency', px.count)\n )\n# Calculate throughput by dividing # of requests by the time interval.\nper_ns_df.request_throughput = per_ns_df.throughput_total / __interval\nper_ns_df.request_throughput = per_ns_df.request_throughput * 1e9\n# Rename 'timestamp' column to 'time_'. The Grafana plugin expects a 'time_'\n# column to display data in a Graph or Time series.\nper_ns_df.time_ = per_ns_df.timestamp\n# Output select columns of the DataFrame.\npx.display(per_ns_df['time_', 'service', 'request_throughput'])\n" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"name": "Raw HTTP Events (Long Format)", | ||
"description": "Query for raw HTTP events. Shouldn't be used with time series.", | ||
"script": "'''\nThis query outputs a table of HTTP events (request and response pairs).\nIt produces output identical to Pixie's \\`px/http_data_filtered\\` script in the Live UI.\n\nTo filter the HTTP events, uncomment lines 41-43. Alternatively, use Grafana's\ntable column filtering feature:\nhttps://grafana.com/docs/grafana/latest/visualizations/table/filter-table-columns/\n\nThis query is for use with Grafana's Pixie Datasource Plugin only,\nas it uses Grafana macros for adding Grafana dashboard context.\n'''\n\n# Import Pixie's module for querying data.\nimport px\n\n# Import HTTP events table.\ndf = px.DataFrame(table='http_events', start_time=__time_from)\n\n# Add columns for service, pod info.\ndf.svc = df.ctx['service']\ndf.pod = df.ctx['pod']\ndf = df.drop('upid')\n\n# EXAMPLE OPTIONAL FILTERS\n#df = df[px.contains(df.svc, 'catalogue')]\n#df = df[px.contains(df.pod, 'catalogue')]\n#df = df[df.req_path == '/healthz']\n\n# Avoid conversion to wide format\ndf.timestamp = df.time_\ndf = df.drop(columns=['time_'])\n\n# Keep only the selected columns (and order them in the following order)\ndf = df[['timestamp', 'remote_addr', 'remote_port', 'req_method', 'req_path', 'resp_status', 'resp_body', 'latency', 'svc', 'pod']]\n\n# Output the DataFrame\npx.display(df)\n" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"name": "HTTP Error Rate by Service (Wide Format)", | ||
"description": "", | ||
"script": "'''\nThis query outputs a table of HTTP error and total request count per service.\n\nThis query is for use with Grafana's Pixie Datasource Plugin only,\nas it uses Grafana macros for adding Grafana dashboard context.\n'''\n\n# Import Pixie's module for querying data.\nimport px\n\n# Import HTTP events table.\ndf = px.DataFrame(table='http_events', start_time=__time_from)\n\n# Add columns for service, namespace info.\ndf.namespace = df.ctx['namespace']\ndf.service = df.ctx['service']\n\n# Filter out requests that don't have a service defined.\ndf = df[df.service != '']\n\n# Filter out requests from the Pixie (pl) namespace.\ndf = df[df.namespace != 'pl']\n\n# Add column for HTTP response status errors.\ndf.error = df.resp_status >= 400\n\n# Group HTTP events by service, counting errors and total HTTP events.\ndf = df.groupby(['service']).agg(\n error_count=('error', px.sum),\n total_requests=('resp_status', px.count)\n)\n\n# Output the DataFrame.\npx.display(df)\n" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,9 +19,10 @@ | |
import defaults from 'lodash/defaults'; | ||
|
||
import React, { ChangeEvent, PureComponent } from 'react'; | ||
import { TextArea } from '@grafana/ui'; | ||
import { QueryEditorProps } from '@grafana/data'; | ||
import { TextArea, Select } from '@grafana/ui'; | ||
import { QueryEditorProps, SelectableValue } from '@grafana/data'; | ||
import { DataSource } from './datasource'; | ||
import { options, scripts } from 'pxl_scripts'; | ||
import { defaultQuery, PixieDataSourceOptions, PixieDataQuery } from './types'; | ||
|
||
type Props = QueryEditorProps<DataSource, PixieDataQuery, PixieDataSourceOptions>; | ||
|
@@ -33,12 +34,26 @@ export class QueryEditor extends PureComponent<Props> { | |
onRunQuery(); | ||
} | ||
|
||
onSelect(option: SelectableValue<number>) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kartik is working on adding some more dropdowns (for example, for column selection, groupbys). Let's name this |
||
if (option.label != null) { | ||
// Load in predefined scripts to the script text box | ||
|
||
const script = scripts.get(option.label); | ||
if (script !== undefined) { | ||
const { onChange, query, onRunQuery } = this.props; | ||
onChange({ ...query, pxlScript: script.script }); | ||
onRunQuery(); | ||
} | ||
} | ||
} | ||
|
||
render() { | ||
const query = defaults(this.props.query, defaultQuery); | ||
const { pxlScript } = query; | ||
|
||
return ( | ||
<div className="gf-form"> | ||
<Select options={options} onChange={this.onSelect.bind(this)} /> | ||
<TextArea | ||
id="PxL Script" | ||
name="PxL Script" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a general rule (only writing it once since it's the same thing elsewhere):
Even though TypeScript can often figure out the type of something for you, it's still a good idea to specify it explicitly when:
Map
, but I have to read surrounding code to realize it's actually aMap<string, Script>
and not aMap<string, string>
)In this specific case,
export const scripts = new Map<string, Script>(...)
would make it nice and clear.