Skip to content

Commit

Permalink
Add Stat Chart (pixie-io#787) (pixie-io#789)
Browse files Browse the repository at this point in the history
Signed-off-by: Nick Lanam <nlanam@pixielabs.ai>

<img width="577" alt="image"
src="https://user-images.githubusercontent.com/314133/217108680-81070f25-58a0-4a29-ad75-4fbc5699bc89.png">

Summary: Adds a new chart type, 'StatChart', which just displays the
latest value of a single metric with units and label.

Relevant Issues: Fixes pixie-io#787

Type of change: /kind feature

Test Plan: Try this script with this vis spec.
```python
import px
import pxviews

ns_per_ms = 1000 * 1000
ns_per_s = 1000 * ns_per_ms
# Window size to use on time_ column for bucketing.
window_ns = px.DurationNanos(10 * ns_per_s)

def resource_timeseries(start_time: str, node: px.Node):
    ''' Gets the windowed process stats (CPU, memory, etc) for the input node.

    Args:
    @start_time Starting time of the data to examine.
    @node: The full name of the node to filter on.
    '''
    df = pxviews.container_process_timeseries(start_time, px.now(), window_ns)
    df = df[df.ctx['node'] == node]
    df['node'] = df.ctx['node']

    df = df.groupby(['time_', 'node']).agg(
        cpu_usage=('cpu_usage', px.sum),
        actual_disk_read_throughput=('actual_disk_read_throughput', px.sum),
        actual_disk_write_throughput=('actual_disk_write_throughput', px.sum),
        total_disk_read_throughput=('total_disk_read_throughput', px.sum),
        total_disk_write_throughput=('total_disk_write_throughput', px.sum),
        rss=('rss', px.sum),
        vsize=('vsize', px.sum),
    )

    df.groupby_col = df['node']
    return df
```
```json
{
  "variables": [
      {
          "name": "start_time",
          "type": "PX_STRING",
          "description": "The relative start time of the window. Current time is assumed to be now",
          "defaultValue": "-5m"
      },
      {
          "name": "node",
          "type": "PX_NODE",
          "description": "The node name to filter on"
      }
  ],
  "globalFuncs": [
      {
          "outputName": "resource_timeseries",
          "func": {
              "name": "resource_timeseries",
              "args": [
                  {
                      "name": "start_time",
                      "variable": "start_time"
                  },
                  {
                      "name": "node",
                      "variable": "node"
                  }
              ]
          }
      }
  ],
  "widgets": [
      {
          "name": "CPU Stat",
          "position": {
              "x": 0,
              "y": 0,
              "w": 1,
              "h": 1
          },
          "globalFuncOutputName": "resource_timeseries",
          "displaySpec": {
              "@type": "types.px.dev/px.vispb.StatChart",
              "title": "CPU Usage",
              "stat": {
                  "value": "cpu_usage"
              }
          }
      },
      {
        "name": "Bytes Read Stat",
        "position": {
            "x": 2,
            "y": 0,
            "w": 2,
            "h": 2
        },
        "globalFuncOutputName": "resource_timeseries",
        "displaySpec": {
            "@type": "types.px.dev/px.vispb.StatChart",
            "title": "Bytes Read",
            "stat": {
                "value": "total_disk_read_throughput"
            }
        }
    }
  ]
}
```

Changelog Message:
```release-note
New chart type: Stat. Shows a label, metric, and units for that metric.
```

---------

Signed-off-by: Nick Lanam <nlanam@pixielabs.ai>
  • Loading branch information
NickLanam authored Feb 10, 2023
1 parent df93b39 commit 2f940fb
Show file tree
Hide file tree
Showing 8 changed files with 1,341 additions and 134 deletions.
745 changes: 620 additions & 125 deletions src/api/proto/vispb/vis.pb.go

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions src/api/proto/vispb/vis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,20 @@ message TimeseriesChart {
Axis y_axis = 4;
}

// StatChart The visual spec for a basic stat chart. Shows the latest value in the table as a big
// number with units.
message StatChart {
// Stat defines what information to show
message Stat {
// value is the ID of the column to use. The column should hold numeric data of some kind.
string value = 1;
}
// stat is the definition of the stat chart
Stat stat = 1;
// title of the chart, shown as a label for the data
string title = 2;
}

// VegaChart the spec for providing a vega or vega lite spec directly to the UI.
message VegaChart {
// spec is the serialized JSON form of the Vega/Vega Lite spec.
Expand Down
93 changes: 93 additions & 0 deletions src/ui/src/containers/live-widgets/charts/stat-chart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* 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
*/

import * as React from 'react';

import { Theme } from '@mui/material/styles';
import { createStyles, makeStyles } from '@mui/styles';

import { VizierTable } from 'app/api';
import { formatBySemType } from 'app/containers/format-data/format-data';
import { WidgetDisplay } from 'app/containers/live/vis';

export interface StatChartDisplay extends WidgetDisplay {
readonly title: string;
readonly stat: {
readonly value: string;
};
}

export interface StatChartProps {
title?: string;
display: StatChartDisplay;
table: VizierTable;
data: any[];
}

const useStyles = makeStyles((theme: Theme) => createStyles({
root: {
position: 'relative',
height: '100%',
boxSizing: 'content-box', // For the next rules to work properly
margin: theme.spacing(-0.75), // Push to the edges of the containing box
paddingBottom: theme.spacing(1.5), // Including the bottom edge
borderRadius: theme.shape.borderRadius, // And match the shape of that box
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
title: {
...theme.typography.caption,
marginTop: theme.spacing(0.25),
},
label: {
...theme.typography.h2,
textAlign: 'center',
},
labelUnits: {
position: 'relative',
left: theme.spacing(0.25),
bottom: '0.75em',
fontSize: '0.75rem',
},
}), { name: 'StatChart' });

export const StatChart = React.memo<StatChartProps>(({
title,
display,
table,
data,
}) => {
const classes = useStyles();

const { stat: { value: yAxis }, title: innerTitle } = display;
const valueST = table.relation.getColumnsList().find(col => col.getColumnName() === yAxis).getColumnSemanticType();
// Just use the latest value in the data set
const label = formatBySemType(valueST, data[data.length - 1][yAxis]);

return (
<div className={classes.root} data-title={title}>
<div className={classes.label}>
{label.val}
<span className={classes.labelUnits}>{label.units}</span>
<div className={classes.title}>{innerTitle}</div>
</div>
</div>
);
});
StatChart.displayName = 'StatChart';
14 changes: 13 additions & 1 deletion src/ui/src/containers/live/canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { isPixieEmbedded } from 'app/common/embed-context';
import { VizierErrorDetails } from 'app/common/errors';
import { buildClass, Spinner } from 'app/components';
import { LiveRouteContext } from 'app/containers/App/live-routing';
import { StatChart, StatChartDisplay } from 'app/containers/live-widgets/charts/stat-chart';
import {
TimeSeriesContext, withTimeSeriesContext,
} from 'app/containers/live-widgets/context/time-series-context';
Expand All @@ -54,7 +55,7 @@ import {
import MutationModal from './mutation-modal';
import {
DISPLAY_TYPE_KEY, GRAPH_DISPLAY_TYPE, REQUEST_GRAPH_DISPLAY_TYPE,
TABLE_DISPLAY_TYPE, Vis, widgetTableName, WidgetDisplay as VisWidgetDisplay,
TABLE_DISPLAY_TYPE, Vis, widgetTableName, WidgetDisplay as VisWidgetDisplay, STAT_CHART_DISPLAY_TYPE,
} from './vis';

const useStyles = makeStyles((theme: Theme) => createStyles({
Expand Down Expand Up @@ -235,6 +236,17 @@ const WidgetDisplay: React.FC<{
);
}

if (display[DISPLAY_TYPE_KEY] === STAT_CHART_DISPLAY_TYPE) {
return (
<StatChart
title={widgetName}
display={display as StatChartDisplay}
table={table}
data={parsedTable}
/>
);
}

try {
return (
<>
Expand Down
1 change: 1 addition & 0 deletions src/ui/src/containers/live/vis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const DISPLAY_TYPE_KEY = '@type';
export const TABLE_DISPLAY_TYPE = 'types.px.dev/px.vispb.Table';
export const GRAPH_DISPLAY_TYPE = 'types.px.dev/px.vispb.Graph';
export const REQUEST_GRAPH_DISPLAY_TYPE = 'types.px.dev/px.vispb.RequestGraph';
export const STAT_CHART_DISPLAY_TYPE = 'types.px.dev/px.vispb.StatChart';

export interface WidgetDisplay {
readonly '@type': string;
Expand Down
189 changes: 189 additions & 0 deletions src/ui/src/types/generated/vis_pb.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 2f940fb

Please sign in to comment.