mirror of
https://github.com/SigNoz/signoz.git
synced 2026-02-16 06:02:13 +00:00
Compare commits
1 Commits
fix/bar-ch
...
nv/10282
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
052cb01e00 |
@@ -73,7 +73,7 @@ describe('convertV5ResponseToLegacy', () => {
|
||||
const v5Data: QueryRangeResponseV5 = {
|
||||
type: 'time_series',
|
||||
data: { results: [timeSeries] },
|
||||
meta: { rowsScanned: 0, bytesScanned: 0, durationMs: 0, stepIntervals: {} },
|
||||
meta: { rowsScanned: 0, bytesScanned: 0, durationMs: 0 },
|
||||
};
|
||||
|
||||
const params = makeBaseParams('time_series', [
|
||||
@@ -156,7 +156,7 @@ describe('convertV5ResponseToLegacy', () => {
|
||||
const v5Data: QueryRangeResponseV5 = {
|
||||
type: 'scalar',
|
||||
data: { results: [scalar] },
|
||||
meta: { rowsScanned: 0, bytesScanned: 0, durationMs: 0, stepIntervals: {} },
|
||||
meta: { rowsScanned: 0, bytesScanned: 0, durationMs: 0 },
|
||||
};
|
||||
|
||||
const params = makeBaseParams('scalar', [
|
||||
@@ -239,7 +239,7 @@ describe('convertV5ResponseToLegacy', () => {
|
||||
const v5Data: QueryRangeResponseV5 = {
|
||||
type: 'scalar',
|
||||
data: { results: [scalar] },
|
||||
meta: { rowsScanned: 0, bytesScanned: 0, durationMs: 0, stepIntervals: {} },
|
||||
meta: { rowsScanned: 0, bytesScanned: 0, durationMs: 0 },
|
||||
};
|
||||
|
||||
const params = makeBaseParams('scalar', [
|
||||
|
||||
@@ -388,7 +388,6 @@ export function convertV5ResponseToLegacy(
|
||||
warnings: v5Data?.data?.warning || [],
|
||||
},
|
||||
warning: v5Data?.warning || undefined,
|
||||
meta: v5Data?.meta,
|
||||
},
|
||||
warning: v5Data?.warning || undefined,
|
||||
};
|
||||
@@ -407,7 +406,6 @@ export function convertV5ResponseToLegacy(
|
||||
payload: {
|
||||
data: convertedData,
|
||||
warning: v5Response.payload?.data?.warning || undefined,
|
||||
meta: v5Data?.meta,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
VisibilityMode,
|
||||
} from 'lib/uPlotV2/config/types';
|
||||
import { UPlotConfigBuilder } from 'lib/uPlotV2/config/UPlotConfigBuilder';
|
||||
import { get } from 'lodash-es';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
@@ -78,12 +77,6 @@ export function prepareBarPanelConfig({
|
||||
builder.setBands(getInitialStackedBands(seriesCount));
|
||||
}
|
||||
|
||||
const stepIntervals: Record<string, number> = get(
|
||||
apiResponse,
|
||||
'data.newResult.meta.stepIntervals',
|
||||
{},
|
||||
);
|
||||
|
||||
const seriesList: QueryData[] = apiResponse?.data?.result || [];
|
||||
seriesList.forEach((series) => {
|
||||
const baseLabelName = getLabelName(
|
||||
@@ -96,8 +89,6 @@ export function prepareBarPanelConfig({
|
||||
? getLegend(series, currentQuery, baseLabelName)
|
||||
: baseLabelName;
|
||||
|
||||
const currentStepInterval = get(stepIntervals, series.queryName, undefined);
|
||||
|
||||
builder.addSeries({
|
||||
scaleKey: 'y',
|
||||
drawStyle: DrawStyle.Bar,
|
||||
@@ -110,7 +101,6 @@ export function prepareBarPanelConfig({
|
||||
showPoints: VisibilityMode.Never,
|
||||
pointSize: 5,
|
||||
isDarkMode,
|
||||
stepInterval: currentStepInterval,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -5,12 +5,16 @@ import { PanelMode } from 'container/DashboardContainer/visualization/panels/typ
|
||||
import { WidgetGraphComponentProps } from 'container/GridCardLayout/GridCard/types';
|
||||
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||
import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
|
||||
import { SuccessResponse } from 'types/api';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { MetricQueryRangeSuccessResponse } from 'types/api/metrics/getQueryRange';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
import { QueryData } from 'types/api/widgets/getQuery';
|
||||
|
||||
export type PanelWrapperProps = {
|
||||
queryResponse: UseQueryResult<MetricQueryRangeSuccessResponse, Error>;
|
||||
queryResponse: UseQueryResult<
|
||||
SuccessResponse<MetricRangePayloadProps, unknown>,
|
||||
Error
|
||||
>;
|
||||
widget: Widgets;
|
||||
setRequestData?: WidgetGraphComponentProps['setRequestData'];
|
||||
isFullViewMode?: boolean;
|
||||
|
||||
@@ -10,12 +10,13 @@ import {
|
||||
GetQueryResultsProps,
|
||||
} from 'lib/dashboard/getQueryResults';
|
||||
import getStartEndRangeTime from 'lib/getStartEndRangeTime';
|
||||
import { SuccessResponse, Warning } from 'types/api';
|
||||
import APIError from 'types/api/error';
|
||||
import { MetricQueryRangeSuccessResponse } from 'types/api/metrics/getQueryRange';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
type UseGetQueryRangeOptions = UseQueryOptions<
|
||||
MetricQueryRangeSuccessResponse,
|
||||
SuccessResponse<MetricRangePayloadProps> & { warning?: Warning },
|
||||
APIError | Error
|
||||
>;
|
||||
|
||||
@@ -29,7 +30,10 @@ type UseGetQueryRange = (
|
||||
widgetIndex: number;
|
||||
publicDashboardId: string;
|
||||
},
|
||||
) => UseQueryResult<MetricQueryRangeSuccessResponse, Error>;
|
||||
) => UseQueryResult<
|
||||
SuccessResponse<MetricRangePayloadProps> & { warning?: Warning },
|
||||
Error
|
||||
>;
|
||||
|
||||
export const useGetQueryRange: UseGetQueryRange = (
|
||||
requestData,
|
||||
@@ -141,7 +145,10 @@ export const useGetQueryRange: UseGetQueryRange = (
|
||||
};
|
||||
}, [options?.retry]);
|
||||
|
||||
return useQuery<MetricQueryRangeSuccessResponse, APIError | Error>({
|
||||
return useQuery<
|
||||
SuccessResponse<MetricRangePayloadProps> & { warning?: Warning },
|
||||
APIError | Error
|
||||
>({
|
||||
queryFn: async ({ signal }) =>
|
||||
GetMetricQueryRange(
|
||||
modifiedRequestData,
|
||||
|
||||
@@ -19,11 +19,7 @@ import { Pagination } from 'hooks/queryPagination';
|
||||
import { convertNewDataToOld } from 'lib/newQueryBuilder/convertNewDataToOld';
|
||||
import { isEmpty } from 'lodash-es';
|
||||
import { SuccessResponse, SuccessResponseV2, Warning } from 'types/api';
|
||||
import {
|
||||
MetricQueryRangeSuccessResponse,
|
||||
MetricRangePayloadProps,
|
||||
} from 'types/api/metrics/getQueryRange';
|
||||
import { ExecStats, MetricRangePayloadV5 } from 'types/api/v5/queryRange';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
import { IBuilderQuery, Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
@@ -209,13 +205,13 @@ export async function GetMetricQueryRange(
|
||||
widgetIndex: number;
|
||||
publicDashboardId: string;
|
||||
},
|
||||
): Promise<MetricQueryRangeSuccessResponse> {
|
||||
): Promise<SuccessResponse<MetricRangePayloadProps> & { warning?: Warning }> {
|
||||
let legendMap: Record<string, string>;
|
||||
let response:
|
||||
| MetricQueryRangeSuccessResponse
|
||||
| SuccessResponseV2<MetricRangePayloadV5>;
|
||||
| SuccessResponse<MetricRangePayloadProps>
|
||||
| SuccessResponseV2<MetricRangePayloadV5>
|
||||
| (SuccessResponse<MetricRangePayloadProps> & { warning?: Warning });
|
||||
let warning: Warning | undefined;
|
||||
let meta: ExecStats | undefined;
|
||||
|
||||
const panelType = props.originalGraphType || props.graphType;
|
||||
|
||||
@@ -303,7 +299,6 @@ export async function GetMetricQueryRange(
|
||||
);
|
||||
|
||||
warning = response.payload.warning || undefined;
|
||||
meta = response.payload.meta || undefined;
|
||||
} else {
|
||||
const v5Response = await getQueryRangeV5(
|
||||
v5Result.queryPayload,
|
||||
@@ -323,7 +318,6 @@ export async function GetMetricQueryRange(
|
||||
);
|
||||
|
||||
warning = response.payload.warning || undefined;
|
||||
meta = response.payload.meta || undefined;
|
||||
}
|
||||
} else {
|
||||
const legacyResult = prepareQueryRangePayload(props);
|
||||
@@ -390,7 +384,6 @@ export async function GetMetricQueryRange(
|
||||
return {
|
||||
...response,
|
||||
warning,
|
||||
meta,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,6 @@ export class UPlotSeriesBuilder extends ConfigBuilder<SeriesProps, Series> {
|
||||
barAlignment,
|
||||
barMaxWidth,
|
||||
barWidthFactor,
|
||||
stepInterval,
|
||||
} = this.props;
|
||||
if (pathBuilder) {
|
||||
return { paths: pathBuilder };
|
||||
@@ -105,7 +104,6 @@ export class UPlotSeriesBuilder extends ConfigBuilder<SeriesProps, Series> {
|
||||
barAlignment,
|
||||
barMaxWidth,
|
||||
barWidthFactor,
|
||||
stepInterval,
|
||||
});
|
||||
|
||||
return pathsBuilder(self, seriesIdx, idx0, idx1);
|
||||
@@ -211,14 +209,12 @@ function getPathBuilder({
|
||||
barAlignment = BarAlignment.Center,
|
||||
barWidthFactor = 0.6,
|
||||
barMaxWidth = 200,
|
||||
stepInterval,
|
||||
}: {
|
||||
drawStyle: DrawStyle;
|
||||
lineInterpolation?: LineInterpolation;
|
||||
barAlignment?: BarAlignment;
|
||||
barMaxWidth?: number;
|
||||
barWidthFactor?: number;
|
||||
stepInterval?: number;
|
||||
}): Series.PathBuilder {
|
||||
if (!builders) {
|
||||
throw new Error('Required uPlot path builders are not available');
|
||||
@@ -226,13 +222,14 @@ function getPathBuilder({
|
||||
|
||||
if (drawStyle === DrawStyle.Bar) {
|
||||
const pathBuilders = uPlot.paths;
|
||||
return getBarPathBuilder({
|
||||
pathBuilders,
|
||||
barAlignment,
|
||||
barWidthFactor,
|
||||
barMaxWidth,
|
||||
stepInterval,
|
||||
});
|
||||
const barsConfigKey = `bars|${barAlignment}|${barWidthFactor}|${barMaxWidth}`;
|
||||
if (!builders[barsConfigKey] && pathBuilders.bars) {
|
||||
builders[barsConfigKey] = pathBuilders.bars({
|
||||
size: [barWidthFactor, barMaxWidth],
|
||||
align: barAlignment,
|
||||
});
|
||||
}
|
||||
return builders[barsConfigKey];
|
||||
}
|
||||
|
||||
if (drawStyle === DrawStyle.Line) {
|
||||
@@ -250,81 +247,4 @@ function getPathBuilder({
|
||||
return builders.spline;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
function getBarPathBuilder({
|
||||
pathBuilders,
|
||||
barAlignment,
|
||||
barWidthFactor,
|
||||
barMaxWidth,
|
||||
stepInterval,
|
||||
}: {
|
||||
pathBuilders: typeof uPlot.paths;
|
||||
barAlignment: BarAlignment;
|
||||
barWidthFactor: number;
|
||||
barMaxWidth: number;
|
||||
stepInterval?: number;
|
||||
}): Series.PathBuilder {
|
||||
if (!builders) {
|
||||
throw new Error('Required uPlot path builders are not available');
|
||||
}
|
||||
|
||||
const barsPathBuilderFactory = pathBuilders.bars;
|
||||
|
||||
// When a stepInterval is provided (in seconds), cap the maximum bar width
|
||||
// so that a single bar never visually spans more than stepInterval worth
|
||||
// of time on the x-scale.
|
||||
if (
|
||||
typeof stepInterval === 'number' &&
|
||||
stepInterval > 0 &&
|
||||
barsPathBuilderFactory
|
||||
) {
|
||||
return (
|
||||
self: uPlot,
|
||||
seriesIdx: number,
|
||||
idx0: number,
|
||||
idx1: number,
|
||||
): Series.Paths | null => {
|
||||
let effectiveBarMaxWidth = barMaxWidth;
|
||||
|
||||
const xScale = self.scales.x as uPlot.Scale | undefined;
|
||||
if (xScale && typeof xScale.min === 'number') {
|
||||
const start = xScale.min as number;
|
||||
const end = start + stepInterval;
|
||||
const startPx = self.valToPos(start, 'x');
|
||||
const endPx = self.valToPos(end, 'x');
|
||||
const intervalPx = Math.abs(endPx - startPx);
|
||||
|
||||
if (intervalPx > 0) {
|
||||
effectiveBarMaxWidth =
|
||||
typeof barMaxWidth === 'number'
|
||||
? Math.min(barMaxWidth, intervalPx)
|
||||
: intervalPx;
|
||||
}
|
||||
}
|
||||
|
||||
const barsCfgKey = `bars|${barAlignment}|${barWidthFactor}|${effectiveBarMaxWidth}`;
|
||||
if (builders && !builders[barsCfgKey]) {
|
||||
builders[barsCfgKey] = barsPathBuilderFactory({
|
||||
size: [barWidthFactor, effectiveBarMaxWidth],
|
||||
align: barAlignment,
|
||||
});
|
||||
}
|
||||
|
||||
return builders && builders[barsCfgKey]
|
||||
? builders[barsCfgKey](self, seriesIdx, idx0, idx1)
|
||||
: null;
|
||||
};
|
||||
}
|
||||
|
||||
const barsCfgKey = `bars|${barAlignment}|${barWidthFactor}|${barMaxWidth}`;
|
||||
if (!builders[barsCfgKey] && barsPathBuilderFactory) {
|
||||
builders[barsCfgKey] = barsPathBuilderFactory({
|
||||
size: [barWidthFactor, barMaxWidth],
|
||||
align: barAlignment,
|
||||
});
|
||||
}
|
||||
|
||||
return builders[barsCfgKey];
|
||||
}
|
||||
|
||||
export type { SeriesProps };
|
||||
|
||||
@@ -176,7 +176,6 @@ export interface SeriesProps extends LineConfig, PointsConfig, BarConfig {
|
||||
show?: boolean;
|
||||
spanGaps?: boolean;
|
||||
isDarkMode?: boolean;
|
||||
stepInterval?: number;
|
||||
}
|
||||
|
||||
export interface LegendItem {
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
import { SuccessResponse, Warning } from '..';
|
||||
import { Warning } from '..';
|
||||
import {
|
||||
IBuilderFormula,
|
||||
IBuilderQuery,
|
||||
IClickHouseQuery,
|
||||
IPromQLQuery,
|
||||
} from '../queryBuilder/queryBuilderData';
|
||||
import { ExecStats } from '../v5/queryRange';
|
||||
import { QueryData, QueryDataV3 } from '../widgets/getQuery';
|
||||
|
||||
export type QueryRangePayload = {
|
||||
@@ -36,15 +35,8 @@ export interface MetricRangePayloadProps {
|
||||
newResult: MetricRangePayloadV3;
|
||||
warnings?: string[];
|
||||
};
|
||||
meta?: ExecStats;
|
||||
}
|
||||
|
||||
/** Query range success response including optional warning and meta */
|
||||
export type MetricQueryRangeSuccessResponse = SuccessResponse<
|
||||
MetricRangePayloadProps,
|
||||
unknown
|
||||
> & { warning?: Warning; meta?: ExecStats };
|
||||
|
||||
export interface MetricRangePayloadV3 {
|
||||
data: {
|
||||
result: QueryDataV3[];
|
||||
@@ -52,5 +44,4 @@ export interface MetricRangePayloadV3 {
|
||||
warnings?: string[];
|
||||
};
|
||||
warning?: Warning;
|
||||
meta?: ExecStats;
|
||||
}
|
||||
|
||||
@@ -334,7 +334,6 @@ export interface ExecStats {
|
||||
rowsScanned: number;
|
||||
bytesScanned: number;
|
||||
durationMs: number;
|
||||
stepIntervals: Record<string, number>;
|
||||
}
|
||||
|
||||
export interface Label {
|
||||
|
||||
@@ -3261,20 +3261,14 @@ func (r *ClickHouseReader) GetMetricAggregateAttributes(ctx context.Context, org
|
||||
metadata := metadataMap[name]
|
||||
|
||||
typ := string(metadata.MetricType)
|
||||
temporality := string(metadata.Temporality)
|
||||
isMonotonic := metadata.IsMonotonic
|
||||
|
||||
// Non-monotonic cumulative sums are treated as gauges
|
||||
if typ == "Sum" && !isMonotonic && temporality == string(v3.Cumulative) {
|
||||
typ = "Gauge"
|
||||
}
|
||||
|
||||
// unlike traces/logs `tag`/`resource` type, the `Type` will be metric type
|
||||
key := v3.AttributeKey{
|
||||
Key: name,
|
||||
DataType: v3.AttributeKeyDataTypeFloat64,
|
||||
Type: v3.AttributeKeyType(typ),
|
||||
IsColumn: true,
|
||||
Key: name,
|
||||
DataType: v3.AttributeKeyDataTypeFloat64,
|
||||
Type: v3.AttributeKeyType(typ),
|
||||
IsMonotonic: metadata.IsMonotonic,
|
||||
IsColumn: true,
|
||||
}
|
||||
|
||||
if _, ok := seen[name+typ]; ok {
|
||||
@@ -5419,6 +5413,7 @@ func (r *ClickHouseReader) ListSummaryMetrics(ctx context.Context, orgID valuer.
|
||||
t.metric_name AS metric_name,
|
||||
ANY_VALUE(t.description) AS description,
|
||||
ANY_VALUE(t.type) AS metric_type,
|
||||
ANY_VALUE(t.is_monotonic) AS metric_is_monotonic,
|
||||
ANY_VALUE(t.unit) AS metric_unit,
|
||||
uniq(t.fingerprint) AS timeseries,
|
||||
uniq(metric_name) OVER() AS total
|
||||
@@ -5450,7 +5445,7 @@ func (r *ClickHouseReader) ListSummaryMetrics(ctx context.Context, orgID valuer.
|
||||
|
||||
for rows.Next() {
|
||||
var metric metrics_explorer.MetricDetail
|
||||
if err := rows.Scan(&metric.MetricName, &metric.Description, &metric.MetricType, &metric.MetricUnit, &metric.TimeSeries, &response.Total); err != nil {
|
||||
if err := rows.Scan(&metric.MetricName, &metric.Description, &metric.MetricType, &metric.IsMonotonic, &metric.MetricUnit, &metric.TimeSeries, &response.Total); err != nil {
|
||||
zap.L().Error("Error scanning metric row", zap.Error(err))
|
||||
return &response, &model.ApiError{Typ: "ClickHouseError", Err: err}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ type MetricDetail struct {
|
||||
TimeSeries uint64 `json:"timeseries"`
|
||||
Samples uint64 `json:"samples"`
|
||||
LastReceived int64 `json:"lastReceived"`
|
||||
IsMonotonic bool `json:"is_monotonic"`
|
||||
}
|
||||
|
||||
type TreeMapResponseItem struct {
|
||||
|
||||
@@ -381,11 +381,12 @@ func (t AttributeKeyType) String() string {
|
||||
}
|
||||
|
||||
type AttributeKey struct {
|
||||
Key string `json:"key"`
|
||||
DataType AttributeKeyDataType `json:"dataType"`
|
||||
Type AttributeKeyType `json:"type"`
|
||||
IsColumn bool `json:"isColumn"`
|
||||
IsJSON bool `json:"isJSON"`
|
||||
Key string `json:"key"`
|
||||
DataType AttributeKeyDataType `json:"dataType"`
|
||||
Type AttributeKeyType `json:"type"`
|
||||
IsColumn bool `json:"isColumn"`
|
||||
IsMonotonic bool `json:"is_monotonic"`
|
||||
IsJSON bool `json:"isJSON"`
|
||||
}
|
||||
|
||||
func (a AttributeKey) CacheKey() string {
|
||||
|
||||
Reference in New Issue
Block a user