mirror of https://github.com/grafana/grafana
Flame graph: Add metadata above flame graph (#61921)
* Remove percentTitle * Flame graph metadata * Remove comment * Update test * Update metadatapull/62495/head
parent
f19b07c0bc
commit
780f43a33d
@ -0,0 +1,75 @@ |
||||
import { ArrayVector, Field, FieldType } from '@grafana/data'; |
||||
|
||||
import { getMetadata } from './FlameGraphMetadata'; |
||||
|
||||
describe('should get metadata correctly', () => { |
||||
it('for bytes', () => { |
||||
const metadata = getMetadata(makeField('bytes'), 1_624_078_250, 8_624_078_250); |
||||
expect(metadata).toEqual({ |
||||
percentValue: 18.83, |
||||
unitTitle: 'RAM', |
||||
unitValue: '1.51 GiB', |
||||
samples: '8,624,078,250', |
||||
}); |
||||
}); |
||||
|
||||
it('with default unit', () => { |
||||
const metadata = getMetadata(makeField('none'), 1_624_078_250, 8_624_078_250); |
||||
expect(metadata).toEqual({ |
||||
percentValue: 18.83, |
||||
unitTitle: 'Count', |
||||
unitValue: '1624078250', |
||||
samples: '8,624,078,250', |
||||
}); |
||||
}); |
||||
|
||||
it('without unit', () => { |
||||
const metadata = getMetadata( |
||||
{ |
||||
name: 'test', |
||||
type: FieldType.number, |
||||
values: new ArrayVector(), |
||||
config: {}, |
||||
}, |
||||
1_624_078_250, |
||||
8_624_078_250 |
||||
); |
||||
expect(metadata).toEqual({ |
||||
percentValue: 18.83, |
||||
unitTitle: 'Count', |
||||
unitValue: '1624078250', |
||||
samples: '8,624,078,250', |
||||
}); |
||||
}); |
||||
|
||||
it('for objects', () => { |
||||
const metadata = getMetadata(makeField('short'), 1_624_078_250, 8_624_078_250); |
||||
expect(metadata).toEqual({ |
||||
percentValue: 18.83, |
||||
unitTitle: 'Count', |
||||
unitValue: '1.62 Bil', |
||||
samples: '8,624,078,250', |
||||
}); |
||||
}); |
||||
|
||||
it('for nanoseconds', () => { |
||||
const metadata = getMetadata(makeField('ns'), 1_624_078_250, 8_624_078_250); |
||||
expect(metadata).toEqual({ |
||||
percentValue: 18.83, |
||||
unitTitle: 'Time', |
||||
unitValue: '1.62 s', |
||||
samples: '8,624,078,250', |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
function makeField(unit: string): Field { |
||||
return { |
||||
name: 'test', |
||||
type: FieldType.number, |
||||
config: { |
||||
unit, |
||||
}, |
||||
values: new ArrayVector(), |
||||
}; |
||||
} |
||||
@ -0,0 +1,70 @@ |
||||
import { css } from '@emotion/css'; |
||||
import React from 'react'; |
||||
|
||||
import { createTheme, Field, getDisplayProcessor, Vector } from '@grafana/data'; |
||||
import { useStyles2 } from '@grafana/ui'; |
||||
|
||||
import { Metadata, SampleUnit } from '../types'; |
||||
|
||||
import { ItemWithStart } from './dataTransform'; |
||||
|
||||
type Props = { |
||||
levels: ItemWithStart[][]; |
||||
topLevelIndex: number; |
||||
selectedBarIndex: number; |
||||
valueField: Field<number, Vector<number>>; |
||||
totalTicks: number; |
||||
}; |
||||
|
||||
const FlameGraphMetadata = React.memo(({ levels, topLevelIndex, selectedBarIndex, valueField, totalTicks }: Props) => { |
||||
const styles = useStyles2(getStyles); |
||||
if (levels[topLevelIndex] && levels[topLevelIndex][selectedBarIndex]) { |
||||
const bar = levels[topLevelIndex][selectedBarIndex]; |
||||
const metadata = getMetadata(valueField, bar.value, totalTicks); |
||||
const metadataText = `${metadata?.unitValue} (${metadata?.percentValue}%) of ${metadata?.samples} total samples (${metadata?.unitTitle})`; |
||||
return <>{<div className={styles.metadata}>{metadataText}</div>}</>; |
||||
} |
||||
return <></>; |
||||
}); |
||||
|
||||
export const getMetadata = (field: Field, value: number, totalTicks: number): Metadata => { |
||||
let unitTitle; |
||||
const processor = getDisplayProcessor({ field, theme: createTheme() /* theme does not matter for us here */ }); |
||||
const displayValue = processor(value); |
||||
const percentValue = Math.round(10000 * (value / totalTicks)) / 100; |
||||
let unitValue = displayValue.text + displayValue.suffix; |
||||
|
||||
switch (field.config.unit) { |
||||
case SampleUnit.Bytes: |
||||
unitTitle = 'RAM'; |
||||
break; |
||||
case SampleUnit.Nanoseconds: |
||||
unitTitle = 'Time'; |
||||
break; |
||||
default: |
||||
unitTitle = 'Count'; |
||||
if (!displayValue.suffix) { |
||||
// Makes sure we don't show 123undefined or something like that if suffix isn't defined
|
||||
unitValue = displayValue.text; |
||||
} |
||||
break; |
||||
} |
||||
|
||||
return { |
||||
percentValue, |
||||
unitTitle, |
||||
unitValue, |
||||
samples: totalTicks.toLocaleString(), |
||||
}; |
||||
}; |
||||
|
||||
FlameGraphMetadata.displayName = 'FlameGraphMetadata'; |
||||
|
||||
const getStyles = () => ({ |
||||
metadata: css` |
||||
margin: 8px 0; |
||||
text-align: center; |
||||
`,
|
||||
}); |
||||
|
||||
export default FlameGraphMetadata; |
||||
Loading…
Reference in new issue