@@ -26,6 +26,10 @@ import {
26
26
import type { ClientMetricsSchema } from '../../../../lib/openapi' ;
27
27
import { nameSchema } from '../../../schema/feature-schema' ;
28
28
import memoizee from 'memoizee' ;
29
+ import {
30
+ MAX_UNKNOWN_FLAGS ,
31
+ type UnknownFlagsService ,
32
+ } from '../unknown-flags/unknown-flags-service' ;
29
33
30
34
export default class ClientMetricsServiceV2 {
31
35
private config : IUnleashConfig ;
@@ -36,6 +40,8 @@ export default class ClientMetricsServiceV2 {
36
40
37
41
private lastSeenService : LastSeenService ;
38
42
43
+ private unknownFlagsService : UnknownFlagsService ;
44
+
39
45
private flagResolver : Pick < IFlagResolver , 'isEnabled' | 'getVariant' > ;
40
46
41
47
private logger : Logger ;
@@ -46,9 +52,11 @@ export default class ClientMetricsServiceV2 {
46
52
{ clientMetricsStoreV2 } : Pick < IUnleashStores , 'clientMetricsStoreV2' > ,
47
53
config : IUnleashConfig ,
48
54
lastSeenService : LastSeenService ,
55
+ unknownFlagsService : UnknownFlagsService ,
49
56
) {
50
57
this . clientMetricsStoreV2 = clientMetricsStoreV2 ;
51
58
this . lastSeenService = lastSeenService ;
59
+ this . unknownFlagsService = unknownFlagsService ;
52
60
this . config = config ;
53
61
this . logger = config . getLogger (
54
62
'/services/client-metrics/client-metrics-service-v2.ts' ,
@@ -113,25 +121,43 @@ export default class ClientMetricsServiceV2 {
113
121
}
114
122
}
115
123
116
- async filterExistingToggleNames ( toggleNames : string [ ] ) : Promise < string [ ] > {
124
+ async filterExistingToggleNames ( toggleNames : string [ ] ) : Promise < {
125
+ validatedToggleNames : string [ ] ;
126
+ unknownToggleNames : string [ ] ;
127
+ } > {
128
+ let unknownToggleNames : string [ ] = [ ] ;
129
+
117
130
if ( this . flagResolver . isEnabled ( 'filterExistingFlagNames' ) ) {
118
131
try {
119
132
const validNames = await this . cachedFeatureNames ( ) ;
120
133
121
134
const existingNames = toggleNames . filter ( ( name ) =>
122
135
validNames . includes ( name ) ,
123
136
) ;
137
+ if ( this . flagResolver . isEnabled ( 'reportUnknownFlags' ) ) {
138
+ unknownToggleNames = toggleNames
139
+ . filter ( ( name ) => ! existingNames . includes ( name ) )
140
+ . slice ( 0 , MAX_UNKNOWN_FLAGS ) ;
141
+ }
124
142
if ( existingNames . length !== toggleNames . length ) {
125
143
this . logger . info (
126
144
`Filtered out ${ toggleNames . length - existingNames . length } toggles with non-existing names` ,
127
145
) ;
128
146
}
129
- return this . filterValidToggleNames ( existingNames ) ;
147
+
148
+ const validatedToggleNames =
149
+ await this . filterValidToggleNames ( existingNames ) ;
150
+
151
+ return { validatedToggleNames, unknownToggleNames } ;
130
152
} catch ( e ) {
131
153
this . logger . error ( e ) ;
132
154
}
133
155
}
134
- return this . filterValidToggleNames ( toggleNames ) ;
156
+
157
+ const validatedToggleNames =
158
+ await this . filterValidToggleNames ( toggleNames ) ;
159
+
160
+ return { validatedToggleNames, unknownToggleNames } ;
135
161
}
136
162
137
163
async filterValidToggleNames ( toggleNames : string [ ] ) : Promise < string [ ] > {
@@ -181,7 +207,7 @@ export default class ClientMetricsServiceV2 {
181
207
) ,
182
208
) ;
183
209
184
- const validatedToggleNames =
210
+ const { validatedToggleNames, unknownToggleNames } =
185
211
await this . filterExistingToggleNames ( toggleNames ) ;
186
212
187
213
this . logger . debug (
@@ -204,6 +230,15 @@ export default class ClientMetricsServiceV2 {
204
230
this . config . eventBus . emit ( CLIENT_REGISTER , heartbeatEvent ) ;
205
231
}
206
232
233
+ if ( unknownToggleNames . length > 0 ) {
234
+ const unknownFlags = unknownToggleNames . map ( ( name ) => ( {
235
+ name,
236
+ appName : value . appName ,
237
+ seenAt : value . bucket . stop ,
238
+ } ) ) ;
239
+ this . unknownFlagsService . register ( unknownFlags ) ;
240
+ }
241
+
207
242
if ( validatedToggleNames . length > 0 ) {
208
243
const clientMetrics : IClientMetricsEnv [ ] = validatedToggleNames . map (
209
244
( name ) => ( {
0 commit comments