mirror of
https://github.com/SigNoz/signoz.git
synced 2026-02-12 12:32:04 +00:00
Compare commits
23 Commits
test/uplot
...
feat/histo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccf337710a | ||
|
|
0d9154ca72 | ||
|
|
68ea28cf6b | ||
|
|
3726c0aac1 | ||
|
|
dae2d3239b | ||
|
|
0c660f8618 | ||
|
|
55d095304d | ||
|
|
3f467bfe9e | ||
|
|
eb8e1307e5 | ||
|
|
304fcb1c10 | ||
|
|
008d6b5f35 | ||
|
|
eba011c2bb | ||
|
|
6c0843595a | ||
|
|
703b221dfe | ||
|
|
9f13086214 | ||
|
|
20e58db10d | ||
|
|
974bfcd732 | ||
|
|
e6d89465da | ||
|
|
a634ae9b66 | ||
|
|
bb1f5ba29f | ||
|
|
30b3a68154 | ||
|
|
08aa8759ba | ||
|
|
c941233723 |
@@ -12,8 +12,6 @@ export interface MockUPlotInstance {
|
||||
export interface MockUPlotPaths {
|
||||
spline: jest.Mock;
|
||||
bars: jest.Mock;
|
||||
linear: jest.Mock;
|
||||
stepped: jest.Mock;
|
||||
}
|
||||
|
||||
// Create mock instance methods
|
||||
@@ -25,23 +23,10 @@ const createMockUPlotInstance = (): MockUPlotInstance => ({
|
||||
setSeries: jest.fn(),
|
||||
});
|
||||
|
||||
// Path builder: (self, seriesIdx, idx0, idx1) => paths or null
|
||||
const createMockPathBuilder = (name: string): jest.Mock =>
|
||||
jest.fn(() => ({
|
||||
name, // To test if the correct pathBuilder is used
|
||||
stroke: jest.fn(),
|
||||
fill: jest.fn(),
|
||||
clip: jest.fn(),
|
||||
}));
|
||||
|
||||
// Create mock paths - linear, spline, stepped needed by UPlotSeriesBuilder.getPathBuilder
|
||||
const mockPaths = {
|
||||
spline: jest.fn(() => createMockPathBuilder('spline')),
|
||||
bars: jest.fn(() => createMockPathBuilder('bars')),
|
||||
linear: jest.fn(() => createMockPathBuilder('linear')),
|
||||
stepped: jest.fn((opts?: { align?: number }) =>
|
||||
createMockPathBuilder(`stepped-(${opts?.align ?? 0})`),
|
||||
),
|
||||
// Create mock paths
|
||||
const mockPaths: MockUPlotPaths = {
|
||||
spline: jest.fn(),
|
||||
bars: jest.fn(),
|
||||
};
|
||||
|
||||
// Mock static methods
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { LoadingOutlined } from '@ant-design/icons';
|
||||
import { Spin, Table, Typography } from 'antd';
|
||||
import { Spin, Table } from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import cx from 'classnames';
|
||||
import QuerySearch from 'components/QueryBuilderV2/QueryV2/QuerySearch/QuerySearch';
|
||||
@@ -14,11 +14,13 @@ import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations
|
||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||
import { useListOverview } from 'hooks/thirdPartyApis/useListOverview';
|
||||
import { get } from 'lodash-es';
|
||||
import { MoveUpRight } from 'lucide-react';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { HandleChangeQueryDataV5 } from 'types/common/operations.types';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import DOCLINKS from 'utils/docLinks';
|
||||
|
||||
import { ApiMonitoringHardcodedAttributeKeys } from '../../constants';
|
||||
import { DEFAULT_PARAMS, useApiMonitoringParams } from '../../queryParams';
|
||||
@@ -125,51 +127,67 @@ function DomainList(): JSX.Element {
|
||||
hardcodedAttributeKeys={ApiMonitoringHardcodedAttributeKeys}
|
||||
/>
|
||||
</div>
|
||||
<Table
|
||||
className={cx('api-monitoring-domain-list-table')}
|
||||
dataSource={isFetching || isLoading ? [] : formattedDataForTable}
|
||||
columns={columnsConfig}
|
||||
loading={{
|
||||
spinning: isFetching || isLoading,
|
||||
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
|
||||
}}
|
||||
locale={{
|
||||
emptyText:
|
||||
isFetching || isLoading ? null : (
|
||||
<div className="no-filtered-domains-message-container">
|
||||
<div className="no-filtered-domains-message-content">
|
||||
<img
|
||||
src="/Icons/emptyState.svg"
|
||||
alt="thinking-emoji"
|
||||
className="empty-state-svg"
|
||||
/>
|
||||
{!isFetching && !isLoading && formattedDataForTable.length === 0 && (
|
||||
<div className="no-filtered-domains-message-container">
|
||||
<div className="no-filtered-domains-message-content">
|
||||
<img
|
||||
src="/Icons/emptyState.svg"
|
||||
alt="thinking-emoji"
|
||||
className="empty-state-svg"
|
||||
/>
|
||||
|
||||
<Typography.Text className="no-filtered-domains-message">
|
||||
This query had no results. Edit your query and try again!
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<div className="no-filtered-domains-message">
|
||||
<div className="no-domain-title">
|
||||
No External API calls detected with applied filters.
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
scroll={{ x: true }}
|
||||
tableLayout="fixed"
|
||||
onRow={(record, index): { onClick: () => void; className: string } => ({
|
||||
onClick: (): void => {
|
||||
if (index !== undefined) {
|
||||
const dataIndex = formattedDataForTable.findIndex(
|
||||
(item) => item.key === record.key,
|
||||
);
|
||||
setSelectedDomainIndex(dataIndex);
|
||||
setParams({ selectedDomain: record.domainName });
|
||||
logEvent('API Monitoring: Domain name row clicked', {});
|
||||
}
|
||||
},
|
||||
className: 'expanded-clickable-row',
|
||||
})}
|
||||
rowClassName={(_, index): string =>
|
||||
index % 2 === 0 ? 'table-row-dark' : 'table-row-light'
|
||||
}
|
||||
/>
|
||||
<div className="no-domain-subtitle">
|
||||
Ensure all HTTP client spans are being sent with kind as{' '}
|
||||
<span className="attribute">Client</span> and url set in{' '}
|
||||
<span className="attribute">url.full</span> or{' '}
|
||||
<span className="attribute">http.url</span> attribute.
|
||||
</div>
|
||||
<a
|
||||
href={DOCLINKS.EXTERNAL_API_MONITORING}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="external-api-doc-link"
|
||||
>
|
||||
Learn how External API monitoring works in SigNoz{' '}
|
||||
<MoveUpRight size={14} />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{(isFetching || isLoading || formattedDataForTable.length > 0) && (
|
||||
<Table
|
||||
className="api-monitoring-domain-list-table"
|
||||
dataSource={isFetching || isLoading ? [] : formattedDataForTable}
|
||||
columns={columnsConfig}
|
||||
loading={{
|
||||
spinning: isFetching || isLoading,
|
||||
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
|
||||
}}
|
||||
scroll={{ x: true }}
|
||||
tableLayout="fixed"
|
||||
onRow={(record, index): { onClick: () => void; className: string } => ({
|
||||
onClick: (): void => {
|
||||
if (index !== undefined) {
|
||||
const dataIndex = formattedDataForTable.findIndex(
|
||||
(item) => item.key === record.key,
|
||||
);
|
||||
setSelectedDomainIndex(dataIndex);
|
||||
setParams({ selectedDomain: record.domainName });
|
||||
logEvent('API Monitoring: Domain name row clicked', {});
|
||||
}
|
||||
},
|
||||
className: 'expanded-clickable-row',
|
||||
})}
|
||||
rowClassName={(_, index): string =>
|
||||
index % 2 === 0 ? 'table-row-dark' : 'table-row-light'
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{selectedDomainIndex !== -1 && (
|
||||
<DomainDetails
|
||||
domainData={formattedDataForTable[selectedDomainIndex]}
|
||||
|
||||
@@ -180,10 +180,59 @@
|
||||
|
||||
.no-filtered-domains-message {
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-direction: column;
|
||||
|
||||
.no-domain-title {
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 20px; /* 142.857% */
|
||||
}
|
||||
|
||||
.no-domain-subtitle {
|
||||
color: var(--bg-vanilla-400, #c0c1c3);
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 20px; /* 142.857% */
|
||||
|
||||
.attribute {
|
||||
font-family: 'Space Mono';
|
||||
}
|
||||
}
|
||||
|
||||
.external-api-doc-link {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lightMode {
|
||||
.no-filtered-domains-message-container {
|
||||
.no-filtered-domains-message-content {
|
||||
.no-filtered-domains-message {
|
||||
.no-domain-title {
|
||||
color: var(--text-ink-500);
|
||||
}
|
||||
|
||||
.no-domain-subtitle {
|
||||
color: var(--text-ink-400);
|
||||
|
||||
.attribute {
|
||||
font-family: 'Space Mono';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.api-monitoring-domain-list-table {
|
||||
.ant-table {
|
||||
.ant-table-thead > tr > th {
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import { useCallback, useLayoutEffect, useMemo, useRef } from 'react';
|
||||
import ChartWrapper from 'container/DashboardContainer/visualization/charts/ChartWrapper/ChartWrapper';
|
||||
import BarChartTooltip from 'lib/uPlotV2/components/Tooltip/BarChartTooltip';
|
||||
import {
|
||||
BarTooltipProps,
|
||||
TooltipRenderArgs,
|
||||
} from 'lib/uPlotV2/components/types';
|
||||
import { has } from 'lodash-es';
|
||||
import uPlot from 'uplot';
|
||||
|
||||
import { BarChartProps } from '../types';
|
||||
import { stack } from './stackUtils';
|
||||
|
||||
/** Returns true if the series at the given index is hidden (e.g. via legend toggle) */
|
||||
function isSeriesHidden(plot: uPlot, seriesIndex: number): boolean {
|
||||
return !plot.series[seriesIndex]?.show;
|
||||
}
|
||||
|
||||
export default function BarChart(props: BarChartProps): JSX.Element {
|
||||
const { children, isStackedBarChart, config, data, ...rest } = props;
|
||||
|
||||
// Store unstacked source data so uPlot hooks can access it (hooks run outside React's render cycle)
|
||||
const unstackedDataRef = useRef<uPlot.AlignedData | null>(null);
|
||||
unstackedDataRef.current = isStackedBarChart ? data : null;
|
||||
|
||||
// Prevents re-entrant calls when we update chart data (avoids infinite loop in setData hook)
|
||||
const isUpdatingChartRef = useRef(false);
|
||||
|
||||
const chartData = useMemo((): uPlot.AlignedData => {
|
||||
if (!isStackedBarChart || !data || data.length < 2) {
|
||||
return data as uPlot.AlignedData;
|
||||
}
|
||||
const noSeriesHidden = (): boolean => false; // include all series in initial stack
|
||||
const { data: stacked } = stack(data as uPlot.AlignedData, noSeriesHidden);
|
||||
return stacked;
|
||||
}, [data, isStackedBarChart]);
|
||||
|
||||
const applyStackingToChart = useCallback((plot: uPlot): void => {
|
||||
const unstacked = unstackedDataRef.current;
|
||||
const hasValidData =
|
||||
unstacked && plot.data && unstacked[0]?.length === plot.data[0]?.length;
|
||||
|
||||
if (!hasValidData || isUpdatingChartRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const shouldExcludeSeries = (idx: number): boolean =>
|
||||
isSeriesHidden(plot, idx);
|
||||
const { data: stacked, bands } = stack(unstacked, shouldExcludeSeries);
|
||||
|
||||
plot.delBand(null);
|
||||
bands.forEach((band: uPlot.Band) => plot.addBand(band));
|
||||
|
||||
isUpdatingChartRef.current = true;
|
||||
plot.setData(stacked);
|
||||
isUpdatingChartRef.current = false;
|
||||
}, []);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!isStackedBarChart || !config) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const onDataChange = (plot: uPlot): void => {
|
||||
if (!isUpdatingChartRef.current) {
|
||||
applyStackingToChart(plot);
|
||||
}
|
||||
};
|
||||
|
||||
const onSeriesVisibilityChange = (
|
||||
plot: uPlot,
|
||||
_seriesIdx: number | null,
|
||||
opts: uPlot.Series,
|
||||
): void => {
|
||||
if (has(opts, 'focus')) {
|
||||
return;
|
||||
}
|
||||
applyStackingToChart(plot);
|
||||
};
|
||||
|
||||
const removeSetDataHook = config.addHook('setData', onDataChange);
|
||||
const removeSetSeriesHook = config.addHook(
|
||||
'setSeries',
|
||||
onSeriesVisibilityChange,
|
||||
);
|
||||
|
||||
return (): void => {
|
||||
removeSetDataHook?.();
|
||||
removeSetSeriesHook?.();
|
||||
};
|
||||
}, [isStackedBarChart, config, applyStackingToChart]);
|
||||
|
||||
const renderTooltip = useCallback(
|
||||
(props: TooltipRenderArgs): React.ReactNode => {
|
||||
const tooltipProps: BarTooltipProps = {
|
||||
...props,
|
||||
timezone: rest.timezone,
|
||||
yAxisUnit: rest.yAxisUnit,
|
||||
decimalPrecision: rest.decimalPrecision,
|
||||
isStackedBarChart: isStackedBarChart,
|
||||
};
|
||||
return <BarChartTooltip {...tooltipProps} />;
|
||||
},
|
||||
[rest.timezone, rest.yAxisUnit, rest.decimalPrecision, isStackedBarChart],
|
||||
);
|
||||
|
||||
return (
|
||||
<ChartWrapper
|
||||
{...rest}
|
||||
config={config}
|
||||
data={chartData}
|
||||
renderTooltip={renderTooltip}
|
||||
>
|
||||
{children}
|
||||
</ChartWrapper>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import uPlot, { AlignedData } from 'uplot';
|
||||
|
||||
/**
|
||||
* Stack data cumulatively (top-down: first series = top, last = bottom).
|
||||
* When omit(i) returns true for a series index, that series is excluded from stacking.
|
||||
*/
|
||||
export function stack(
|
||||
data: AlignedData,
|
||||
omit: (seriesIndex: number) => boolean,
|
||||
): { data: AlignedData; bands: uPlot.Band[] } {
|
||||
const d0Len = data[0].length;
|
||||
const n = data.length - 1;
|
||||
const data2: (number | null)[][] = Array(n);
|
||||
const accum = Array(d0Len).fill(0) as number[];
|
||||
|
||||
// Accumulate from last series upward: last = raw, first = total
|
||||
for (let i = n; i >= 1; i--) {
|
||||
const seriesData = data[i] as (number | null)[];
|
||||
if (omit(i)) {
|
||||
data2[i - 1] = seriesData;
|
||||
} else {
|
||||
data2[i - 1] = seriesData.map((v, idx) => {
|
||||
const val = v == null ? 0 : Number(v);
|
||||
return (accum[idx] += val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const bands: uPlot.Band[] = [];
|
||||
// Bands: [upper, lower] - fill between consecutive visible series
|
||||
for (let i = 1; i < data.length; i++) {
|
||||
if (!omit(i)) {
|
||||
const nextIdx = data.findIndex((_, j) => j > i && !omit(j));
|
||||
if (nextIdx >= 1) {
|
||||
bands.push({ series: [i, nextIdx] });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
data: [data[0], ...data2] as AlignedData,
|
||||
bands,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns band indices for initial stacked state (no series omitted).
|
||||
* Top-down: first series at top, band fills between consecutive series.
|
||||
* uPlot band format: [upperSeriesIdx, lowerSeriesIdx].
|
||||
*/
|
||||
export function getInitialStackedBands(seriesCount: number): uPlot.Band[] {
|
||||
const bands: uPlot.Band[] = [];
|
||||
for (let i = 1; i < seriesCount; i++) {
|
||||
bands.push({ series: [i, i + 1] });
|
||||
}
|
||||
return bands;
|
||||
}
|
||||
@@ -23,6 +23,7 @@ export default function ChartWrapper({
|
||||
width: containerWidth,
|
||||
height: containerHeight,
|
||||
showTooltip = true,
|
||||
showLegend = true,
|
||||
canPinTooltip = false,
|
||||
syncMode,
|
||||
syncKey,
|
||||
@@ -36,6 +37,9 @@ export default function ChartWrapper({
|
||||
|
||||
const legendComponent = useCallback(
|
||||
(averageLegendWidth: number): React.ReactNode => {
|
||||
if (!showLegend) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Legend
|
||||
config={config}
|
||||
@@ -44,7 +48,7 @@ export default function ChartWrapper({
|
||||
/>
|
||||
);
|
||||
},
|
||||
[config, legendConfig.position],
|
||||
[config, legendConfig.position, showLegend],
|
||||
);
|
||||
|
||||
const renderTooltipCallback = useCallback(
|
||||
@@ -60,6 +64,7 @@ export default function ChartWrapper({
|
||||
return (
|
||||
<PlotContextProvider>
|
||||
<ChartLayout
|
||||
showLegend={showLegend}
|
||||
config={config}
|
||||
containerWidth={containerWidth}
|
||||
containerHeight={containerHeight}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { useCallback } from 'react';
|
||||
import ChartWrapper from 'container/DashboardContainer/visualization/charts/ChartWrapper/ChartWrapper';
|
||||
import HistogramTooltip from 'lib/uPlotV2/components/Tooltip/HistogramTooltip';
|
||||
import { buildTooltipContent } from 'lib/uPlotV2/components/Tooltip/utils';
|
||||
import {
|
||||
HistogramTooltipProps,
|
||||
TooltipRenderArgs,
|
||||
} from 'lib/uPlotV2/components/types';
|
||||
|
||||
import { HistogramChartProps } from '../types';
|
||||
|
||||
export default function Histogram(props: HistogramChartProps): JSX.Element {
|
||||
const {
|
||||
children,
|
||||
renderTooltip: customRenderTooltip,
|
||||
isQueriesMerged,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const renderTooltip = useCallback(
|
||||
(props: TooltipRenderArgs): React.ReactNode => {
|
||||
if (customRenderTooltip) {
|
||||
return customRenderTooltip(props);
|
||||
}
|
||||
const content = buildTooltipContent({
|
||||
data: props.uPlotInstance.data,
|
||||
series: props.uPlotInstance.series,
|
||||
dataIndexes: props.dataIndexes,
|
||||
activeSeriesIndex: props.seriesIndex,
|
||||
uPlotInstance: props.uPlotInstance,
|
||||
yAxisUnit: rest.yAxisUnit ?? '',
|
||||
decimalPrecision: rest.decimalPrecision,
|
||||
});
|
||||
const tooltipProps: HistogramTooltipProps = {
|
||||
...props,
|
||||
timezone: rest.timezone,
|
||||
yAxisUnit: rest.yAxisUnit,
|
||||
decimalPrecision: rest.decimalPrecision,
|
||||
content,
|
||||
};
|
||||
return <HistogramTooltip {...tooltipProps} />;
|
||||
},
|
||||
[customRenderTooltip, rest.timezone, rest.yAxisUnit, rest.decimalPrecision],
|
||||
);
|
||||
|
||||
return (
|
||||
<ChartWrapper
|
||||
showLegend={!isQueriesMerged}
|
||||
{...rest}
|
||||
renderTooltip={renderTooltip}
|
||||
>
|
||||
{children}
|
||||
</ChartWrapper>
|
||||
);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ interface BaseChartProps {
|
||||
width: number;
|
||||
height: number;
|
||||
showTooltip?: boolean;
|
||||
showLegend?: boolean;
|
||||
timezone: string;
|
||||
canPinTooltip?: boolean;
|
||||
yAxisUnit?: string;
|
||||
@@ -17,6 +18,7 @@ interface BaseChartProps {
|
||||
interface UPlotBasedChartProps {
|
||||
config: UPlotConfigBuilder;
|
||||
data: uPlot.AlignedData;
|
||||
legendConfig: LegendConfig;
|
||||
syncMode?: DashboardCursorSync;
|
||||
syncKey?: string;
|
||||
plotRef?: (plot: uPlot | null) => void;
|
||||
@@ -26,14 +28,20 @@ interface UPlotBasedChartProps {
|
||||
}
|
||||
|
||||
export interface TimeSeriesChartProps
|
||||
extends BaseChartProps,
|
||||
UPlotBasedChartProps {}
|
||||
|
||||
export interface HistogramChartProps
|
||||
extends BaseChartProps,
|
||||
UPlotBasedChartProps {
|
||||
legendConfig: LegendConfig;
|
||||
isQueriesMerged?: boolean;
|
||||
}
|
||||
|
||||
export interface BarChartProps extends BaseChartProps, UPlotBasedChartProps {
|
||||
legendConfig: LegendConfig;
|
||||
isStackedBarChart?: boolean;
|
||||
}
|
||||
|
||||
export type ChartProps = TimeSeriesChartProps | BarChartProps;
|
||||
export type ChartProps =
|
||||
| TimeSeriesChartProps
|
||||
| BarChartProps
|
||||
| HistogramChartProps;
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { useMemo } from 'react';
|
||||
import cx from 'classnames';
|
||||
import { calculateChartDimensions } from 'container/DashboardContainer/visualization/charts/utils';
|
||||
import { MAX_LEGEND_WIDTH } from 'lib/uPlotV2/components/Legend/Legend';
|
||||
import { LegendConfig, LegendPosition } from 'lib/uPlotV2/components/types';
|
||||
import { UPlotConfigBuilder } from 'lib/uPlotV2/config/UPlotConfigBuilder';
|
||||
|
||||
import './ChartLayout.styles.scss';
|
||||
|
||||
export interface ChartLayoutProps {
|
||||
showLegend?: boolean;
|
||||
legendComponent: (legendPerSet: number) => React.ReactNode;
|
||||
children: (props: {
|
||||
chartWidth: number;
|
||||
@@ -20,6 +22,7 @@ export interface ChartLayoutProps {
|
||||
config: UPlotConfigBuilder;
|
||||
}
|
||||
export default function ChartLayout({
|
||||
showLegend = true,
|
||||
legendComponent,
|
||||
children,
|
||||
layoutChildren,
|
||||
@@ -30,6 +33,15 @@ export default function ChartLayout({
|
||||
}: ChartLayoutProps): JSX.Element {
|
||||
const chartDimensions = useMemo(
|
||||
() => {
|
||||
if (!showLegend) {
|
||||
return {
|
||||
width: containerWidth,
|
||||
height: containerHeight,
|
||||
legendWidth: 0,
|
||||
legendHeight: 0,
|
||||
averageLegendWidth: MAX_LEGEND_WIDTH,
|
||||
};
|
||||
}
|
||||
const legendItemsMap = config.getLegendItems();
|
||||
const seriesLabels = Object.values(legendItemsMap)
|
||||
.map((item) => item.label)
|
||||
@@ -42,7 +54,7 @@ export default function ChartLayout({
|
||||
});
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[containerWidth, containerHeight, legendConfig],
|
||||
[containerWidth, containerHeight, legendConfig, showLegend],
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -60,15 +72,17 @@ export default function ChartLayout({
|
||||
averageLegendWidth: chartDimensions.averageLegendWidth,
|
||||
})}
|
||||
</div>
|
||||
<div
|
||||
className="chart-layout__legend-wrapper"
|
||||
style={{
|
||||
height: chartDimensions.legendHeight,
|
||||
width: chartDimensions.legendWidth,
|
||||
}}
|
||||
>
|
||||
{legendComponent(chartDimensions.averageLegendWidth)}
|
||||
</div>
|
||||
{showLegend && (
|
||||
<div
|
||||
className="chart-layout__legend-wrapper"
|
||||
style={{
|
||||
height: chartDimensions.legendHeight,
|
||||
width: chartDimensions.legendWidth,
|
||||
}}
|
||||
>
|
||||
{legendComponent(chartDimensions.averageLegendWidth)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{layoutChildren}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { PanelWrapperProps } from 'container/PanelWrapper/panelWrapper.types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { useResizeObserver } from 'hooks/useDimensions';
|
||||
import { LegendPosition } from 'lib/uPlotV2/components/types';
|
||||
import ContextMenu from 'periscope/components/ContextMenu';
|
||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||
import { useTimezone } from 'providers/Timezone';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
import uPlot from 'uplot';
|
||||
import { getTimeRange } from 'utils/getTimeRange';
|
||||
|
||||
import BarChart from '../../charts/BarChart/BarChart';
|
||||
import ChartManager from '../../components/ChartManager/ChartManager';
|
||||
import { usePanelContextMenu } from '../../hooks/usePanelContextMenu';
|
||||
import { prepareBarPanelConfig, prepareBarPanelData } from './utils';
|
||||
|
||||
function BarPanel(props: PanelWrapperProps): JSX.Element {
|
||||
const {
|
||||
panelMode,
|
||||
queryResponse,
|
||||
widget,
|
||||
onDragSelect,
|
||||
isFullViewMode,
|
||||
onToggleModelHandler,
|
||||
} = props;
|
||||
const uPlotRef = useRef<uPlot | null>(null);
|
||||
const { toScrollWidgetId, setToScrollWidgetId } = useDashboard();
|
||||
const graphRef = useRef<HTMLDivElement>(null);
|
||||
const [minTimeScale, setMinTimeScale] = useState<number>();
|
||||
const [maxTimeScale, setMaxTimeScale] = useState<number>();
|
||||
const containerDimensions = useResizeObserver(graphRef);
|
||||
|
||||
const isDarkMode = useIsDarkMode();
|
||||
const { timezone } = useTimezone();
|
||||
|
||||
useEffect(() => {
|
||||
if (toScrollWidgetId === widget.id) {
|
||||
graphRef.current?.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'center',
|
||||
});
|
||||
graphRef.current?.focus();
|
||||
setToScrollWidgetId('');
|
||||
}
|
||||
}, [toScrollWidgetId, setToScrollWidgetId, widget.id]);
|
||||
|
||||
useEffect((): void => {
|
||||
const { startTime, endTime } = getTimeRange(queryResponse);
|
||||
|
||||
setMinTimeScale(startTime);
|
||||
setMaxTimeScale(endTime);
|
||||
}, [queryResponse]);
|
||||
|
||||
const {
|
||||
coordinates,
|
||||
popoverPosition,
|
||||
onClose,
|
||||
menuItemsConfig,
|
||||
clickHandlerWithContextMenu,
|
||||
} = usePanelContextMenu({
|
||||
widget,
|
||||
queryResponse,
|
||||
});
|
||||
|
||||
const config = useMemo(() => {
|
||||
return prepareBarPanelConfig({
|
||||
widget,
|
||||
isDarkMode,
|
||||
currentQuery: widget.query,
|
||||
onClick: clickHandlerWithContextMenu,
|
||||
onDragSelect,
|
||||
apiResponse: queryResponse?.data?.payload as MetricRangePayloadProps,
|
||||
timezone,
|
||||
panelMode,
|
||||
minTimeScale: minTimeScale,
|
||||
maxTimeScale: maxTimeScale,
|
||||
});
|
||||
}, [
|
||||
widget,
|
||||
isDarkMode,
|
||||
queryResponse?.data?.payload,
|
||||
clickHandlerWithContextMenu,
|
||||
onDragSelect,
|
||||
minTimeScale,
|
||||
maxTimeScale,
|
||||
timezone,
|
||||
panelMode,
|
||||
]);
|
||||
|
||||
const chartData = useMemo(() => {
|
||||
if (!queryResponse?.data?.payload) {
|
||||
return [];
|
||||
}
|
||||
return prepareBarPanelData(queryResponse?.data?.payload);
|
||||
}, [queryResponse?.data?.payload]);
|
||||
|
||||
const layoutChildren = useMemo(() => {
|
||||
if (!isFullViewMode) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<ChartManager
|
||||
config={config}
|
||||
alignedData={chartData}
|
||||
yAxisUnit={widget.yAxisUnit}
|
||||
onCancel={onToggleModelHandler}
|
||||
/>
|
||||
);
|
||||
}, [
|
||||
isFullViewMode,
|
||||
config,
|
||||
chartData,
|
||||
widget.yAxisUnit,
|
||||
onToggleModelHandler,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div style={{ height: '100%', width: '100%' }} ref={graphRef}>
|
||||
{containerDimensions.width > 0 && containerDimensions.height > 0 && (
|
||||
<BarChart
|
||||
config={config}
|
||||
legendConfig={{
|
||||
position: widget?.legendPosition ?? LegendPosition.BOTTOM,
|
||||
}}
|
||||
plotRef={(plot: uPlot | null): void => {
|
||||
uPlotRef.current = plot;
|
||||
}}
|
||||
onDestroy={(): void => {
|
||||
uPlotRef.current = null;
|
||||
}}
|
||||
yAxisUnit={widget.yAxisUnit}
|
||||
decimalPrecision={widget.decimalPrecision}
|
||||
timezone={timezone.value}
|
||||
data={chartData as uPlot.AlignedData}
|
||||
width={containerDimensions.width}
|
||||
height={containerDimensions.height}
|
||||
layoutChildren={layoutChildren}
|
||||
isStackedBarChart={widget.stackedBarChart ?? false}
|
||||
>
|
||||
<ContextMenu
|
||||
coordinates={coordinates}
|
||||
popoverPosition={popoverPosition}
|
||||
title={menuItemsConfig.header as string}
|
||||
items={menuItemsConfig.items}
|
||||
onClose={onClose}
|
||||
/>
|
||||
</BarChart>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default BarPanel;
|
||||
@@ -0,0 +1,108 @@
|
||||
import { Timezone } from 'components/CustomTimePicker/timezoneUtils';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { getInitialStackedBands } from 'container/DashboardContainer/visualization/charts/BarChart/stackUtils';
|
||||
import { getLegend } from 'lib/dashboard/getQueryResults';
|
||||
import getLabelName from 'lib/getLabelName';
|
||||
import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
|
||||
import {
|
||||
DrawStyle,
|
||||
LineInterpolation,
|
||||
LineStyle,
|
||||
VisibilityMode,
|
||||
} from 'lib/uPlotV2/config/types';
|
||||
import { UPlotConfigBuilder } from 'lib/uPlotV2/config/UPlotConfigBuilder';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { QueryData } from 'types/api/widgets/getQuery';
|
||||
import { AlignedData } from 'uplot';
|
||||
|
||||
import { PanelMode } from '../types';
|
||||
import { fillMissingXAxisTimestamps, getXAxisTimestamps } from '../utils';
|
||||
import { buildBaseConfig } from '../utils/baseConfigBuilder';
|
||||
|
||||
export function prepareBarPanelData(
|
||||
apiResponse: MetricRangePayloadProps,
|
||||
): AlignedData {
|
||||
const seriesList = apiResponse?.data?.result || [];
|
||||
const timestampArr = getXAxisTimestamps(seriesList);
|
||||
const yAxisValuesArr = fillMissingXAxisTimestamps(timestampArr, seriesList);
|
||||
return [timestampArr, ...yAxisValuesArr];
|
||||
}
|
||||
|
||||
export function prepareBarPanelConfig({
|
||||
widget,
|
||||
isDarkMode,
|
||||
currentQuery,
|
||||
onClick,
|
||||
onDragSelect,
|
||||
apiResponse,
|
||||
timezone,
|
||||
panelMode,
|
||||
minTimeScale,
|
||||
maxTimeScale,
|
||||
}: {
|
||||
widget: Widgets;
|
||||
isDarkMode: boolean;
|
||||
currentQuery: Query;
|
||||
onClick: OnClickPluginOpts['onClick'];
|
||||
onDragSelect: (startTime: number, endTime: number) => void;
|
||||
apiResponse: MetricRangePayloadProps;
|
||||
timezone: Timezone;
|
||||
panelMode: PanelMode;
|
||||
minTimeScale?: number;
|
||||
maxTimeScale?: number;
|
||||
}): UPlotConfigBuilder {
|
||||
const builder = buildBaseConfig({
|
||||
widget,
|
||||
isDarkMode,
|
||||
onClick,
|
||||
onDragSelect,
|
||||
apiResponse,
|
||||
timezone,
|
||||
panelMode,
|
||||
panelType: PANEL_TYPES.BAR,
|
||||
minTimeScale,
|
||||
maxTimeScale,
|
||||
});
|
||||
|
||||
builder.setCursor({
|
||||
focus: {
|
||||
prox: 1e3,
|
||||
},
|
||||
});
|
||||
|
||||
if (widget.stackedBarChart) {
|
||||
const seriesCount = (apiResponse?.data?.result?.length ?? 0) + 1; // +1 for 1-based uPlot series indices
|
||||
builder.setBands(getInitialStackedBands(seriesCount));
|
||||
}
|
||||
|
||||
const seriesList: QueryData[] = apiResponse?.data?.result || [];
|
||||
seriesList.forEach((series) => {
|
||||
const baseLabelName = getLabelName(
|
||||
series.metric,
|
||||
series.queryName || '', // query
|
||||
series.legend || '',
|
||||
);
|
||||
|
||||
const label = currentQuery
|
||||
? getLegend(series, currentQuery, baseLabelName)
|
||||
: baseLabelName;
|
||||
|
||||
builder.addSeries({
|
||||
scaleKey: 'y',
|
||||
drawStyle: DrawStyle.Bar,
|
||||
panelType: PANEL_TYPES.BAR,
|
||||
label: label,
|
||||
colorMapping: widget.customLegendColors ?? {},
|
||||
spanGaps: false,
|
||||
lineStyle: LineStyle.Solid,
|
||||
lineInterpolation: LineInterpolation.Spline,
|
||||
showPoints: VisibilityMode.Never,
|
||||
pointSize: 5,
|
||||
isDarkMode,
|
||||
});
|
||||
});
|
||||
|
||||
return builder;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { PanelWrapperProps } from 'container/PanelWrapper/panelWrapper.types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { useResizeObserver } from 'hooks/useDimensions';
|
||||
import { LegendPosition } from 'lib/uPlotV2/components/types';
|
||||
import { DashboardCursorSync } from 'lib/uPlotV2/plugins/TooltipPlugin/types';
|
||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||
import { useTimezone } from 'providers/Timezone';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
import uPlot from 'uplot';
|
||||
|
||||
import Histogram from '../../charts/Histogram/Histogram';
|
||||
import ChartManager from '../../components/ChartManager/ChartManager';
|
||||
import {
|
||||
prepareHistogramPanelConfig,
|
||||
prepareHistogramPanelData,
|
||||
} from './utils';
|
||||
|
||||
function HistogramPanel(props: PanelWrapperProps): JSX.Element {
|
||||
const {
|
||||
panelMode,
|
||||
queryResponse,
|
||||
widget,
|
||||
isFullViewMode,
|
||||
onToggleModelHandler,
|
||||
} = props;
|
||||
const uPlotRef = useRef<uPlot | null>(null);
|
||||
const { toScrollWidgetId, setToScrollWidgetId } = useDashboard();
|
||||
const graphRef = useRef<HTMLDivElement>(null);
|
||||
const containerDimensions = useResizeObserver(graphRef);
|
||||
|
||||
const isDarkMode = useIsDarkMode();
|
||||
const { timezone } = useTimezone();
|
||||
|
||||
useEffect(() => {
|
||||
if (toScrollWidgetId === widget.id) {
|
||||
graphRef.current?.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'center',
|
||||
});
|
||||
graphRef.current?.focus();
|
||||
setToScrollWidgetId('');
|
||||
}
|
||||
}, [toScrollWidgetId, setToScrollWidgetId, widget.id]);
|
||||
|
||||
const config = useMemo(() => {
|
||||
return prepareHistogramPanelConfig({
|
||||
widget,
|
||||
isDarkMode,
|
||||
apiResponse: queryResponse?.data?.payload as MetricRangePayloadProps,
|
||||
panelMode,
|
||||
});
|
||||
}, [widget, isDarkMode, queryResponse?.data?.payload, panelMode]);
|
||||
|
||||
const chartData = useMemo(() => {
|
||||
if (!queryResponse?.data?.payload) {
|
||||
return [];
|
||||
}
|
||||
return prepareHistogramPanelData({
|
||||
apiResponse: queryResponse?.data?.payload as MetricRangePayloadProps,
|
||||
bucketWidth: widget?.bucketWidth,
|
||||
bucketCount: widget?.bucketCount,
|
||||
mergeAllActiveQueries: widget?.mergeAllActiveQueries,
|
||||
});
|
||||
}, [
|
||||
queryResponse?.data?.payload,
|
||||
widget?.bucketWidth,
|
||||
widget?.bucketCount,
|
||||
widget?.mergeAllActiveQueries,
|
||||
]);
|
||||
|
||||
const layoutChildren = useMemo(() => {
|
||||
if (!isFullViewMode) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<ChartManager
|
||||
config={config}
|
||||
alignedData={chartData}
|
||||
yAxisUnit={widget.yAxisUnit}
|
||||
onCancel={onToggleModelHandler}
|
||||
/>
|
||||
);
|
||||
}, [
|
||||
isFullViewMode,
|
||||
config,
|
||||
chartData,
|
||||
widget.yAxisUnit,
|
||||
onToggleModelHandler,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div style={{ height: '100%', width: '100%' }} ref={graphRef}>
|
||||
{containerDimensions.width > 0 && containerDimensions.height > 0 && (
|
||||
<Histogram
|
||||
config={config}
|
||||
legendConfig={{
|
||||
position: widget?.legendPosition ?? LegendPosition.BOTTOM,
|
||||
}}
|
||||
plotRef={(plot: uPlot | null): void => {
|
||||
uPlotRef.current = plot;
|
||||
}}
|
||||
onDestroy={(): void => {
|
||||
uPlotRef.current = null;
|
||||
}}
|
||||
isQueriesMerged={widget.mergeAllActiveQueries}
|
||||
yAxisUnit={widget.yAxisUnit}
|
||||
decimalPrecision={widget.decimalPrecision}
|
||||
syncMode={DashboardCursorSync.Crosshair}
|
||||
timezone={timezone.value}
|
||||
data={chartData as uPlot.AlignedData}
|
||||
width={containerDimensions.width}
|
||||
height={containerDimensions.height}
|
||||
layoutChildren={layoutChildren}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default HistogramPanel;
|
||||
@@ -0,0 +1,214 @@
|
||||
import { histogramBucketSizes } from '@grafana/data';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { DEFAULT_BUCKET_COUNT } from 'container/PanelWrapper/constants';
|
||||
import { getLegend } from 'lib/dashboard/getQueryResults';
|
||||
import getLabelName from 'lib/getLabelName';
|
||||
import { DrawStyle, VisibilityMode } from 'lib/uPlotV2/config/types';
|
||||
import { UPlotConfigBuilder } from 'lib/uPlotV2/config/UPlotConfigBuilder';
|
||||
import { incrRoundDn } from 'lib/uPlotV2/utils/scale';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
import { AlignedData } from 'uplot';
|
||||
|
||||
import { PanelMode } from '../types';
|
||||
import { buildBaseConfig } from '../utils/baseConfigBuilder';
|
||||
import {
|
||||
addNullToFirstHistogram,
|
||||
histogram,
|
||||
join,
|
||||
replaceUndefinedWithNull,
|
||||
roundDecimals,
|
||||
} from '../utils/histogram';
|
||||
|
||||
export interface PrepareHistogramPanelDataParams {
|
||||
apiResponse: MetricRangePayloadProps;
|
||||
bucketWidth?: number;
|
||||
bucketCount?: number;
|
||||
mergeAllActiveQueries?: boolean;
|
||||
}
|
||||
|
||||
const BUCKET_OFFSET = 0;
|
||||
const HIST_SORT = (a: number, b: number): number => a - b;
|
||||
|
||||
function extractNumericValues(
|
||||
result: MetricRangePayloadProps['data']['result'],
|
||||
): number[] {
|
||||
const values: number[] = [];
|
||||
for (const item of result) {
|
||||
for (const [, valueStr] of item.values) {
|
||||
values.push(Number.parseFloat(valueStr) || 0);
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
function computeSmallestDelta(sortedValues: number[]): number {
|
||||
if (sortedValues.length <= 1) {
|
||||
return 0;
|
||||
}
|
||||
let smallest = Infinity;
|
||||
for (let i = 1; i < sortedValues.length; i++) {
|
||||
const delta = sortedValues[i] - sortedValues[i - 1];
|
||||
if (delta > 0) {
|
||||
smallest = Math.min(smallest, delta);
|
||||
}
|
||||
}
|
||||
return smallest === Infinity ? 0 : smallest;
|
||||
}
|
||||
|
||||
function selectBucketSize({
|
||||
range,
|
||||
bucketCount,
|
||||
smallestDelta,
|
||||
bucketWidthOverride,
|
||||
}: {
|
||||
range: number;
|
||||
bucketCount: number;
|
||||
smallestDelta: number;
|
||||
bucketWidthOverride?: number;
|
||||
}): number {
|
||||
if (bucketWidthOverride != null && bucketWidthOverride > 0) {
|
||||
return bucketWidthOverride;
|
||||
}
|
||||
const targetSize = range / bucketCount;
|
||||
for (const candidate of histogramBucketSizes) {
|
||||
if (targetSize < candidate && candidate >= smallestDelta) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function buildFrames(
|
||||
result: MetricRangePayloadProps['data']['result'],
|
||||
mergeAllActiveQueries: boolean,
|
||||
): number[][] {
|
||||
const frames: number[][] = result.map((item) =>
|
||||
item.values.map(([, valueStr]) => Number.parseFloat(valueStr) || 0),
|
||||
);
|
||||
if (mergeAllActiveQueries && frames.length > 1) {
|
||||
const first = frames[0];
|
||||
for (let i = 1; i < frames.length; i++) {
|
||||
first.push(...frames[i]);
|
||||
frames[i] = [];
|
||||
}
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
export function prepareHistogramPanelData({
|
||||
apiResponse,
|
||||
bucketWidth,
|
||||
bucketCount: bucketCountProp = DEFAULT_BUCKET_COUNT,
|
||||
mergeAllActiveQueries = false,
|
||||
}: PrepareHistogramPanelDataParams): AlignedData {
|
||||
const bucketCount = bucketCountProp ?? DEFAULT_BUCKET_COUNT;
|
||||
const result = apiResponse.data.result;
|
||||
|
||||
const seriesValues = extractNumericValues(result);
|
||||
if (seriesValues.length === 0) {
|
||||
return [[]];
|
||||
}
|
||||
|
||||
const sorted = [...seriesValues].sort((a, b) => a - b);
|
||||
const min = sorted[0];
|
||||
const max = sorted[sorted.length - 1];
|
||||
const range = max - min;
|
||||
const smallestDelta = computeSmallestDelta(sorted);
|
||||
let bucketSize = selectBucketSize({
|
||||
range,
|
||||
bucketCount,
|
||||
smallestDelta,
|
||||
bucketWidthOverride: bucketWidth,
|
||||
});
|
||||
if (bucketSize <= 0) {
|
||||
bucketSize = range > 0 ? range / bucketCount : 1;
|
||||
}
|
||||
|
||||
const getBucket = (v: number): number =>
|
||||
roundDecimals(incrRoundDn(v - BUCKET_OFFSET, bucketSize) + BUCKET_OFFSET, 9);
|
||||
|
||||
const frames = buildFrames(result, mergeAllActiveQueries);
|
||||
const histograms: AlignedData[] = frames
|
||||
.filter((frame) => frame.length > 0)
|
||||
.map((frame) => histogram(frame, getBucket, HIST_SORT));
|
||||
|
||||
if (histograms.length === 0) {
|
||||
return [[]];
|
||||
}
|
||||
|
||||
const joined = join(histograms);
|
||||
replaceUndefinedWithNull(joined);
|
||||
addNullToFirstHistogram(joined, bucketSize);
|
||||
return joined;
|
||||
}
|
||||
|
||||
export function prepareHistogramPanelConfig({
|
||||
widget,
|
||||
apiResponse,
|
||||
panelMode,
|
||||
isDarkMode,
|
||||
}: {
|
||||
widget: Widgets;
|
||||
apiResponse: MetricRangePayloadProps;
|
||||
panelMode: PanelMode;
|
||||
isDarkMode: boolean;
|
||||
}): UPlotConfigBuilder {
|
||||
const builder = buildBaseConfig({
|
||||
widget,
|
||||
isDarkMode,
|
||||
apiResponse,
|
||||
panelMode,
|
||||
panelType: PANEL_TYPES.HISTOGRAM,
|
||||
});
|
||||
builder.setCursor({
|
||||
drag: {
|
||||
x: false,
|
||||
y: false,
|
||||
setScale: true,
|
||||
},
|
||||
focus: {
|
||||
prox: 1e3,
|
||||
},
|
||||
});
|
||||
|
||||
builder.addScale({
|
||||
scaleKey: 'x',
|
||||
time: false,
|
||||
auto: true,
|
||||
});
|
||||
builder.addScale({
|
||||
scaleKey: 'y',
|
||||
time: false,
|
||||
auto: true,
|
||||
});
|
||||
|
||||
const currentQuery = widget.query;
|
||||
|
||||
apiResponse.data.result.forEach((series) => {
|
||||
const baseLabelName = getLabelName(
|
||||
series.metric,
|
||||
series.queryName || '', // query
|
||||
series.legend || '',
|
||||
);
|
||||
|
||||
const label = currentQuery
|
||||
? getLegend(series, currentQuery, baseLabelName)
|
||||
: baseLabelName;
|
||||
|
||||
builder.addSeries({
|
||||
label: label,
|
||||
scaleKey: 'y',
|
||||
drawStyle: DrawStyle.Bar,
|
||||
panelType: PANEL_TYPES.HISTOGRAM,
|
||||
colorMapping: widget.customLegendColors ?? {},
|
||||
spanGaps: false,
|
||||
barWidthFactor: 1,
|
||||
showPoints: VisibilityMode.Never,
|
||||
pointSize: 5,
|
||||
isDarkMode,
|
||||
});
|
||||
});
|
||||
|
||||
return builder;
|
||||
}
|
||||
@@ -19,9 +19,9 @@ export interface BaseConfigBuilderProps {
|
||||
widget: Widgets;
|
||||
apiResponse: MetricRangePayloadProps;
|
||||
isDarkMode: boolean;
|
||||
onClick: OnClickPluginOpts['onClick'];
|
||||
onDragSelect: (startTime: number, endTime: number) => void;
|
||||
timezone: Timezone;
|
||||
onClick?: OnClickPluginOpts['onClick'];
|
||||
onDragSelect?: (startTime: number, endTime: number) => void;
|
||||
timezone?: Timezone;
|
||||
panelMode: PanelMode;
|
||||
panelType: PANEL_TYPES;
|
||||
minTimeScale?: number;
|
||||
@@ -40,8 +40,10 @@ export function buildBaseConfig({
|
||||
minTimeScale,
|
||||
maxTimeScale,
|
||||
}: BaseConfigBuilderProps): UPlotConfigBuilder {
|
||||
const tzDate = (timestamp: number): Date =>
|
||||
uPlot.tzDate(new Date(timestamp * 1e3), timezone.value);
|
||||
const tzDate = timezone
|
||||
? (timestamp: number): Date =>
|
||||
uPlot.tzDate(new Date(timestamp * 1e3), timezone.value)
|
||||
: undefined;
|
||||
|
||||
const builder = new UPlotConfigBuilder({
|
||||
onDragSelect,
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable no-param-reassign */
|
||||
import {
|
||||
NULL_EXPAND,
|
||||
NULL_REMOVE,
|
||||
NULL_RETAIN,
|
||||
} from 'container/PanelWrapper/constants';
|
||||
import { AlignedData } from 'uplot';
|
||||
|
||||
export function incrRoundDn(num: number, incr: number): number {
|
||||
return Math.floor(num / incr) * incr;
|
||||
}
|
||||
|
||||
export function roundDecimals(val: number, dec = 0): number {
|
||||
if (Number.isInteger(val)) {
|
||||
return val;
|
||||
}
|
||||
|
||||
const p = 10 ** dec;
|
||||
const n = val * p * (1 + Number.EPSILON);
|
||||
return Math.round(n) / p;
|
||||
}
|
||||
|
||||
function nullExpand(
|
||||
yVals: Array<number | null>,
|
||||
nullIdxs: number[],
|
||||
alignedLen: number,
|
||||
): void {
|
||||
for (let i = 0, xi, lastNullIdx = -1; i < nullIdxs.length; i++) {
|
||||
const nullIdx = nullIdxs[i];
|
||||
|
||||
if (nullIdx > lastNullIdx) {
|
||||
xi = nullIdx - 1;
|
||||
while (xi >= 0 && yVals[xi] == null) {
|
||||
yVals[xi--] = null;
|
||||
}
|
||||
|
||||
xi = nullIdx + 1;
|
||||
while (xi < alignedLen && yVals[xi] == null) {
|
||||
yVals[(lastNullIdx = xi++)] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function join(
|
||||
tables: AlignedData[],
|
||||
nullModes?: number[][],
|
||||
): AlignedData {
|
||||
let xVals: Set<number>;
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
xVals = new Set();
|
||||
|
||||
for (let ti = 0; ti < tables.length; ti++) {
|
||||
const t = tables[ti];
|
||||
const xs = t[0];
|
||||
const len = xs.length;
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
xVals.add(xs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const data = [Array.from(xVals).sort((a, b) => a - b)];
|
||||
|
||||
const alignedLen = data[0].length;
|
||||
|
||||
const xIdxs = new Map();
|
||||
|
||||
for (let i = 0; i < alignedLen; i++) {
|
||||
xIdxs.set(data[0][i], i);
|
||||
}
|
||||
|
||||
for (let ti = 0; ti < tables.length; ti++) {
|
||||
const t = tables[ti];
|
||||
const xs = t[0];
|
||||
|
||||
for (let si = 1; si < t.length; si++) {
|
||||
const ys = t[si];
|
||||
|
||||
const yVals = Array(alignedLen).fill(undefined);
|
||||
|
||||
const nullMode = nullModes ? nullModes[ti][si] : NULL_RETAIN;
|
||||
|
||||
const nullIdxs = [];
|
||||
|
||||
for (let i = 0; i < ys.length; i++) {
|
||||
const yVal = ys[i];
|
||||
const alignedIdx = xIdxs.get(xs[i]);
|
||||
|
||||
if (yVal === null) {
|
||||
if (nullMode !== NULL_REMOVE) {
|
||||
yVals[alignedIdx] = yVal;
|
||||
|
||||
if (nullMode === NULL_EXPAND) {
|
||||
nullIdxs.push(alignedIdx);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
yVals[alignedIdx] = yVal;
|
||||
}
|
||||
}
|
||||
|
||||
nullExpand(yVals, nullIdxs, alignedLen);
|
||||
|
||||
data.push(yVals);
|
||||
}
|
||||
}
|
||||
|
||||
return data as AlignedData;
|
||||
}
|
||||
|
||||
export function histogram(
|
||||
vals: number[],
|
||||
getBucket: (v: number) => number,
|
||||
sort?: ((a: number, b: number) => number) | null,
|
||||
): AlignedData {
|
||||
const hist = new Map();
|
||||
|
||||
for (let i = 0; i < vals.length; i++) {
|
||||
let v = vals[i];
|
||||
|
||||
if (v != null) {
|
||||
v = getBucket(v);
|
||||
}
|
||||
|
||||
const entry = hist.get(v);
|
||||
|
||||
if (entry) {
|
||||
entry.count++;
|
||||
} else {
|
||||
hist.set(v, { value: v, count: 1 });
|
||||
}
|
||||
}
|
||||
|
||||
const bins = [...hist.values()];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
sort && bins.sort((a, b) => sort(a.value, b.value));
|
||||
|
||||
const values = Array(bins.length);
|
||||
const counts = Array(bins.length);
|
||||
|
||||
for (let i = 0; i < bins.length; i++) {
|
||||
values[i] = bins[i].value;
|
||||
counts[i] = bins[i].count;
|
||||
}
|
||||
|
||||
return [values, counts];
|
||||
}
|
||||
|
||||
export function replaceUndefinedWithNull(data: AlignedData): AlignedData {
|
||||
const arrays = data as (number | null | undefined)[][];
|
||||
for (let i = 0; i < arrays.length; i++) {
|
||||
for (let j = 0; j < arrays[i].length; j++) {
|
||||
if (arrays[i][j] === undefined) {
|
||||
arrays[i][j] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
export function addNullToFirstHistogram(
|
||||
data: AlignedData,
|
||||
bucketSize: number,
|
||||
): void {
|
||||
const histograms = data as (number | null)[][];
|
||||
if (
|
||||
histograms.length > 0 &&
|
||||
histograms[0].length > 0 &&
|
||||
histograms[0][0] !== null
|
||||
) {
|
||||
histograms[0].unshift(histograms[0][0] - bucketSize);
|
||||
for (let i = 1; i < histograms.length; i++) {
|
||||
histograms[i].unshift(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,10 +35,10 @@
|
||||
box-shadow: 4px 10px 16px 2px rgba(0, 0, 0, 0.2);
|
||||
backdrop-filter: blur(20px);
|
||||
padding: 0px;
|
||||
.group-by-clause {
|
||||
.more-filter-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
gap: 8px;
|
||||
color: var(--bg-vanilla-400);
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
@@ -53,7 +53,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.group-by-clause:hover {
|
||||
.more-filter-actions:hover {
|
||||
background-color: unset !important;
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@
|
||||
border: 1px solid var(--bg-vanilla-400);
|
||||
background: var(--bg-vanilla-100) !important;
|
||||
|
||||
.group-by-clause {
|
||||
.more-filter-actions {
|
||||
color: var(--bg-ink-400);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eslint-disable sonarjs/no-duplicate-string */
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
@@ -16,7 +17,12 @@ import { MetricsType } from 'container/MetricsApplication/constant';
|
||||
import { useGetSearchQueryParam } from 'hooks/queryBuilder/useGetSearchQueryParam';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { ICurrentQueryData } from 'hooks/useHandleExplorerTabChange';
|
||||
import { ArrowDownToDot, ArrowUpFromDot, Ellipsis } from 'lucide-react';
|
||||
import {
|
||||
ArrowDownToDot,
|
||||
ArrowUpFromDot,
|
||||
Ellipsis,
|
||||
RefreshCw,
|
||||
} from 'lucide-react';
|
||||
import { ExplorerViews } from 'pages/LogsExplorer/utils';
|
||||
import { useTimezone } from 'providers/Timezone';
|
||||
import {
|
||||
@@ -205,6 +211,70 @@ export default function TableViewActions(
|
||||
viewName,
|
||||
]);
|
||||
|
||||
const handleReplaceFilter = useCallback((): void => {
|
||||
if (!stagedQuery) {
|
||||
return;
|
||||
}
|
||||
const normalizedDataType: DataTypes | undefined =
|
||||
dataType && Object.values(DataTypes).includes(dataType as DataTypes)
|
||||
? (dataType as DataTypes)
|
||||
: undefined;
|
||||
|
||||
const updatedQuery = updateQueriesData(
|
||||
stagedQuery,
|
||||
'queryData',
|
||||
(item, index) => {
|
||||
// Only replace filters for index 0
|
||||
if (index === 0) {
|
||||
const newFilterItem: BaseAutocompleteData = {
|
||||
key: fieldFilterKey,
|
||||
type: fieldType || '',
|
||||
dataType: normalizedDataType,
|
||||
};
|
||||
|
||||
// Create new filter items array with single IN filter
|
||||
const newFilters = {
|
||||
items: [
|
||||
{
|
||||
id: '',
|
||||
key: newFilterItem,
|
||||
op: OPERATORS.IN,
|
||||
value: [parseFieldValue(fieldData.value)],
|
||||
},
|
||||
],
|
||||
op: 'AND',
|
||||
};
|
||||
|
||||
// Clear the expression and update filters
|
||||
return {
|
||||
...item,
|
||||
filters: newFilters,
|
||||
filter: { expression: '' },
|
||||
};
|
||||
}
|
||||
|
||||
return item;
|
||||
},
|
||||
);
|
||||
|
||||
const queryData: ICurrentQueryData = {
|
||||
name: viewName,
|
||||
id: updatedQuery.id,
|
||||
query: updatedQuery,
|
||||
};
|
||||
|
||||
handleChangeSelectedView?.(ExplorerViews.LIST, queryData);
|
||||
}, [
|
||||
stagedQuery,
|
||||
updateQueriesData,
|
||||
fieldFilterKey,
|
||||
fieldType,
|
||||
dataType,
|
||||
fieldData,
|
||||
handleChangeSelectedView,
|
||||
viewName,
|
||||
]);
|
||||
|
||||
// Memoize textToCopy computation
|
||||
const textToCopy = useMemo(() => {
|
||||
let text = fieldData.value;
|
||||
@@ -327,13 +397,21 @@ export default function TableViewActions(
|
||||
content={
|
||||
<div>
|
||||
<Button
|
||||
className="group-by-clause"
|
||||
className="more-filter-actions"
|
||||
type="text"
|
||||
icon={<GroupByIcon />}
|
||||
onClick={handleGroupByAttribute}
|
||||
>
|
||||
Group By Attribute
|
||||
</Button>
|
||||
<Button
|
||||
className="more-filter-actions"
|
||||
type="text"
|
||||
icon={<RefreshCw size={14} />}
|
||||
onClick={handleReplaceFilter}
|
||||
>
|
||||
Replace filters with this value
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
rootClassName="table-view-actions-content"
|
||||
@@ -405,13 +483,21 @@ export default function TableViewActions(
|
||||
content={
|
||||
<div>
|
||||
<Button
|
||||
className="group-by-clause"
|
||||
className="more-filter-actions"
|
||||
type="text"
|
||||
icon={<GroupByIcon />}
|
||||
onClick={handleGroupByAttribute}
|
||||
>
|
||||
Group By Attribute
|
||||
</Button>
|
||||
<Button
|
||||
className="more-filter-actions"
|
||||
type="text"
|
||||
icon={<RefreshCw size={14} />}
|
||||
onClick={handleReplaceFilter}
|
||||
>
|
||||
Replace filters with this value
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
rootClassName="table-view-actions-content"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { BarTooltipProps, TooltipContentItem } from '../types';
|
||||
import Tooltip from './Tooltip';
|
||||
import { buildTooltipContent } from './utils';
|
||||
|
||||
export default function BarChartTooltip(props: BarTooltipProps): JSX.Element {
|
||||
const content = useMemo(
|
||||
(): TooltipContentItem[] =>
|
||||
buildTooltipContent({
|
||||
data: props.uPlotInstance.data,
|
||||
series: props.uPlotInstance.series,
|
||||
dataIndexes: props.dataIndexes,
|
||||
activeSeriesIndex: props.seriesIndex,
|
||||
uPlotInstance: props.uPlotInstance,
|
||||
yAxisUnit: props.yAxisUnit ?? '',
|
||||
decimalPrecision: props.decimalPrecision,
|
||||
isStackedBarChart: props.isStackedBarChart,
|
||||
}),
|
||||
[
|
||||
props.uPlotInstance,
|
||||
props.seriesIndex,
|
||||
props.dataIndexes,
|
||||
props.yAxisUnit,
|
||||
props.decimalPrecision,
|
||||
props.isStackedBarChart,
|
||||
],
|
||||
);
|
||||
|
||||
return <Tooltip {...props} content={content} />;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { HistogramTooltipProps } from '../types';
|
||||
import Tooltip from './Tooltip';
|
||||
|
||||
export default function HistogramTooltip(
|
||||
props: HistogramTooltipProps,
|
||||
): JSX.Element {
|
||||
return <Tooltip {...props} showTooltipHeader={false} />;
|
||||
}
|
||||
@@ -16,12 +16,16 @@ export default function Tooltip({
|
||||
uPlotInstance,
|
||||
timezone,
|
||||
content,
|
||||
showTooltipHeader = true,
|
||||
}: TooltipProps): JSX.Element {
|
||||
const isDarkMode = useIsDarkMode();
|
||||
|
||||
const tooltipContent = content ?? [];
|
||||
|
||||
const headerTitle = useMemo(() => {
|
||||
if (!showTooltipHeader) {
|
||||
return null;
|
||||
}
|
||||
const data = uPlotInstance.data;
|
||||
const cursorIdx = uPlotInstance.cursor.idx;
|
||||
if (cursorIdx == null) {
|
||||
@@ -30,7 +34,12 @@ export default function Tooltip({
|
||||
return dayjs(data[0][cursorIdx] * 1000)
|
||||
.tz(timezone)
|
||||
.format(DATE_TIME_FORMATS.MONTH_DATETIME_SECONDS);
|
||||
}, [timezone, uPlotInstance.data, uPlotInstance.cursor.idx]);
|
||||
}, [
|
||||
timezone,
|
||||
uPlotInstance.data,
|
||||
uPlotInstance.cursor.idx,
|
||||
showTooltipHeader,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -39,9 +48,11 @@ export default function Tooltip({
|
||||
isDarkMode ? 'darkMode' : 'lightMode',
|
||||
)}
|
||||
>
|
||||
<div className="uplot-tooltip-header">
|
||||
<span>{headerTitle}</span>
|
||||
</div>
|
||||
{showTooltipHeader && (
|
||||
<div className="uplot-tooltip-header">
|
||||
<span>{headerTitle}</span>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
height: Math.min(
|
||||
|
||||
@@ -25,16 +25,28 @@ export function getTooltipBaseValue({
|
||||
index,
|
||||
dataIndex,
|
||||
isStackedBarChart,
|
||||
series,
|
||||
}: {
|
||||
data: AlignedData;
|
||||
index: number;
|
||||
dataIndex: number;
|
||||
isStackedBarChart?: boolean;
|
||||
series?: Series[];
|
||||
}): number | null {
|
||||
let baseValue = data[index][dataIndex] ?? null;
|
||||
if (isStackedBarChart && index + 1 < data.length && baseValue !== null) {
|
||||
const nextValue = data[index + 1][dataIndex] ?? null;
|
||||
if (nextValue !== null) {
|
||||
// Top-down stacking (first series at top): raw = stacked[i] - stacked[nextVisible].
|
||||
// When series are hidden, we must use the next *visible* series, not index+1,
|
||||
// since hidden series keep raw values and would produce negative/wrong results.
|
||||
if (isStackedBarChart && baseValue !== null && series) {
|
||||
let nextVisibleIdx = -1;
|
||||
for (let j = index + 1; j < series.length; j++) {
|
||||
if (series[j]?.show) {
|
||||
nextVisibleIdx = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nextVisibleIdx >= 1) {
|
||||
const nextValue = data[nextVisibleIdx][dataIndex] ?? 0;
|
||||
baseValue = baseValue - nextValue;
|
||||
}
|
||||
}
|
||||
@@ -80,6 +92,7 @@ export function buildTooltipContent({
|
||||
index,
|
||||
dataIndex,
|
||||
isStackedBarChart,
|
||||
series,
|
||||
});
|
||||
|
||||
const isActive = index === activeSeriesIndex;
|
||||
|
||||
@@ -60,6 +60,7 @@ export interface TooltipRenderArgs {
|
||||
}
|
||||
|
||||
export interface BaseTooltipProps {
|
||||
showTooltipHeader?: boolean;
|
||||
timezone: string;
|
||||
yAxisUnit?: string;
|
||||
decimalPrecision?: PrecisionOption;
|
||||
@@ -74,7 +75,14 @@ export interface BarTooltipProps extends BaseTooltipProps, TooltipRenderArgs {
|
||||
isStackedBarChart?: boolean;
|
||||
}
|
||||
|
||||
export type TooltipProps = TimeSeriesTooltipProps | BarTooltipProps;
|
||||
export interface HistogramTooltipProps
|
||||
extends BaseTooltipProps,
|
||||
TooltipRenderArgs {}
|
||||
|
||||
export type TooltipProps =
|
||||
| TimeSeriesTooltipProps
|
||||
| BarTooltipProps
|
||||
| HistogramTooltipProps;
|
||||
|
||||
export enum LegendPosition {
|
||||
BOTTOM = 'bottom',
|
||||
|
||||
@@ -4,12 +4,12 @@ import uPlot, { Axis } from 'uplot';
|
||||
|
||||
import { uPlotXAxisValuesFormat } from '../../uPlotLib/utils/constants';
|
||||
import getGridColor from '../../uPlotLib/utils/getGridColor';
|
||||
import { buildYAxisSizeCalculator } from '../utils/axis';
|
||||
import { AxisProps, ConfigBuilder } from './types';
|
||||
|
||||
const PANEL_TYPES_WITH_X_AXIS_DATETIME_FORMAT = [
|
||||
PANEL_TYPES.TIME_SERIES,
|
||||
PANEL_TYPES.BAR,
|
||||
PANEL_TYPES.PIE,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -114,6 +114,81 @@ export class UPlotAxisBuilder extends ConfigBuilder<AxisProps, Axis> {
|
||||
: undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate axis size from existing size property
|
||||
*/
|
||||
private getExistingAxisSize(
|
||||
self: uPlot,
|
||||
axis: Axis,
|
||||
values: string[] | undefined,
|
||||
axisIdx: number,
|
||||
cycleNum: number,
|
||||
): number {
|
||||
const internalSize = (axis as { _size?: number })._size;
|
||||
if (internalSize !== undefined) {
|
||||
return internalSize;
|
||||
}
|
||||
|
||||
const existingSize = axis.size;
|
||||
if (typeof existingSize === 'function') {
|
||||
return existingSize(self, values ?? [], axisIdx, cycleNum);
|
||||
}
|
||||
|
||||
return existingSize ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate text width for longest value
|
||||
*/
|
||||
private calculateTextWidth(
|
||||
self: uPlot,
|
||||
axis: Axis,
|
||||
values: string[] | undefined,
|
||||
): number {
|
||||
if (!values || values.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Find longest value
|
||||
const longestVal = values.reduce(
|
||||
(acc, val) => (val.length > acc.length ? val : acc),
|
||||
'',
|
||||
);
|
||||
|
||||
if (longestVal === '' || !axis.font?.[0]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line prefer-destructuring, no-param-reassign
|
||||
self.ctx.font = axis.font[0];
|
||||
return self.ctx.measureText(longestVal).width / devicePixelRatio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Y-axis dynamic size calculator
|
||||
*/
|
||||
private buildYAxisSizeCalculator(): uPlot.Axis.Size {
|
||||
return (
|
||||
self: uPlot,
|
||||
values: string[] | undefined,
|
||||
axisIdx: number,
|
||||
cycleNum: number,
|
||||
): number => {
|
||||
const axis = self.axes[axisIdx];
|
||||
|
||||
// Bail out, force convergence
|
||||
if (cycleNum > 1) {
|
||||
return this.getExistingAxisSize(self, axis, values, axisIdx, cycleNum);
|
||||
}
|
||||
|
||||
const gap = this.props.gap ?? 5;
|
||||
let axisSize = (axis.ticks?.size ?? 0) + gap;
|
||||
axisSize += this.calculateTextWidth(self, axis, values);
|
||||
|
||||
return Math.ceil(axisSize);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build dynamic size calculator for Y-axis
|
||||
*/
|
||||
@@ -127,7 +202,7 @@ export class UPlotAxisBuilder extends ConfigBuilder<AxisProps, Axis> {
|
||||
|
||||
// Y-axis needs dynamic sizing based on text width
|
||||
if (scaleKey === 'y') {
|
||||
return buildYAxisSizeCalculator(this.props.gap ?? 5);
|
||||
return this.buildYAxisSizeCalculator();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { themeColors } from 'constants/theme';
|
||||
import { generateColor } from 'lib/uPlotLib/utils/generateColor';
|
||||
import uPlot, { Series } from 'uplot';
|
||||
|
||||
import {
|
||||
BarAlignment,
|
||||
ConfigBuilder,
|
||||
DrawStyle,
|
||||
LineInterpolation,
|
||||
@@ -15,44 +17,13 @@ import {
|
||||
* Builder for uPlot series configuration
|
||||
* Handles creation of series settings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Path builders are static and shared across all instances of UPlotSeriesBuilder
|
||||
*/
|
||||
let builders: PathBuilders | null = null;
|
||||
export class UPlotSeriesBuilder extends ConfigBuilder<SeriesProps, Series> {
|
||||
constructor(props: SeriesProps) {
|
||||
super(props);
|
||||
const pathBuilders = uPlot.paths;
|
||||
|
||||
if (!builders) {
|
||||
const linearBuilder = pathBuilders.linear;
|
||||
const splineBuilder = pathBuilders.spline;
|
||||
const steppedBuilder = pathBuilders.stepped;
|
||||
|
||||
if (!linearBuilder || !splineBuilder || !steppedBuilder) {
|
||||
throw new Error('Required uPlot path builders are not available');
|
||||
}
|
||||
builders = {
|
||||
linear: linearBuilder(),
|
||||
spline: splineBuilder(),
|
||||
stepBefore: steppedBuilder({ align: -1 }),
|
||||
stepAfter: steppedBuilder({ align: 1 }),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private buildLineConfig({
|
||||
lineColor,
|
||||
lineWidth,
|
||||
lineStyle,
|
||||
lineCap,
|
||||
}: {
|
||||
lineColor: string;
|
||||
lineWidth?: number;
|
||||
lineStyle?: LineStyle;
|
||||
lineCap?: Series.Cap;
|
||||
}): Partial<Series> {
|
||||
const { lineWidth, lineStyle, lineCap } = this.props;
|
||||
const lineConfig: Partial<Series> = {
|
||||
stroke: lineColor,
|
||||
width: lineWidth ?? 2,
|
||||
@@ -65,21 +36,28 @@ export class UPlotSeriesBuilder extends ConfigBuilder<SeriesProps, Series> {
|
||||
if (lineCap) {
|
||||
lineConfig.cap = lineCap;
|
||||
}
|
||||
|
||||
if (this.props.panelType === PANEL_TYPES.BAR) {
|
||||
lineConfig.fill = lineColor;
|
||||
} else if (this.props.panelType === PANEL_TYPES.HISTOGRAM) {
|
||||
lineConfig.fill = `${lineColor}40`;
|
||||
}
|
||||
|
||||
return lineConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build path configuration
|
||||
*/
|
||||
private buildPathConfig({
|
||||
pathBuilder,
|
||||
drawStyle,
|
||||
lineInterpolation,
|
||||
}: {
|
||||
pathBuilder?: Series.PathBuilder | null;
|
||||
drawStyle: DrawStyle;
|
||||
lineInterpolation?: LineInterpolation;
|
||||
}): Partial<Series> {
|
||||
private buildPathConfig(): Partial<Series> {
|
||||
const {
|
||||
pathBuilder,
|
||||
drawStyle,
|
||||
lineInterpolation,
|
||||
barAlignment,
|
||||
barMaxWidth,
|
||||
barWidthFactor,
|
||||
} = this.props;
|
||||
if (pathBuilder) {
|
||||
return { paths: pathBuilder };
|
||||
}
|
||||
@@ -96,7 +74,13 @@ export class UPlotSeriesBuilder extends ConfigBuilder<SeriesProps, Series> {
|
||||
idx0: number,
|
||||
idx1: number,
|
||||
): Series.Paths | null => {
|
||||
const pathsBuilder = getPathBuilder(drawStyle, lineInterpolation);
|
||||
const pathsBuilder = getPathBuilder({
|
||||
drawStyle,
|
||||
lineInterpolation,
|
||||
barAlignment,
|
||||
barMaxWidth,
|
||||
barWidthFactor,
|
||||
});
|
||||
|
||||
return pathsBuilder(self, seriesIdx, idx0, idx1);
|
||||
},
|
||||
@@ -111,21 +95,17 @@ export class UPlotSeriesBuilder extends ConfigBuilder<SeriesProps, Series> {
|
||||
*/
|
||||
private buildPointsConfig({
|
||||
lineColor,
|
||||
lineWidth,
|
||||
pointSize,
|
||||
pointsBuilder,
|
||||
pointsFilter,
|
||||
drawStyle,
|
||||
showPoints,
|
||||
}: {
|
||||
lineColor: string;
|
||||
lineWidth?: number;
|
||||
pointSize?: number;
|
||||
pointsBuilder: Series.Points.Show | null;
|
||||
pointsFilter: Series.Points.Filter | null;
|
||||
drawStyle: DrawStyle;
|
||||
showPoints?: VisibilityMode;
|
||||
}): Partial<Series.Points> {
|
||||
const {
|
||||
lineWidth,
|
||||
pointSize,
|
||||
pointsBuilder,
|
||||
pointsFilter,
|
||||
drawStyle,
|
||||
showPoints,
|
||||
} = this.props;
|
||||
const pointsConfig: Partial<Series.Points> = {
|
||||
stroke: lineColor,
|
||||
fill: lineColor,
|
||||
@@ -162,44 +142,16 @@ export class UPlotSeriesBuilder extends ConfigBuilder<SeriesProps, Series> {
|
||||
}
|
||||
|
||||
getConfig(): Series {
|
||||
const {
|
||||
drawStyle,
|
||||
pathBuilder,
|
||||
pointsBuilder,
|
||||
pointsFilter,
|
||||
lineInterpolation,
|
||||
lineWidth,
|
||||
lineStyle,
|
||||
lineCap,
|
||||
showPoints,
|
||||
pointSize,
|
||||
scaleKey,
|
||||
label,
|
||||
spanGaps,
|
||||
show = true,
|
||||
} = this.props;
|
||||
const { scaleKey, label, spanGaps, show = true } = this.props;
|
||||
|
||||
const lineColor = this.getLineColor();
|
||||
|
||||
const lineConfig = this.buildLineConfig({
|
||||
lineColor,
|
||||
lineWidth,
|
||||
lineStyle,
|
||||
lineCap,
|
||||
});
|
||||
const pathConfig = this.buildPathConfig({
|
||||
pathBuilder,
|
||||
drawStyle,
|
||||
lineInterpolation,
|
||||
});
|
||||
const pathConfig = this.buildPathConfig();
|
||||
const pointsConfig = this.buildPointsConfig({
|
||||
lineColor,
|
||||
lineWidth,
|
||||
pointSize,
|
||||
pointsBuilder: pointsBuilder ?? null,
|
||||
pointsFilter: pointsFilter ?? null,
|
||||
drawStyle,
|
||||
showPoints,
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -224,18 +176,55 @@ interface PathBuilders {
|
||||
[key: string]: Series.PathBuilder;
|
||||
}
|
||||
|
||||
let builders: PathBuilders | null = null;
|
||||
|
||||
/**
|
||||
* Get path builder based on draw style and interpolation
|
||||
*/
|
||||
function getPathBuilder(
|
||||
style: DrawStyle,
|
||||
lineInterpolation?: LineInterpolation,
|
||||
): Series.PathBuilder {
|
||||
function getPathBuilder({
|
||||
drawStyle,
|
||||
lineInterpolation,
|
||||
barAlignment = BarAlignment.Center,
|
||||
barWidthFactor = 0.6,
|
||||
barMaxWidth = 200,
|
||||
}: {
|
||||
drawStyle: DrawStyle;
|
||||
lineInterpolation?: LineInterpolation;
|
||||
barAlignment?: BarAlignment;
|
||||
barMaxWidth?: number;
|
||||
barWidthFactor?: number;
|
||||
}): Series.PathBuilder {
|
||||
const pathBuilders = uPlot.paths;
|
||||
|
||||
if (!builders) {
|
||||
throw new Error('Required uPlot path builders are not available');
|
||||
const linearBuilder = pathBuilders.linear;
|
||||
const splineBuilder = pathBuilders.spline;
|
||||
const steppedBuilder = pathBuilders.stepped;
|
||||
|
||||
if (!linearBuilder || !splineBuilder || !steppedBuilder) {
|
||||
throw new Error('Required uPlot path builders are not available');
|
||||
}
|
||||
|
||||
builders = {
|
||||
linear: linearBuilder(),
|
||||
spline: splineBuilder(),
|
||||
stepBefore: steppedBuilder({ align: -1 }),
|
||||
stepAfter: steppedBuilder({ align: 1 }),
|
||||
};
|
||||
}
|
||||
|
||||
if (style === DrawStyle.Line) {
|
||||
if (drawStyle === DrawStyle.Bar) {
|
||||
const barsCfgKey = `bars|${barAlignment}|${barWidthFactor}|${barMaxWidth}`;
|
||||
if (!builders[barsCfgKey] && pathBuilders.bars) {
|
||||
builders[barsCfgKey] = pathBuilders.bars({
|
||||
size: [barWidthFactor, barMaxWidth],
|
||||
align: barAlignment,
|
||||
});
|
||||
}
|
||||
return builders[barsCfgKey];
|
||||
}
|
||||
|
||||
if (drawStyle === DrawStyle.Line) {
|
||||
if (lineInterpolation === LineInterpolation.StepBefore) {
|
||||
return builders.stepBefore;
|
||||
}
|
||||
|
||||
@@ -1,393 +0,0 @@
|
||||
import { getToolTipValue } from 'components/Graph/yAxisConfig';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { uPlotXAxisValuesFormat } from 'lib/uPlotLib/utils/constants';
|
||||
import type uPlot from 'uplot';
|
||||
|
||||
import type { AxisProps } from '../types';
|
||||
import { UPlotAxisBuilder } from '../UPlotAxisBuilder';
|
||||
|
||||
jest.mock('components/Graph/yAxisConfig', () => ({
|
||||
getToolTipValue: jest.fn(),
|
||||
}));
|
||||
|
||||
const createAxisProps = (overrides: Partial<AxisProps> = {}): AxisProps => ({
|
||||
scaleKey: 'x',
|
||||
label: 'Time',
|
||||
isDarkMode: false,
|
||||
show: true,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
describe('UPlotAxisBuilder', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('builds basic axis config with defaults', () => {
|
||||
const builder = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
scaleKey: 'x',
|
||||
label: 'Time',
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.scale).toBe('x');
|
||||
expect(config.label).toBe('Time');
|
||||
expect(config.show).toBe(true);
|
||||
expect(config.side).toBe(2);
|
||||
expect(config.gap).toBe(5);
|
||||
|
||||
// Default grid and ticks are created
|
||||
expect(config.grid).toEqual({
|
||||
stroke: 'rgba(0,0,0,0.5)',
|
||||
width: 0.2,
|
||||
show: true,
|
||||
});
|
||||
expect(config.ticks).toEqual({
|
||||
width: 0.3,
|
||||
show: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('sets config values when provided', () => {
|
||||
const builder = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
scaleKey: 'x',
|
||||
label: 'Time',
|
||||
show: false,
|
||||
side: 0,
|
||||
gap: 10,
|
||||
grid: {
|
||||
stroke: '#ff0000',
|
||||
width: 1,
|
||||
show: false,
|
||||
},
|
||||
ticks: {
|
||||
stroke: '#00ff00',
|
||||
width: 1,
|
||||
show: false,
|
||||
size: 10,
|
||||
},
|
||||
values: ['1', '2', '3'],
|
||||
space: 20,
|
||||
size: 100,
|
||||
stroke: '#0000ff',
|
||||
}),
|
||||
);
|
||||
const config = builder.getConfig();
|
||||
expect(config.scale).toBe('x');
|
||||
expect(config.label).toBe('Time');
|
||||
expect(config.show).toBe(false);
|
||||
expect(config.gap).toBe(10);
|
||||
expect(config.grid).toEqual({
|
||||
stroke: '#ff0000',
|
||||
width: 1,
|
||||
show: false,
|
||||
});
|
||||
expect(config.ticks).toEqual({
|
||||
stroke: '#00ff00',
|
||||
width: 1,
|
||||
show: false,
|
||||
size: 10,
|
||||
});
|
||||
expect(config.values).toEqual(['1', '2', '3']);
|
||||
expect(config.space).toBe(20);
|
||||
expect(config.size).toBe(100);
|
||||
expect(config.stroke).toBe('#0000ff');
|
||||
});
|
||||
|
||||
it('merges custom grid config over defaults and respects isDarkMode and isLogScale', () => {
|
||||
const builder = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
isDarkMode: true,
|
||||
isLogScale: true,
|
||||
grid: {
|
||||
width: 1,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.grid).toEqual({
|
||||
// stroke falls back to theme-based default when not provided
|
||||
stroke: 'rgba(231,233,237,0.3)',
|
||||
// provided width overrides default
|
||||
width: 1,
|
||||
// show falls back to default when not provided
|
||||
show: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('uses provided ticks config when present and falls back to defaults otherwise', () => {
|
||||
const customTicks = { width: 1, show: false };
|
||||
const withTicks = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
ticks: customTicks,
|
||||
}),
|
||||
);
|
||||
const withoutTicks = new UPlotAxisBuilder(createAxisProps());
|
||||
|
||||
expect(withTicks.getConfig().ticks).toBe(customTicks);
|
||||
expect(withoutTicks.getConfig().ticks).toEqual({
|
||||
width: 0.3,
|
||||
show: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('uses time-based X-axis values formatter for time-series like panels', () => {
|
||||
const builder = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
scaleKey: 'x',
|
||||
panelType: PANEL_TYPES.TIME_SERIES,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.values).toBe(uPlotXAxisValuesFormat);
|
||||
});
|
||||
|
||||
it('does not attach X-axis datetime formatter when panel type is not supported', () => {
|
||||
const builder = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
scaleKey: 'x',
|
||||
panelType: PANEL_TYPES.LIST, // not in PANEL_TYPES_WITH_X_AXIS_DATETIME_FORMAT
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.values).toBeUndefined();
|
||||
});
|
||||
|
||||
it('builds Y-axis values formatter that delegates to getToolTipValue', () => {
|
||||
const yBuilder = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
scaleKey: 'y',
|
||||
yAxisUnit: 'ms',
|
||||
decimalPrecision: 3,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = yBuilder.getConfig();
|
||||
expect(typeof config.values).toBe('function');
|
||||
|
||||
(getToolTipValue as jest.Mock).mockImplementation(
|
||||
(value: string, unit?: string, precision?: unknown) =>
|
||||
`formatted:${value}:${unit}:${precision}`,
|
||||
);
|
||||
|
||||
// Simulate uPlot calling the values formatter
|
||||
const valuesFn = (config.values as unknown) as (
|
||||
self: uPlot,
|
||||
vals: unknown[],
|
||||
) => string[];
|
||||
const result = valuesFn({} as uPlot, [1, null, 2, Number.NaN]);
|
||||
|
||||
expect(getToolTipValue).toHaveBeenCalledTimes(2);
|
||||
expect(getToolTipValue).toHaveBeenNthCalledWith(1, '1', 'ms', 3);
|
||||
expect(getToolTipValue).toHaveBeenNthCalledWith(2, '2', 'ms', 3);
|
||||
|
||||
// Null/NaN values should map to empty strings
|
||||
expect(result).toEqual(['formatted:1:ms:3', '', 'formatted:2:ms:3', '']);
|
||||
});
|
||||
|
||||
it('adds dynamic size calculator only for Y-axis when size is not provided', () => {
|
||||
const yBuilder = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
scaleKey: 'y',
|
||||
}),
|
||||
);
|
||||
const xBuilder = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
scaleKey: 'x',
|
||||
}),
|
||||
);
|
||||
|
||||
const yConfig = yBuilder.getConfig();
|
||||
const xConfig = xBuilder.getConfig();
|
||||
|
||||
expect(typeof yConfig.size).toBe('function');
|
||||
expect(xConfig.size).toBeUndefined();
|
||||
});
|
||||
|
||||
it('uses explicit size function when provided', () => {
|
||||
const sizeFn: uPlot.Axis.Size = jest.fn(() => 100) as uPlot.Axis.Size;
|
||||
|
||||
const builder = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
scaleKey: 'y',
|
||||
size: sizeFn,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
expect(config.size).toBe(sizeFn);
|
||||
});
|
||||
|
||||
it('builds stroke color based on stroke and isDarkMode', () => {
|
||||
const explicitStroke = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
stroke: '#ff0000',
|
||||
}),
|
||||
);
|
||||
const darkStroke = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
stroke: undefined,
|
||||
isDarkMode: true,
|
||||
}),
|
||||
);
|
||||
const lightStroke = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
stroke: undefined,
|
||||
isDarkMode: false,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(explicitStroke.getConfig().stroke).toBe('#ff0000');
|
||||
expect(darkStroke.getConfig().stroke).toBe('white');
|
||||
expect(lightStroke.getConfig().stroke).toBe('black');
|
||||
});
|
||||
|
||||
it('uses explicit values formatter when provided', () => {
|
||||
const customValues: uPlot.Axis.Values = jest.fn(() => ['a', 'b', 'c']);
|
||||
|
||||
const builder = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
scaleKey: 'y',
|
||||
values: customValues,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.values).toBe(customValues);
|
||||
});
|
||||
|
||||
it('returns undefined values for scaleKey neither x nor y', () => {
|
||||
const builder = new UPlotAxisBuilder(createAxisProps({ scaleKey: 'custom' }));
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.values).toBeUndefined();
|
||||
});
|
||||
|
||||
it('includes space in config when provided', () => {
|
||||
const builder = new UPlotAxisBuilder(
|
||||
createAxisProps({ scaleKey: 'y', space: 50 }),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.space).toBe(50);
|
||||
});
|
||||
|
||||
it('includes PANEL_TYPES.BAR and PANEL_TYPES.TIME_SERIES in X-axis datetime formatter', () => {
|
||||
const barBuilder = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
scaleKey: 'x',
|
||||
panelType: PANEL_TYPES.BAR,
|
||||
}),
|
||||
);
|
||||
expect(barBuilder.getConfig().values).toBe(uPlotXAxisValuesFormat);
|
||||
|
||||
const timeSeriesBuilder = new UPlotAxisBuilder(
|
||||
createAxisProps({
|
||||
scaleKey: 'x',
|
||||
panelType: PANEL_TYPES.TIME_SERIES,
|
||||
}),
|
||||
);
|
||||
expect(timeSeriesBuilder.getConfig().values).toBe(uPlotXAxisValuesFormat);
|
||||
});
|
||||
|
||||
it('should return the existing size when cycleNum > 1', () => {
|
||||
const builder = new UPlotAxisBuilder(createAxisProps({ scaleKey: 'y' }));
|
||||
|
||||
const config = builder.getConfig();
|
||||
const sizeFn = config.size;
|
||||
expect(typeof sizeFn).toBe('function');
|
||||
|
||||
const mockAxis = {
|
||||
_size: 80,
|
||||
ticks: { size: 10 },
|
||||
font: ['12px sans-serif'],
|
||||
};
|
||||
const mockSelf = ({
|
||||
axes: [mockAxis],
|
||||
ctx: { measureText: jest.fn(() => ({ width: 60 })), font: '' },
|
||||
} as unknown) as uPlot;
|
||||
|
||||
const result = (sizeFn as (
|
||||
s: uPlot,
|
||||
v: string[],
|
||||
a: number,
|
||||
c: number,
|
||||
) => number)(
|
||||
mockSelf,
|
||||
['100', '200'],
|
||||
0,
|
||||
2, // cycleNum > 1
|
||||
);
|
||||
|
||||
expect(result).toBe(80);
|
||||
});
|
||||
|
||||
it('should invoke the size calculator and compute from text width when cycleNum <= 1', () => {
|
||||
const builder = new UPlotAxisBuilder(
|
||||
createAxisProps({ scaleKey: 'y', gap: 8 }),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
const sizeFn = config.size;
|
||||
expect(typeof sizeFn).toBe('function');
|
||||
|
||||
const mockAxis = {
|
||||
ticks: { size: 12 },
|
||||
font: ['12px sans-serif'],
|
||||
};
|
||||
const measureText = jest.fn(() => ({ width: 48 }));
|
||||
const mockSelf = ({
|
||||
axes: [mockAxis],
|
||||
ctx: {
|
||||
measureText,
|
||||
get font() {
|
||||
return '';
|
||||
},
|
||||
set font(_v: string) {
|
||||
/* noop */
|
||||
},
|
||||
},
|
||||
} as unknown) as uPlot;
|
||||
|
||||
const result = (sizeFn as (
|
||||
s: uPlot,
|
||||
v: string[],
|
||||
a: number,
|
||||
c: number,
|
||||
) => number)(
|
||||
mockSelf,
|
||||
['10', '2000ms'],
|
||||
0,
|
||||
0, // cycleNum <= 1
|
||||
);
|
||||
|
||||
expect(measureText).toHaveBeenCalledWith('2000ms');
|
||||
expect(result).toBeGreaterThanOrEqual(12 + 8);
|
||||
});
|
||||
|
||||
it('merge updates axis props', () => {
|
||||
const builder = new UPlotAxisBuilder(
|
||||
createAxisProps({ scaleKey: 'y', label: 'Original' }),
|
||||
);
|
||||
|
||||
builder.merge({ label: 'Merged', yAxisUnit: 'bytes' });
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.label).toBe('Merged');
|
||||
expect(config.values).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -1,340 +0,0 @@
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import uPlot from 'uplot';
|
||||
|
||||
import type { SeriesProps } from '../types';
|
||||
import { DrawStyle, SelectionPreferencesSource } from '../types';
|
||||
import { UPlotConfigBuilder } from '../UPlotConfigBuilder';
|
||||
|
||||
// Mock only the real boundary that hits localStorage
|
||||
jest.mock(
|
||||
'container/DashboardContainer/visualization/panels/utils/legendVisibilityUtils',
|
||||
() => ({
|
||||
getStoredSeriesVisibility: jest.fn(),
|
||||
}),
|
||||
);
|
||||
|
||||
const getStoredSeriesVisibilityMock = jest.requireMock(
|
||||
'container/DashboardContainer/visualization/panels/utils/legendVisibilityUtils',
|
||||
) as {
|
||||
getStoredSeriesVisibility: jest.Mock;
|
||||
};
|
||||
|
||||
describe('UPlotConfigBuilder', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
const createSeriesProps = (
|
||||
overrides: Partial<SeriesProps> = {},
|
||||
): SeriesProps => ({
|
||||
scaleKey: 'y',
|
||||
label: 'Requests',
|
||||
colorMapping: {},
|
||||
drawStyle: DrawStyle.Line,
|
||||
panelType: PANEL_TYPES.TIME_SERIES,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
it('returns correct save selection preference flag from constructor args', () => {
|
||||
const builder = new UPlotConfigBuilder({
|
||||
shouldSaveSelectionPreference: true,
|
||||
});
|
||||
|
||||
expect(builder.getShouldSaveSelectionPreference()).toBe(true);
|
||||
});
|
||||
|
||||
it('returns widgetId from constructor args', () => {
|
||||
const builder = new UPlotConfigBuilder({ widgetId: 'widget-123' });
|
||||
|
||||
expect(builder.getWidgetId()).toBe('widget-123');
|
||||
});
|
||||
|
||||
it('sets tzDate from constructor and includes it in config', () => {
|
||||
const tzDate = (ts: number): Date => new Date(ts);
|
||||
const builder = new UPlotConfigBuilder({ tzDate });
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.tzDate).toBe(tzDate);
|
||||
});
|
||||
|
||||
it('does not call onDragSelect for click without drag (width === 0)', () => {
|
||||
const onDragSelect = jest.fn();
|
||||
const builder = new UPlotConfigBuilder({ onDragSelect });
|
||||
|
||||
const config = builder.getConfig();
|
||||
const setSelectHooks = config.hooks?.setSelect ?? [];
|
||||
expect(setSelectHooks.length).toBe(1);
|
||||
|
||||
const uplotInstance = ({
|
||||
select: { left: 10, width: 0 },
|
||||
posToVal: jest.fn(),
|
||||
} as unknown) as uPlot;
|
||||
|
||||
// Simulate uPlot calling the hook
|
||||
const setSelectHook = setSelectHooks[0];
|
||||
setSelectHook!(uplotInstance);
|
||||
|
||||
expect(onDragSelect).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls onDragSelect with start and end times in milliseconds for a drag selection', () => {
|
||||
const onDragSelect = jest.fn();
|
||||
const builder = new UPlotConfigBuilder({ onDragSelect });
|
||||
|
||||
const config = builder.getConfig();
|
||||
const setSelectHooks = config.hooks?.setSelect ?? [];
|
||||
expect(setSelectHooks.length).toBe(1);
|
||||
|
||||
const posToVal = jest
|
||||
.fn()
|
||||
// left position
|
||||
.mockReturnValueOnce(100)
|
||||
// left + width
|
||||
.mockReturnValueOnce(110);
|
||||
|
||||
const uplotInstance = ({
|
||||
select: { left: 50, width: 20 },
|
||||
posToVal,
|
||||
} as unknown) as uPlot;
|
||||
|
||||
const setSelectHook = setSelectHooks[0];
|
||||
setSelectHook!(uplotInstance);
|
||||
|
||||
expect(onDragSelect).toHaveBeenCalledTimes(1);
|
||||
// 100 and 110 seconds converted to milliseconds
|
||||
expect(onDragSelect).toHaveBeenCalledWith(100_000, 110_000);
|
||||
});
|
||||
|
||||
it('adds and removes hooks via addHook, and exposes them through getConfig', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
const drawHook = jest.fn();
|
||||
|
||||
const remove = builder.addHook('draw', drawHook as uPlot.Hooks.Defs['draw']);
|
||||
|
||||
let config = builder.getConfig();
|
||||
expect(config.hooks?.draw).toContain(drawHook);
|
||||
|
||||
// Remove and ensure it no longer appears in config
|
||||
remove();
|
||||
config = builder.getConfig();
|
||||
expect(config.hooks?.draw ?? []).not.toContain(drawHook);
|
||||
});
|
||||
|
||||
it('adds axes, scales, and series and wires them into the final config', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
|
||||
// Add axis and scale
|
||||
builder.addAxis({ scaleKey: 'y', label: 'Requests' });
|
||||
builder.addScale({ scaleKey: 'y' });
|
||||
|
||||
// Add two series – legend indices should start from 1 (0 is the timestamp series)
|
||||
builder.addSeries(createSeriesProps({ label: 'Requests' }));
|
||||
builder.addSeries(createSeriesProps({ label: 'Errors' }));
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
// Axes
|
||||
expect(config.axes).toHaveLength(1);
|
||||
expect(config.axes?.[0].scale).toBe('y');
|
||||
|
||||
// Scales are returned as an object keyed by scaleKey
|
||||
expect(config.scales).toBeDefined();
|
||||
expect(Object.keys(config.scales ?? {})).toContain('y');
|
||||
|
||||
// Series: base timestamp + 2 data series
|
||||
expect(config.series).toHaveLength(3);
|
||||
// Base series (index 0) has a value formatter that returns empty string
|
||||
const baseSeries = config.series?.[0] as { value?: () => string };
|
||||
expect(typeof baseSeries?.value).toBe('function');
|
||||
expect(baseSeries?.value?.()).toBe('');
|
||||
|
||||
// Legend items align with series and carry label and color from series config
|
||||
const legendItems = builder.getLegendItems();
|
||||
expect(Object.keys(legendItems)).toEqual(['1', '2']);
|
||||
expect(legendItems[1].seriesIndex).toBe(1);
|
||||
expect(legendItems[1].label).toBe('Requests');
|
||||
expect(legendItems[2].label).toBe('Errors');
|
||||
});
|
||||
|
||||
it('merges axis when addAxis is called twice with same scaleKey', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
|
||||
builder.addAxis({ scaleKey: 'y', label: 'Requests' });
|
||||
builder.addAxis({ scaleKey: 'y', label: 'Updated Label', show: false });
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.axes).toHaveLength(1);
|
||||
expect(config.axes?.[0].label).toBe('Updated Label');
|
||||
expect(config.axes?.[0].show).toBe(false);
|
||||
});
|
||||
|
||||
it('merges scale when addScale is called twice with same scaleKey', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
|
||||
builder.addScale({ scaleKey: 'y', min: 0 });
|
||||
builder.addScale({ scaleKey: 'y', max: 100 });
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
// Only one scale entry for 'y' (merge path used, no duplicate added)
|
||||
expect(config.scales).toBeDefined();
|
||||
const scales = config.scales ?? {};
|
||||
expect(Object.keys(scales)).toEqual(['y']);
|
||||
expect(scales.y?.range).toBeDefined();
|
||||
});
|
||||
|
||||
it('restores visibility state from localStorage when selectionPreferencesSource is LOCAL_STORAGE', () => {
|
||||
const visibilityMap = new Map<string, boolean>([
|
||||
['Requests', true],
|
||||
['Errors', false],
|
||||
]);
|
||||
|
||||
getStoredSeriesVisibilityMock.getStoredSeriesVisibility.mockReturnValue(
|
||||
visibilityMap,
|
||||
);
|
||||
|
||||
const builder = new UPlotConfigBuilder({
|
||||
widgetId: 'widget-1',
|
||||
selectionPreferencesSource: SelectionPreferencesSource.LOCAL_STORAGE,
|
||||
});
|
||||
|
||||
builder.addSeries(createSeriesProps({ label: 'Requests' }));
|
||||
builder.addSeries(createSeriesProps({ label: 'Errors' }));
|
||||
|
||||
const legendItems = builder.getLegendItems();
|
||||
|
||||
// When any series is hidden, legend visibility is driven by the stored map
|
||||
expect(legendItems[1].show).toBe(true);
|
||||
expect(legendItems[2].show).toBe(false);
|
||||
|
||||
const config = builder.getConfig();
|
||||
const [, firstSeries, secondSeries] = config.series ?? [];
|
||||
|
||||
expect(firstSeries?.show).toBe(true);
|
||||
expect(secondSeries?.show).toBe(false);
|
||||
});
|
||||
|
||||
it('does not attempt to read stored visibility when using in-memory preferences', () => {
|
||||
const builder = new UPlotConfigBuilder({
|
||||
widgetId: 'widget-1',
|
||||
selectionPreferencesSource: SelectionPreferencesSource.IN_MEMORY,
|
||||
});
|
||||
|
||||
builder.addSeries(createSeriesProps({ label: 'Requests' }));
|
||||
|
||||
builder.getLegendItems();
|
||||
builder.getConfig();
|
||||
|
||||
expect(
|
||||
getStoredSeriesVisibilityMock.getStoredSeriesVisibility,
|
||||
).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('adds thresholds only once per scale key', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
|
||||
const thresholdsOptions = {
|
||||
scaleKey: 'y',
|
||||
thresholds: [{ thresholdValue: 100 }],
|
||||
};
|
||||
|
||||
builder.addThresholds(thresholdsOptions);
|
||||
builder.addThresholds(thresholdsOptions);
|
||||
|
||||
const config = builder.getConfig();
|
||||
const drawHooks = config.hooks?.draw ?? [];
|
||||
|
||||
// Only a single draw hook should be registered for the same scaleKey
|
||||
expect(drawHooks.length).toBe(1);
|
||||
});
|
||||
|
||||
it('adds multiple thresholds when scale key is different', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
|
||||
const thresholdsOptions = {
|
||||
scaleKey: 'y',
|
||||
thresholds: [{ thresholdValue: 100 }],
|
||||
};
|
||||
builder.addThresholds(thresholdsOptions);
|
||||
const thresholdsOptions2 = {
|
||||
scaleKey: 'y2',
|
||||
thresholds: [{ thresholdValue: 200 }],
|
||||
};
|
||||
builder.addThresholds(thresholdsOptions2);
|
||||
|
||||
const config = builder.getConfig();
|
||||
const drawHooks = config.hooks?.draw ?? [];
|
||||
|
||||
// Two draw hooks should be registered for different scaleKeys
|
||||
expect(drawHooks.length).toBe(2);
|
||||
});
|
||||
|
||||
it('merges cursor configuration with defaults instead of replacing them', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
|
||||
builder.setCursor({
|
||||
drag: { setScale: false },
|
||||
});
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.cursor?.drag?.setScale).toBe(false);
|
||||
// Points configuration from DEFAULT_CURSOR_CONFIG should still be present
|
||||
expect(config.cursor?.points).toBeDefined();
|
||||
});
|
||||
|
||||
it('adds plugins and includes them in config', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
const plugin: uPlot.Plugin = {
|
||||
opts: (): void => {},
|
||||
hooks: {},
|
||||
};
|
||||
|
||||
builder.addPlugin(plugin);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.plugins).toContain(plugin);
|
||||
});
|
||||
|
||||
it('sets padding, legend, focus, select, tzDate, bands and includes them in config', () => {
|
||||
const tzDate = (ts: number): Date => new Date(ts);
|
||||
const builder = new UPlotConfigBuilder();
|
||||
|
||||
const bands: uPlot.Band[] = [{ series: [1, 2], fill: (): string => '#000' }];
|
||||
|
||||
builder.setBands(bands);
|
||||
builder.setPadding([10, 20, 30, 40]);
|
||||
builder.setLegend({ show: true, live: true });
|
||||
builder.setFocus({ alpha: 0.5 });
|
||||
builder.setSelect({ left: 0, width: 0, top: 0, height: 0 });
|
||||
builder.setTzDate(tzDate);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.bands).toEqual(bands);
|
||||
expect(config.padding).toEqual([10, 20, 30, 40]);
|
||||
expect(config.legend).toEqual({ show: true, live: true });
|
||||
expect(config.focus).toEqual({ alpha: 0.5 });
|
||||
expect(config.select).toEqual({ left: 0, width: 0, top: 0, height: 0 });
|
||||
expect(config.tzDate).toBe(tzDate);
|
||||
});
|
||||
|
||||
it('does not include plugins when none added', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.plugins).toBeUndefined();
|
||||
});
|
||||
|
||||
it('does not include bands when empty', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.bands).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -1,236 +0,0 @@
|
||||
import type uPlot from 'uplot';
|
||||
|
||||
import * as scaleUtils from '../../utils/scale';
|
||||
import type { ScaleProps } from '../types';
|
||||
import { DistributionType } from '../types';
|
||||
import { UPlotScaleBuilder } from '../UPlotScaleBuilder';
|
||||
|
||||
const createScaleProps = (overrides: Partial<ScaleProps> = {}): ScaleProps => ({
|
||||
scaleKey: 'y',
|
||||
time: false,
|
||||
auto: undefined,
|
||||
min: undefined,
|
||||
max: undefined,
|
||||
softMin: undefined,
|
||||
softMax: undefined,
|
||||
distribution: DistributionType.Linear,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
describe('UPlotScaleBuilder', () => {
|
||||
const getFallbackMinMaxSpy = jest.spyOn(
|
||||
scaleUtils,
|
||||
'getFallbackMinMaxTimeStamp',
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('initializes softMin/softMax correctly when both are 0 (treated as unset)', () => {
|
||||
const builder = new UPlotScaleBuilder(
|
||||
createScaleProps({
|
||||
softMin: 0,
|
||||
softMax: 0,
|
||||
}),
|
||||
);
|
||||
|
||||
// Non-time scale so config path uses thresholds pipeline; we just care that
|
||||
// adjustSoftLimitsWithThresholds receives null soft limits instead of 0/0.
|
||||
const adjustSpy = jest.spyOn(scaleUtils, 'adjustSoftLimitsWithThresholds');
|
||||
|
||||
builder.getConfig();
|
||||
|
||||
expect(adjustSpy).toHaveBeenCalledWith(null, null, undefined, undefined);
|
||||
});
|
||||
|
||||
it('handles time scales using explicit min/max and rounds max down to the previous minute', () => {
|
||||
const min = 1_700_000_000; // seconds
|
||||
const max = 1_700_000_600; // seconds
|
||||
|
||||
const builder = new UPlotScaleBuilder(
|
||||
createScaleProps({
|
||||
scaleKey: 'x',
|
||||
time: true,
|
||||
min,
|
||||
max,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
const xScale = config.x;
|
||||
|
||||
expect(xScale.time).toBe(true);
|
||||
expect(xScale.auto).toBe(false);
|
||||
expect(Array.isArray(xScale.range)).toBe(true);
|
||||
|
||||
const [resolvedMin, resolvedMax] = xScale.range as [number, number];
|
||||
|
||||
// min is passed through
|
||||
expect(resolvedMin).toBe(min);
|
||||
|
||||
// max is coerced to "endTime - 1 minute" and rounded down to minute precision
|
||||
const oneMinuteAgoTimestamp = (max - 60) * 1000;
|
||||
const currentDate = new Date(oneMinuteAgoTimestamp);
|
||||
currentDate.setSeconds(0);
|
||||
currentDate.setMilliseconds(0);
|
||||
const expectedMax = Math.floor(currentDate.getTime() / 1000);
|
||||
|
||||
expect(resolvedMax).toBe(expectedMax);
|
||||
});
|
||||
|
||||
it('falls back to getFallbackMinMaxTimeStamp when time scale has no min/max', () => {
|
||||
getFallbackMinMaxSpy.mockReturnValue({
|
||||
fallbackMin: 100,
|
||||
fallbackMax: 200,
|
||||
});
|
||||
|
||||
const builder = new UPlotScaleBuilder(
|
||||
createScaleProps({
|
||||
scaleKey: 'x',
|
||||
time: true,
|
||||
min: undefined,
|
||||
max: undefined,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
const [resolvedMin, resolvedMax] = config.x.range as [number, number];
|
||||
|
||||
expect(getFallbackMinMaxSpy).toHaveBeenCalled();
|
||||
expect(resolvedMin).toBe(100);
|
||||
// max is aligned to "fallbackMax - 60 seconds" minute boundary
|
||||
expect(resolvedMax).toBeLessThanOrEqual(200);
|
||||
expect(resolvedMax).toBeGreaterThan(100);
|
||||
});
|
||||
|
||||
it('pipes limits through soft-limit adjustment and log-scale normalization before range config', () => {
|
||||
const adjustSpy = jest.spyOn(scaleUtils, 'adjustSoftLimitsWithThresholds');
|
||||
const normalizeSpy = jest.spyOn(scaleUtils, 'normalizeLogScaleLimits');
|
||||
const getRangeConfigSpy = jest.spyOn(scaleUtils, 'getRangeConfig');
|
||||
|
||||
const thresholds = {
|
||||
scaleKey: 'y',
|
||||
thresholds: [{ thresholdValue: 10 }],
|
||||
yAxisUnit: 'ms',
|
||||
};
|
||||
|
||||
const builder = new UPlotScaleBuilder(
|
||||
createScaleProps({
|
||||
softMin: 1,
|
||||
softMax: 5,
|
||||
min: 0,
|
||||
max: 100,
|
||||
distribution: DistributionType.Logarithmic,
|
||||
thresholds,
|
||||
logBase: 2,
|
||||
padMinBy: 0.1,
|
||||
padMaxBy: 0.2,
|
||||
}),
|
||||
);
|
||||
|
||||
builder.getConfig();
|
||||
|
||||
expect(adjustSpy).toHaveBeenCalledWith(1, 5, thresholds.thresholds, 'ms');
|
||||
expect(normalizeSpy).toHaveBeenCalledWith({
|
||||
distr: DistributionType.Logarithmic,
|
||||
logBase: 2,
|
||||
limits: {
|
||||
min: 0,
|
||||
max: 100,
|
||||
softMin: expect.anything(),
|
||||
softMax: expect.anything(),
|
||||
},
|
||||
});
|
||||
expect(getRangeConfigSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('computes distribution config for non-time scales and wires range function when range is not provided', () => {
|
||||
const createRangeFnSpy = jest.spyOn(scaleUtils, 'createRangeFunction');
|
||||
|
||||
const builder = new UPlotScaleBuilder(
|
||||
createScaleProps({
|
||||
scaleKey: 'y',
|
||||
time: false,
|
||||
distribution: DistributionType.Linear,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
const yScale = config.y;
|
||||
|
||||
expect(createRangeFnSpy).toHaveBeenCalled();
|
||||
|
||||
// range should be a function when not provided explicitly
|
||||
expect(typeof yScale.range).toBe('function');
|
||||
|
||||
// distribution config should be applied
|
||||
expect(yScale.distr).toBeDefined();
|
||||
expect(yScale.log).toBeDefined();
|
||||
});
|
||||
|
||||
it('respects explicit range function when provided on props', () => {
|
||||
const explicitRange: uPlot.Scale.Range = jest.fn(() => [
|
||||
0,
|
||||
10,
|
||||
]) as uPlot.Scale.Range;
|
||||
|
||||
const builder = new UPlotScaleBuilder(
|
||||
createScaleProps({
|
||||
scaleKey: 'y',
|
||||
range: explicitRange,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
const yScale = config.y;
|
||||
|
||||
expect(yScale.range).toBe(explicitRange);
|
||||
});
|
||||
|
||||
it('derives auto flag when not explicitly provided, based on hasFixedRange and time', () => {
|
||||
const getRangeConfigSpy = jest.spyOn(scaleUtils, 'getRangeConfig');
|
||||
|
||||
const builder = new UPlotScaleBuilder(
|
||||
createScaleProps({
|
||||
min: 0,
|
||||
max: 100,
|
||||
time: false,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
const yScale = config.y;
|
||||
|
||||
expect(getRangeConfigSpy).toHaveBeenCalled();
|
||||
// For non-time scale with fixed min/max, hasFixedRange is true → auto should remain false
|
||||
expect(yScale.auto).toBe(false);
|
||||
});
|
||||
|
||||
it('merge updates internal min/max/soft limits while preserving other props', () => {
|
||||
const builder = new UPlotScaleBuilder(
|
||||
createScaleProps({
|
||||
scaleKey: 'y',
|
||||
min: 0,
|
||||
max: 10,
|
||||
softMin: 1,
|
||||
softMax: 9,
|
||||
time: false,
|
||||
}),
|
||||
);
|
||||
|
||||
builder.merge({
|
||||
min: 2,
|
||||
softMax: undefined,
|
||||
});
|
||||
|
||||
expect(builder.props.min).toBe(2);
|
||||
expect(builder.props.softMax).toBe(undefined);
|
||||
expect(builder.props.max).toBe(10);
|
||||
expect(builder.props.softMin).toBe(1);
|
||||
expect(builder.props.time).toBe(false);
|
||||
expect(builder.props.scaleKey).toBe('y');
|
||||
expect(builder.props.distribution).toBe(DistributionType.Linear);
|
||||
expect(builder.props.thresholds).toBe(undefined);
|
||||
});
|
||||
});
|
||||
@@ -1,295 +0,0 @@
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { themeColors } from 'constants/theme';
|
||||
import uPlot from 'uplot';
|
||||
|
||||
import type { SeriesProps } from '../types';
|
||||
import {
|
||||
DrawStyle,
|
||||
LineInterpolation,
|
||||
LineStyle,
|
||||
VisibilityMode,
|
||||
} from '../types';
|
||||
import { UPlotSeriesBuilder } from '../UPlotSeriesBuilder';
|
||||
|
||||
const createBaseProps = (
|
||||
overrides: Partial<SeriesProps> = {},
|
||||
): SeriesProps => ({
|
||||
scaleKey: 'y',
|
||||
label: 'Requests',
|
||||
colorMapping: {},
|
||||
drawStyle: DrawStyle.Line,
|
||||
isDarkMode: false,
|
||||
panelType: PANEL_TYPES.TIME_SERIES,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
interface MockPath extends uPlot.Series.Paths {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
describe('UPlotSeriesBuilder', () => {
|
||||
it('maps basic props into uPlot series config', () => {
|
||||
const builder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
label: 'Latency',
|
||||
spanGaps: true,
|
||||
show: false,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.scale).toBe('y');
|
||||
expect(config.label).toBe('Latency');
|
||||
expect(config.spanGaps).toBe(true);
|
||||
expect(config.show).toBe(false);
|
||||
expect(config.pxAlign).toBe(true);
|
||||
expect(typeof config.value).toBe('function');
|
||||
});
|
||||
|
||||
it('uses explicit lineColor when provided, regardless of mapping', () => {
|
||||
const builder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
lineColor: '#ff00ff',
|
||||
colorMapping: { Requests: '#00ff00' },
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.stroke).toBe('#ff00ff');
|
||||
});
|
||||
|
||||
it('falls back to theme colors when no label is provided', () => {
|
||||
const darkBuilder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
label: undefined,
|
||||
isDarkMode: true,
|
||||
lineColor: undefined,
|
||||
}),
|
||||
);
|
||||
const lightBuilder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
label: undefined,
|
||||
isDarkMode: false,
|
||||
lineColor: undefined,
|
||||
}),
|
||||
);
|
||||
|
||||
const darkConfig = darkBuilder.getConfig();
|
||||
const lightConfig = lightBuilder.getConfig();
|
||||
|
||||
expect(darkConfig.stroke).toBe(themeColors.white);
|
||||
expect(lightConfig.stroke).toBe(themeColors.black);
|
||||
});
|
||||
|
||||
it('uses colorMapping when available and no explicit lineColor is provided', () => {
|
||||
const builder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
label: 'Requests',
|
||||
colorMapping: { Requests: '#123456' },
|
||||
lineColor: undefined,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.stroke).toBe('#123456');
|
||||
});
|
||||
|
||||
it('passes through a custom pathBuilder when provided', () => {
|
||||
const customPaths = (jest.fn() as unknown) as uPlot.Series.PathBuilder;
|
||||
|
||||
const builder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
pathBuilder: customPaths,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.paths).toBe(customPaths);
|
||||
});
|
||||
|
||||
it('does not build line paths when drawStyle is Points, but still renders points', () => {
|
||||
const builder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
drawStyle: DrawStyle.Points,
|
||||
pointSize: 4,
|
||||
lineWidth: 2,
|
||||
lineColor: '#aa00aa',
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(typeof config.paths).toBe('function');
|
||||
expect(config.paths && config.paths({} as uPlot, 1, 0, 10)).toBeNull();
|
||||
|
||||
expect(config.points).toBeDefined();
|
||||
expect(config.points?.stroke).toBe('#aa00aa');
|
||||
expect(config.points?.fill).toBe('#aa00aa');
|
||||
expect(config.points?.show).toBe(true);
|
||||
expect(config.points?.size).toBe(4);
|
||||
});
|
||||
|
||||
it('derives point size based on lineWidth and pointSize', () => {
|
||||
const smallPointsBuilder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
lineWidth: 4,
|
||||
pointSize: 2,
|
||||
}),
|
||||
);
|
||||
const largePointsBuilder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
lineWidth: 2,
|
||||
pointSize: 4,
|
||||
}),
|
||||
);
|
||||
|
||||
const smallConfig = smallPointsBuilder.getConfig();
|
||||
const largeConfig = largePointsBuilder.getConfig();
|
||||
|
||||
expect(smallConfig.points?.size).toBeUndefined();
|
||||
expect(largeConfig.points?.size).toBe(4);
|
||||
});
|
||||
|
||||
it('uses pointsBuilder when provided instead of default visibility logic', () => {
|
||||
const pointsBuilder: uPlot.Series.Points.Show = jest.fn(
|
||||
() => true,
|
||||
) as uPlot.Series.Points.Show;
|
||||
|
||||
const builder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
pointsBuilder,
|
||||
drawStyle: DrawStyle.Line,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.points?.show).toBe(pointsBuilder);
|
||||
});
|
||||
|
||||
it('respects VisibilityMode for point visibility when no custom pointsBuilder is given', () => {
|
||||
const neverPointsBuilder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
drawStyle: DrawStyle.Line,
|
||||
showPoints: VisibilityMode.Never,
|
||||
}),
|
||||
);
|
||||
const alwaysPointsBuilder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
drawStyle: DrawStyle.Line,
|
||||
showPoints: VisibilityMode.Always,
|
||||
}),
|
||||
);
|
||||
|
||||
const neverConfig = neverPointsBuilder.getConfig();
|
||||
const alwaysConfig = alwaysPointsBuilder.getConfig();
|
||||
|
||||
expect(neverConfig.points?.show).toBe(false);
|
||||
expect(alwaysConfig.points?.show).toBe(true);
|
||||
});
|
||||
|
||||
it('applies LineStyle.Dashed and lineCap to line config', () => {
|
||||
const builder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
lineStyle: LineStyle.Dashed,
|
||||
lineCap: 'round' as CanvasLineCap,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.dash).toEqual([10, 10]);
|
||||
expect(config.cap).toBe('round');
|
||||
});
|
||||
|
||||
it('builds default paths for Line drawStyle and invokes the path builder', () => {
|
||||
const builder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
drawStyle: DrawStyle.Line,
|
||||
lineInterpolation: LineInterpolation.Linear,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
const result = config.paths?.({} as uPlot, 1, 0, 10);
|
||||
expect((result as MockPath).name).toBe('linear');
|
||||
});
|
||||
|
||||
it('uses StepBefore and StepAfter interpolation for line paths', () => {
|
||||
const stepBeforeBuilder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
drawStyle: DrawStyle.Line,
|
||||
lineInterpolation: LineInterpolation.StepBefore,
|
||||
}),
|
||||
);
|
||||
const stepAfterBuilder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
drawStyle: DrawStyle.Line,
|
||||
lineInterpolation: LineInterpolation.StepAfter,
|
||||
}),
|
||||
);
|
||||
|
||||
const stepBeforeConfig = stepBeforeBuilder.getConfig();
|
||||
const stepAfterConfig = stepAfterBuilder.getConfig();
|
||||
const stepBeforePath = stepBeforeConfig.paths?.({} as uPlot, 1, 0, 5);
|
||||
const stepAfterPath = stepAfterConfig.paths?.({} as uPlot, 1, 0, 5);
|
||||
expect((stepBeforePath as MockPath).name).toBe('stepped-(-1)');
|
||||
expect((stepAfterPath as MockPath).name).toBe('stepped-(1)');
|
||||
});
|
||||
|
||||
it('defaults to spline interpolation when lineInterpolation is Spline or undefined', () => {
|
||||
const splineBuilder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
drawStyle: DrawStyle.Line,
|
||||
lineInterpolation: LineInterpolation.Spline,
|
||||
}),
|
||||
);
|
||||
const defaultBuilder = new UPlotSeriesBuilder(
|
||||
createBaseProps({ drawStyle: DrawStyle.Line }),
|
||||
);
|
||||
|
||||
const splineConfig = splineBuilder.getConfig();
|
||||
const defaultConfig = defaultBuilder.getConfig();
|
||||
|
||||
const splinePath = splineConfig.paths?.({} as uPlot, 1, 0, 10);
|
||||
const defaultPath = defaultConfig.paths?.({} as uPlot, 1, 0, 10);
|
||||
|
||||
expect((splinePath as MockPath).name).toBe('spline');
|
||||
expect((defaultPath as MockPath).name).toBe('spline');
|
||||
});
|
||||
|
||||
it('uses generateColor when label has no colorMapping and no lineColor', () => {
|
||||
const builder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
label: 'CustomSeries',
|
||||
colorMapping: {},
|
||||
lineColor: undefined,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
expect(config.stroke).toBe('#E64A3C');
|
||||
});
|
||||
|
||||
it('passes through pointsFilter when provided', () => {
|
||||
const pointsFilter: uPlot.Series.Points.Filter = jest.fn(
|
||||
(_self, _seriesIdx, _show) => null,
|
||||
);
|
||||
|
||||
const builder = new UPlotSeriesBuilder(
|
||||
createBaseProps({
|
||||
pointsFilter,
|
||||
drawStyle: DrawStyle.Line,
|
||||
}),
|
||||
);
|
||||
|
||||
const config = builder.getConfig();
|
||||
|
||||
expect(config.points?.filter).toBe(pointsFilter);
|
||||
});
|
||||
});
|
||||
@@ -126,7 +126,45 @@ export enum VisibilityMode {
|
||||
Never = 'never',
|
||||
}
|
||||
|
||||
export interface SeriesProps {
|
||||
/**
|
||||
* Props for configuring lines
|
||||
*/
|
||||
export interface LineConfig {
|
||||
lineColor?: string;
|
||||
lineInterpolation?: LineInterpolation;
|
||||
lineStyle?: LineStyle;
|
||||
lineWidth?: number;
|
||||
lineCap?: Series.Cap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alignment of bars
|
||||
*/
|
||||
export enum BarAlignment {
|
||||
After = 1,
|
||||
Before = -1,
|
||||
Center = 0,
|
||||
}
|
||||
|
||||
/**
|
||||
* Props for configuring bars
|
||||
*/
|
||||
export interface BarConfig {
|
||||
barAlignment?: BarAlignment;
|
||||
barMaxWidth?: number;
|
||||
barWidthFactor?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Props for configuring points
|
||||
*/
|
||||
export interface PointsConfig {
|
||||
pointColor?: string;
|
||||
pointSize?: number;
|
||||
showPoints?: VisibilityMode;
|
||||
}
|
||||
|
||||
export interface SeriesProps extends LineConfig, PointsConfig, BarConfig {
|
||||
scaleKey: string;
|
||||
label?: string;
|
||||
panelType: PANEL_TYPES;
|
||||
@@ -137,20 +175,7 @@ export interface SeriesProps {
|
||||
pointsBuilder?: Series.Points.Show;
|
||||
show?: boolean;
|
||||
spanGaps?: boolean;
|
||||
|
||||
isDarkMode?: boolean;
|
||||
|
||||
// Line config
|
||||
lineColor?: string;
|
||||
lineInterpolation?: LineInterpolation;
|
||||
lineStyle?: LineStyle;
|
||||
lineWidth?: number;
|
||||
lineCap?: Series.Cap;
|
||||
|
||||
// Points config
|
||||
pointColor?: string;
|
||||
pointSize?: number;
|
||||
showPoints?: VisibilityMode;
|
||||
}
|
||||
|
||||
export interface LegendItem {
|
||||
|
||||
@@ -1,218 +0,0 @@
|
||||
import type uPlot from 'uplot';
|
||||
import { Axis } from 'uplot';
|
||||
|
||||
import {
|
||||
buildYAxisSizeCalculator,
|
||||
calculateTextWidth,
|
||||
getExistingAxisSize,
|
||||
} from '../axis';
|
||||
|
||||
describe('axis utils', () => {
|
||||
describe('calculateTextWidth', () => {
|
||||
it('returns 0 when values are undefined or empty', () => {
|
||||
const mockSelf = ({
|
||||
ctx: {
|
||||
measureText: jest.fn(),
|
||||
font: '',
|
||||
},
|
||||
} as unknown) as uPlot;
|
||||
|
||||
// internally the type is string but it is an array of strings
|
||||
const mockAxis: Axis = { font: (['12px sans-serif'] as unknown) as string };
|
||||
|
||||
expect(calculateTextWidth(mockSelf, mockAxis, undefined)).toBe(0);
|
||||
expect(calculateTextWidth(mockSelf, mockAxis, [])).toBe(0);
|
||||
});
|
||||
|
||||
it('returns 0 when longest value is empty string or axis has no usable font', () => {
|
||||
const mockSelf = ({
|
||||
ctx: {
|
||||
measureText: jest.fn(),
|
||||
font: '',
|
||||
},
|
||||
} as unknown) as uPlot;
|
||||
|
||||
const axisWithoutFont: Axis = { font: '' };
|
||||
const axisWithEmptyFontArray: Axis = { font: '' };
|
||||
|
||||
expect(calculateTextWidth(mockSelf, axisWithoutFont, [''])).toBe(0);
|
||||
expect(
|
||||
calculateTextWidth(mockSelf, axisWithEmptyFontArray, ['a', 'bb']),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it('measures longest value using canvas context and axis font', () => {
|
||||
const measureText = jest.fn(() => ({ width: 100 }));
|
||||
const mockSelf = ({
|
||||
ctx: {
|
||||
font: '',
|
||||
measureText,
|
||||
},
|
||||
} as unknown) as uPlot;
|
||||
|
||||
const mockAxis: Axis = { font: (['14px Arial'] as unknown) as string };
|
||||
const values = ['1', '1234', '12'];
|
||||
const dpr =
|
||||
((global as unknown) as { devicePixelRatio?: number }).devicePixelRatio ??
|
||||
1;
|
||||
|
||||
const result = calculateTextWidth(mockSelf, mockAxis, values);
|
||||
|
||||
expect(measureText).toHaveBeenCalledWith('1234');
|
||||
expect(mockSelf.ctx.font).toBe('14px Arial');
|
||||
expect(result).toBe(100 / dpr);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getExistingAxisSize', () => {
|
||||
it('returns internal _size when present', () => {
|
||||
const axis: any = {
|
||||
_size: 42,
|
||||
size: 10,
|
||||
};
|
||||
|
||||
const result = getExistingAxisSize({
|
||||
uplotInstance: ({} as unknown) as uPlot,
|
||||
axis,
|
||||
axisIdx: 0,
|
||||
cycleNum: 0,
|
||||
});
|
||||
|
||||
expect(result).toBe(42);
|
||||
});
|
||||
|
||||
it('invokes size function when _size is not set', () => {
|
||||
const sizeFn = jest.fn(() => 24);
|
||||
const axis: Axis = { size: sizeFn };
|
||||
const instance = ({} as unknown) as uPlot;
|
||||
|
||||
const result = getExistingAxisSize({
|
||||
uplotInstance: instance,
|
||||
axis,
|
||||
values: ['10', '20'],
|
||||
axisIdx: 1,
|
||||
cycleNum: 2,
|
||||
});
|
||||
|
||||
expect(sizeFn).toHaveBeenCalledWith(instance, ['10', '20'], 1, 2);
|
||||
expect(result).toBe(24);
|
||||
});
|
||||
|
||||
it('returns numeric size or 0 when neither _size nor size are provided', () => {
|
||||
const axisWithSize: Axis = { size: 16 };
|
||||
const axisWithoutSize: Axis = {};
|
||||
const instance = ({} as unknown) as uPlot;
|
||||
|
||||
expect(
|
||||
getExistingAxisSize({
|
||||
uplotInstance: instance,
|
||||
axis: axisWithSize,
|
||||
axisIdx: 0,
|
||||
cycleNum: 0,
|
||||
}),
|
||||
).toBe(16);
|
||||
|
||||
expect(
|
||||
getExistingAxisSize({
|
||||
uplotInstance: instance,
|
||||
axis: axisWithoutSize,
|
||||
axisIdx: 0,
|
||||
cycleNum: 0,
|
||||
}),
|
||||
).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildYAxisSizeCalculator', () => {
|
||||
it('delegates to getExistingAxisSize when cycleNum > 1', () => {
|
||||
const sizeCalculator = buildYAxisSizeCalculator(5);
|
||||
|
||||
const axis: any = {
|
||||
_size: 80,
|
||||
ticks: { size: 10 },
|
||||
font: ['12px sans-serif'],
|
||||
};
|
||||
|
||||
const measureText = jest.fn(() => ({ width: 60 }));
|
||||
const self = ({
|
||||
axes: [axis],
|
||||
ctx: {
|
||||
font: '',
|
||||
measureText,
|
||||
},
|
||||
} as unknown) as uPlot;
|
||||
|
||||
if (typeof sizeCalculator === 'number') {
|
||||
throw new Error('Size calculator is a number');
|
||||
}
|
||||
|
||||
const result = sizeCalculator(self, ['10', '20'], 0, 2);
|
||||
|
||||
expect(result).toBe(80);
|
||||
expect(measureText).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('computes size from ticks, gap and text width when cycleNum <= 1', () => {
|
||||
const gap = 7;
|
||||
const sizeCalculator = buildYAxisSizeCalculator(gap);
|
||||
|
||||
const axis: Axis = {
|
||||
ticks: { size: 12 },
|
||||
font: (['12px sans-serif'] as unknown) as string,
|
||||
};
|
||||
|
||||
const measureText = jest.fn(() => ({ width: 50 }));
|
||||
const self = ({
|
||||
axes: [axis],
|
||||
ctx: {
|
||||
font: '',
|
||||
measureText,
|
||||
},
|
||||
} as unknown) as uPlot;
|
||||
|
||||
const dpr =
|
||||
((global as unknown) as { devicePixelRatio?: number }).devicePixelRatio ??
|
||||
1;
|
||||
const expected = Math.ceil(12 + gap + 50 / dpr);
|
||||
|
||||
if (typeof sizeCalculator === 'number') {
|
||||
throw new Error('Size calculator is a number');
|
||||
}
|
||||
|
||||
const result = sizeCalculator(self, ['short', 'the-longest'], 0, 0);
|
||||
expect(measureText).toHaveBeenCalledWith('the-longest');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('uses 0 ticks size when ticks are not defined', () => {
|
||||
const gap = 4;
|
||||
const sizeCalculator = buildYAxisSizeCalculator(gap);
|
||||
|
||||
const axis: Axis = {
|
||||
font: (['12px sans-serif'] as unknown) as string,
|
||||
};
|
||||
|
||||
const measureText = jest.fn(() => ({ width: 40 }));
|
||||
const self = ({
|
||||
axes: [axis],
|
||||
ctx: {
|
||||
font: '',
|
||||
measureText,
|
||||
},
|
||||
} as unknown) as uPlot;
|
||||
|
||||
const dpr =
|
||||
((global as unknown) as { devicePixelRatio?: number }).devicePixelRatio ??
|
||||
1;
|
||||
const expected = Math.ceil(gap + 40 / dpr);
|
||||
|
||||
if (typeof sizeCalculator === 'number') {
|
||||
throw new Error('Size calculator is a number');
|
||||
}
|
||||
|
||||
const result = sizeCalculator(self, ['1', '123'], 0, 1);
|
||||
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,80 +0,0 @@
|
||||
import { Axis } from 'uplot';
|
||||
|
||||
/**
|
||||
* Calculate text width for longest value
|
||||
*/
|
||||
export function calculateTextWidth(
|
||||
self: uPlot,
|
||||
axis: Axis,
|
||||
values: string[] | undefined,
|
||||
): number {
|
||||
if (!values || values.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Find longest value
|
||||
const longestVal = values.reduce(
|
||||
(acc, val) => (val.length > acc.length ? val : acc),
|
||||
'',
|
||||
);
|
||||
|
||||
if (longestVal === '' || !axis.font?.[0]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
self.ctx.font = axis.font[0];
|
||||
return self.ctx.measureText(longestVal).width / devicePixelRatio;
|
||||
}
|
||||
|
||||
export function getExistingAxisSize({
|
||||
uplotInstance,
|
||||
axis,
|
||||
values,
|
||||
axisIdx,
|
||||
cycleNum,
|
||||
}: {
|
||||
uplotInstance: uPlot;
|
||||
axis: Axis;
|
||||
values?: string[];
|
||||
axisIdx: number;
|
||||
cycleNum: number;
|
||||
}): number {
|
||||
const internalSize = (axis as { _size?: number })._size;
|
||||
if (internalSize !== undefined) {
|
||||
return internalSize;
|
||||
}
|
||||
|
||||
const existingSize = axis.size;
|
||||
if (typeof existingSize === 'function') {
|
||||
return existingSize(uplotInstance, values ?? [], axisIdx, cycleNum);
|
||||
}
|
||||
|
||||
return existingSize ?? 0;
|
||||
}
|
||||
|
||||
export function buildYAxisSizeCalculator(gap: number): uPlot.Axis.Size {
|
||||
return (
|
||||
self: uPlot,
|
||||
values: string[] | undefined,
|
||||
axisIdx: number,
|
||||
cycleNum: number,
|
||||
): number => {
|
||||
const axis = self.axes[axisIdx];
|
||||
|
||||
// Bail out, force convergence
|
||||
if (cycleNum > 1) {
|
||||
return getExistingAxisSize({
|
||||
uplotInstance: self,
|
||||
axis,
|
||||
values,
|
||||
axisIdx,
|
||||
cycleNum,
|
||||
});
|
||||
}
|
||||
|
||||
let axisSize = (axis.ticks?.size ?? 0) + gap;
|
||||
axisSize += calculateTextWidth(self, axis, values);
|
||||
|
||||
return Math.ceil(axisSize);
|
||||
};
|
||||
}
|
||||
@@ -6,6 +6,8 @@ const DOCLINKS = {
|
||||
'https://signoz.io/docs/product-features/trace-explorer/?utm_source=product&utm_medium=traces-explorer-trace-tab#traces-view',
|
||||
METRICS_EXPLORER_EMPTY_STATE:
|
||||
'https://signoz.io/docs/userguide/send-metrics-cloud/',
|
||||
EXTERNAL_API_MONITORING:
|
||||
'https://signoz.io/docs/external-api-monitoring/overview/',
|
||||
};
|
||||
|
||||
export default DOCLINKS;
|
||||
|
||||
@@ -278,7 +278,7 @@ func (q *querier) QueryRange(ctx context.Context, orgID valuer.UUID, req *qbtype
|
||||
var metricTemporality map[string]metrictypes.Temporality
|
||||
if len(metricNames) > 0 {
|
||||
var err error
|
||||
metricTemporality, err = q.metadataStore.FetchTemporalityMulti(ctx, metricNames...)
|
||||
metricTemporality, err = q.metadataStore.FetchTemporalityMulti(ctx, req.Start, req.End, metricNames...)
|
||||
if err != nil {
|
||||
q.logger.WarnContext(ctx, "failed to fetch metric temporality", "error", err, "metrics", metricNames)
|
||||
// Continue without temporality - statement builder will handle unspecified
|
||||
|
||||
@@ -1597,12 +1597,12 @@ func (t *telemetryMetaStore) GetAllValues(ctx context.Context, fieldValueSelecto
|
||||
return values, complete, nil
|
||||
}
|
||||
|
||||
func (t *telemetryMetaStore) FetchTemporality(ctx context.Context, metricName string) (metrictypes.Temporality, error) {
|
||||
func (t *telemetryMetaStore) FetchTemporality(ctx context.Context, queryTimeRangeStartTs, queryTimeRangeEndTs uint64, metricName string) (metrictypes.Temporality, error) {
|
||||
if metricName == "" {
|
||||
return metrictypes.Unknown, errors.Newf(errors.TypeInternal, errors.CodeInternal, "metric name cannot be empty")
|
||||
}
|
||||
|
||||
temporalityMap, err := t.FetchTemporalityMulti(ctx, metricName)
|
||||
temporalityMap, err := t.FetchTemporalityMulti(ctx, queryTimeRangeStartTs, queryTimeRangeEndTs, metricName)
|
||||
if err != nil {
|
||||
return metrictypes.Unknown, err
|
||||
}
|
||||
@@ -1615,13 +1615,13 @@ func (t *telemetryMetaStore) FetchTemporality(ctx context.Context, metricName st
|
||||
return temporality, nil
|
||||
}
|
||||
|
||||
func (t *telemetryMetaStore) FetchTemporalityMulti(ctx context.Context, metricNames ...string) (map[string]metrictypes.Temporality, error) {
|
||||
func (t *telemetryMetaStore) FetchTemporalityMulti(ctx context.Context, queryTimeRangeStartTs, queryTimeRangeEndTs uint64, metricNames ...string) (map[string]metrictypes.Temporality, error) {
|
||||
if len(metricNames) == 0 {
|
||||
return make(map[string]metrictypes.Temporality), nil
|
||||
}
|
||||
|
||||
result := make(map[string]metrictypes.Temporality)
|
||||
metricsTemporality, err := t.fetchMetricsTemporality(ctx, metricNames...)
|
||||
metricsTemporality, err := t.fetchMetricsTemporality(ctx, queryTimeRangeStartTs, queryTimeRangeEndTs, metricNames...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1630,8 +1630,12 @@ func (t *telemetryMetaStore) FetchTemporalityMulti(ctx context.Context, metricNa
|
||||
|
||||
// For metrics not found in the database, set to Unknown
|
||||
for _, metricName := range metricNames {
|
||||
if temporality, exists := metricsTemporality[metricName]; exists {
|
||||
result[metricName] = temporality
|
||||
if temporality, exists := metricsTemporality[metricName]; exists && len(temporality) > 0 {
|
||||
if len(temporality) > 1 {
|
||||
result[metricName] = metrictypes.Multiple
|
||||
} else {
|
||||
result[metricName] = temporality[0]
|
||||
}
|
||||
continue
|
||||
}
|
||||
if temporality, exists := meterMetricsTemporality[metricName]; exists {
|
||||
@@ -1644,8 +1648,10 @@ func (t *telemetryMetaStore) FetchTemporalityMulti(ctx context.Context, metricNa
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (t *telemetryMetaStore) fetchMetricsTemporality(ctx context.Context, metricNames ...string) (map[string]metrictypes.Temporality, error) {
|
||||
result := make(map[string]metrictypes.Temporality)
|
||||
func (t *telemetryMetaStore) fetchMetricsTemporality(ctx context.Context, queryTimeRangeStartTs, queryTimeRangeEndTs uint64, metricNames ...string) (map[string][]metrictypes.Temporality, error) {
|
||||
result := make(map[string][]metrictypes.Temporality)
|
||||
|
||||
adjustedStartTs, adjustedEndTs, tsTableName, _ := telemetrymetrics.WhichTSTableToUse(queryTimeRangeStartTs, queryTimeRangeEndTs, nil)
|
||||
|
||||
// Build query to fetch temporality for all metrics
|
||||
// We use attr_string_value where attr_name = '__temporality__'
|
||||
@@ -1653,14 +1659,18 @@ func (t *telemetryMetaStore) fetchMetricsTemporality(ctx context.Context, metric
|
||||
// and metric_name column contains temporality value, so we use the correct mapping
|
||||
sb := sqlbuilder.Select(
|
||||
"metric_name",
|
||||
"argMax(temporality, last_reported_unix_milli) as temporality",
|
||||
).From(t.metricsDBName + "." + t.metricsFieldsTblName)
|
||||
"temporality",
|
||||
).
|
||||
From(t.metricsDBName + "." + tsTableName)
|
||||
|
||||
// Filter by metric names (in the temporality column due to data mix-up)
|
||||
sb.Where(sb.In("metric_name", metricNames))
|
||||
sb.Where(
|
||||
sb.In("metric_name", metricNames),
|
||||
sb.GTE("unix_milli", adjustedStartTs),
|
||||
sb.LT("unix_milli", adjustedEndTs),
|
||||
)
|
||||
|
||||
// Group by metric name to get one temporality per metric
|
||||
sb.GroupBy("metric_name")
|
||||
sb.GroupBy("metric_name", "temporality")
|
||||
|
||||
query, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
|
||||
|
||||
@@ -1692,8 +1702,12 @@ func (t *telemetryMetaStore) fetchMetricsTemporality(ctx context.Context, metric
|
||||
// Unknown or empty temporality
|
||||
temporality = metrictypes.Unknown
|
||||
}
|
||||
|
||||
result[metricName] = temporality
|
||||
if temporality != metrictypes.Unknown {
|
||||
result[metricName] = append(result[metricName], temporality)
|
||||
}
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, "error iterating over metrics temporality rows")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
@@ -21,6 +21,10 @@ const (
|
||||
RateWithoutNegative = `If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1, toDateTime(fromUnixTimestamp64Milli(%d))) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDateTime(fromUnixTimestamp64Milli(%d))) OVER rate_window))`
|
||||
IncreaseWithoutNegative = `If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, per_series_value, ((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDateTime(fromUnixTimestamp64Milli(%d))) OVER rate_window)) * (ts - lagInFrame(ts, 1, toDateTime(fromUnixTimestamp64Milli(%d))) OVER rate_window))`
|
||||
|
||||
RateWithoutNegativeMultiTemporality = `IF(LOWER(temporality) LIKE LOWER('delta'), %s, IF((%s - lagInFrame(%s, 1, 0) OVER rate_window) < 0, %s / (ts - lagInFrame(ts, 1, toDateTime(fromUnixTimestamp64Milli(%d))) OVER rate_window), (%s - lagInFrame(%s, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDateTime(fromUnixTimestamp64Milli(%d))) OVER rate_window))) AS per_series_value`
|
||||
IncreaseWithoutNegativeMultiTemporality = `IF(LOWER(temporality) LIKE LOWER('delta'), %s, IF((%s - lagInFrame(%s, 1, 0) OVER rate_window) < 0, %s, ((%s - lagInFrame(%s, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDateTime(fromUnixTimestamp64Milli(%d))) OVER rate_window)) * (ts - lagInFrame(ts, 1, toDateTime(fromUnixTimestamp64Milli(%d))) OVER rate_window))) AS per_series_value`
|
||||
OthersMultiTemporality = `IF(LOWER(temporality) LIKE LOWER('delta'), %s, %s) AS per_series_value`
|
||||
|
||||
RateWithInterpolation = `
|
||||
CASE
|
||||
WHEN row_number() OVER rate_window = 1 THEN
|
||||
@@ -377,7 +381,7 @@ func (b *MetricQueryStatementBuilder) buildTimeSeriesCTE(
|
||||
sb.LTE("unix_milli", end),
|
||||
)
|
||||
|
||||
if query.Aggregations[0].Temporality != metrictypes.Unknown {
|
||||
if query.Aggregations[0].Temporality != metrictypes.Multiple && query.Aggregations[0].Temporality != metrictypes.Unknown {
|
||||
sb.Where(sb.ILike("temporality", query.Aggregations[0].Temporality.StringValue()))
|
||||
}
|
||||
|
||||
@@ -407,8 +411,10 @@ func (b *MetricQueryStatementBuilder) buildTemporalAggregationCTE(
|
||||
) (string, []any, error) {
|
||||
if query.Aggregations[0].Temporality == metrictypes.Delta {
|
||||
return b.buildTemporalAggDelta(ctx, start, end, query, timeSeriesCTE, timeSeriesCTEArgs)
|
||||
} else if query.Aggregations[0].Temporality != metrictypes.Multiple {
|
||||
return b.buildTemporalAggCumulativeOrUnspecified(ctx, start, end, query, timeSeriesCTE, timeSeriesCTEArgs)
|
||||
}
|
||||
return b.buildTemporalAggCumulativeOrUnspecified(ctx, start, end, query, timeSeriesCTE, timeSeriesCTEArgs)
|
||||
return b.buildTemporalAggForMultipleTemporalities(ctx, start, end, query, timeSeriesCTE, timeSeriesCTEArgs)
|
||||
}
|
||||
|
||||
func (b *MetricQueryStatementBuilder) buildTemporalAggDelta(
|
||||
@@ -528,6 +534,58 @@ func (b *MetricQueryStatementBuilder) buildTemporalAggCumulativeOrUnspecified(
|
||||
}
|
||||
}
|
||||
|
||||
// because RateInterpolation is not enabled anywhere due to some gaps in the logic wrt cache handling, it hasn't been considered for the multi temporality
|
||||
func (b *MetricQueryStatementBuilder) buildTemporalAggForMultipleTemporalities(
|
||||
_ context.Context,
|
||||
start, end uint64,
|
||||
query qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation],
|
||||
timeSeriesCTE string,
|
||||
timeSeriesCTEArgs []any,
|
||||
) (string, []any, error) {
|
||||
stepSec := int64(query.StepInterval.Seconds())
|
||||
sb := sqlbuilder.NewSelectBuilder()
|
||||
|
||||
sb.SelectMore(fmt.Sprintf(
|
||||
"toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(%d)) AS ts",
|
||||
stepSec,
|
||||
))
|
||||
for _, g := range query.GroupBy {
|
||||
sb.SelectMore(fmt.Sprintf("`%s`", g.TelemetryFieldKey.Name))
|
||||
}
|
||||
|
||||
aggForDeltaTemporality := AggregationColumnForSamplesTable(start, end, query.Aggregations[0].Type, metrictypes.Delta, query.Aggregations[0].TimeAggregation, query.Aggregations[0].TableHints)
|
||||
aggForCumulativeTemporality := AggregationColumnForSamplesTable(start, end, query.Aggregations[0].Type, metrictypes.Cumulative, query.Aggregations[0].TimeAggregation, query.Aggregations[0].TableHints)
|
||||
if query.Aggregations[0].TimeAggregation == metrictypes.TimeAggregationRate {
|
||||
aggForDeltaTemporality = fmt.Sprintf("%s/%d", aggForDeltaTemporality, stepSec)
|
||||
}
|
||||
|
||||
switch query.Aggregations[0].TimeAggregation {
|
||||
case metrictypes.TimeAggregationRate:
|
||||
rateExpr := fmt.Sprintf(RateWithoutNegativeMultiTemporality, aggForDeltaTemporality, aggForCumulativeTemporality, aggForCumulativeTemporality, aggForCumulativeTemporality, start, aggForCumulativeTemporality, aggForCumulativeTemporality, start)
|
||||
sb.SelectMore(rateExpr)
|
||||
case metrictypes.TimeAggregationIncrease:
|
||||
increaseExpr := fmt.Sprintf(IncreaseWithoutNegativeMultiTemporality, aggForDeltaTemporality, aggForCumulativeTemporality, aggForCumulativeTemporality, aggForCumulativeTemporality, aggForCumulativeTemporality, aggForCumulativeTemporality, start, start)
|
||||
sb.SelectMore(increaseExpr)
|
||||
default:
|
||||
expr := fmt.Sprintf(OthersMultiTemporality, aggForDeltaTemporality, aggForCumulativeTemporality)
|
||||
sb.SelectMore(expr)
|
||||
}
|
||||
|
||||
tbl := WhichSamplesTableToUse(start, end, query.Aggregations[0].Type, query.Aggregations[0].TimeAggregation, query.Aggregations[0].TableHints)
|
||||
sb.From(fmt.Sprintf("%s.%s AS points", DBName, tbl))
|
||||
sb.JoinWithOption(sqlbuilder.InnerJoin, timeSeriesCTE, "points.fingerprint = filtered_time_series.fingerprint")
|
||||
sb.Where(
|
||||
sb.In("metric_name", query.Aggregations[0].MetricName),
|
||||
sb.GTE("unix_milli", start),
|
||||
sb.LT("unix_milli", end),
|
||||
)
|
||||
sb.GroupBy("fingerprint", "ts", "temporality")
|
||||
sb.GroupBy(querybuilder.GroupByKeys(query.GroupBy)...)
|
||||
queryWithoutWindow, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse, timeSeriesCTEArgs...)
|
||||
queryWithWindowAndOrder := queryWithoutWindow + " WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint ASC, ts ASC) ORDER BY ts"
|
||||
return fmt.Sprintf("__temporal_aggregation_cte AS (%s)", queryWithWindowAndOrder), args, nil
|
||||
}
|
||||
|
||||
func (b *MetricQueryStatementBuilder) buildSpatialAggregationCTE(
|
||||
_ context.Context,
|
||||
_ uint64,
|
||||
|
||||
@@ -151,7 +151,8 @@ func (c *AccountConfig) Value() (driver.Value, error) {
|
||||
if err != nil {
|
||||
return nil, errors.WrapInternalf(err, errors.CodeInternal, "couldn't serialize cloud account config to JSON")
|
||||
}
|
||||
return serialized, nil
|
||||
// Return as string instead of []byte to ensure PostgreSQL stores as text, not bytea
|
||||
return string(serialized), nil
|
||||
}
|
||||
|
||||
type AgentReport struct {
|
||||
@@ -186,7 +187,8 @@ func (r *AgentReport) Value() (driver.Value, error) {
|
||||
err, errors.CodeInternal, "couldn't serialize agent report to JSON",
|
||||
)
|
||||
}
|
||||
return serialized, nil
|
||||
// Return as string instead of []byte to ensure PostgreSQL stores as text, not bytea
|
||||
return string(serialized), nil
|
||||
}
|
||||
|
||||
type CloudIntegrationService struct {
|
||||
@@ -240,5 +242,6 @@ func (c *CloudServiceConfig) Value() (driver.Value, error) {
|
||||
err, errors.CodeInternal, "couldn't serialize cloud service config to JSON",
|
||||
)
|
||||
}
|
||||
return serialized, nil
|
||||
// Return as string instead of []byte to ensure PostgreSQL stores as text, not bytea
|
||||
return string(serialized), nil
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ var (
|
||||
Cumulative = Temporality{valuer.NewString("cumulative")}
|
||||
Unspecified = Temporality{valuer.NewString("unspecified")}
|
||||
Unknown = Temporality{valuer.NewString("")}
|
||||
Multiple = Temporality{valuer.NewString("__multiple__")}
|
||||
)
|
||||
|
||||
func (t Temporality) Value() (driver.Value, error) {
|
||||
|
||||
@@ -27,10 +27,10 @@ type MetadataStore interface {
|
||||
GetAllValues(ctx context.Context, fieldValueSelector *FieldValueSelector) (*TelemetryFieldValues, bool, error)
|
||||
|
||||
// FetchTemporality fetches the temporality for metric
|
||||
FetchTemporality(ctx context.Context, metricName string) (metrictypes.Temporality, error)
|
||||
FetchTemporality(ctx context.Context, queryTimeRangeStartTs, queryTimeRangeEndTs uint64, metricName string) (metrictypes.Temporality, error)
|
||||
|
||||
// FetchTemporalityMulti fetches the temporality for multiple metrics
|
||||
FetchTemporalityMulti(ctx context.Context, metricNames ...string) (map[string]metrictypes.Temporality, error)
|
||||
FetchTemporalityMulti(ctx context.Context, queryTimeRangeStartTs, queryTimeRangeEndTs uint64, metricNames ...string) (map[string]metrictypes.Temporality, error)
|
||||
|
||||
// ListLogsJSONIndexes lists the JSON indexes for the logs table.
|
||||
ListLogsJSONIndexes(ctx context.Context, filters ...string) (map[string][]schemamigrator.Index, error)
|
||||
|
||||
@@ -265,7 +265,7 @@ func (m *MockMetadataStore) SetAllValues(lookupKey string, values *telemetrytype
|
||||
}
|
||||
|
||||
// FetchTemporality fetches the temporality for a metric
|
||||
func (m *MockMetadataStore) FetchTemporality(ctx context.Context, metricName string) (metrictypes.Temporality, error) {
|
||||
func (m *MockMetadataStore) FetchTemporality(ctx context.Context, queryTimeRangeStartTs, queryTimeRangeEndTs uint64, metricName string) (metrictypes.Temporality, error) {
|
||||
if temporality, exists := m.TemporalityMap[metricName]; exists {
|
||||
return temporality, nil
|
||||
}
|
||||
@@ -273,7 +273,7 @@ func (m *MockMetadataStore) FetchTemporality(ctx context.Context, metricName str
|
||||
}
|
||||
|
||||
// FetchTemporalityMulti fetches the temporality for multiple metrics
|
||||
func (m *MockMetadataStore) FetchTemporalityMulti(ctx context.Context, metricNames ...string) (map[string]metrictypes.Temporality, error) {
|
||||
func (m *MockMetadataStore) FetchTemporalityMulti(ctx context.Context, queryTimeRangeStartTs, queryTimeRangeEndTs uint64, metricNames ...string) (map[string]metrictypes.Temporality, error) {
|
||||
result := make(map[string]metrictypes.Temporality)
|
||||
|
||||
for _, metricName := range metricNames {
|
||||
|
||||
@@ -20,6 +20,7 @@ pytest_plugins = [
|
||||
"fixtures.idputils",
|
||||
"fixtures.notification_channel",
|
||||
"fixtures.alerts",
|
||||
"fixtures.cloudintegrations",
|
||||
]
|
||||
|
||||
|
||||
|
||||
88
tests/integration/fixtures/cloudintegrations.py
Normal file
88
tests/integration/fixtures/cloudintegrations.py
Normal file
@@ -0,0 +1,88 @@
|
||||
"""Fixtures for cloud integration tests."""
|
||||
from typing import Callable, Optional
|
||||
from http import HTTPStatus
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from fixtures import types
|
||||
from fixtures.logger import setup_logger
|
||||
from fixtures.auth import USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD
|
||||
|
||||
logger = setup_logger(__name__)
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def create_cloud_integration_account(
|
||||
request: pytest.FixtureRequest,
|
||||
signoz: types.SigNoz,
|
||||
) -> Callable[[str, str], dict]:
|
||||
created_account_id: Optional[str] = None
|
||||
cloud_provider_used: Optional[str] = None
|
||||
|
||||
def _create(
|
||||
admin_token: str,
|
||||
cloud_provider: str = "aws",
|
||||
) -> dict:
|
||||
nonlocal created_account_id, cloud_provider_used
|
||||
endpoint = (
|
||||
f"/api/v1/cloud-integrations/{cloud_provider}/accounts/generate-connection-url"
|
||||
)
|
||||
|
||||
request_payload = {
|
||||
"account_config": {"regions": ["us-east-1"]},
|
||||
"agent_config": {
|
||||
"region": "us-east-1",
|
||||
"ingestion_url": "https://ingest.test.signoz.cloud",
|
||||
"ingestion_key": "test-ingestion-key-123456",
|
||||
"signoz_api_url": "https://test-deployment.test.signoz.cloud",
|
||||
"signoz_api_key": "test-api-key-789",
|
||||
"version": "v0.0.8",
|
||||
},
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
json=request_payload,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Failed to create test account: {response.status_code}"
|
||||
|
||||
data = response.json().get("data", response.json())
|
||||
created_account_id = data.get("account_id")
|
||||
cloud_provider_used = cloud_provider
|
||||
|
||||
return data
|
||||
|
||||
def _disconnect(admin_token: str, cloud_provider: str) -> requests.Response:
|
||||
assert created_account_id
|
||||
disconnect_endpoint = (
|
||||
f"/api/v1/cloud-integrations/{cloud_provider}/accounts/{created_account_id}/disconnect"
|
||||
)
|
||||
return requests.post(
|
||||
signoz.self.host_configs["8080"].get(disconnect_endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
# Yield factory to the test
|
||||
yield _create
|
||||
|
||||
# Post-test cleanup: generate admin token and disconnect the created account
|
||||
if created_account_id and cloud_provider_used:
|
||||
get_token = request.getfixturevalue("get_token")
|
||||
try:
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
r = _disconnect(admin_token, cloud_provider_used)
|
||||
if r.status_code != HTTPStatus.OK:
|
||||
logger.info(
|
||||
"Disconnect cleanup returned %s for account %s",
|
||||
r.status_code,
|
||||
created_account_id,
|
||||
)
|
||||
logger.info("Cleaned up test account: %s", created_account_id)
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
logger.info("Post-test disconnect cleanup failed: %s", exc)
|
||||
46
tests/integration/fixtures/cloudintegrationsutils.py
Normal file
46
tests/integration/fixtures/cloudintegrationsutils.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""Fixtures for cloud integration tests."""
|
||||
from http import HTTPStatus
|
||||
|
||||
import requests
|
||||
|
||||
from fixtures import types
|
||||
from fixtures.logger import setup_logger
|
||||
|
||||
logger = setup_logger(__name__)
|
||||
|
||||
|
||||
def simulate_agent_checkin(
|
||||
signoz: types.SigNoz,
|
||||
admin_token: str,
|
||||
cloud_provider: str,
|
||||
account_id: str,
|
||||
cloud_account_id: str,
|
||||
) -> dict:
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/agent-check-in"
|
||||
|
||||
checkin_payload = {
|
||||
"account_id": account_id,
|
||||
"cloud_account_id": cloud_account_id,
|
||||
"data": {},
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
json=checkin_payload,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
if response.status_code != HTTPStatus.OK:
|
||||
logger.error(
|
||||
"Agent check-in failed: %s, response: %s",
|
||||
response.status_code,
|
||||
response.text,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Agent check-in failed: {response.status_code}"
|
||||
|
||||
response_data = response.json()
|
||||
return response_data.get("data", response_data)
|
||||
@@ -52,7 +52,7 @@ def build_builder_query(
|
||||
time_aggregation: str,
|
||||
space_aggregation: str,
|
||||
*,
|
||||
temporality: str = "cumulative",
|
||||
temporality: Optional[str] = None,
|
||||
step_interval: int = DEFAULT_STEP_INTERVAL,
|
||||
group_by: Optional[List[str]] = None,
|
||||
filter_expression: Optional[str] = None,
|
||||
@@ -65,7 +65,6 @@ def build_builder_query(
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": metric_name,
|
||||
"temporality": temporality,
|
||||
"timeAggregation": time_aggregation,
|
||||
"spaceAggregation": space_aggregation,
|
||||
}
|
||||
@@ -73,6 +72,8 @@ def build_builder_query(
|
||||
"stepInterval": step_interval,
|
||||
"disabled": disabled,
|
||||
}
|
||||
if temporality:
|
||||
spec["aggregations"][0]["temporality"] = temporality
|
||||
|
||||
if group_by:
|
||||
spec["groupBy"] = [
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
from http import HTTPStatus
|
||||
from typing import Callable
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from fixtures import types
|
||||
from fixtures.auth import USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD
|
||||
from fixtures.logger import setup_logger
|
||||
|
||||
logger = setup_logger(__name__)
|
||||
|
||||
|
||||
def test_generate_connection_url(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Test to generate connection URL for AWS CloudFormation stack deployment."""
|
||||
|
||||
# Get authentication token for admin user
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
cloud_provider = "aws"
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/accounts/generate-connection-url"
|
||||
|
||||
# Prepare request payload
|
||||
request_payload = {
|
||||
"account_config": {"regions": ["us-east-1", "us-west-2"]},
|
||||
"agent_config": {
|
||||
"region": "us-east-1",
|
||||
"ingestion_url": "https://ingest.test.signoz.cloud",
|
||||
"ingestion_key": "test-ingestion-key-123456",
|
||||
"signoz_api_url": "https://test-deployment.test.signoz.cloud",
|
||||
"signoz_api_key": "test-api-key-789",
|
||||
"version": "v0.0.8",
|
||||
},
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
json=request_payload,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
# Assert successful response
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}: {response.text}"
|
||||
|
||||
# Parse response JSON
|
||||
response_data = response.json()
|
||||
|
||||
# Assert response structure contains expected data
|
||||
assert "data" in response_data, "Response should contain 'data' field"
|
||||
|
||||
# Assert required fields in the response data
|
||||
expected_fields = ["account_id", "connection_url"]
|
||||
|
||||
for field in expected_fields:
|
||||
assert (
|
||||
field in response_data["data"]
|
||||
), f"Response data should contain '{field}' field"
|
||||
|
||||
data = response_data["data"]
|
||||
|
||||
# Assert account_id is a valid UUID format
|
||||
assert (
|
||||
len(data["account_id"]) > 0
|
||||
), "account_id should be a non-empty string (UUID)"
|
||||
|
||||
# Assert connection_url contains expected CloudFormation parameters
|
||||
connection_url = data["connection_url"]
|
||||
|
||||
# Verify it's an AWS CloudFormation URL
|
||||
assert (
|
||||
"console.aws.amazon.com/cloudformation" in connection_url
|
||||
), "connection_url should be an AWS CloudFormation URL"
|
||||
|
||||
# Verify region is included
|
||||
assert (
|
||||
"region=us-east-1" in connection_url
|
||||
), "connection_url should contain the specified region"
|
||||
|
||||
# Verify required parameters are in the URL
|
||||
required_params = [
|
||||
"param_SigNozIntegrationAgentVersion=v0.0.8",
|
||||
"param_SigNozApiUrl=https%3A%2F%2Ftest-deployment.test.signoz.cloud",
|
||||
"param_SigNozApiKey=test-api-key-789",
|
||||
"param_SigNozAccountId=", # Will be a UUID
|
||||
"param_IngestionUrl=https%3A%2F%2Fingest.test.signoz.cloud",
|
||||
"param_IngestionKey=test-ingestion-key-123456",
|
||||
"stackName=signoz-integration",
|
||||
"templateURL=https%3A%2F%2Fsignoz-integrations.s3.us-east-1.amazonaws.com%2Faws-quickcreate-template-v0.0.8.json",
|
||||
]
|
||||
|
||||
for param in required_params:
|
||||
assert (
|
||||
param in connection_url
|
||||
), f"connection_url should contain parameter: {param}"
|
||||
|
||||
|
||||
def test_generate_connection_url_unsupported_provider(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Test that unsupported cloud providers return an error."""
|
||||
# Get authentication token for admin user
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
# Try with GCP (unsupported)
|
||||
cloud_provider = "gcp"
|
||||
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/accounts/generate-connection-url"
|
||||
|
||||
request_payload = {
|
||||
"account_config": {"regions": ["us-central1"]},
|
||||
"agent_config": {
|
||||
"region": "us-central1",
|
||||
"ingestion_url": "https://ingest.test.signoz.cloud",
|
||||
"ingestion_key": "test-ingestion-key-123456",
|
||||
"signoz_api_url": "https://test-deployment.test.signoz.cloud",
|
||||
"signoz_api_key": "test-api-key-789",
|
||||
},
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
json=request_payload,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
# Should return Bad Request for unsupported provider
|
||||
assert (
|
||||
response.status_code == HTTPStatus.BAD_REQUEST
|
||||
), f"Expected 400 for unsupported provider, got {response.status_code}"
|
||||
|
||||
response_data = response.json()
|
||||
assert "error" in response_data, "Response should contain 'error' field"
|
||||
assert (
|
||||
"unsupported cloud provider" in response_data["error"].lower()
|
||||
), "Error message should indicate unsupported provider"
|
||||
316
tests/integration/src/cloudintegrations/03_accounts.py
Normal file
316
tests/integration/src/cloudintegrations/03_accounts.py
Normal file
@@ -0,0 +1,316 @@
|
||||
from http import HTTPStatus
|
||||
from typing import Callable
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from fixtures import types
|
||||
from fixtures.auth import USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD
|
||||
from fixtures.logger import setup_logger
|
||||
from fixtures.cloudintegrations import (
|
||||
create_cloud_integration_account,
|
||||
)
|
||||
from fixtures.cloudintegrationsutils import simulate_agent_checkin
|
||||
|
||||
logger = setup_logger(__name__)
|
||||
|
||||
|
||||
def test_list_connected_accounts_empty(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Test listing connected accounts when there are none."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
cloud_provider = "aws"
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/accounts"
|
||||
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}"
|
||||
|
||||
response_data = response.json()
|
||||
data = response_data.get("data", response_data)
|
||||
assert "accounts" in data, "Response should contain 'accounts' field"
|
||||
assert isinstance(data["accounts"], list), "Accounts should be a list"
|
||||
assert len(data["accounts"]) == 0, "Accounts list should be empty when no accounts are connected"
|
||||
|
||||
|
||||
|
||||
def test_list_connected_accounts_with_account(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
create_cloud_integration_account: Callable,
|
||||
) -> None:
|
||||
"""Test listing connected accounts after creating one."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
# Create a test account
|
||||
cloud_provider = "aws"
|
||||
account_data = create_cloud_integration_account(admin_token, cloud_provider)
|
||||
account_id = account_data["account_id"]
|
||||
|
||||
# Simulate agent check-in to mark as connected
|
||||
cloud_account_id = str(uuid.uuid4())
|
||||
simulate_agent_checkin(signoz, admin_token, cloud_provider, account_id, cloud_account_id)
|
||||
|
||||
# List accounts
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/accounts"
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}"
|
||||
|
||||
response_data = response.json()
|
||||
data = response_data.get("data", response_data)
|
||||
assert "accounts" in data, "Response should contain 'accounts' field"
|
||||
assert isinstance(data["accounts"], list), "Accounts should be a list"
|
||||
|
||||
# Find our account in the list (there may be leftover accounts from previous test runs)
|
||||
account = next((a for a in data["accounts"] if a["id"] == account_id), None)
|
||||
assert account is not None, f"Account {account_id} should be found in list"
|
||||
assert account["id"] == account_id, "Account ID should match"
|
||||
assert "config" in account, "Account should have config field"
|
||||
assert "status" in account, "Account should have status field"
|
||||
|
||||
|
||||
|
||||
def test_get_account_status(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
create_cloud_integration_account: Callable,
|
||||
) -> None:
|
||||
"""Test getting the status of a specific account."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
# Create a test account (no check-in needed for status check)
|
||||
cloud_provider = "aws"
|
||||
account_data = create_cloud_integration_account(admin_token, cloud_provider)
|
||||
account_id = account_data["account_id"]
|
||||
|
||||
# Get account status
|
||||
endpoint = (
|
||||
f"/api/v1/cloud-integrations/{cloud_provider}/accounts/{account_id}/status"
|
||||
)
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}"
|
||||
|
||||
response_data = response.json()
|
||||
data = response_data.get("data", response_data)
|
||||
assert "id" in data, "Response should contain 'id' field"
|
||||
assert data["id"] == account_id, "Account ID should match"
|
||||
assert "status" in data, "Response should contain 'status' field"
|
||||
assert "integration" in data["status"], "Status should contain 'integration' field"
|
||||
|
||||
|
||||
def test_get_account_status_not_found(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Test getting status for a non-existent account."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
cloud_provider = "aws"
|
||||
fake_account_id = "00000000-0000-0000-0000-000000000000"
|
||||
|
||||
endpoint = (
|
||||
f"/api/v1/cloud-integrations/{cloud_provider}/accounts/{fake_account_id}/status"
|
||||
)
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.NOT_FOUND
|
||||
), f"Expected 404, got {response.status_code}"
|
||||
|
||||
|
||||
def test_update_account_config(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
create_cloud_integration_account: Callable,
|
||||
) -> None:
|
||||
"""Test updating account configuration."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
# Create a test account
|
||||
cloud_provider = "aws"
|
||||
account_data = create_cloud_integration_account(admin_token, cloud_provider)
|
||||
account_id = account_data["account_id"]
|
||||
|
||||
# Simulate agent check-in to mark as connected
|
||||
cloud_account_id = str(uuid.uuid4())
|
||||
simulate_agent_checkin(signoz, admin_token, cloud_provider, account_id, cloud_account_id)
|
||||
|
||||
# Update account configuration
|
||||
endpoint = (
|
||||
f"/api/v1/cloud-integrations/{cloud_provider}/accounts/{account_id}/config"
|
||||
)
|
||||
|
||||
updated_config = {
|
||||
"config": {"regions": ["us-east-1", "us-west-2", "eu-west-1"]}
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
json=updated_config,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}"
|
||||
|
||||
response_data = response.json()
|
||||
data = response_data.get("data", response_data)
|
||||
assert "id" in data, "Response should contain 'id' field"
|
||||
assert data["id"] == account_id, "Account ID should match"
|
||||
|
||||
# Verify the update by listing accounts
|
||||
list_endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/accounts"
|
||||
list_response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(list_endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
|
||||
list_response_data = list_response.json()
|
||||
list_data = list_response_data.get("data", list_response_data)
|
||||
account = next((a for a in list_data["accounts"] if a["id"] == account_id), None)
|
||||
assert account is not None, "Account should be found in list"
|
||||
assert "config" in account, "Account should have config"
|
||||
assert "regions" in account["config"], "Config should have regions"
|
||||
assert len(account["config"]["regions"]) == 3, "Should have 3 regions"
|
||||
assert set(account["config"]["regions"]) == {
|
||||
"us-east-1",
|
||||
"us-west-2",
|
||||
"eu-west-1",
|
||||
}, "Regions should match updated config"
|
||||
|
||||
|
||||
|
||||
def test_disconnect_account(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
create_cloud_integration_account: Callable,
|
||||
) -> None:
|
||||
"""Test disconnecting an account."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
# Create a test account
|
||||
cloud_provider = "aws"
|
||||
account_data = create_cloud_integration_account(admin_token, cloud_provider)
|
||||
account_id = account_data["account_id"]
|
||||
|
||||
# Simulate agent check-in to mark as connected
|
||||
cloud_account_id = str(uuid.uuid4())
|
||||
simulate_agent_checkin(signoz, admin_token, cloud_provider, account_id, cloud_account_id)
|
||||
|
||||
# Disconnect the account
|
||||
endpoint = (
|
||||
f"/api/v1/cloud-integrations/{cloud_provider}/accounts/{account_id}/disconnect"
|
||||
)
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}"
|
||||
|
||||
# Verify our specific account is no longer in the connected list
|
||||
list_endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/accounts"
|
||||
list_response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(list_endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
list_response_data = list_response.json()
|
||||
list_data = list_response_data.get("data", list_response_data)
|
||||
|
||||
# Check that our specific account is not in the list
|
||||
disconnected_account = next(
|
||||
(a for a in list_data["accounts"] if a["id"] == account_id), None
|
||||
)
|
||||
assert disconnected_account is None, f"Account {account_id} should be removed from connected accounts"
|
||||
|
||||
|
||||
|
||||
def test_disconnect_account_not_found(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Test disconnecting a non-existent account."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
cloud_provider = "aws"
|
||||
fake_account_id = "00000000-0000-0000-0000-000000000000"
|
||||
|
||||
endpoint = (
|
||||
f"/api/v1/cloud-integrations/{cloud_provider}/accounts/{fake_account_id}/disconnect"
|
||||
)
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.NOT_FOUND
|
||||
), f"Expected 404, got {response.status_code}"
|
||||
|
||||
|
||||
|
||||
def test_list_accounts_unsupported_provider(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Test listing accounts for an unsupported cloud provider."""
|
||||
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
cloud_provider = "gcp" # Unsupported provider
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/accounts"
|
||||
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.BAD_REQUEST
|
||||
), f"Expected 400, got {response.status_code}"
|
||||
468
tests/integration/src/cloudintegrations/04_services.py
Normal file
468
tests/integration/src/cloudintegrations/04_services.py
Normal file
@@ -0,0 +1,468 @@
|
||||
from http import HTTPStatus
|
||||
from typing import Callable
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from fixtures import types
|
||||
from fixtures.auth import USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD
|
||||
from fixtures.logger import setup_logger
|
||||
from fixtures.cloudintegrations import (
|
||||
create_cloud_integration_account,
|
||||
)
|
||||
from fixtures.cloudintegrationsutils import simulate_agent_checkin
|
||||
|
||||
logger = setup_logger(__name__)
|
||||
|
||||
|
||||
def test_list_services_without_account(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Test listing available services without specifying an account."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
cloud_provider = "aws"
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services"
|
||||
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}"
|
||||
|
||||
response_data = response.json()
|
||||
data = response_data.get("data", response_data)
|
||||
assert "services" in data, "Response should contain 'services' field"
|
||||
assert isinstance(data["services"], list), "Services should be a list"
|
||||
assert len(data["services"]) > 0, "Should have at least one service available"
|
||||
|
||||
# Verify service structure
|
||||
service = data["services"][0]
|
||||
assert "id" in service, "Service should have 'id' field"
|
||||
assert "title" in service, "Service should have 'title' field"
|
||||
assert "icon" in service, "Service should have 'icon' field"
|
||||
|
||||
|
||||
|
||||
def test_list_services_with_account(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
create_cloud_integration_account: Callable,
|
||||
) -> None:
|
||||
"""Test listing services for a specific connected account."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
# Create a test account and do check-in
|
||||
cloud_provider = "aws"
|
||||
account_data = create_cloud_integration_account(admin_token, cloud_provider)
|
||||
account_id = account_data["account_id"]
|
||||
|
||||
cloud_account_id = str(uuid.uuid4())
|
||||
simulate_agent_checkin(signoz, admin_token, cloud_provider, account_id, cloud_account_id)
|
||||
|
||||
# List services for the account
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services?cloud_account_id={cloud_account_id}"
|
||||
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}"
|
||||
|
||||
response_data = response.json()
|
||||
data = response_data.get("data", response_data)
|
||||
assert "services" in data, "Response should contain 'services' field"
|
||||
assert isinstance(data["services"], list), "Services should be a list"
|
||||
assert len(data["services"]) > 0, "Should have at least one service available"
|
||||
|
||||
# Services should include config field (may be null if not configured)
|
||||
service = data["services"][0]
|
||||
assert "id" in service, "Service should have 'id' field"
|
||||
assert "title" in service, "Service should have 'title' field"
|
||||
assert "icon" in service, "Service should have 'icon' field"
|
||||
|
||||
|
||||
|
||||
def test_get_service_details_without_account(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Test getting service details without specifying an account."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
cloud_provider = "aws"
|
||||
# First get the list of services to get a valid service ID
|
||||
list_endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services"
|
||||
list_response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(list_endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
list_data = list_response.json().get("data", list_response.json())
|
||||
assert len(list_data["services"]) > 0, "Should have at least one service"
|
||||
service_id = list_data["services"][0]["id"]
|
||||
|
||||
# Get service details
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services/{service_id}"
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}"
|
||||
|
||||
response_data = response.json()
|
||||
data = response_data.get("data", response_data)
|
||||
|
||||
# Verify service details structure
|
||||
assert "id" in data, "Service details should have 'id' field"
|
||||
assert data["id"] == service_id, "Service ID should match requested ID"
|
||||
assert "title" in data, "Service details should have 'title' field"
|
||||
assert "overview" in data, "Service details should have 'overview' field"
|
||||
# assert assets to had list of dashboards
|
||||
assert "assets" in data, "Service details should have 'assets' field"
|
||||
assert isinstance(data["assets"], dict), "Assets should be a dictionary"
|
||||
|
||||
|
||||
|
||||
def test_get_service_details_with_account(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
create_cloud_integration_account: Callable,
|
||||
) -> None:
|
||||
"""Test getting service details for a specific connected account."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
# Create a test account and do check-in
|
||||
cloud_provider = "aws"
|
||||
account_data = create_cloud_integration_account(admin_token, cloud_provider)
|
||||
account_id = account_data["account_id"]
|
||||
|
||||
cloud_account_id = str(uuid.uuid4())
|
||||
simulate_agent_checkin(signoz, admin_token, cloud_provider, account_id, cloud_account_id)
|
||||
|
||||
# Get list of services first
|
||||
list_endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services"
|
||||
list_response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(list_endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
list_data = list_response.json().get("data", list_response.json())
|
||||
assert len(list_data["services"]) > 0, "Should have at least one service"
|
||||
service_id = list_data["services"][0]["id"]
|
||||
|
||||
# Get service details with account
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services/{service_id}?cloud_account_id={cloud_account_id}"
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}"
|
||||
|
||||
response_data = response.json()
|
||||
data = response_data.get("data", response_data)
|
||||
|
||||
# Verify service details structure
|
||||
assert "id" in data, "Service details should have 'id' field"
|
||||
assert data["id"] == service_id, "Service ID should match requested ID"
|
||||
assert "title" in data, "Service details should have 'title' field"
|
||||
assert "overview" in data, "Service details should have 'overview' field"
|
||||
assert "assets" in data, "Service details should have 'assets' field"
|
||||
assert "config" in data, "Service details should have 'config' field"
|
||||
assert "status" in data, "Config should have 'status' field"
|
||||
|
||||
|
||||
|
||||
def test_get_service_details_invalid_service(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Test getting details for a non-existent service."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
cloud_provider = "aws"
|
||||
fake_service_id = "non-existent-service"
|
||||
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services/{fake_service_id}"
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.NOT_FOUND
|
||||
), f"Expected 404, got {response.status_code}"
|
||||
|
||||
|
||||
|
||||
def test_list_services_unsupported_provider(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Test listing services for an unsupported cloud provider."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
cloud_provider = "gcp" # Unsupported provider
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services"
|
||||
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.BAD_REQUEST
|
||||
), f"Expected 400, got {response.status_code}"
|
||||
|
||||
|
||||
|
||||
def test_update_service_config(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
create_cloud_integration_account: Callable,
|
||||
) -> None:
|
||||
"""Test updating service configuration for a connected account."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
# Create a test account and do check-in
|
||||
cloud_provider = "aws"
|
||||
account_data = create_cloud_integration_account(admin_token, cloud_provider)
|
||||
account_id = account_data["account_id"]
|
||||
|
||||
cloud_account_id = str(uuid.uuid4())
|
||||
simulate_agent_checkin(signoz, admin_token, cloud_provider, account_id, cloud_account_id)
|
||||
|
||||
# Get list of services to pick a valid service ID
|
||||
list_endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services"
|
||||
list_response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(list_endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
list_data = list_response.json().get("data", list_response.json())
|
||||
assert len(list_data["services"]) > 0, "Should have at least one service"
|
||||
service_id = list_data["services"][0]["id"]
|
||||
|
||||
# Update service configuration
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services/{service_id}/config"
|
||||
|
||||
config_payload = {
|
||||
"cloud_account_id": cloud_account_id,
|
||||
"config": {
|
||||
"metrics": {"enabled": True},
|
||||
"logs": {"enabled": True},
|
||||
},
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
json=config_payload,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}"
|
||||
|
||||
response_data = response.json()
|
||||
data = response_data.get("data", response_data)
|
||||
|
||||
# Verify response structure
|
||||
assert "id" in data, "Response should contain 'id' field"
|
||||
assert data["id"] == service_id, "Service ID should match"
|
||||
assert "config" in data, "Response should contain 'config' field"
|
||||
assert "metrics" in data["config"], "Config should contain 'metrics' field"
|
||||
assert "logs" in data["config"], "Config should contain 'logs' field"
|
||||
|
||||
|
||||
|
||||
def test_update_service_config_without_account(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Test updating service config without a connected account should fail."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
cloud_provider = "aws"
|
||||
|
||||
# Get a valid service ID
|
||||
list_endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services"
|
||||
list_response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(list_endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
list_data = list_response.json().get("data", list_response.json())
|
||||
service_id = list_data["services"][0]["id"]
|
||||
|
||||
# Try to update config with non-existent account
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services/{service_id}/config"
|
||||
|
||||
fake_cloud_account_id = str(uuid.uuid4())
|
||||
config_payload = {
|
||||
"cloud_account_id": fake_cloud_account_id,
|
||||
"config": {
|
||||
"metrics": {"enabled": True},
|
||||
},
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
json=config_payload,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR
|
||||
), f"Expected 500 for non-existent account, got {response.status_code}"
|
||||
|
||||
|
||||
|
||||
def test_update_service_config_invalid_service(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
create_cloud_integration_account: Callable,
|
||||
) -> None:
|
||||
"""Test updating config for a non-existent service should fail."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
# Create a test account and do check-in
|
||||
cloud_provider = "aws"
|
||||
account_data = create_cloud_integration_account(admin_token, cloud_provider)
|
||||
account_id = account_data["account_id"]
|
||||
|
||||
cloud_account_id = str(uuid.uuid4())
|
||||
simulate_agent_checkin(signoz, admin_token, cloud_provider, account_id, cloud_account_id)
|
||||
|
||||
# Try to update config for invalid service
|
||||
fake_service_id = "non-existent-service"
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services/{fake_service_id}/config"
|
||||
|
||||
config_payload = {
|
||||
"cloud_account_id": cloud_account_id,
|
||||
"config": {
|
||||
"metrics": {"enabled": True},
|
||||
},
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
json=config_payload,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.NOT_FOUND
|
||||
), f"Expected 404 for invalid service, got {response.status_code}"
|
||||
|
||||
|
||||
|
||||
def test_update_service_config_disable_service(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
create_cloud_integration_account: Callable,
|
||||
) -> None:
|
||||
"""Test disabling a service by updating config with enabled=false."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
# Create a test account and do check-in
|
||||
cloud_provider = "aws"
|
||||
account_data = create_cloud_integration_account(admin_token, cloud_provider)
|
||||
account_id = account_data["account_id"]
|
||||
|
||||
cloud_account_id = str(uuid.uuid4())
|
||||
simulate_agent_checkin(signoz, admin_token, cloud_provider, account_id, cloud_account_id)
|
||||
|
||||
# Get a valid service
|
||||
list_endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services"
|
||||
list_response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(list_endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
list_data = list_response.json().get("data", list_response.json())
|
||||
service_id = list_data["services"][0]["id"]
|
||||
|
||||
# First enable the service
|
||||
endpoint = f"/api/v1/cloud-integrations/{cloud_provider}/services/{service_id}/config"
|
||||
|
||||
enable_payload = {
|
||||
"cloud_account_id": cloud_account_id,
|
||||
"config": {
|
||||
"metrics": {"enabled": True},
|
||||
},
|
||||
}
|
||||
|
||||
enable_response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
json=enable_payload,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert enable_response.status_code == HTTPStatus.OK, "Failed to enable service"
|
||||
|
||||
# Now disable the service
|
||||
disable_payload = {
|
||||
"cloud_account_id": cloud_account_id,
|
||||
"config": {
|
||||
"metrics": {"enabled": False},
|
||||
"logs": {"enabled": False},
|
||||
},
|
||||
}
|
||||
|
||||
disable_response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(endpoint),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
json=disable_payload,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
disable_response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {disable_response.status_code}"
|
||||
|
||||
response_data = disable_response.json()
|
||||
data = response_data.get("data", response_data)
|
||||
|
||||
# Verify service is disabled
|
||||
assert data["config"]["metrics"]["enabled"] is False, "Metrics should be disabled"
|
||||
assert data["config"]["logs"]["enabled"] is False, "Logs should be disabled"
|
||||
399
tests/integration/src/querier/07_metrics_multi_temporality.py
Normal file
399
tests/integration/src/querier/07_metrics_multi_temporality.py
Normal file
@@ -0,0 +1,399 @@
|
||||
"""
|
||||
Look at the multi_temporality_counters_1h.jsonl file for the relevant data
|
||||
"""
|
||||
|
||||
import os
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from http import HTTPStatus
|
||||
import random
|
||||
from typing import Any, Callable, List
|
||||
import pytest
|
||||
|
||||
from fixtures import types
|
||||
from fixtures.auth import USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD
|
||||
from fixtures.metrics import Metrics
|
||||
from fixtures.querier import (
|
||||
build_builder_query,
|
||||
get_all_series,
|
||||
get_series_values,
|
||||
make_query_request,
|
||||
)
|
||||
from fixtures.utils import get_testdata_file_path
|
||||
|
||||
MULTI_TEMPORALITY_FILE = get_testdata_file_path("multi_temporality_counters_1h.jsonl")
|
||||
MULTI_TEMPORALITY_FILE_10h = get_testdata_file_path("multi_temporality_counters_10h.jsonl")
|
||||
MULTI_TEMPORALITY_FILE_24h = get_testdata_file_path("multi_temporality_counters_24h.jsonl")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"time_aggregation, expected_value_at_31st_minute, expected_value_at_32nd_minute, steady_value",
|
||||
[
|
||||
("rate", 0.0167, 0.133, 0.0833),
|
||||
("increase", 2, 8, 5),
|
||||
],
|
||||
)
|
||||
def test_with_steady_values_and_reset(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: None, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
insert_metrics: Callable[[List[Metrics]], None],
|
||||
time_aggregation: str,
|
||||
expected_value_at_31st_minute: float,
|
||||
expected_value_at_32nd_minute: float,
|
||||
steady_value: float
|
||||
) -> None:
|
||||
now = datetime.now(tz=timezone.utc).replace(second=0, microsecond=0)
|
||||
start_ms = int((now - timedelta(minutes=65)).timestamp() * 1000)
|
||||
end_ms = int(now.timestamp() * 1000)
|
||||
metric_name = f"test_{time_aggregation}_stale"
|
||||
|
||||
metrics = Metrics.load_from_file(
|
||||
MULTI_TEMPORALITY_FILE,
|
||||
base_time=now - timedelta(minutes=60),
|
||||
metric_name_override=metric_name,
|
||||
)
|
||||
insert_metrics(metrics)
|
||||
|
||||
token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
query = build_builder_query(
|
||||
"A",
|
||||
metric_name,
|
||||
time_aggregation,
|
||||
"sum",
|
||||
filter_expression='endpoint = "/orders"',
|
||||
)
|
||||
|
||||
response = make_query_request(signoz, token, start_ms, end_ms, [query])
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
|
||||
data = response.json()
|
||||
result_values = sorted(get_series_values(data, "A"), key=lambda x: x["timestamp"])
|
||||
assert len(result_values) >= 59
|
||||
# the counter reset happened at 31st minute
|
||||
assert (
|
||||
result_values[30]["value"] == expected_value_at_31st_minute
|
||||
)
|
||||
assert (
|
||||
result_values[31]["value"] == expected_value_at_32nd_minute
|
||||
)
|
||||
assert (
|
||||
result_values[39]["value"] == steady_value
|
||||
) # 39th minute is when cumulative shifts to delta
|
||||
count_of_steady_rate = sum(1 for v in result_values if v["value"] == steady_value)
|
||||
assert (
|
||||
count_of_steady_rate >= 56
|
||||
) # 59 - (1 reset + 1 high rate + 1 at the beginning)
|
||||
# All rates should be non-negative (stale periods = 0 rate)
|
||||
for v in result_values:
|
||||
assert v["value"] >= 0, f"{time_aggregation} should not be negative: {v['value']}"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"time_aggregation, stable_health_value, stable_products_value, stable_checkout_value, spike_checkout_value, stable_orders_value, spike_users_value",
|
||||
[
|
||||
("rate", 0.167, 0.333, 0.0167, 0.833, 0.0833, 0.0167),
|
||||
("increase", 10, 20, 1, 50, 5, 1),
|
||||
],
|
||||
)
|
||||
def test_group_by_endpoint(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: None, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
insert_metrics: Callable[[List[Metrics]], None],
|
||||
time_aggregation: str,
|
||||
stable_health_value: float,
|
||||
stable_products_value: float,
|
||||
stable_checkout_value: float,
|
||||
spike_checkout_value: float,
|
||||
stable_orders_value: float,
|
||||
spike_users_value: float,
|
||||
) -> None:
|
||||
now = datetime.now(tz=timezone.utc).replace(second=0, microsecond=0)
|
||||
start_ms = int((now - timedelta(minutes=65)).timestamp() * 1000)
|
||||
end_ms = int(now.timestamp() * 1000)
|
||||
metric_name = f"test_{time_aggregation}_groupby"
|
||||
|
||||
metrics = Metrics.load_from_file(
|
||||
MULTI_TEMPORALITY_FILE,
|
||||
base_time=now - timedelta(minutes=60),
|
||||
metric_name_override=metric_name,
|
||||
)
|
||||
insert_metrics(metrics)
|
||||
|
||||
token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
query = build_builder_query(
|
||||
"A",
|
||||
metric_name,
|
||||
time_aggregation,
|
||||
"sum",
|
||||
group_by=["endpoint"],
|
||||
)
|
||||
|
||||
response = make_query_request(signoz, token, start_ms, end_ms, [query])
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
|
||||
data = response.json()
|
||||
all_series = get_all_series(data, "A")
|
||||
# Should have 5 different endpoints
|
||||
assert (
|
||||
len(all_series) == 5
|
||||
), f"Expected 5 series for 5 endpoints, got {len(all_series)}"
|
||||
|
||||
# endpoint -> values
|
||||
endpoint_values = {}
|
||||
for series in all_series:
|
||||
endpoint = series.get("labels", [{}])[0].get("value", "unknown")
|
||||
values = sorted(series.get("values", []), key=lambda x: x["timestamp"])
|
||||
endpoint_values[endpoint] = values
|
||||
|
||||
expected_endpoints = {"/products", "/health", "/checkout", "/orders", "/users"}
|
||||
assert (
|
||||
set(endpoint_values.keys()) == expected_endpoints
|
||||
), f"Expected endpoints {expected_endpoints}, got {set(endpoint_values.keys())}"
|
||||
|
||||
# at no point rate should be negative
|
||||
for endpoint, values in endpoint_values.items():
|
||||
for v in values:
|
||||
assert (
|
||||
v["value"] >= 0
|
||||
), f"Rate for {endpoint} should not be negative: {v['value']}"
|
||||
|
||||
# /health: 60 data points (t01-t60), steady +10/min
|
||||
health_values = endpoint_values["/health"]
|
||||
assert (
|
||||
len(health_values) >= 58
|
||||
), f"Expected >= 58 values for /health, got {len(health_values)}"
|
||||
count_steady_health = sum(1 for v in health_values if v["value"] == stable_health_value)
|
||||
assert (
|
||||
count_steady_health >= 57
|
||||
), f"Expected >= 57 steady rate values ({stable_health_value}) for /health, got {count_steady_health}"
|
||||
# all /health rates should be state except possibly first/last due to boundaries
|
||||
for v in health_values[1:-1]:
|
||||
assert v["value"] == stable_health_value, f"Expected /health rate {stable_health_value}, got {v['value']}"
|
||||
|
||||
# /products: 51 data points with 10-minute gap (t20-t29 missing), steady +20/min
|
||||
products_values = endpoint_values["/products"]
|
||||
assert (
|
||||
len(products_values) >= 49
|
||||
), f"Expected >= 49 values for /products, got {len(products_values)}"
|
||||
count_steady_products = sum(1 for v in products_values if v["value"] == stable_products_value)
|
||||
|
||||
# most values should be stable, some boundary values differ due to 10-min gap
|
||||
assert (
|
||||
count_steady_products >= 46
|
||||
), f"Expected >= 46 steady rate values ({stable_products_value}) for /products, got {count_steady_products}"
|
||||
|
||||
# check that non-stable values are due to gap averaging (should be lower)
|
||||
gap_boundary_values = [v["value"] for v in products_values if v["value"] != stable_products_value]
|
||||
for val in gap_boundary_values:
|
||||
assert (
|
||||
0 < val < stable_products_value
|
||||
), f"Gap boundary values should be between 0 and {stable_products_value}, got {val}"
|
||||
|
||||
# /checkout: 61 data points (t00-t60), +1/min normal, +50/min spike at t40-t44
|
||||
checkout_values = endpoint_values["/checkout"]
|
||||
assert (
|
||||
len(checkout_values) >= 59
|
||||
), f"Expected >= 59 values for /checkout, got {len(checkout_values)}"
|
||||
count_steady_checkout = sum(1 for v in checkout_values if v["value"] == stable_checkout_value)
|
||||
assert (
|
||||
count_steady_checkout >= 53
|
||||
), f"Expected >= 53 steady {time_aggregation} values ({stable_checkout_value}) for /checkout, got {count_steady_checkout}"
|
||||
# check that spike values exist (traffic spike +50/min at t40-t44)
|
||||
count_spike_checkout = sum(1 for v in checkout_values if v["value"] == spike_checkout_value)
|
||||
assert (
|
||||
count_spike_checkout >= 4
|
||||
), f"Expected >= 4 spike {time_aggregation} values ({spike_checkout_value}) for /checkout, got {count_spike_checkout}"
|
||||
|
||||
# spike values should be consecutive
|
||||
spike_indices = [
|
||||
i for i, v in enumerate(checkout_values) if v["value"] == spike_checkout_value
|
||||
]
|
||||
assert len(spike_indices) >= 4, f"Expected >= 4 spike indices, got {spike_indices}"
|
||||
# consecutiveness
|
||||
for i in range(1, len(spike_indices)):
|
||||
assert (
|
||||
spike_indices[i] == spike_indices[i - 1] + 1
|
||||
), f"Spike indices should be consecutive, got {spike_indices}"
|
||||
|
||||
# /orders: 60 data points (t00-t60) with gap at t30, counter reset at t31 (150->2)
|
||||
# reset at t31 causes: rate/increase at t30 includes gap (lower), t31 has high rate after reset
|
||||
orders_values = endpoint_values["/orders"]
|
||||
assert (
|
||||
len(orders_values) >= 58
|
||||
), f"Expected >= 58 values for /orders, got {len(orders_values)}"
|
||||
count_steady_orders = sum(1 for v in orders_values if v["value"] == stable_orders_value)
|
||||
assert (
|
||||
count_steady_orders >= 55
|
||||
), f"Expected >= 55 steady {time_aggregation} values ({stable_orders_value}) for /orders, got {count_steady_orders}"
|
||||
# check for counter reset effects - there should be some non-standard values
|
||||
non_standard_orders = [v["value"] for v in orders_values if v["value"] != stable_orders_value]
|
||||
assert (
|
||||
len(non_standard_orders) >= 2
|
||||
), f"Expected >= 2 non-standard values due to counter reset, got {non_standard_orders}"
|
||||
# post-reset value should be higher (new counter value / interval)
|
||||
high_rate_orders = [v for v in non_standard_orders if v > stable_orders_value]
|
||||
assert (
|
||||
len(high_rate_orders) >= 1
|
||||
), f"Expected at least one high {time_aggregation} value after counter reset, got {non_standard_orders}"
|
||||
|
||||
# /users: 56 data points (t05-t60), sparse +1 every 5 minutes
|
||||
users_values = endpoint_values["/users"]
|
||||
assert (
|
||||
len(users_values) >= 54
|
||||
), f"Expected >= 54 values for /users, got {len(users_values)}"
|
||||
count_zero_users = sum(1 for v in users_values if v["value"] == 0)
|
||||
# most values should be 0 (flat periods between increments)
|
||||
assert (
|
||||
count_zero_users >= 40
|
||||
), f"Expected >= 40 zero {time_aggregation} values for /users (sparse data), got {count_zero_users}"
|
||||
# non-zero values should be 0.0167 (1/60 increment rate)
|
||||
non_zero_users = [v["value"] for v in users_values if v["value"] != 0]
|
||||
count_increment_rate = sum(1 for v in non_zero_users if v == spike_users_value)
|
||||
assert (
|
||||
count_increment_rate >= 8
|
||||
), f"Expected >= 8 increment {time_aggregation} values ({spike_users_value}) for /users, got {count_increment_rate}"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"time_aggregation, expected_value_at_30th_minute, expected_value_at_31st_minute, value_at_switch",
|
||||
[
|
||||
("rate", 0.183, 0.183, 0.25),
|
||||
("increase", 11, 12, 15),
|
||||
],
|
||||
)
|
||||
def test_for_service_with_switch(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: None, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
insert_metrics: Callable[[List[Metrics]], None],
|
||||
time_aggregation: str,
|
||||
expected_value_at_30th_minute: float,
|
||||
expected_value_at_31st_minute: float,
|
||||
value_at_switch: float
|
||||
) -> None:
|
||||
now = datetime.now(tz=timezone.utc).replace(second=0, microsecond=0)
|
||||
start_ms = int((now - timedelta(minutes=65)).timestamp() * 1000)
|
||||
end_ms = int(now.timestamp() * 1000)
|
||||
metric_name = f"test_{time_aggregation}_count"
|
||||
|
||||
metrics = Metrics.load_from_file(
|
||||
MULTI_TEMPORALITY_FILE,
|
||||
base_time=now - timedelta(minutes=60),
|
||||
metric_name_override=metric_name,
|
||||
)
|
||||
insert_metrics(metrics)
|
||||
|
||||
token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
query = build_builder_query(
|
||||
"A",
|
||||
metric_name,
|
||||
time_aggregation,
|
||||
"sum",
|
||||
filter_expression='service = "api"',
|
||||
)
|
||||
|
||||
response = make_query_request(signoz, token, start_ms, end_ms, [query])
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
|
||||
data = response.json()
|
||||
result_values = sorted(get_series_values(data, "A"), key=lambda x: x["timestamp"])
|
||||
assert len(result_values) >= 60
|
||||
assert (
|
||||
result_values[30]["value"] == expected_value_at_30th_minute #0.183
|
||||
)
|
||||
assert (
|
||||
result_values[31]["value"] == expected_value_at_31st_minute # 0.183
|
||||
)
|
||||
assert (
|
||||
result_values[38]["value"] == value_at_switch # 0.25
|
||||
)
|
||||
assert (
|
||||
result_values[39]["value"] == value_at_switch # 0.25
|
||||
) # 39th minute is when cumulative shifts to delta
|
||||
# All rates should be non-negative (stale periods = 0 rate)
|
||||
for v in result_values:
|
||||
assert v["value"] >= 0, f"{time_aggregation} should not be negative: {v['value']}"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"time_aggregation, expected_value",
|
||||
[
|
||||
("rate", 0.0122),
|
||||
("increase", 22),
|
||||
],
|
||||
)
|
||||
def test_for_week_long_time_range(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: None, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
insert_metrics: Callable[[List[Metrics]], None],
|
||||
time_aggregation: str,
|
||||
expected_value: float,
|
||||
) -> None:
|
||||
now = datetime.now(tz=timezone.utc).replace(second=0, microsecond=0)
|
||||
start_ms = int((now - timedelta(days=7)).timestamp() * 1000)
|
||||
end_ms = int(now.timestamp() * 1000)
|
||||
metric_name = f"test_{time_aggregation}_" + hex(random.getrandbits(32))[2:]
|
||||
|
||||
metrics = Metrics.load_from_file(
|
||||
MULTI_TEMPORALITY_FILE_10h,
|
||||
base_time=now - timedelta(minutes=600),
|
||||
metric_name_override=metric_name,
|
||||
)
|
||||
insert_metrics(metrics)
|
||||
|
||||
token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
query = build_builder_query(
|
||||
"A",
|
||||
metric_name,
|
||||
time_aggregation,
|
||||
"sum",
|
||||
)
|
||||
|
||||
response = make_query_request(signoz, token, start_ms, end_ms, [query])
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
data = response.json()
|
||||
result_values = sorted(get_series_values(data, "A"), key=lambda x: x["timestamp"])
|
||||
# the zeroth value may not cover the whole time range
|
||||
for value in result_values[1:]:
|
||||
assert value["value"] == expected_value
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"time_aggregation, expected_value",
|
||||
[
|
||||
("rate", 0.0122),
|
||||
("increase", 110),
|
||||
],
|
||||
)
|
||||
def test_for_month_long_time_range(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: None, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
insert_metrics: Callable[[List[Metrics]], None],
|
||||
time_aggregation: str,
|
||||
expected_value: float,
|
||||
) -> None:
|
||||
now = datetime.now(tz=timezone.utc).replace(second=0, microsecond=0)
|
||||
start_ms = int((now - timedelta(days=31)).timestamp() * 1000)
|
||||
end_ms = int(now.timestamp() * 1000)
|
||||
metric_name = f"test_{time_aggregation}_" + hex(random.getrandbits(32))[2:]
|
||||
|
||||
metrics = Metrics.load_from_file(
|
||||
MULTI_TEMPORALITY_FILE_24h,
|
||||
base_time=now - timedelta(minutes=1441),
|
||||
metric_name_override=metric_name,
|
||||
)
|
||||
insert_metrics(metrics)
|
||||
|
||||
token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
query = build_builder_query(
|
||||
"A",
|
||||
metric_name,
|
||||
time_aggregation,
|
||||
"sum",
|
||||
)
|
||||
|
||||
response = make_query_request(signoz, token, start_ms, end_ms, [query])
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
data = response.json()
|
||||
result_values = sorted(get_series_values(data, "A"), key=lambda x: x["timestamp"])
|
||||
## the zeroth and last values may not cover the whole 9000 seconds
|
||||
for value in result_values[1:-1]:
|
||||
assert value["value"] == expected_value
|
||||
84
tests/integration/testdata/multi_temporality_counters_10h.jsonl
vendored
Normal file
84
tests/integration/testdata/multi_temporality_counters_10h.jsonl
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:00:00+00:00","value":10,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:30:00+00:00","value":20,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T11:00:00+00:00","value":30,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T11:30:00+00:00","value":40,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T12:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T12:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T13:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T13:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T14:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T14:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T15:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T15:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T16:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T16:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T17:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T17:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T18:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T18:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T19:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T19:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T20:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:00:00+00:00","value":1,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:30:00+00:00","value":2,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T11:00:00+00:00","value":3,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T11:30:00+00:00","value":4,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T12:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T12:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T13:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T13:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T14:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T14:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T15:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T15:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T16:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T16:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T17:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T17:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T18:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T18:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T19:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T19:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T20:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:00:00+00:00","value":10,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:30:00+00:00","value":20,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T11:00:00+00:00","value":30,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T11:30:00+00:00","value":40,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T12:00:00+00:00","value":50,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T12:30:00+00:00","value":60,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T13:00:00+00:00","value":70,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T13:30:00+00:00","value":80,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T14:00:00+00:00","value":90,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T14:30:00+00:00","value":100,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T15:00:00+00:00","value":110,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T15:30:00+00:00","value":120,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T16:00:00+00:00","value":130,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T16:30:00+00:00","value":140,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T17:00:00+00:00","value":150,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T17:30:00+00:00","value":160,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T18:00:00+00:00","value":170,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T18:30:00+00:00","value":180,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T19:00:00+00:00","value":190,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T19:30:00+00:00","value":200,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T20:00:00+00:00","value":210,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T10:00:00+00:00","value":1,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T10:30:00+00:00","value":2,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T11:00:00+00:00","value":3,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T11:30:00+00:00","value":4,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T12:00:00+00:00","value":5,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T12:30:00+00:00","value":6,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T13:00:00+00:00","value":7,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T13:30:00+00:00","value":8,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T14:00:00+00:00","value":9,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T14:30:00+00:00","value":10,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T15:00:00+00:00","value":11,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T15:30:00+00:00","value":12,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T16:00:00+00:00","value":13,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T16:30:00+00:00","value":14,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T17:00:00+00:00","value":15,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T17:30:00+00:00","value":16,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T18:00:00+00:00","value":17,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T18:30:00+00:00","value":18,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T19:00:00+00:00","value":19,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T19:30:00+00:00","value":20,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T20:00:00+00:00","value":21,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
288
tests/integration/testdata/multi_temporality_counters_1h.jsonl
vendored
Normal file
288
tests/integration/testdata/multi_temporality_counters_1h.jsonl
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:01:00+00:00","value":10,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:02:00+00:00","value":20,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:03:00+00:00","value":30,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:04:00+00:00","value":40,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:05:00+00:00","value":50,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:06:00+00:00","value":60,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:07:00+00:00","value":70,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:08:00+00:00","value":80,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:09:00+00:00","value":90,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:10:00+00:00","value":100,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:11:00+00:00","value":110,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:12:00+00:00","value":120,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:13:00+00:00","value":130,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:14:00+00:00","value":140,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:15:00+00:00","value":150,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:16:00+00:00","value":160,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:17:00+00:00","value":170,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:18:00+00:00","value":180,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:19:00+00:00","value":190,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:20:00+00:00","value":200,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:21:00+00:00","value":210,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:22:00+00:00","value":220,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:23:00+00:00","value":230,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:24:00+00:00","value":240,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:25:00+00:00","value":250,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:26:00+00:00","value":260,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:27:00+00:00","value":270,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:28:00+00:00","value":280,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:29:00+00:00","value":290,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:30:00+00:00","value":300,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:31:00+00:00","value":310,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:32:00+00:00","value":320,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:33:00+00:00","value":330,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:34:00+00:00","value":340,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:35:00+00:00","value":350,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:36:00+00:00","value":360,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:37:00+00:00","value":370,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:38:00+00:00","value":380,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:39:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:40:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:41:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:42:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:43:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:44:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:45:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:46:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:47:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:48:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:49:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:50:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:51:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:52:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:53:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:54:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:55:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:56:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:57:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:58:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:59:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T11:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:05:00+00:00","value":1,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:06:00+00:00","value":1,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:07:00+00:00","value":1,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:08:00+00:00","value":1,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:09:00+00:00","value":1,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:10:00+00:00","value":2,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:11:00+00:00","value":2,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:12:00+00:00","value":2,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:13:00+00:00","value":2,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:14:00+00:00","value":2,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:15:00+00:00","value":3,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:16:00+00:00","value":3,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:17:00+00:00","value":3,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:18:00+00:00","value":3,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:19:00+00:00","value":3,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:20:00+00:00","value":4,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:21:00+00:00","value":4,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:22:00+00:00","value":4,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:23:00+00:00","value":4,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:24:00+00:00","value":4,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:25:00+00:00","value":5,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:26:00+00:00","value":5,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:27:00+00:00","value":5,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:28:00+00:00","value":5,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:29:00+00:00","value":5,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:30:00+00:00","value":6,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:31:00+00:00","value":6,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:32:00+00:00","value":6,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:33:00+00:00","value":6,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:34:00+00:00","value":6,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:35:00+00:00","value":7,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:36:00+00:00","value":7,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:37:00+00:00","value":7,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:38:00+00:00","value":7,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:39:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:40:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:41:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:42:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:43:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:44:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:45:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:46:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:47:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:48:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:49:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:50:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:51:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:52:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:53:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:54:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:55:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:56:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:57:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:58:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:59:00+00:00","value":0,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T11:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:00:00+00:00","value":5,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:01:00+00:00","value":10,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:02:00+00:00","value":15,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:03:00+00:00","value":20,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:04:00+00:00","value":25,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:05:00+00:00","value":30,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:06:00+00:00","value":35,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:07:00+00:00","value":40,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:08:00+00:00","value":45,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:09:00+00:00","value":50,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:10:00+00:00","value":55,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:11:00+00:00","value":60,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:12:00+00:00","value":65,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:13:00+00:00","value":70,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:14:00+00:00","value":75,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:15:00+00:00","value":80,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:16:00+00:00","value":85,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:17:00+00:00","value":90,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:18:00+00:00","value":95,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:19:00+00:00","value":100,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:20:00+00:00","value":105,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:21:00+00:00","value":110,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:22:00+00:00","value":115,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:23:00+00:00","value":120,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:24:00+00:00","value":125,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:25:00+00:00","value":130,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:26:00+00:00","value":135,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:27:00+00:00","value":140,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:28:00+00:00","value":145,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:29:00+00:00","value":150,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:31:00+00:00","value":2,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:32:00+00:00","value":10,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:33:00+00:00","value":15,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:34:00+00:00","value":20,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:35:00+00:00","value":25,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:36:00+00:00","value":30,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:37:00+00:00","value":35,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:38:00+00:00","value":40,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:39:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:40:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:41:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:42:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:43:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:44:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:45:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:46:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:47:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:48:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:49:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:50:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:51:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:52:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:53:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:54:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:55:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:56:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:57:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:58:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T10:59:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/orders","status_code":"200"},"timestamp":"2025-01-10T11:00:00+00:00","value":5,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:00:00+00:00","value":20,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:01:00+00:00","value":40,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:02:00+00:00","value":60,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:03:00+00:00","value":80,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:04:00+00:00","value":100,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:05:00+00:00","value":120,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:06:00+00:00","value":140,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:07:00+00:00","value":160,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:08:00+00:00","value":180,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:09:00+00:00","value":200,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:10:00+00:00","value":220,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:11:00+00:00","value":240,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:12:00+00:00","value":260,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:13:00+00:00","value":280,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:14:00+00:00","value":300,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:15:00+00:00","value":320,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:16:00+00:00","value":340,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:17:00+00:00","value":360,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:18:00+00:00","value":380,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:19:00+00:00","value":400,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:30:00+00:00","value":420,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:31:00+00:00","value":440,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:32:00+00:00","value":460,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:33:00+00:00","value":480,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:34:00+00:00","value":500,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:35:00+00:00","value":520,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:36:00+00:00","value":540,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:37:00+00:00","value":560,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:38:00+00:00","value":580,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:39:00+00:00","value":600,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:40:00+00:00","value":620,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:41:00+00:00","value":640,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:42:00+00:00","value":660,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:43:00+00:00","value":680,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:44:00+00:00","value":700,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:45:00+00:00","value":720,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:46:00+00:00","value":740,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:47:00+00:00","value":760,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:48:00+00:00","value":780,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:49:00+00:00","value":800,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:50:00+00:00","value":820,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:51:00+00:00","value":840,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:52:00+00:00","value":860,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:53:00+00:00","value":880,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:54:00+00:00","value":900,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:55:00+00:00","value":920,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:56:00+00:00","value":940,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:57:00+00:00","value":960,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:58:00+00:00","value":980,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:59:00+00:00","value":1000,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T11:00:00+00:00","value":1020,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:00:00+00:00","value":1,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:01:00+00:00","value":2,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:02:00+00:00","value":3,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:03:00+00:00","value":4,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:04:00+00:00","value":5,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:05:00+00:00","value":6,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:06:00+00:00","value":7,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:07:00+00:00","value":8,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:08:00+00:00","value":9,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:09:00+00:00","value":10,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:10:00+00:00","value":11,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:11:00+00:00","value":12,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:12:00+00:00","value":13,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:13:00+00:00","value":14,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:14:00+00:00","value":15,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:15:00+00:00","value":16,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:16:00+00:00","value":17,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:17:00+00:00","value":18,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:18:00+00:00","value":19,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:19:00+00:00","value":20,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:20:00+00:00","value":21,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:21:00+00:00","value":22,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:22:00+00:00","value":23,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:23:00+00:00","value":24,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:24:00+00:00","value":25,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:25:00+00:00","value":26,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:26:00+00:00","value":27,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:27:00+00:00","value":28,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:28:00+00:00","value":29,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:29:00+00:00","value":30,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:30:00+00:00","value":31,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:31:00+00:00","value":32,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:32:00+00:00","value":33,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:33:00+00:00","value":34,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:34:00+00:00","value":35,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:35:00+00:00","value":36,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:36:00+00:00","value":37,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:37:00+00:00","value":38,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:38:00+00:00","value":39,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:39:00+00:00","value":40,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:40:00+00:00","value":90,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:41:00+00:00","value":140,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:42:00+00:00","value":190,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:43:00+00:00","value":240,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:44:00+00:00","value":290,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:45:00+00:00","value":291,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:46:00+00:00","value":292,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:47:00+00:00","value":293,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:48:00+00:00","value":294,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:49:00+00:00","value":295,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:50:00+00:00","value":296,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:51:00+00:00","value":297,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:52:00+00:00","value":298,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:53:00+00:00","value":299,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:54:00+00:00","value":300,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:55:00+00:00","value":301,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:56:00+00:00","value":302,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:57:00+00:00","value":303,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:58:00+00:00","value":304,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T10:59:00+00:00","value":305,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"429"},"timestamp":"2025-01-10T11:00:00+00:00","value":306,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
196
tests/integration/testdata/multi_temporality_counters_24h.jsonl
vendored
Normal file
196
tests/integration/testdata/multi_temporality_counters_24h.jsonl
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T00:00:00+00:00","value":10,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T00:30:00+00:00","value":20,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T01:00:00+00:00","value":30,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T01:30:00+00:00","value":40,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T02:00:00+00:00","value":50,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T02:30:00+00:00","value":60,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T03:00:00+00:00","value":70,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T03:30:00+00:00","value":80,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T04:00:00+00:00","value":90,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T04:30:00+00:00","value":100,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T05:00:00+00:00","value":110,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T05:30:00+00:00","value":120,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T06:00:00+00:00","value":130,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T06:30:00+00:00","value":140,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T07:00:00+00:00","value":150,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T07:30:00+00:00","value":160,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T08:00:00+00:00","value":170,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T08:30:00+00:00","value":180,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T09:00:00+00:00","value":190,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T09:30:00+00:00","value":200,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:00:00+00:00","value":210,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T10:30:00+00:00","value":220,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T11:00:00+00:00","value":230,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T11:30:00+00:00","value":240,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T12:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T12:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T13:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T13:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T14:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T14:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T15:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T15:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T16:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T16:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T17:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T17:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T18:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T18:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T19:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T19:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T20:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T20:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T21:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T21:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T22:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T22:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T23:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-10T23:30:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/health","status_code":"200"},"timestamp":"2025-01-11T00:00:00+00:00","value":10,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T00:00:00+00:00","value":1,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T00:30:00+00:00","value":2,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T01:00:00+00:00","value":3,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T01:30:00+00:00","value":4,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T02:00:00+00:00","value":5,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T02:30:00+00:00","value":6,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T03:00:00+00:00","value":7,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T03:30:00+00:00","value":8,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T04:00:00+00:00","value":9,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T04:30:00+00:00","value":10,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T05:00:00+00:00","value":11,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T05:30:00+00:00","value":12,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T06:00:00+00:00","value":13,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T06:30:00+00:00","value":14,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T07:00:00+00:00","value":15,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T07:30:00+00:00","value":16,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T08:00:00+00:00","value":17,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T08:30:00+00:00","value":18,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T09:00:00+00:00","value":19,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T09:30:00+00:00","value":20,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:00:00+00:00","value":21,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T10:30:00+00:00","value":22,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T11:00:00+00:00","value":23,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T11:30:00+00:00","value":24,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T12:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T12:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T13:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T13:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T14:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T14:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T15:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T15:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T16:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T16:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T17:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T17:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T18:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T18:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T19:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T19:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T20:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T20:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T21:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T21:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T22:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T22:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T23:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-10T23:30:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Delta","service":"api","endpoint":"/users","status_code":"500"},"timestamp":"2025-01-11T00:00:00+00:00","value":1,"temporality":"Delta","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T00:00:00+00:00","value":10,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T00:30:00+00:00","value":20,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T01:00:00+00:00","value":30,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T01:30:00+00:00","value":40,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T02:00:00+00:00","value":50,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T02:30:00+00:00","value":60,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T03:00:00+00:00","value":70,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T03:30:00+00:00","value":80,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T04:00:00+00:00","value":90,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T04:30:00+00:00","value":100,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T05:00:00+00:00","value":110,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T05:30:00+00:00","value":120,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T06:00:00+00:00","value":130,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T06:30:00+00:00","value":140,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T07:00:00+00:00","value":150,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T07:30:00+00:00","value":160,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T08:00:00+00:00","value":170,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T08:30:00+00:00","value":180,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T09:00:00+00:00","value":190,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T09:30:00+00:00","value":200,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:00:00+00:00","value":210,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T10:30:00+00:00","value":220,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T11:00:00+00:00","value":230,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T11:30:00+00:00","value":240,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T12:00:00+00:00","value":250,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T12:30:00+00:00","value":260,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T13:00:00+00:00","value":270,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T13:30:00+00:00","value":280,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T14:00:00+00:00","value":290,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T14:30:00+00:00","value":300,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T15:00:00+00:00","value":310,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T15:30:00+00:00","value":320,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T16:00:00+00:00","value":330,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T16:30:00+00:00","value":340,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T17:00:00+00:00","value":350,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T17:30:00+00:00","value":360,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T18:00:00+00:00","value":370,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T18:30:00+00:00","value":380,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T19:00:00+00:00","value":390,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T19:30:00+00:00","value":400,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T20:00:00+00:00","value":410,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T20:30:00+00:00","value":420,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T21:00:00+00:00","value":430,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T21:30:00+00:00","value":440,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T22:00:00+00:00","value":450,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T22:30:00+00:00","value":460,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T23:00:00+00:00","value":470,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-10T23:30:00+00:00","value":480,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/products","status_code":"200"},"timestamp":"2025-01-11T00:00:00+00:00","value":490,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T00:00:00+00:00","value":1,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T00:30:00+00:00","value":2,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T01:00:00+00:00","value":3,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T01:30:00+00:00","value":4,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T02:00:00+00:00","value":5,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T02:30:00+00:00","value":6,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T03:00:00+00:00","value":7,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T03:30:00+00:00","value":8,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T04:00:00+00:00","value":9,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T04:30:00+00:00","value":10,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T05:00:00+00:00","value":11,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T05:30:00+00:00","value":12,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T06:00:00+00:00","value":13,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T06:30:00+00:00","value":14,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T07:00:00+00:00","value":15,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T07:30:00+00:00","value":16,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T08:00:00+00:00","value":17,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T08:30:00+00:00","value":18,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T09:00:00+00:00","value":19,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T09:30:00+00:00","value":20,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T10:00:00+00:00","value":21,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T10:30:00+00:00","value":22,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T11:00:00+00:00","value":23,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T11:30:00+00:00","value":24,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T12:00:00+00:00","value":25,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T12:30:00+00:00","value":26,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T13:00:00+00:00","value":27,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T13:30:00+00:00","value":28,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T14:00:00+00:00","value":29,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T14:30:00+00:00","value":30,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T15:00:00+00:00","value":31,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T15:30:00+00:00","value":32,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T16:00:00+00:00","value":33,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T16:30:00+00:00","value":34,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T17:00:00+00:00","value":35,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T17:30:00+00:00","value":36,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T18:00:00+00:00","value":37,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T18:30:00+00:00","value":38,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T19:00:00+00:00","value":39,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T19:30:00+00:00","value":40,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T20:00:00+00:00","value":41,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T20:30:00+00:00","value":42,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T21:00:00+00:00","value":43,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T21:30:00+00:00","value":44,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T22:00:00+00:00","value":45,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T22:30:00+00:00","value":46,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T23:00:00+00:00","value":47,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-10T23:30:00+00:00","value":48,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
{"metric_name":"http.request.count","labels":{"__temporality__":"Cumulative","service":"web","endpoint":"/checkout","status_code":"200"},"timestamp":"2025-01-11T00:00:00+00:00","value":49,"temporality":"Cumulative","type_":"Sum","is_monotonic":true,"flags":0,"description":"","unit":"","env":"default","resource_attrs":{},"scope_attrs":{}}
|
||||
Reference in New Issue
Block a user