fix: services endpoint bug (#219)

The bug happened when:
1. Property map has custom attributes
2. Found log lines don't have custom properties

And because the query has 'group-by' column checks in where clause, it ends up no matches
even 'service' should exist.
This commit is contained in:
Warren 2024-01-10 09:59:26 -08:00 committed by GitHub
parent 2f40c30157
commit 95ddbb87bf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 90 additions and 24 deletions

View file

@ -0,0 +1,6 @@
---
'@hyperdx/api': patch
'@hyperdx/app': patch
---
fix: services endpoint bug (missing log lines results in no matches)

View file

@ -9,6 +9,7 @@ import {
closeDB,
getLoggedInAgent,
getServer,
mockLogsPropertyTypeMappingsModel,
} from '@/fixtures';
describe('charts router', () => {
@ -119,6 +120,43 @@ Object {
"service1": Array [],
"service2": Array [],
}
`);
});
it('GET /chart/services (missing data but custom attributes exist)', async () => {
const now = Date.now();
const { agent, team } = await getLoggedInAgent(server);
await clickhouse.bulkInsertTeamLogStream(
team.logStreamTableVersion,
team.id,
[
buildEvent({
timestamp: now,
service: 'service1',
}),
buildEvent({
timestamp: now,
service: 'service1',
}),
buildEvent({
timestamp: now - ms('1d'),
service: 'service2',
}),
],
);
mockLogsPropertyTypeMappingsModel({
service: 'string',
'k8s.namespace.name': 'string',
});
const results = await agent.get('/chart/services').expect(200);
expect(results.body.data).toMatchInlineSnapshot(`
Object {
"service1": Array [],
"service2": Array [],
}
`);
});
});

View file

@ -48,37 +48,59 @@ router.get('/services', async (req, res, next) => {
const MAX_NUM_GROUPS = 2000;
const simpleCache = new SimpleCache<
Awaited<ReturnType<typeof clickhouse.getMultiSeriesChart>>
Awaited<ReturnType<typeof clickhouse.getMultiSeriesChart>>[]
>(`chart-services-${teamId}`, ms('10m'), () =>
clickhouse.getMultiSeriesChart({
series: [
{
aggFn: clickhouse.AggFn.Count,
groupBy: targetGroupByFields,
table: 'logs',
type: 'table',
where: '',
},
],
endTime,
granularity: undefined,
maxNumGroups: MAX_NUM_GROUPS,
startTime,
tableVersion: team.logStreamTableVersion,
teamId: teamId.toString(),
seriesReturnType: clickhouse.SeriesReturnType.Column,
}),
Promise.all([
clickhouse.getMultiSeriesChart({
series: [
{
aggFn: clickhouse.AggFn.Count,
groupBy: targetGroupByFields,
table: 'logs',
type: 'table',
where: '',
},
],
endTime,
granularity: undefined,
maxNumGroups: MAX_NUM_GROUPS,
startTime,
tableVersion: team.logStreamTableVersion,
teamId: teamId.toString(),
seriesReturnType: clickhouse.SeriesReturnType.Column,
}),
clickhouse.getMultiSeriesChart({
series: [
{
aggFn: clickhouse.AggFn.Count,
groupBy: ['service'],
table: 'logs',
type: 'table',
where: '',
},
],
endTime,
granularity: undefined,
maxNumGroups: MAX_NUM_GROUPS,
startTime,
tableVersion: team.logStreamTableVersion,
teamId: teamId.toString(),
seriesReturnType: clickhouse.SeriesReturnType.Column,
}),
]),
);
const results = await simpleCache.get();
const [customAttrsResults, servicesResults] = await simpleCache.get();
// restructure service maps
const serviceMap: Record<string, Record<string, string>[]> = {};
for (const row of results.data) {
for (const row of servicesResults.data) {
const service = row.group[0];
serviceMap[service] = [];
}
for (const row of customAttrsResults.data) {
const values = row.group;
const service = values[0];
if (!(service in serviceMap)) {
serviceMap[service] = [];
}
const attrs: Record<string, string> = {};
for (let i = 1; i < values.length; i++) {
const field = targetGroupByFields[i];