mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* Add UMLs * Add rendered diagrams * Move QueryCtrl to flux * Remove redundant param in the reducer * Use named imports for lodash and fix typing for GraphiteTagOperator * Add missing async/await * Extract providers to a separate file * Clean up async await * Rename controller functions back to main * Simplify creating actions * Re-order controller functions * Separate helpers from actions * Rename vars * Simplify helpers * Move controller methods to state reducers * Remove docs (they are added in design doc) * Move actions.ts to state folder * Add docs * Add old methods stubs for easier review * Check how state dependencies will be mapped * Rename state to store * Rename state to store * Rewrite spec tests for Graphite Query Controller * Update docs * Update docs * Add GraphiteTextEditor * Add play button * Add AddGraphiteFunction * Use Segment to simplify AddGraphiteFunction * Memoize function defs * Fix useCallback deps * Update public/app/plugins/datasource/graphite/state/helpers.ts Co-authored-by: Giordano Ricci <me@giordanoricci.com> * Update public/app/plugins/datasource/graphite/state/helpers.ts Co-authored-by: Giordano Ricci <me@giordanoricci.com> * Update public/app/plugins/datasource/graphite/state/helpers.ts Co-authored-by: Giordano Ricci <me@giordanoricci.com> * Update public/app/plugins/datasource/graphite/state/providers.ts Co-authored-by: Giordano Ricci <me@giordanoricci.com> * Update public/app/plugins/datasource/graphite/state/providers.ts Co-authored-by: Giordano Ricci <me@giordanoricci.com> * Update public/app/plugins/datasource/graphite/state/providers.ts Co-authored-by: Giordano Ricci <me@giordanoricci.com> * Update public/app/plugins/datasource/graphite/state/providers.ts Co-authored-by: Giordano Ricci <me@giordanoricci.com> * Update public/app/plugins/datasource/graphite/state/providers.ts Co-authored-by: Giordano Ricci <me@giordanoricci.com> * Update public/app/plugins/datasource/graphite/state/providers.ts Co-authored-by: Giordano Ricci <me@giordanoricci.com> * Add more type definitions * Remove submitOnClickAwayOption This behavior is actually needed to remove parameters in functions * Load function definitions before parsing the target on initial load * Add button padding * Fix loading function definitions * Change targetChanged to updateQuery to avoid mutating state directly It's also needed for extra refresh/runQuery execution as handleTargetChanged doesn't handle changing the raw query * Fix updating query after adding a function * Simplify updating function params * Migrate function editor to react * Simplify setting Segment Select min width * Remove unnecessary changes to SegmentInput * Extract view logic to a helper and update types definitions * Clean up types * Update FuncDef types and add tests * Show red border for unknown functions * Autofocus on new params * Extract params mapping to a helper * Split code between params and function editor * Focus on the first param when a function is added even if it's an optional argument * Add function editor tests * Remove todo marker * Fix adding new functions * Allow empty value in selects for removing function params * Add placeholders and fix styling * Add more docs * Create basic implementation for metrics and tags * Post merge fixes These files are not .ts * Remove mapping to Angular dropdowns * Simplify mapping tag names, values and operators * Simplify mapping metrics * Fix removing tags and autocomplete * Simplify debouncing providers * Ensure options are loaded twice and segment is opened * Remove focusing new segments logic (not supported by React's segment) * Clean up * Move debouncing to components * Simplify mapping to selectable options * Add docs * Group all components * Remove unused controller methods * Create Dispatch context * Group Series and Tags Sections * Create Functions section * Create Section component * use getStyles * remove redundant async/await * Remove * remove redundant async/await * Remove console.log and silent test console output * Do not display the name of the selected dropdown option * Move Section to grafana-ui * Update storybook * Simplify SectionLabel * Fix Influx tests * Fix API Extractor warnings * Fix API Extractor warnings * Do not show hidden functions * Use block docs for better doc generation * Handle undefined values provided for autocomplete * Section -> SegmentSection * Simplify section styling * Remove redundant div * Simplify SegmentSection component * Use theme.spacing * Use empty label instead of a single space label Co-authored-by: Giordano Ricci <me@giordanoricci.com>
182 lines
6.3 KiB
TypeScript
182 lines
6.3 KiB
TypeScript
import { css, cx } from '@emotion/css';
|
|
import React, { PureComponent } from 'react';
|
|
import { MetadataInspectorProps, rangeUtil } from '@grafana/data';
|
|
import { GraphiteDatasource } from '../datasource';
|
|
import { GraphiteQuery, GraphiteOptions, MetricTankSeriesMeta } from '../types';
|
|
import { parseSchemaRetentions, getRollupNotice, getRuntimeConsolidationNotice } from '../meta';
|
|
import { stylesFactory } from '@grafana/ui';
|
|
import { config } from 'app/core/config';
|
|
|
|
export type Props = MetadataInspectorProps<GraphiteDatasource, GraphiteQuery, GraphiteOptions>;
|
|
|
|
export interface State {
|
|
index: number;
|
|
}
|
|
|
|
export class MetricTankMetaInspector extends PureComponent<Props, State> {
|
|
renderMeta(meta: MetricTankSeriesMeta, key: string) {
|
|
const styles = getStyles();
|
|
const buckets = parseSchemaRetentions(meta['schema-retentions']);
|
|
const rollupNotice = getRollupNotice([meta]);
|
|
const runtimeNotice = getRuntimeConsolidationNotice([meta]);
|
|
const normFunc = (meta['consolidator-normfetch'] ?? '').replace('Consolidator', '');
|
|
|
|
const totalSeconds = buckets.reduce(
|
|
(acc, bucket) => acc + (bucket.retention ? rangeUtil.intervalToSeconds(bucket.retention) : 0),
|
|
0
|
|
);
|
|
|
|
return (
|
|
<div className={styles.metaItem} key={key}>
|
|
<div className={styles.metaItemHeader}>
|
|
Schema: {meta['schema-name']}
|
|
<div className="small muted">Series count: {meta.count}</div>
|
|
</div>
|
|
<div className={styles.metaItemBody}>
|
|
<div className={styles.step}>
|
|
<div className={styles.stepHeading}>Step 1: Fetch</div>
|
|
<div className={styles.stepDescription}>
|
|
First data is fetched, either from raw data archive or a rollup archive
|
|
</div>
|
|
|
|
{rollupNotice && <p>{rollupNotice.text}</p>}
|
|
{!rollupNotice && <p>No rollup archive was used</p>}
|
|
|
|
<div>
|
|
{buckets.map((bucket, index) => {
|
|
const bucketLength = bucket.retention ? rangeUtil.intervalToSeconds(bucket.retention) : 0;
|
|
const lengthPercent = (bucketLength / totalSeconds) * 100;
|
|
const isActive = index === meta['archive-read'];
|
|
|
|
return (
|
|
<div key={bucket.retention} className={styles.bucket}>
|
|
<div className={styles.bucketInterval}>{bucket.interval}</div>
|
|
<div
|
|
className={cx(styles.bucketRetention, { [styles.bucketRetentionActive]: isActive })}
|
|
style={{ flexGrow: lengthPercent }}
|
|
/>
|
|
<div style={{ flexGrow: 100 - lengthPercent }}>{bucket.retention}</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles.step}>
|
|
<div className={styles.stepHeading}>Step 2: Normalization</div>
|
|
<div className={styles.stepDescription}>
|
|
Normalization happens when series with different intervals between points are combined.
|
|
</div>
|
|
|
|
{meta['aggnum-norm'] > 1 && <p>Normalization did occur using {normFunc}</p>}
|
|
{meta['aggnum-norm'] === 1 && <p>No normalization was needed</p>}
|
|
</div>
|
|
|
|
<div className={styles.step}>
|
|
<div className={styles.stepHeading}>Step 3: Runtime consolidation</div>
|
|
<div className={styles.stepDescription}>
|
|
If there are too many data points at this point Metrictank will consolidate them down to below max data
|
|
points (set in queries tab).
|
|
</div>
|
|
|
|
{runtimeNotice && <p>{runtimeNotice.text}</p>}
|
|
{!runtimeNotice && <p>No runtime consolidation</p>}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
render() {
|
|
const { data } = this.props;
|
|
|
|
// away to dedupe them
|
|
const seriesMetas: Record<string, MetricTankSeriesMeta> = {};
|
|
|
|
for (const series of data) {
|
|
if (series.meta && series.meta.custom) {
|
|
for (const metaItem of series.meta.custom.seriesMetaList as MetricTankSeriesMeta[]) {
|
|
// key is to dedupe as many series will have identitical meta
|
|
const key = `${JSON.stringify(metaItem)}`;
|
|
|
|
if (seriesMetas[key]) {
|
|
seriesMetas[key].count += metaItem.count;
|
|
} else {
|
|
seriesMetas[key] = metaItem;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Object.keys(seriesMetas).length === 0) {
|
|
return <div>No response meta data</div>;
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<h2 className="page-heading">Metrictank Lineage</h2>
|
|
{Object.keys(seriesMetas).map((key) => this.renderMeta(seriesMetas[key], key))}
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
const getStyles = stylesFactory(() => {
|
|
const { theme } = config;
|
|
const borderColor = theme.isDark ? theme.palette.gray25 : theme.palette.gray85;
|
|
const background = theme.isDark ? theme.palette.dark1 : theme.palette.white;
|
|
const headerBg = theme.isDark ? theme.palette.gray15 : theme.palette.gray85;
|
|
|
|
return {
|
|
metaItem: css`
|
|
background: ${background};
|
|
border: 1px solid ${borderColor};
|
|
margin-bottom: ${theme.spacing.md};
|
|
`,
|
|
metaItemHeader: css`
|
|
background: ${headerBg};
|
|
padding: ${theme.spacing.xs} ${theme.spacing.md};
|
|
font-size: ${theme.typography.size.md};
|
|
display: flex;
|
|
justify-content: space-between;
|
|
`,
|
|
metaItemBody: css`
|
|
padding: ${theme.spacing.md};
|
|
`,
|
|
stepHeading: css`
|
|
font-size: ${theme.typography.size.md};
|
|
`,
|
|
stepDescription: css`
|
|
font-size: ${theme.typography.size.sm};
|
|
color: ${theme.colors.textWeak};
|
|
margin-bottom: ${theme.spacing.sm};
|
|
`,
|
|
step: css`
|
|
margin-bottom: ${theme.spacing.lg};
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
`,
|
|
bucket: css`
|
|
display: flex;
|
|
margin-bottom: ${theme.spacing.sm};
|
|
border-radius: ${theme.border.radius.md};
|
|
`,
|
|
bucketInterval: css`
|
|
flex-grow: 0;
|
|
width: 60px;
|
|
`,
|
|
bucketRetention: css`
|
|
background: linear-gradient(0deg, ${theme.palette.blue85}, ${theme.palette.blue95});
|
|
text-align: center;
|
|
color: ${theme.palette.white};
|
|
margin-right: ${theme.spacing.md};
|
|
border-radius: ${theme.border.radius.md};
|
|
`,
|
|
bucketRetentionActive: css`
|
|
background: linear-gradient(0deg, ${theme.palette.greenBase}, ${theme.palette.greenShade});
|
|
`,
|
|
};
|
|
});
|