Skip to content

Commit f73d40a

Browse files
xuyushun441-sysos-zhuangclaude
authored
fix(analytics): log scalar auto-inferred cubes at debug, not warn (#2223)
* chore: bump objectui to 2270239793db feat(core,react): scoped style-object rendering (ADR-0065) (#1912) objectui@2270239793db989e3aec2f8fccfcc1925963b2e9 * fix(analytics): log scalar auto-inferred cubes at debug, not warn `object-metric` KPI tiles (e.g. the showcase home/My Work pages) query analytics by the raw object name with a bare aggregate and no grouping. No explicit Cube is registered for those names, so the service auto-infers a trivial count/sum cube — the intended behaviour for that first-class "metric over an object" path. Logging that at warn spams the boot/render path ("No cube registered for showcase_task ...") for a non-problem. Downgrade the auto-infer message to debug for scalar queries (measures only, no `dimensions`/`timeDimensions`). Keep warn for grouped queries over an unregistered cube, where a forgotten cube registration is a real mistake worth surfacing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(changeset): patch @objectstack/service-analytics Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent cb82ec8 commit f73d40a

3 files changed

Lines changed: 56 additions & 3 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@objectstack/service-analytics": patch
3+
---
4+
5+
fix(analytics): log scalar auto-inferred cubes at debug, not warn
6+
7+
Scalar metric queries (measures only, no `dimensions`/`timeDimensions`) over an
8+
unregistered cube — the first-class `object-metric` "metric over an object" path
9+
— auto-infer a trivial count/sum cube by design. That auto-infer now logs at
10+
`debug` instead of `warn`, so boot/render no longer spams
11+
`No cube registered for "..."` for a non-problem. Grouped queries (explicit
12+
dimension / time bucket) over an unregistered cube keep the `warn`, where a
13+
forgotten cube registration is a real mistake.

packages/services/service-analytics/src/__tests__/analytics-service.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,3 +704,34 @@ describe('AnalyticsService — RAW_SQL_UNSUPPORTED fallback', () => {
704704
await expect(service.query({ cube: 'orders', measures: ['count'] })).rejects.toThrow('No strategy can handle');
705705
});
706706
});
707+
708+
// ─────────────────────────────────────────────────────────────────
709+
// Auto-inferred cube log level (object-metric KPI tiles).
710+
//
711+
// A scalar metric query (measures only, no grouping) is the supported
712+
// "metric over an object" path — auto-inferring a count/sum cube is
713+
// expected, so it logs at debug, not warn. A grouped query (explicit
714+
// dimension / time bucket) over an unregistered cube keeps the warn,
715+
// since a forgotten cube registration there is a real mistake.
716+
717+
describe('AnalyticsService — auto-inferred cube log level', () => {
718+
const makeService = (logger: any) =>
719+
new AnalyticsService({
720+
logger,
721+
executeAggregate: vi.fn().mockResolvedValue([{ count: 3 }]),
722+
queryCapabilities: () => ({ nativeSql: false, objectqlAggregate: true, inMemory: false }),
723+
});
724+
725+
it('logs at debug (not warn) for a scalar metric over an unregistered cube', async () => {
726+
const logger = { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn(), child: vi.fn().mockReturnThis() } as any;
727+
await makeService(logger).query({ cube: 'showcase_task', measures: ['count'] });
728+
expect(logger.warn).not.toHaveBeenCalled();
729+
expect(logger.debug).toHaveBeenCalledWith(expect.stringContaining('No cube registered for "showcase_task"'));
730+
});
731+
732+
it('keeps warn for a grouped query over an unregistered cube', async () => {
733+
const logger = { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn(), child: vi.fn().mockReturnThis() } as any;
734+
await makeService(logger).query({ cube: 'showcase_task', measures: ['count'], dimensions: ['status'] });
735+
expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('No cube registered for "showcase_task"'));
736+
});
737+
});

packages/services/service-analytics/src/analytics-service.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -642,12 +642,21 @@ export class AnalyticsService implements IAnalyticsService {
642642
if (!cube) {
643643
cube = this.inferCubeFromQuery(query);
644644
this.cubeRegistry.register(cube);
645-
this.logger.warn(
645+
// A scalar query — only measures, no grouping (no `dimensions`/
646+
// `timeDimensions`) — is the first-class "metric over an object" path
647+
// (e.g. the `object-metric` KPI widget). Auto-inferring a count/sum cube
648+
// is the intended behaviour there, so log at debug. A query that groups
649+
// by an explicit dimension or time bucket almost certainly meant to hit a
650+
// registered cube; keep that at warn so a forgotten registration is loud.
651+
const isScalarMetric =
652+
(query.dimensions?.length ?? 0) === 0 && (query.timeDimensions?.length ?? 0) === 0;
653+
const message =
646654
`[Analytics] No cube registered for "${name}"; auto-inferred a minimal cube ` +
647655
`(sql="${name}", measures=${Object.keys(cube.measures).join(',') || '(none)'}, ` +
648656
`dimensions=${Object.keys(cube.dimensions).join(',') || '(none)'}). ` +
649-
`Define an explicit Cube in your stack for full control.`,
650-
);
657+
`Define an explicit Cube in your stack for full control.`;
658+
if (isScalarMetric) this.logger.debug(message);
659+
else this.logger.warn(message);
651660
return;
652661
}
653662

0 commit comments

Comments
 (0)