Skip to content

Commit fe42395

Browse files
Add basic telemetry support (#36)
* add basic telemetry support * add comment * fix lint * update testcase * update * move import to the top front
1 parent 525092d commit fe42395

File tree

7 files changed

+304
-61
lines changed

7 files changed

+304
-61
lines changed

sdk/feature-management/src/featureManager.ts

Lines changed: 69 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { isTargetedGroup, isTargetedPercentile, isTargetedUser } from "./common/
1414
export class FeatureManager implements IFeatureManager {
1515
#provider: IFeatureFlagProvider;
1616
#featureFilters: Map<string, IFeatureFilter> = new Map();
17+
#onFeatureEvaluated?: (event: EvaluationResult) => void;
1718

1819
constructor(provider: IFeatureFlagProvider, options?: FeatureManagerOptions) {
1920
this.#provider = provider;
@@ -24,6 +25,8 @@ export class FeatureManager implements IFeatureManager {
2425
for (const filter of [...builtinFilters, ...(options?.customFilters ?? [])]) {
2526
this.#featureFilters.set(filter.name, filter);
2627
}
28+
29+
this.#onFeatureEvaluated = options?.onFeatureEvaluated;
2730
}
2831

2932
async listFeatureNames(): Promise<string[]> {
@@ -127,6 +130,9 @@ export class FeatureManager implements IFeatureManager {
127130
// Evaluate if the feature is enabled.
128131
result.enabled = await this.#isEnabled(featureFlag, context);
129132

133+
const targetingContext = context as ITargetingContext;
134+
result.userId = targetingContext?.userId;
135+
130136
// Determine Variant
131137
let variantDef: VariantDefinition | undefined;
132138
let reason: VariantAssignmentReason = VariantAssignmentReason.None;
@@ -146,7 +152,7 @@ export class FeatureManager implements IFeatureManager {
146152
} else {
147153
// enabled, assign based on allocation
148154
if (context !== undefined && featureFlag.allocation !== undefined) {
149-
const variantAndReason = await this.#assignVariant(featureFlag, context as ITargetingContext);
155+
const variantAndReason = await this.#assignVariant(featureFlag, targetingContext);
150156
variantDef = variantAndReason.variant;
151157
reason = variantAndReason.reason;
152158
}
@@ -164,9 +170,6 @@ export class FeatureManager implements IFeatureManager {
164170
}
165171
}
166172

167-
// TODO: send telemetry for variant assignment reason in the future.
168-
console.log(`Variant assignment for feature ${featureName}: ${variantDef?.name ?? "default"} (${reason})`);
169-
170173
result.variant = variantDef !== undefined ? new Variant(variantDef.name, variantDef.configuration_value) : undefined;
171174
result.variantAssignmentReason = reason;
172175

@@ -179,12 +182,73 @@ export class FeatureManager implements IFeatureManager {
179182
}
180183
}
181184

185+
// The callback will only be executed if telemetry is enabled for the feature flag
186+
if (featureFlag.telemetry?.enabled && this.#onFeatureEvaluated !== undefined) {
187+
this.#onFeatureEvaluated(result);
188+
}
189+
182190
return result;
183191
}
184192
}
185193

186-
interface FeatureManagerOptions {
194+
export interface FeatureManagerOptions {
195+
/**
196+
* The custom filters to be used by the feature manager.
197+
*/
187198
customFilters?: IFeatureFilter[];
199+
200+
/**
201+
* The callback function that is called when a feature flag is evaluated.
202+
* The callback function is called only when telemetry is enabled for the feature flag.
203+
*/
204+
onFeatureEvaluated?: (event: EvaluationResult) => void;
205+
}
206+
207+
export class EvaluationResult {
208+
constructor(
209+
// feature flag definition
210+
public readonly feature: FeatureFlag | undefined,
211+
212+
// enabled state
213+
public enabled: boolean = false,
214+
215+
// variant assignment
216+
public userId: string | undefined = undefined,
217+
public variant: Variant | undefined = undefined,
218+
public variantAssignmentReason: VariantAssignmentReason = VariantAssignmentReason.None
219+
) { }
220+
}
221+
222+
export enum VariantAssignmentReason {
223+
/**
224+
* Variant allocation did not happen. No variant is assigned.
225+
*/
226+
None = "None",
227+
228+
/**
229+
* The default variant is assigned when a feature flag is disabled.
230+
*/
231+
DefaultWhenDisabled = "DefaultWhenDisabled",
232+
233+
/**
234+
* The default variant is assigned because of no applicable user/group/percentile allocation when a feature flag is enabled.
235+
*/
236+
DefaultWhenEnabled = "DefaultWhenEnabled",
237+
238+
/**
239+
* The variant is assigned because of the user allocation when a feature flag is enabled.
240+
*/
241+
User = "User",
242+
243+
/**
244+
* The variant is assigned because of the group allocation when a feature flag is enabled.
245+
*/
246+
Group = "Group",
247+
248+
/**
249+
* The variant is assigned because of the percentile allocation when a feature flag is enabled.
250+
*/
251+
Percentile = "Percentile"
188252
}
189253

190254
/**
@@ -225,49 +289,3 @@ type VariantAssignment = {
225289
variant: VariantDefinition | undefined;
226290
reason: VariantAssignmentReason;
227291
};
228-
229-
enum VariantAssignmentReason {
230-
/**
231-
* Variant allocation did not happen. No variant is assigned.
232-
*/
233-
None,
234-
235-
/**
236-
* The default variant is assigned when a feature flag is disabled.
237-
*/
238-
DefaultWhenDisabled,
239-
240-
/**
241-
* The default variant is assigned because of no applicable user/group/percentile allocation when a feature flag is enabled.
242-
*/
243-
DefaultWhenEnabled,
244-
245-
/**
246-
* The variant is assigned because of the user allocation when a feature flag is enabled.
247-
*/
248-
User,
249-
250-
/**
251-
* The variant is assigned because of the group allocation when a feature flag is enabled.
252-
*/
253-
Group,
254-
255-
/**
256-
* The variant is assigned because of the percentile allocation when a feature flag is enabled.
257-
*/
258-
Percentile
259-
}
260-
261-
class EvaluationResult {
262-
constructor(
263-
// feature flag definition
264-
public readonly feature: FeatureFlag | undefined,
265-
266-
// enabled state
267-
public enabled: boolean = false,
268-
269-
// variant assignment
270-
public variant: Variant | undefined = undefined,
271-
public variantAssignmentReason: VariantAssignmentReason = VariantAssignmentReason.None
272-
) { }
273-
}

sdk/feature-management/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT license.
33

4-
export { FeatureManager } from "./featureManager.js";
4+
export { FeatureManager, FeatureManagerOptions, EvaluationResult, VariantAssignmentReason } from "./featureManager.js";
55
export { ConfigurationMapFeatureFlagProvider, ConfigurationObjectFeatureFlagProvider, IFeatureFlagProvider } from "./featureProvider.js";
66
export { IFeatureFilter } from "./filter/FeatureFilter.js";

0 commit comments

Comments
 (0)