Skip to content

Commit a197093

Browse files
Add node.js app insights package (#64)
* init * add node.js package * fix lint * add exp telemetry fields * update * update * align with other FM to produce True/False instead of true/false
1 parent 6bd8759 commit a197093

File tree

19 files changed

+3341
-65
lines changed

19 files changed

+3341
-65
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,12 @@ jobs:
5959

6060
- name: Run lint check for feature-management-applicationinsights-browser
6161
run: npm run lint
62-
working-directory: sdk/feature-management-applicationinsights-browser
62+
working-directory: sdk/feature-management-applicationinsights-browser
63+
64+
- name: Build feature-management-applicationinsights-node
65+
run: npm run build
66+
working-directory: sdk/feature-management-applicationinsights-node
67+
68+
- name: Run lint check for feature-management-applicationinsights-node
69+
run: npm run lint
70+
working-directory: sdk/feature-management-applicationinsights-node

scripts/build-and-pack.sh

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,19 @@ echo "npm pack in $PACKAGE_DIR"
4141
npm pack
4242

4343
echo "copy $PACKAGE package to $PROJECT_BASE_DIR"
44-
cp "$PACKAGE_DIR"/*.tgz "$PROJECT_BASE_DIR"
44+
cp "$PACKAGE_DIR"/*.tgz "$PROJECT_BASE_DIR"
45+
46+
PACKAGE="feature-management-applicationinsights-node"
47+
PACKAGE_DIR="$SDK_DIR/$PACKAGE"
48+
49+
echo "Building package $PACKAGE in $PACKAGE_DIR"
50+
cd "$PACKAGE_DIR"
51+
52+
echo "npm run build in $PACKAGE_DIR"
53+
npm run build
54+
55+
echo "npm pack in $PACKAGE_DIR"
56+
npm pack
57+
58+
echo "copy $PACKAGE package to $PROJECT_BASE_DIR"
59+
cp "$PACKAGE_DIR"/*.tgz "$PROJECT_BASE_DIR"

sdk/feature-management-applicationinsights-browser/.eslintrc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
{
22
"env": {
33
"browser": true,
4-
"commonjs": true,
54
"es2021": true,
6-
"node": true,
75
"mocha": true
86
},
97
"extends": [

sdk/feature-management-applicationinsights-browser/README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@ Feature Management Application Insights Plugin for Browser provides a solution f
44

55
## Getting Started
66

7-
### Prerequisites
8-
9-
- Node.js LTS version
10-
117
### Usage
128

139
``` javascript

sdk/feature-management-applicationinsights-browser/src/telemetry.ts

Lines changed: 5 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,24 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT license.
33

4-
import { EvaluationResult, VariantAssignmentReason } from "@microsoft/feature-management";
4+
import { EvaluationResult, createFeatureEvaluationEventProperties } from "@microsoft/feature-management";
55
import { ApplicationInsights, IEventTelemetry } from "@microsoft/applicationinsights-web";
6-
import { EVALUATION_EVENT_VERSION } from "./version.js";
76

8-
const VERSION = "Version";
9-
const FEATURE_NAME = "FeatureName";
10-
const ENABLED = "Enabled";
117
const TARGETING_ID = "TargetingId";
12-
const VARIANT = "Variant";
13-
const VARIANT_ASSIGNMENT_REASON = "VariantAssignmentReason";
14-
const DEFAULT_WHEN_ENABLED = "DefaultWhenEnabled";
15-
const VARIANT_ASSIGNMENT_PERCENTAGE = "VariantAssignmentPercentage";
168
const FEATURE_EVALUATION_EVENT_NAME = "FeatureEvaluation";
179

1810
/**
1911
* Creates a telemetry publisher that sends feature evaluation events to Application Insights.
2012
* @param client The Application Insights telemetry client.
2113
* @returns A callback function that takes an evaluation result and tracks an event with the evaluation details.
2214
*/
23-
export function createTelemetryPublisher(client: ApplicationInsights): (event: EvaluationResult) => void {
24-
return (event: EvaluationResult) => {
25-
if (event.feature === undefined) {
15+
export function createTelemetryPublisher(client: ApplicationInsights): (result: EvaluationResult) => void {
16+
return (result: EvaluationResult) => {
17+
if (result.feature === undefined) {
2618
return;
2719
}
2820

29-
const eventProperties = {
30-
[VERSION]: EVALUATION_EVENT_VERSION,
31-
[FEATURE_NAME]: event.feature ? event.feature.id : "",
32-
[ENABLED]: event.enabled.toString(),
33-
// Ensure targetingId is string so that it will be placed in customDimensions
34-
[TARGETING_ID]: event.targetingId ? event.targetingId.toString() : "",
35-
[VARIANT]: event.variant ? event.variant.name : "",
36-
[VARIANT_ASSIGNMENT_REASON]: event.variantAssignmentReason,
37-
};
38-
39-
if (event.feature.allocation?.default_when_enabled) {
40-
eventProperties[DEFAULT_WHEN_ENABLED] = event.feature.allocation.default_when_enabled;
41-
}
42-
43-
if (event.variantAssignmentReason === VariantAssignmentReason.DefaultWhenEnabled) {
44-
let percentileAllocationPercentage = 0;
45-
if (event.variant !== undefined && event.feature.allocation !== undefined && event.feature.allocation.percentile !== undefined) {
46-
for (const percentile of event.feature.allocation.percentile) {
47-
percentileAllocationPercentage += percentile.to - percentile.from;
48-
}
49-
}
50-
eventProperties[VARIANT_ASSIGNMENT_PERCENTAGE] = (100 - percentileAllocationPercentage).toString();
51-
}
52-
else if (event.variantAssignmentReason === VariantAssignmentReason.Percentile) {
53-
let percentileAllocationPercentage = 0;
54-
if (event.variant !== undefined && event.feature.allocation !== undefined && event.feature.allocation.percentile !== undefined) {
55-
for (const percentile of event.feature.allocation.percentile) {
56-
if (percentile.variant === event.variant.name) {
57-
percentileAllocationPercentage += percentile.to - percentile.from;
58-
}
59-
}
60-
}
61-
eventProperties[VARIANT_ASSIGNMENT_PERCENTAGE] = percentileAllocationPercentage.toString();
62-
}
63-
64-
const metadata = event.feature.telemetry?.metadata;
65-
if (metadata) {
66-
for (const key in metadata) {
67-
if (!(key in eventProperties)) {
68-
eventProperties[key] = metadata[key];
69-
}
70-
}
71-
}
72-
21+
const eventProperties = createFeatureEvaluationEventProperties(result);
7322
client.trackEvent({ name: FEATURE_EVALUATION_EVENT_NAME }, eventProperties);
7423
};
7524
}

sdk/feature-management-applicationinsights-browser/src/version.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,3 @@
22
// Licensed under the MIT license.
33

44
export const VERSION = "2.0.0-preview.2";
5-
export const EVALUATION_EVENT_VERSION = "1.0.0";
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"env": {
3+
"commonjs": true,
4+
"es2021": true,
5+
"node": true,
6+
"mocha": true
7+
},
8+
"extends": [
9+
"eslint:recommended",
10+
"plugin:@typescript-eslint/recommended"
11+
],
12+
"ignorePatterns": [
13+
],
14+
"overrides": [
15+
{
16+
"env": {
17+
"node": true
18+
},
19+
"files": [
20+
".eslintrc.{js,cjs}"
21+
],
22+
"parserOptions": {
23+
"sourceType": "script"
24+
}
25+
}
26+
],
27+
"parser": "@typescript-eslint/parser",
28+
"parserOptions": {
29+
"ecmaVersion": "latest"
30+
},
31+
"plugins": [
32+
"@typescript-eslint"
33+
],
34+
"rules": {
35+
"quotes": [
36+
"error",
37+
"double",
38+
{
39+
"avoidEscape": true
40+
}
41+
],
42+
"@typescript-eslint/no-explicit-any": "off",
43+
"eol-last": [
44+
"error",
45+
"always"
46+
],
47+
"no-trailing-spaces": "error",
48+
"space-before-blocks": [
49+
"error",
50+
"always"
51+
],
52+
"no-multi-spaces": "error",
53+
"no-multiple-empty-lines": [
54+
"error",
55+
{
56+
"max": 1
57+
}
58+
],
59+
"semi": ["error", "always"]
60+
}
61+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) Microsoft Corporation.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Microsoft Feature Management Application Insights Plugin for Browser
2+
3+
Feature Management Application Insights Plugin for Browser provides a solution for sending feature flag evaluation events produced by the Feature Management library.
4+
5+
## Getting Started
6+
7+
### Prerequisites
8+
9+
- Node.js LTS version
10+
11+
### Usage
12+
13+
``` javascript
14+
import appInsights from "applicationinsights";
15+
import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "@microsoft/feature-management";
16+
import { trackEvent, publishTelemetry } from "@microsoft/feature-management-applicationinsights-node";
17+
18+
appInsights.setup(CONNECTION_STRING)
19+
.start();
20+
21+
const publishTelemetry = createTelemetryPublisher(appInsights.defaultClient);
22+
const provider = new ConfigurationObjectFeatureFlagProvider(jsonObject);
23+
const featureManager = new FeatureManager(provider, {onFeatureEvaluated: publishTelemetry});
24+
25+
// FeatureEvaluation event will be emitted when a feature flag is evaluated
26+
featureManager.getVariant("TestFeature", {userId : TARGETING_ID}).then((variant) => { /* do something*/ });
27+
28+
// Emit a custom event with targeting id attached.
29+
trackEvent(appInsights.defaultClient, TARGETING_ID, {name: "TestEvent"});
30+
```
31+
32+
## Contributing
33+
34+
This project welcomes contributions and suggestions. Most contributions require you to agree to a
35+
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
36+
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
37+
38+
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
39+
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
40+
provided by the bot. You will only need to do this once across all repos using our CLA.
41+
42+
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
43+
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
44+
contact [[email protected]](mailto:[email protected]) with any additional questions or comments.
45+
46+
## Trademarks
47+
48+
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
49+
trademarks or logos is subject to and must follow
50+
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
51+
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
52+
Any use of third-party trademarks or logos are subject to those third-party's policies.

0 commit comments

Comments
 (0)