This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new 489b18962 fix(metrics): keep CSV epochs in one unit (#5726)
489b18962 is described below
commit 489b189628b248b80b09e568083d38090de9304f
Author: 0 <[email protected]>
AuthorDate: Mon Oct 19 18:13:56 2026 +0800
fix(metrics): keep CSV epochs in one unit (#5726)
Verified against `rocketmq-studio` at 86aa49c34 before merging: 缺陷仍在。文件已从
`web/src/pages/metrics/MetricsExplorer.tsx` 迁到
`web/src/components/MetricsExplorer.tsx`,但链路一模一样:`:612` `const queriedAt =
Date.now()`(毫秒)、`:
merge-tree clean against the current trunk and no outstanding must-fix
items; merged as-is (squash) per the maintainer review of 2026-10-19.
---
web/src/utils/metricsExplorerDiagnostics.test.ts | 18 ++++++++++++++++++
web/src/utils/metricsExplorerDiagnostics.ts | 13 ++++++++++++-
2 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/web/src/utils/metricsExplorerDiagnostics.test.ts
b/web/src/utils/metricsExplorerDiagnostics.test.ts
index ca12f237c..09362bc99 100644
--- a/web/src/utils/metricsExplorerDiagnostics.test.ts
+++ b/web/src/utils/metricsExplorerDiagnostics.test.ts
@@ -322,6 +322,24 @@ describe('metrics explorer diagnostics', () => {
expect(csv).toContain('"2027-01-15T07:00:00.000Z"');
});
+ it('keeps every epoch column of a CSV row in the same time unit', () => {
+ const rows = buildMetricCsvRows(metricData, metric, {
+ profileName: 'RocketMQ 5.x Native',
+ sourceName: 'Prometheus prod',
+ queryStart: 1_799_996_400,
+ queryEnd: 1_800_000_000,
+ queriedAt: 1_800_000_000_000,
+ });
+
+ // Timestamp / Query Start / Query End are epoch seconds; Queried At
arrives from the
+ // caller as epoch milliseconds, but one CSV file must not mix the two
units.
+ for (const row of rows) {
+ expect(row.queriedAt).toBe(1_800_000_000);
+ expect(row.queryStart).toBe(1_799_996_400);
+ expect(row.queryEnd).toBe(1_800_000_000);
+ }
+ });
+
it('creates deterministic CSV filenames from metric identity', () => {
expect(buildMetricCsvFilename(metric, 1_800_000_000_000)).toBe(
'rocketmq-studio-metrics-message-in-tps-2027-01-15T08-00-00-000Z.csv',
diff --git a/web/src/utils/metricsExplorerDiagnostics.ts
b/web/src/utils/metricsExplorerDiagnostics.ts
index c3bfcd741..4c1e89128 100644
--- a/web/src/utils/metricsExplorerDiagnostics.ts
+++ b/web/src/utils/metricsExplorerDiagnostics.ts
@@ -52,8 +52,11 @@ export interface MetricResultSummary {
export interface MetricCsvContext {
profileName: string;
sourceName: string;
+ /** Epoch seconds of the query window start. */
queryStart?: number;
+ /** Epoch seconds of the query window end. */
queryEnd?: number;
+ /** Wall-clock `Date.now()` of the query, in epoch milliseconds. */
queriedAt?: number;
}
@@ -74,8 +77,11 @@ export interface MetricCsvRow {
value: number;
histogramCount?: number;
histogramSum?: number;
+ /** Epoch seconds, like every other epoch column in the row. */
queryStart?: number;
+ /** Epoch seconds, like every other epoch column in the row. */
queryEnd?: number;
+ /** Epoch seconds, like every other epoch column in the row. */
queriedAt?: number;
}
@@ -258,6 +264,11 @@ export const buildMetricCsvRows = (
const { samples } = toMetricSeriesSamples(series);
const seriesLabel = metricSeriesLabel(series, metric.name);
const labels = stableLabelsText(series.labels);
+ // Timestamp / Query Start / Query End are epoch seconds; `queriedAt` is a
wall-clock
+ // `Date.now()` in milliseconds. One CSV file must not mix the two units,
so the query
+ // instant is emitted in the same seconds unit as the rest of the epoch
columns.
+ const queriedAtSeconds =
+ context.queriedAt === undefined ? undefined :
Math.floor(context.queriedAt / 1000);
return samples.map((sample) => ({
profileName: context.profileName,
sourceName: context.sourceName,
@@ -277,7 +288,7 @@ export const buildMetricCsvRows = (
histogramSum: sample.histogramSum,
queryStart: context.queryStart,
queryEnd: context.queryEnd,
- queriedAt: context.queriedAt,
+ queriedAt: queriedAtSeconds,
}));
});