mirror of
https://github.com/SigNoz/signoz.git
synced 2026-02-16 06:02:13 +00:00
Compare commits
4 Commits
fix/bar-ch
...
ns/ext-api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6897c48db | ||
|
|
54f3276378 | ||
|
|
5bfea56e8e | ||
|
|
ff3f41f88f |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,8 +1,11 @@
|
||||
|
||||
node_modules
|
||||
|
||||
# editor
|
||||
.vscode
|
||||
!.vscode/settings.json
|
||||
.zed
|
||||
.idea
|
||||
|
||||
deploy/docker/environment_tiny/common_test
|
||||
frontend/node_modules
|
||||
@@ -31,8 +34,6 @@ frontend/yarn-debug.log*
|
||||
frontend/yarn-error.log*
|
||||
frontend/src/constants/env.ts
|
||||
|
||||
.idea
|
||||
|
||||
**/build
|
||||
**/storage
|
||||
**/locust-scripts/__pycache__/
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -14,6 +14,6 @@ export const VIEW_TYPES = {
|
||||
export const SPAN_ATTRIBUTES = {
|
||||
URL_PATH: 'http.url',
|
||||
RESPONSE_STATUS_CODE: 'response_status_code',
|
||||
SERVER_NAME: 'net.peer.name',
|
||||
SERVER_NAME: 'http_host',
|
||||
SERVER_PORT: 'net.peer.port',
|
||||
} as const;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { rest, server } from 'mocks-server/server';
|
||||
import { fireEvent, render, screen, waitFor, within } from 'tests/test-utils';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import { SPAN_ATTRIBUTES } from '../Explorer/Domains/DomainDetails/constants';
|
||||
import TopErrors from '../Explorer/Domains/DomainDetails/TopErrors';
|
||||
import { getTopErrorsQueryPayload } from '../utils';
|
||||
|
||||
@@ -215,7 +216,7 @@ describe('TopErrors', () => {
|
||||
value: 'true',
|
||||
}),
|
||||
expect.objectContaining({
|
||||
key: expect.objectContaining({ key: 'net.peer.name' }),
|
||||
key: expect.objectContaining({ key: SPAN_ATTRIBUTES.SERVER_NAME }),
|
||||
op: '=',
|
||||
value: 'test-domain',
|
||||
}),
|
||||
|
||||
@@ -638,7 +638,7 @@ export const getEndPointsQueryPayload = (
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
key: SPAN_ATTRIBUTES.SERVER_NAME,
|
||||
type: 'tag',
|
||||
type: '',
|
||||
},
|
||||
op: '=',
|
||||
value: domainName,
|
||||
@@ -685,7 +685,7 @@ export const getEndPointsQueryPayload = (
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
key: SPAN_ATTRIBUTES.SERVER_NAME,
|
||||
type: 'tag',
|
||||
type: '',
|
||||
},
|
||||
op: '=',
|
||||
value: domainName,
|
||||
@@ -733,7 +733,7 @@ export const getEndPointsQueryPayload = (
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
key: SPAN_ATTRIBUTES.SERVER_NAME,
|
||||
type: 'tag',
|
||||
type: '',
|
||||
},
|
||||
op: '=',
|
||||
value: domainName,
|
||||
@@ -780,7 +780,7 @@ export const getEndPointsQueryPayload = (
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
key: SPAN_ATTRIBUTES.SERVER_NAME,
|
||||
type: 'tag',
|
||||
type: '',
|
||||
},
|
||||
op: '=',
|
||||
value: domainName,
|
||||
@@ -1302,7 +1302,7 @@ export const getTopErrorsCoRelationQueryFilters = (
|
||||
{
|
||||
id: 'e8a043b7',
|
||||
key: {
|
||||
key: 'net.peer.name',
|
||||
key: SPAN_ATTRIBUTES.SERVER_NAME,
|
||||
dataType: DataTypes.String,
|
||||
type: '',
|
||||
},
|
||||
@@ -2198,7 +2198,7 @@ export const getEndPointZeroStateQueryPayload = (
|
||||
key: {
|
||||
key: SPAN_ATTRIBUTES.SERVER_NAME,
|
||||
dataType: DataTypes.String,
|
||||
type: 'tag',
|
||||
type: '',
|
||||
},
|
||||
op: '=',
|
||||
value: domainName,
|
||||
@@ -2793,7 +2793,7 @@ export const getStatusCodeBarChartWidgetData = (
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
key: SPAN_ATTRIBUTES.SERVER_NAME,
|
||||
type: 'tag',
|
||||
type: '',
|
||||
},
|
||||
op: '=',
|
||||
value: domainName,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -12,60 +12,30 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
urlPathKeyLegacy = "http.url"
|
||||
serverAddressKeyLegacy = "net.peer.name"
|
||||
|
||||
urlPathKey = "url.full"
|
||||
serverAddressKey = "server.address"
|
||||
derivedKeyHTTPURL = "http_url" // https://signoz.io/docs/traces-management/guides/derived-fields-spans/#http_url
|
||||
derivedKeyHTTPHost = "http_host"
|
||||
)
|
||||
|
||||
var defaultStepInterval = 60 * time.Second
|
||||
|
||||
type SemconvFieldMapping struct {
|
||||
LegacyField string
|
||||
CurrentField string
|
||||
FieldType telemetrytypes.FieldDataType
|
||||
Context telemetrytypes.FieldContext
|
||||
}
|
||||
|
||||
var dualSemconvGroupByKeys = map[string][]qbtypes.GroupByKey{
|
||||
"server": {
|
||||
{
|
||||
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
|
||||
Name: serverAddressKey,
|
||||
FieldDataType: telemetrytypes.FieldDataTypeString,
|
||||
FieldContext: telemetrytypes.FieldContextAttribute,
|
||||
Signal: telemetrytypes.SignalTraces,
|
||||
},
|
||||
var (
|
||||
groupByKeyHTTPHost = qbtypes.GroupByKey{
|
||||
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
|
||||
Name: derivedKeyHTTPHost,
|
||||
FieldDataType: telemetrytypes.FieldDataTypeString,
|
||||
FieldContext: telemetrytypes.FieldContextSpan,
|
||||
Signal: telemetrytypes.SignalTraces,
|
||||
},
|
||||
{
|
||||
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
|
||||
Name: serverAddressKeyLegacy,
|
||||
FieldDataType: telemetrytypes.FieldDataTypeString,
|
||||
FieldContext: telemetrytypes.FieldContextAttribute,
|
||||
Signal: telemetrytypes.SignalTraces,
|
||||
},
|
||||
}
|
||||
groupByKeyHTTPURL = qbtypes.GroupByKey{
|
||||
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
|
||||
Name: derivedKeyHTTPURL,
|
||||
FieldDataType: telemetrytypes.FieldDataTypeString,
|
||||
FieldContext: telemetrytypes.FieldContextSpan,
|
||||
Signal: telemetrytypes.SignalTraces,
|
||||
},
|
||||
},
|
||||
"url": {
|
||||
{
|
||||
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
|
||||
Name: urlPathKey,
|
||||
FieldDataType: telemetrytypes.FieldDataTypeString,
|
||||
FieldContext: telemetrytypes.FieldContextAttribute,
|
||||
Signal: telemetrytypes.SignalTraces,
|
||||
},
|
||||
},
|
||||
{
|
||||
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
|
||||
Name: urlPathKeyLegacy,
|
||||
FieldDataType: telemetrytypes.FieldDataTypeString,
|
||||
FieldContext: telemetrytypes.FieldContextAttribute,
|
||||
Signal: telemetrytypes.SignalTraces,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
func FilterIntermediateColumns(result *qbtypes.QueryRangeResponse) *qbtypes.QueryRangeResponse {
|
||||
if result == nil || result.Data.Results == nil {
|
||||
@@ -114,103 +84,6 @@ func FilterIntermediateColumns(result *qbtypes.QueryRangeResponse) *qbtypes.Quer
|
||||
return result
|
||||
}
|
||||
|
||||
func MergeSemconvColumns(result *qbtypes.QueryRangeResponse) *qbtypes.QueryRangeResponse {
|
||||
if result == nil || result.Data.Results == nil {
|
||||
return result
|
||||
}
|
||||
|
||||
for _, res := range result.Data.Results {
|
||||
scalarData, ok := res.(*qbtypes.ScalarData)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
serverAddressKeyIdx := -1
|
||||
serverAddressKeyLegacyIdx := -1
|
||||
|
||||
for i, col := range scalarData.Columns {
|
||||
if col.Name == serverAddressKey {
|
||||
serverAddressKeyIdx = i
|
||||
} else if col.Name == serverAddressKeyLegacy {
|
||||
serverAddressKeyLegacyIdx = i
|
||||
}
|
||||
}
|
||||
|
||||
if serverAddressKeyIdx == -1 || serverAddressKeyLegacyIdx == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
var newRows [][]any
|
||||
for _, row := range scalarData.Data {
|
||||
if len(row) <= serverAddressKeyIdx || len(row) <= serverAddressKeyLegacyIdx {
|
||||
continue
|
||||
}
|
||||
|
||||
var serverName any
|
||||
if isValidValue(row[serverAddressKeyIdx]) {
|
||||
serverName = row[serverAddressKeyIdx]
|
||||
} else if isValidValue(row[serverAddressKeyLegacyIdx]) {
|
||||
serverName = row[serverAddressKeyLegacyIdx]
|
||||
}
|
||||
|
||||
if serverName != nil {
|
||||
newRow := make([]any, len(row)-1)
|
||||
newRow[0] = serverName
|
||||
|
||||
targetIdx := 1
|
||||
for i, val := range row {
|
||||
if i != serverAddressKeyLegacyIdx && i != serverAddressKeyIdx {
|
||||
if targetIdx < len(newRow) {
|
||||
newRow[targetIdx] = val
|
||||
targetIdx++
|
||||
}
|
||||
}
|
||||
}
|
||||
newRows = append(newRows, newRow)
|
||||
}
|
||||
}
|
||||
|
||||
newColumns := make([]*qbtypes.ColumnDescriptor, len(scalarData.Columns)-1)
|
||||
targetIdx := 0
|
||||
for i, col := range scalarData.Columns {
|
||||
if i == serverAddressKeyIdx {
|
||||
newCol := &qbtypes.ColumnDescriptor{
|
||||
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
|
||||
Name: serverAddressKeyLegacy,
|
||||
FieldDataType: col.FieldDataType,
|
||||
FieldContext: col.FieldContext,
|
||||
Signal: col.Signal,
|
||||
},
|
||||
QueryName: col.QueryName,
|
||||
AggregationIndex: col.AggregationIndex,
|
||||
Meta: col.Meta,
|
||||
Type: col.Type,
|
||||
}
|
||||
newColumns[targetIdx] = newCol
|
||||
targetIdx++
|
||||
} else if i != serverAddressKeyLegacyIdx {
|
||||
newColumns[targetIdx] = col
|
||||
targetIdx++
|
||||
}
|
||||
}
|
||||
|
||||
scalarData.Columns = newColumns
|
||||
scalarData.Data = newRows
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func isValidValue(val any) bool {
|
||||
if val == nil {
|
||||
return false
|
||||
}
|
||||
if str, ok := val.(string); ok {
|
||||
return str != "" && str != "n/a"
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func FilterResponse(results []*qbtypes.QueryRangeResponse) []*qbtypes.QueryRangeResponse {
|
||||
filteredResults := make([]*qbtypes.QueryRangeResponse, 0, len(results))
|
||||
|
||||
@@ -261,7 +134,7 @@ func FilterResponse(results []*qbtypes.QueryRangeResponse) []*qbtypes.QueryRange
|
||||
|
||||
func shouldIncludeSeries(series *qbtypes.TimeSeries) bool {
|
||||
for _, label := range series.Labels {
|
||||
if label.Key.Name == serverAddressKeyLegacy || label.Key.Name == serverAddressKey {
|
||||
if label.Key.Name == derivedKeyHTTPHost {
|
||||
if strVal, ok := label.Value.(string); ok {
|
||||
if net.ParseIP(strVal) != nil {
|
||||
return false
|
||||
@@ -274,12 +147,10 @@ func shouldIncludeSeries(series *qbtypes.TimeSeries) bool {
|
||||
|
||||
func shouldIncludeRow(row *qbtypes.RawRow) bool {
|
||||
if row.Data != nil {
|
||||
for _, key := range []string{serverAddressKeyLegacy, serverAddressKey} {
|
||||
if domainVal, ok := row.Data[key]; ok {
|
||||
if domainStr, ok := domainVal.(string); ok {
|
||||
if net.ParseIP(domainStr) != nil {
|
||||
return false
|
||||
}
|
||||
if domainVal, ok := row.Data[derivedKeyHTTPHost]; ok {
|
||||
if domainStr, ok := domainVal.(string); ok {
|
||||
if net.ParseIP(domainStr) != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,8 +158,8 @@ func shouldIncludeRow(row *qbtypes.RawRow) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func mergeGroupBy(base, additional []qbtypes.GroupByKey) []qbtypes.GroupByKey {
|
||||
return append(base, additional...)
|
||||
func mergeGroupBy(base qbtypes.GroupByKey, additional []qbtypes.GroupByKey) []qbtypes.GroupByKey {
|
||||
return append([]qbtypes.GroupByKey{base}, additional...)
|
||||
}
|
||||
|
||||
func BuildDomainList(req *thirdpartyapitypes.ThirdPartyApiRequest) (*qbtypes.QueryRangeRequest, error) {
|
||||
@@ -354,10 +225,10 @@ func buildEndpointsQuery(req *thirdpartyapitypes.ThirdPartyApiRequest) qbtypes.Q
|
||||
Signal: telemetrytypes.SignalTraces,
|
||||
StepInterval: qbtypes.Step{Duration: defaultStepInterval},
|
||||
Aggregations: []qbtypes.TraceAggregation{
|
||||
{Expression: "count_distinct(http.url)"},
|
||||
{Expression: fmt.Sprintf("count_distinct(%s)", derivedKeyHTTPURL)},
|
||||
},
|
||||
Filter: buildBaseFilter(req.Filter),
|
||||
GroupBy: mergeGroupBy(dualSemconvGroupByKeys["server"], req.GroupBy),
|
||||
GroupBy: mergeGroupBy(groupByKeyHTTPHost, req.GroupBy),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -373,7 +244,7 @@ func buildLastSeenQuery(req *thirdpartyapitypes.ThirdPartyApiRequest) qbtypes.Qu
|
||||
{Expression: "max(timestamp)"},
|
||||
},
|
||||
Filter: buildBaseFilter(req.Filter),
|
||||
GroupBy: mergeGroupBy(dualSemconvGroupByKeys["server"], req.GroupBy),
|
||||
GroupBy: mergeGroupBy(groupByKeyHTTPHost, req.GroupBy),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -389,7 +260,7 @@ func buildRpsQuery(req *thirdpartyapitypes.ThirdPartyApiRequest) qbtypes.QueryEn
|
||||
{Expression: "rate()"},
|
||||
},
|
||||
Filter: buildBaseFilter(req.Filter),
|
||||
GroupBy: mergeGroupBy(dualSemconvGroupByKeys["server"], req.GroupBy),
|
||||
GroupBy: mergeGroupBy(groupByKeyHTTPHost, req.GroupBy),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -407,7 +278,7 @@ func buildErrorQuery(req *thirdpartyapitypes.ThirdPartyApiRequest) qbtypes.Query
|
||||
{Expression: "count()"},
|
||||
},
|
||||
Filter: filter,
|
||||
GroupBy: mergeGroupBy(dualSemconvGroupByKeys["server"], req.GroupBy),
|
||||
GroupBy: mergeGroupBy(groupByKeyHTTPHost, req.GroupBy),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -423,7 +294,7 @@ func buildTotalSpanQuery(req *thirdpartyapitypes.ThirdPartyApiRequest) qbtypes.Q
|
||||
{Expression: "count()"},
|
||||
},
|
||||
Filter: buildBaseFilter(req.Filter),
|
||||
GroupBy: mergeGroupBy(dualSemconvGroupByKeys["server"], req.GroupBy),
|
||||
GroupBy: mergeGroupBy(groupByKeyHTTPHost, req.GroupBy),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -439,7 +310,7 @@ func buildP99Query(req *thirdpartyapitypes.ThirdPartyApiRequest) qbtypes.QueryEn
|
||||
{Expression: "p99(duration_nano)"},
|
||||
},
|
||||
Filter: buildBaseFilter(req.Filter),
|
||||
GroupBy: mergeGroupBy(dualSemconvGroupByKeys["server"], req.GroupBy),
|
||||
GroupBy: mergeGroupBy(groupByKeyHTTPHost, req.GroupBy),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -462,10 +333,10 @@ func buildEndpointsInfoQuery(req *thirdpartyapitypes.ThirdPartyApiRequest) qbtyp
|
||||
Signal: telemetrytypes.SignalTraces,
|
||||
StepInterval: qbtypes.Step{Duration: defaultStepInterval},
|
||||
Aggregations: []qbtypes.TraceAggregation{
|
||||
{Expression: "rate(http.url)"},
|
||||
{Expression: fmt.Sprintf("rate(%s)", derivedKeyHTTPURL)},
|
||||
},
|
||||
Filter: buildBaseFilter(req.Filter),
|
||||
GroupBy: mergeGroupBy(dualSemconvGroupByKeys["url"], req.GroupBy),
|
||||
GroupBy: mergeGroupBy(groupByKeyHTTPURL, req.GroupBy),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -519,8 +390,7 @@ func buildLastSeenInfoQuery(req *thirdpartyapitypes.ThirdPartyApiRequest) qbtype
|
||||
}
|
||||
|
||||
func buildBaseFilter(additionalFilter *qbtypes.Filter) *qbtypes.Filter {
|
||||
baseExpression := fmt.Sprintf("(%s EXISTS OR %s EXISTS) AND kind_string = 'Client'",
|
||||
urlPathKeyLegacy, urlPathKey)
|
||||
baseExpression := fmt.Sprintf("%s EXISTS AND kind_string = 'Client'", derivedKeyHTTPURL)
|
||||
|
||||
if additionalFilter != nil && additionalFilter.Expression != "" {
|
||||
// even if it contains kind_string we add with an AND so it doesn't matter if the user is overriding it.
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package thirdpartyapi
|
||||
|
||||
import (
|
||||
"github.com/SigNoz/signoz/pkg/types/thirdpartyapitypes"
|
||||
"testing"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/types/thirdpartyapitypes"
|
||||
|
||||
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -28,7 +29,7 @@ func TestFilterResponse(t *testing.T) {
|
||||
{
|
||||
Labels: []*qbtypes.Label{
|
||||
{
|
||||
Key: telemetrytypes.TelemetryFieldKey{Name: "net.peer.name"},
|
||||
Key: telemetrytypes.TelemetryFieldKey{Name: derivedKeyHTTPHost},
|
||||
Value: "192.168.1.1",
|
||||
},
|
||||
},
|
||||
@@ -36,7 +37,7 @@ func TestFilterResponse(t *testing.T) {
|
||||
{
|
||||
Labels: []*qbtypes.Label{
|
||||
{
|
||||
Key: telemetrytypes.TelemetryFieldKey{Name: "net.peer.name"},
|
||||
Key: telemetrytypes.TelemetryFieldKey{Name: derivedKeyHTTPHost},
|
||||
Value: "example.com",
|
||||
},
|
||||
},
|
||||
@@ -60,7 +61,7 @@ func TestFilterResponse(t *testing.T) {
|
||||
{
|
||||
Labels: []*qbtypes.Label{
|
||||
{
|
||||
Key: telemetrytypes.TelemetryFieldKey{Name: "net.peer.name"},
|
||||
Key: telemetrytypes.TelemetryFieldKey{Name: derivedKeyHTTPHost},
|
||||
Value: "example.com",
|
||||
},
|
||||
},
|
||||
@@ -84,12 +85,12 @@ func TestFilterResponse(t *testing.T) {
|
||||
Rows: []*qbtypes.RawRow{
|
||||
{
|
||||
Data: map[string]any{
|
||||
"net.peer.name": "192.168.1.1",
|
||||
derivedKeyHTTPHost: "192.168.1.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Data: map[string]any{
|
||||
"net.peer.name": "example.com",
|
||||
derivedKeyHTTPHost: "example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -106,7 +107,7 @@ func TestFilterResponse(t *testing.T) {
|
||||
Rows: []*qbtypes.RawRow{
|
||||
{
|
||||
Data: map[string]any{
|
||||
"net.peer.name": "example.com",
|
||||
derivedKeyHTTPHost: "example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -4996,7 +4996,6 @@ func (aH *APIHandler) getDomainList(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
result = thirdpartyapi.MergeSemconvColumns(result)
|
||||
result = thirdpartyapi.FilterIntermediateColumns(result)
|
||||
|
||||
// Filter IP addresses if ShowIp is false
|
||||
@@ -5053,7 +5052,6 @@ func (aH *APIHandler) getDomainInfo(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
result = thirdpartyapi.MergeSemconvColumns(result)
|
||||
result = thirdpartyapi.FilterIntermediateColumns(result)
|
||||
|
||||
// Filter IP addresses if ShowIp is false
|
||||
|
||||
Reference in New Issue
Block a user