- Unknown flags are feature flags that
- your SDKs tried to evaluate but which Unleash doesn't
- recognize. Tracking them helps you catch typos, remove
- outdated flags, and keep your code and configuration in
- sync. These can include:
-
-
-
-
- Missing flags: typos or flags referenced in
- code that don't exist in Unleash.
-
-
- Invalid flags: flags with malformed or
- unexpected names, unsupported by Unleash.
-
-
-
-
- Each row in the table represents an{' '}
- unknown flag report, which is a unique
- combination of flag name, application,
- and environment. The same flag name may appear
- multiple times if it's been seen in different
- applications or environments.
+
+ Clean up unknown flags to keep your code and
+ configuration in sync
+
+
+ Unknown flags are feature flags that your SDKs tried to
+ evaluate but which Unleash doesn't recognize.
- We display up to 1,000 unknown flag reports from the
- last 24 hours. Older reports are automatically pruned.
+ Unknown flags can include:
+
+
+ Missing flags: typos or flags referenced in code
+ that don't exist in Unleash.
+
+
+ Invalid flags: flags with malformed or
+ unexpected names, unsupported by Unleash.
+
+
+
+
+
+ Why do I see the same flag name multiple times?
+
+ The same flag name will appear multiple times if it's
+ been seen in different applications or environments.
diff --git a/frontend/src/component/unknownFlags/hooks/useUnknownFlags.ts b/frontend/src/component/unknownFlags/hooks/useUnknownFlags.ts
index d8f71c8717..1923a4276c 100644
--- a/frontend/src/component/unknownFlags/hooks/useUnknownFlags.ts
+++ b/frontend/src/component/unknownFlags/hooks/useUnknownFlags.ts
@@ -10,6 +10,7 @@ export type UnknownFlag = {
appName: string;
seenAt: Date;
environment: string;
+ lastEventAt: Date;
};
type UnknownFlagsResponse = {
diff --git a/src/lib/features/metrics/unknown-flags/unknown-flags-store.ts b/src/lib/features/metrics/unknown-flags/unknown-flags-store.ts
index 86836bf817..f665f75a3d 100644
--- a/src/lib/features/metrics/unknown-flags/unknown-flags-store.ts
+++ b/src/lib/features/metrics/unknown-flags/unknown-flags-store.ts
@@ -2,6 +2,7 @@ import type { Db } from '../../../db/db.js';
import type { Logger, LogProvider } from '../../../logger.js';
const TABLE = 'unknown_flags';
+const TABLE_EVENTS = 'events';
const MAX_INSERT_BATCH_SIZE = 100;
export type UnknownFlag = {
@@ -9,6 +10,7 @@ export type UnknownFlag = {
appName: string;
seenAt: Date;
environment: string;
+ lastEventAt?: Date;
};
export type QueryParams = {
@@ -64,11 +66,17 @@ export class UnknownFlagsStore implements IUnknownFlagsStore {
}
async getAll({ limit, orderBy }: QueryParams = {}): Promise {
- let query = this.db(TABLE).select(
- 'name',
- 'app_name',
- 'seen_at',
- 'environment',
+ let query = this.db(`${TABLE} AS uf`).select(
+ 'uf.name',
+ 'uf.app_name',
+ 'uf.seen_at',
+ 'uf.environment',
+ this.db.raw(
+ `(SELECT MAX(e.created_at)
+ FROM ${TABLE_EVENTS} AS e
+ WHERE e.feature_name = uf.name)
+ AS last_event_at`,
+ ),
);
if (orderBy) {
@@ -84,8 +92,9 @@ export class UnknownFlagsStore implements IUnknownFlagsStore {
return rows.map((row) => ({
name: row.name,
appName: row.app_name,
- seenAt: new Date(row.seen_at),
+ seenAt: row.seen_at,
environment: row.environment,
+ lastEventAt: row.last_event_at,
}));
}
diff --git a/src/lib/openapi/spec/unknown-flag-schema.ts b/src/lib/openapi/spec/unknown-flag-schema.ts
index c921c2c695..cb6394cdb6 100644
--- a/src/lib/openapi/spec/unknown-flag-schema.ts
+++ b/src/lib/openapi/spec/unknown-flag-schema.ts
@@ -31,6 +31,14 @@ export const unknownFlagSchema = {
'The environment in which the unknown flag was reported.',
example: 'production',
},
+ lastEventAt: {
+ type: 'string',
+ format: 'date-time',
+ description:
+ 'The date and time when the last event for the unknown flag name occurred, if any.',
+ example: '2023-10-01T12:00:00Z',
+ nullable: true,
+ },
},
components: {},
} as const;