@fluidframework/app-insights-logger 2.91.0 → 2.93.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +1 -1
- package/beta.d.ts +1 -1
- package/dist/beta.d.ts +1 -1
- package/dist/fluidAppInsightsLogger.d.ts.map +1 -1
- package/dist/fluidAppInsightsLogger.js +1 -5
- package/dist/fluidAppInsightsLogger.js.map +1 -1
- package/dist/public.d.ts +1 -1
- package/eslint.config.mts +12 -2
- package/internal.d.ts +1 -1
- package/lib/beta.d.ts +1 -1
- package/lib/fluidAppInsightsLogger.d.ts.map +1 -1
- package/lib/fluidAppInsightsLogger.js +0 -1
- package/lib/fluidAppInsightsLogger.js.map +1 -1
- package/lib/public.d.ts +1 -1
- package/lib/tsdoc-metadata.json +1 -1
- package/package.json +14 -26
- package/src/fluidAppInsightsLogger.ts +0 -1
- package/tsconfig.json +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -119,7 +119,7 @@ When making such a request please include if the configuration already works (an
|
|
|
119
119
|
|
|
120
120
|
### Supported Runtimes
|
|
121
121
|
|
|
122
|
-
- NodeJs ^
|
|
122
|
+
- NodeJs ^22.22.2 except that we will drop support for it [when NodeJs 22 loses its upstream support on 2027-04-30](https://github.com/nodejs/release#release-schedule), and will support a newer LTS version of NodeJS at least 1 year before 22 is end-of-life.
|
|
123
123
|
- Running Fluid in a Node.js environment with the `--no-experimental-fetch` flag is not supported.
|
|
124
124
|
- Modern browsers supporting the es2022 standard library: in response to asks we can add explicit support for using babel to polyfill to target specific standards or runtimes (meaning we can avoid/remove use of things that don't polyfill robustly, but otherwise target modern standards).
|
|
125
125
|
|
package/beta.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluid-tools/build-cli.
|
|
8
|
+
* Generated by "flub generate entrypoints --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
export * from "./lib/beta.js";
|
package/dist/beta.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluid-tools/build-cli.
|
|
8
|
+
* Generated by "flub generate entrypoints --resolutionConditions require --outDir ./dist" in @fluid-tools/build-cli.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fluidAppInsightsLogger.d.ts","sourceRoot":"","sources":["../src/fluidAppInsightsLogger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAEX,oBAAoB,EACpB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"fluidAppInsightsLogger.d.ts","sourceRoot":"","sources":["../src/fluidAppInsightsLogger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAEX,oBAAoB,EACpB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAE9E;;;;;;;;;GASG;AACH,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;AAEzE;;;GAGG;AACH,MAAM,WAAW,4BAA4B;IAC5C;;;OAGG;IACH,SAAS,EAAE;QACV;;;;;;WAMG;QACH,IAAI,EAAE,WAAW,GAAG,WAAW,CAAC;QAChC;;;;;;;;;;WAUG;QACH,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;KAC5B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B;;OAEG;IACH,UAAU,EAAE,sBAAsB,EAAE,CAAC;CACrC;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B;;;;;;OAMG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,0BAA0B,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,MAAM,eAAe,GACxB,cAAc,GACd,eAAe,GACf,CAAC,cAAc,GAAG,eAAe,CAAC,CAAC;AA6LtC;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC3B,MAAM,EAAE,mBAAmB,EAC3B,MAAM,CAAC,EAAE,4BAA4B,GACnC,oBAAoB,CAEtB"}
|
|
@@ -3,12 +3,8 @@
|
|
|
3
3
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
-
};
|
|
9
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
7
|
exports.createLogger = void 0;
|
|
11
|
-
const structured_clone_1 = __importDefault(require("@ungap/structured-clone"));
|
|
12
8
|
/**
|
|
13
9
|
* An implementation of {@link @fluidframework/core-interfaces#ITelemetryBaseLogger}
|
|
14
10
|
* that routes Fluid telemetry events to Azure App Insights using the App Insights trackEvent API.
|
|
@@ -22,7 +18,7 @@ class FluidAppInsightsLogger {
|
|
|
22
18
|
this.baseLoggingClient = client;
|
|
23
19
|
// Deep copy config to prevent issues if user mutates the object they passed in
|
|
24
20
|
this.config = config
|
|
25
|
-
? (
|
|
21
|
+
? structuredClone(config)
|
|
26
22
|
: {
|
|
27
23
|
filtering: {
|
|
28
24
|
mode: "exclusive",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fluidAppInsightsLogger.js","sourceRoot":"","sources":["../src/fluidAppInsightsLogger.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tITelemetryBaseEvent,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport type { ApplicationInsights } from \"@microsoft/applicationinsights-web\";\nimport structuredClone from \"@ungap/structured-clone\";\n\n/**\n * The categories FF uses when instrumenting the code.\n *\n * generic - Informational log event\n *\n * error - Error log event, ideally 0 of these are logged during a session\n *\n * performance - Includes duration, and often has _start, _end, or _cancel suffixes for activity tracking\n * @beta\n */\nexport type TelemetryEventCategory = \"generic\" | \"error\" | \"performance\";\n\n/**\n * The configuration object for creating the logger via {@link createLogger}.\n * @beta\n */\nexport interface FluidAppInsightsLoggerConfig {\n\t/**\n\t * This Configuration defines how filtering will be applied to Fluid telemetry events flowing through the logger.\n\t * This determines which events will be sent to Azure App Insights.\n\t */\n\tfiltering: {\n\t\t/**\n\t\t * Determines whether all telemetry events are sent or not sent by default and whether filters will exclude matching telemetry events or include them.\n\t\t *\n\t\t * \"inclusive\" mode means all logs are NOT SENT by default and only the events that match at least one or more specified filters WILL be sent (included).\n\t\t *\n\t\t * \"exclusive\" mode means all logs ARE SENT by default and only the events that match at least one or more specified filters WILL NOT be sent (excluded).\n\t\t */\n\t\tmode: \"inclusive\" | \"exclusive\";\n\t\t/**\n\t\t * Controls the filtering of log events.\n\t\t *\n\t\t * @remarks Leaving this undefined will be treated as an empty array.\n\t\t *\n\t\t * In order for the filters to be valid they must meet the following conditions:\n\t\t *\n\t\t * 1. There must not be any two filters with the same `namespacePattern`.\n\t\t *\n\t\t * 2. All {@link NamespaceFilter} must not have any defined `namespacePatternException` that is not a child of the parent `namespacePattern`\n\t\t */\n\t\tfilters?: TelemetryFilter[];\n\t};\n}\n\n/**\n * A filter used to match against the category of a telemetry event\n * @beta\n */\nexport interface CategoryFilter {\n\t/**\n\t * The categories of telemetry events that this filter applies to\n\t */\n\tcategories: TelemetryEventCategory[];\n}\n\n/**\n * A filter used to match against the namespaces of a telemetry event\n * @beta\n */\nexport interface NamespaceFilter {\n\t/**\n\t * The namespace pattern to filter telemetry events.\n\t *\n\t * @remarks This will match namespaces that start with the given string. It is not a Regex pattern.\n\t * @example\n\t * \"perf:latency\" will match any namespace starting with \"perf:latency\"\n\t */\n\tnamespacePattern: string;\n\t/**\n\t * A list of namespace patterns to explicitly exclude from the filter.\n\t *\n\t * @example\n\t * If you have a namespacePattern of \"perf:latency\" but want to exclude\n\t * events from \"perf:latency:ops\", you would add \"perf:latency:ops\" to this list.\n\t */\n\tnamespacePatternExceptions?: Set<string>;\n}\n\n/**\n * Object used with an {@link FluidAppInsightsLoggerConfig}\n * to define a filter with logic for matching it to telemetry events.\n * Filters can include either a category, namespace or both types of filters; a valid filter must have at least one defined.\n * Not definining the `categories` filter array is the same as providing an array with all possible categories.\n *\n * Events must satisify the following rules for a telemetry filter:\n *\n * 1. The event must match the requirements of the most specific relevant filter to it. This takes precedence over a more generic filter.\n * The less categories and longer the namespace within a filter, the more specific it is. Definining no categories is equivalant to defining all categories.\n *\n * 2. If a {@link TelemetryFilter} specifies both `categories` and a `namespace`, the event must match both.\n *\n * 3. If only `categories` or a `namespace` is provided, the event should just match the with whatever was defined.\n *\n * 4. If a `namespace` pattern exception is specified in the {@link TelemetryFilter}, the event should not match the exception pattern.\n * @example\n * With the following configuration, an event `{ namespace: \"A.B.C\", categories: [\"generic\"] }` will not be sent despite matching the first, less specific filter because it did not match the second filter which was the most relevant and specific\n * ```\n * const logger = new FluidAppInsightsLogger(appInsightsClient, {\n *\t\t\tfiltering: {\n *\t\t\t\tmode: \"inclusive\",\n *\t\t\t\tfilters: [\n *\t\t\t\t\t{\n *\t\t\t\t\t\tnamespacePattern: \"A:B\",\n *\t\t\t\t\t\tcategories: [\"generic\", \"error\"],\n *\t\t\t\t\t},\n *\t\t\t\t\t{\n *\t\t\t\t\t\tnamespacePattern: \"A:B:C\",\n *\t\t\t\t\t\tcategories: [\"error\"],\n *\t\t\t\t\t},\n *\t\t\t\t],\n *\t\t\t},\n *\t\t});\n * ```\n * @beta\n */\nexport type TelemetryFilter =\n\t| CategoryFilter\n\t| NamespaceFilter\n\t| (CategoryFilter & NamespaceFilter);\n\n/**\n * An implementation of {@link @fluidframework/core-interfaces#ITelemetryBaseLogger}\n * that routes Fluid telemetry events to Azure App Insights using the App Insights trackEvent API.\n * The provided ApplicationInsights instance MUST be initialized with client.loadAppInsights()\n * or else logging will not occur.\n *\n * @sealed\n */\nclass FluidAppInsightsLogger implements ITelemetryBaseLogger {\n\t/**\n\t * The Azure ApplicationInsights client utilized by this logger.\n\t * The ApplicationInsights instance MUST be initialized with client.loadAppInsights()\n\t * or else logging will not occur.\n\t */\n\tprivate readonly baseLoggingClient: ApplicationInsights;\n\tprivate readonly config: FluidAppInsightsLoggerConfig;\n\tpublic constructor(client: ApplicationInsights, config?: FluidAppInsightsLoggerConfig) {\n\t\tthis.baseLoggingClient = client;\n\t\t// Deep copy config to prevent issues if user mutates the object they passed in\n\t\tthis.config = config\n\t\t\t? structuredClone(config)\n\t\t\t: {\n\t\t\t\t\tfiltering: {\n\t\t\t\t\t\tmode: \"exclusive\",\n\t\t\t\t\t\tfilters: [],\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\tif (this.config.filtering.filters) {\n\t\t\tthis.validateFilters(this.config.filtering.filters);\n\t\t\t// Sort filters by longest namespace first.\n\t\t\tthis.config.filtering.filters.sort((a, b) => {\n\t\t\t\tconst namespaceALength =\n\t\t\t\t\t\"namespacePattern\" in a && a.namespacePattern !== undefined\n\t\t\t\t\t\t? a.namespacePattern.length\n\t\t\t\t\t\t: 0;\n\t\t\t\tconst namespaceBLength =\n\t\t\t\t\t\"namespacePattern\" in b && b.namespacePattern !== undefined\n\t\t\t\t\t\t? b.namespacePattern.length\n\t\t\t\t\t\t: 0;\n\t\t\t\treturn namespaceBLength - namespaceALength;\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Routes Fluid telemetry events to the trackEvent App Insights API.\n\t * This method also uses the provided {@link FluidAppInsightsLoggerConfig} to\n\t * determine whether an event should be sent or not.\n\t */\n\tpublic send(event: ITelemetryBaseEvent): void {\n\t\tif (this.shouldSendEvent(event)) {\n\t\t\tthis.baseLoggingClient.trackEvent({\n\t\t\t\tname: event.eventName,\n\t\t\t\tproperties: event,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate shouldSendEvent(event: ITelemetryBaseEvent): boolean {\n\t\t// No events should be sent by default in \"inclusive\" mode, and all events should be\n\t\t// sent by default in \"exclusive\" mode.\n\t\tlet shouldSendEvent = this.config.filtering.mode === \"inclusive\" ? false : true;\n\t\tif (this.doesEventMatchFilter(event)) {\n\t\t\t// If the event does match a filter, in \"inclusive\" filter mode that means it should\n\t\t\t// be sent (included). In \"exclusive\" mode the opposite is true.\n\t\t\tshouldSendEvent = this.config.filtering.mode === \"inclusive\" ? true : false;\n\t\t}\n\t\treturn shouldSendEvent;\n\t}\n\n\t/**\n\t * Checks if a given telemetry event conforms to any of the provided {@link TelemetryFilter} rules.\n\t *\n\t * 1. The event must match the requirements of the most specific relevant filter to it. This takes precedence over a more generic filter.\n\t * The less categories and longer the namespace within a filter, the more specific it is. Definining no categories is equivalant to defining all categories.\n\t *\n\t * 2. If a {@link TelemetryFilter} specifies both `categories` and a `namespace`, the event must match both.\n\t *\n\t * 3. If only `categories` or a `namespace` is provided, the event should match either one of them.\n\t *\n\t * 4. If a `namespace` pattern exception is specified in the {@link TelemetryFilter}, the event should not match the exception pattern.\n\t *\n\t * @param event - The telemetry event to check against the filters.\n\t *\n\t * @returns `true` if the event matches any filter, otherwise `false`.\n\t */\n\tprivate doesEventMatchFilter(event: ITelemetryBaseEvent): boolean {\n\t\tfor (const filter of this.config.filtering.filters ?? []) {\n\t\t\tif (\"namespacePattern\" in filter && filter.namespacePattern !== undefined) {\n\t\t\t\tif (event.eventName.startsWith(filter.namespacePattern)) {\n\t\t\t\t\t// Found matching namespace pattern, since filters are ordered in most specific first,\n\t\t\t\t\t// this is the most specific, relevant matching filter for the event.\n\n\t\t\t\t\t// By default, if no categories are defined then any category is a valid match.\n\t\t\t\t\tlet doesFilterCategoriesMatch = true;\n\t\t\t\t\tif (\n\t\t\t\t\t\t\"categories\" in filter &&\n\t\t\t\t\t\tfilter.categories !== undefined &&\n\t\t\t\t\t\tfilter.categories.length > 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tdoesFilterCategoriesMatch = false;\n\t\t\t\t\t\tconst matchingCategory = filter.categories.find(\n\t\t\t\t\t\t\t(category) => category === event.category,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tdoesFilterCategoriesMatch = matchingCategory ? true : false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (doesFilterCategoriesMatch) {\n\t\t\t\t\t\t// The most specific, relevant filter matches so no need to attempt to evaluate against other filters\n\t\t\t\t\t\t// as long as the events namespace does not match any defined namespace exception.\n\t\t\t\t\t\tif (filter.namespacePatternExceptions !== undefined) {\n\t\t\t\t\t\t\tfor (const patternException of filter.namespacePatternExceptions) {\n\t\t\t\t\t\t\t\tif (event.eventName.startsWith(patternException)) {\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Filter only has categories defined\n\t\t\telse if (\n\t\t\t\t\"categories\" in filter &&\n\t\t\t\tfilter.categories !== undefined &&\n\t\t\t\tfilter.categories.length > 0\n\t\t\t) {\n\t\t\t\tconst doesFilterCategoriesMatch = filter.categories.find(\n\t\t\t\t\t(category) => category === event.category,\n\t\t\t\t);\n\n\t\t\t\t// This filter specified no namespaces but it has a category match.\n\t\t\t\t// Since filters are ordered by most specific first, we know that no previous\n\t\t\t\t// filters with namespaces matched so we can return true.\n\t\t\t\tif (doesFilterCategoriesMatch) {\n\t\t\t\t\treturn true;\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Checks an array of telemetry filters for any issues, merges redundant filters, and returns a fully validated array.\n\t *\n\t * @throws An Error if there are two filters with duplicate namespace patterns or a filter with a pattern exception that is not a child of the parent pattern.\n\t */\n\tprivate validateFilters(filters: TelemetryFilter[]): void {\n\t\tconst uniqueFilterNamespaces = new Set<string>();\n\n\t\tfor (const filter of filters) {\n\t\t\tif (\"namespacePattern\" in filter && filter.namespacePattern !== undefined) {\n\t\t\t\tif (uniqueFilterNamespaces.has(filter.namespacePattern)) {\n\t\t\t\t\tthrow new Error(\"Cannot have duplicate namespace pattern filters\");\n\t\t\t\t} else {\n\t\t\t\t\tuniqueFilterNamespaces.add(filter.namespacePattern);\n\t\t\t\t}\n\n\t\t\t\tfor (const patternException of filter.namespacePatternExceptions ?? []) {\n\t\t\t\t\tif (!patternException.startsWith(filter.namespacePattern)) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\"Cannot have a namespace pattern exception that is not a child of the parent namespace\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (\"categories\" in filter && filter.categories !== undefined) {\n\t\t\t\t// These are filters that only contain \"categories\". For the purpose of this validation logic, we are treating filters\n\t\t\t\t// that does not contain a defined namespace as the the same as a blank \"\" namespace pattern (which will match any event).\n\t\t\t\tif (uniqueFilterNamespaces.has(\"\")) {\n\t\t\t\t\tthrow new Error(\"Cannot have multiple filters that only define categories\");\n\t\t\t\t}\n\t\t\t\tuniqueFilterNamespaces.add(\"\");\n\t\t\t} else {\n\t\t\t\tthrow new Error(\"Invalid filter does not have either a namespace or a category.\");\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Creates an {@link @fluidframework/core-interfaces#ITelemetryBaseLogger}\n * that routes Fluid telemetry events to Azure App Insights using the App Insights trackEvent API.\n *\n * The provided ApplicationInsights instance MUST be initialized with client.loadAppInsights(),\n * or else logging will not occur.\n *\n * @beta\n */\nexport function createLogger(\n\tclient: ApplicationInsights,\n\tconfig?: FluidAppInsightsLoggerConfig,\n): ITelemetryBaseLogger {\n\treturn new FluidAppInsightsLogger(client, config);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"fluidAppInsightsLogger.js","sourceRoot":"","sources":["../src/fluidAppInsightsLogger.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tITelemetryBaseEvent,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport type { ApplicationInsights } from \"@microsoft/applicationinsights-web\";\n\n/**\n * The categories FF uses when instrumenting the code.\n *\n * generic - Informational log event\n *\n * error - Error log event, ideally 0 of these are logged during a session\n *\n * performance - Includes duration, and often has _start, _end, or _cancel suffixes for activity tracking\n * @beta\n */\nexport type TelemetryEventCategory = \"generic\" | \"error\" | \"performance\";\n\n/**\n * The configuration object for creating the logger via {@link createLogger}.\n * @beta\n */\nexport interface FluidAppInsightsLoggerConfig {\n\t/**\n\t * This Configuration defines how filtering will be applied to Fluid telemetry events flowing through the logger.\n\t * This determines which events will be sent to Azure App Insights.\n\t */\n\tfiltering: {\n\t\t/**\n\t\t * Determines whether all telemetry events are sent or not sent by default and whether filters will exclude matching telemetry events or include them.\n\t\t *\n\t\t * \"inclusive\" mode means all logs are NOT SENT by default and only the events that match at least one or more specified filters WILL be sent (included).\n\t\t *\n\t\t * \"exclusive\" mode means all logs ARE SENT by default and only the events that match at least one or more specified filters WILL NOT be sent (excluded).\n\t\t */\n\t\tmode: \"inclusive\" | \"exclusive\";\n\t\t/**\n\t\t * Controls the filtering of log events.\n\t\t *\n\t\t * @remarks Leaving this undefined will be treated as an empty array.\n\t\t *\n\t\t * In order for the filters to be valid they must meet the following conditions:\n\t\t *\n\t\t * 1. There must not be any two filters with the same `namespacePattern`.\n\t\t *\n\t\t * 2. All {@link NamespaceFilter} must not have any defined `namespacePatternException` that is not a child of the parent `namespacePattern`\n\t\t */\n\t\tfilters?: TelemetryFilter[];\n\t};\n}\n\n/**\n * A filter used to match against the category of a telemetry event\n * @beta\n */\nexport interface CategoryFilter {\n\t/**\n\t * The categories of telemetry events that this filter applies to\n\t */\n\tcategories: TelemetryEventCategory[];\n}\n\n/**\n * A filter used to match against the namespaces of a telemetry event\n * @beta\n */\nexport interface NamespaceFilter {\n\t/**\n\t * The namespace pattern to filter telemetry events.\n\t *\n\t * @remarks This will match namespaces that start with the given string. It is not a Regex pattern.\n\t * @example\n\t * \"perf:latency\" will match any namespace starting with \"perf:latency\"\n\t */\n\tnamespacePattern: string;\n\t/**\n\t * A list of namespace patterns to explicitly exclude from the filter.\n\t *\n\t * @example\n\t * If you have a namespacePattern of \"perf:latency\" but want to exclude\n\t * events from \"perf:latency:ops\", you would add \"perf:latency:ops\" to this list.\n\t */\n\tnamespacePatternExceptions?: Set<string>;\n}\n\n/**\n * Object used with an {@link FluidAppInsightsLoggerConfig}\n * to define a filter with logic for matching it to telemetry events.\n * Filters can include either a category, namespace or both types of filters; a valid filter must have at least one defined.\n * Not definining the `categories` filter array is the same as providing an array with all possible categories.\n *\n * Events must satisify the following rules for a telemetry filter:\n *\n * 1. The event must match the requirements of the most specific relevant filter to it. This takes precedence over a more generic filter.\n * The less categories and longer the namespace within a filter, the more specific it is. Definining no categories is equivalant to defining all categories.\n *\n * 2. If a {@link TelemetryFilter} specifies both `categories` and a `namespace`, the event must match both.\n *\n * 3. If only `categories` or a `namespace` is provided, the event should just match the with whatever was defined.\n *\n * 4. If a `namespace` pattern exception is specified in the {@link TelemetryFilter}, the event should not match the exception pattern.\n * @example\n * With the following configuration, an event `{ namespace: \"A.B.C\", categories: [\"generic\"] }` will not be sent despite matching the first, less specific filter because it did not match the second filter which was the most relevant and specific\n * ```\n * const logger = new FluidAppInsightsLogger(appInsightsClient, {\n *\t\t\tfiltering: {\n *\t\t\t\tmode: \"inclusive\",\n *\t\t\t\tfilters: [\n *\t\t\t\t\t{\n *\t\t\t\t\t\tnamespacePattern: \"A:B\",\n *\t\t\t\t\t\tcategories: [\"generic\", \"error\"],\n *\t\t\t\t\t},\n *\t\t\t\t\t{\n *\t\t\t\t\t\tnamespacePattern: \"A:B:C\",\n *\t\t\t\t\t\tcategories: [\"error\"],\n *\t\t\t\t\t},\n *\t\t\t\t],\n *\t\t\t},\n *\t\t});\n * ```\n * @beta\n */\nexport type TelemetryFilter =\n\t| CategoryFilter\n\t| NamespaceFilter\n\t| (CategoryFilter & NamespaceFilter);\n\n/**\n * An implementation of {@link @fluidframework/core-interfaces#ITelemetryBaseLogger}\n * that routes Fluid telemetry events to Azure App Insights using the App Insights trackEvent API.\n * The provided ApplicationInsights instance MUST be initialized with client.loadAppInsights()\n * or else logging will not occur.\n *\n * @sealed\n */\nclass FluidAppInsightsLogger implements ITelemetryBaseLogger {\n\t/**\n\t * The Azure ApplicationInsights client utilized by this logger.\n\t * The ApplicationInsights instance MUST be initialized with client.loadAppInsights()\n\t * or else logging will not occur.\n\t */\n\tprivate readonly baseLoggingClient: ApplicationInsights;\n\tprivate readonly config: FluidAppInsightsLoggerConfig;\n\tpublic constructor(client: ApplicationInsights, config?: FluidAppInsightsLoggerConfig) {\n\t\tthis.baseLoggingClient = client;\n\t\t// Deep copy config to prevent issues if user mutates the object they passed in\n\t\tthis.config = config\n\t\t\t? structuredClone(config)\n\t\t\t: {\n\t\t\t\t\tfiltering: {\n\t\t\t\t\t\tmode: \"exclusive\",\n\t\t\t\t\t\tfilters: [],\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\tif (this.config.filtering.filters) {\n\t\t\tthis.validateFilters(this.config.filtering.filters);\n\t\t\t// Sort filters by longest namespace first.\n\t\t\tthis.config.filtering.filters.sort((a, b) => {\n\t\t\t\tconst namespaceALength =\n\t\t\t\t\t\"namespacePattern\" in a && a.namespacePattern !== undefined\n\t\t\t\t\t\t? a.namespacePattern.length\n\t\t\t\t\t\t: 0;\n\t\t\t\tconst namespaceBLength =\n\t\t\t\t\t\"namespacePattern\" in b && b.namespacePattern !== undefined\n\t\t\t\t\t\t? b.namespacePattern.length\n\t\t\t\t\t\t: 0;\n\t\t\t\treturn namespaceBLength - namespaceALength;\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Routes Fluid telemetry events to the trackEvent App Insights API.\n\t * This method also uses the provided {@link FluidAppInsightsLoggerConfig} to\n\t * determine whether an event should be sent or not.\n\t */\n\tpublic send(event: ITelemetryBaseEvent): void {\n\t\tif (this.shouldSendEvent(event)) {\n\t\t\tthis.baseLoggingClient.trackEvent({\n\t\t\t\tname: event.eventName,\n\t\t\t\tproperties: event,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate shouldSendEvent(event: ITelemetryBaseEvent): boolean {\n\t\t// No events should be sent by default in \"inclusive\" mode, and all events should be\n\t\t// sent by default in \"exclusive\" mode.\n\t\tlet shouldSendEvent = this.config.filtering.mode === \"inclusive\" ? false : true;\n\t\tif (this.doesEventMatchFilter(event)) {\n\t\t\t// If the event does match a filter, in \"inclusive\" filter mode that means it should\n\t\t\t// be sent (included). In \"exclusive\" mode the opposite is true.\n\t\t\tshouldSendEvent = this.config.filtering.mode === \"inclusive\" ? true : false;\n\t\t}\n\t\treturn shouldSendEvent;\n\t}\n\n\t/**\n\t * Checks if a given telemetry event conforms to any of the provided {@link TelemetryFilter} rules.\n\t *\n\t * 1. The event must match the requirements of the most specific relevant filter to it. This takes precedence over a more generic filter.\n\t * The less categories and longer the namespace within a filter, the more specific it is. Definining no categories is equivalant to defining all categories.\n\t *\n\t * 2. If a {@link TelemetryFilter} specifies both `categories` and a `namespace`, the event must match both.\n\t *\n\t * 3. If only `categories` or a `namespace` is provided, the event should match either one of them.\n\t *\n\t * 4. If a `namespace` pattern exception is specified in the {@link TelemetryFilter}, the event should not match the exception pattern.\n\t *\n\t * @param event - The telemetry event to check against the filters.\n\t *\n\t * @returns `true` if the event matches any filter, otherwise `false`.\n\t */\n\tprivate doesEventMatchFilter(event: ITelemetryBaseEvent): boolean {\n\t\tfor (const filter of this.config.filtering.filters ?? []) {\n\t\t\tif (\"namespacePattern\" in filter && filter.namespacePattern !== undefined) {\n\t\t\t\tif (event.eventName.startsWith(filter.namespacePattern)) {\n\t\t\t\t\t// Found matching namespace pattern, since filters are ordered in most specific first,\n\t\t\t\t\t// this is the most specific, relevant matching filter for the event.\n\n\t\t\t\t\t// By default, if no categories are defined then any category is a valid match.\n\t\t\t\t\tlet doesFilterCategoriesMatch = true;\n\t\t\t\t\tif (\n\t\t\t\t\t\t\"categories\" in filter &&\n\t\t\t\t\t\tfilter.categories !== undefined &&\n\t\t\t\t\t\tfilter.categories.length > 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tdoesFilterCategoriesMatch = false;\n\t\t\t\t\t\tconst matchingCategory = filter.categories.find(\n\t\t\t\t\t\t\t(category) => category === event.category,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tdoesFilterCategoriesMatch = matchingCategory ? true : false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (doesFilterCategoriesMatch) {\n\t\t\t\t\t\t// The most specific, relevant filter matches so no need to attempt to evaluate against other filters\n\t\t\t\t\t\t// as long as the events namespace does not match any defined namespace exception.\n\t\t\t\t\t\tif (filter.namespacePatternExceptions !== undefined) {\n\t\t\t\t\t\t\tfor (const patternException of filter.namespacePatternExceptions) {\n\t\t\t\t\t\t\t\tif (event.eventName.startsWith(patternException)) {\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Filter only has categories defined\n\t\t\telse if (\n\t\t\t\t\"categories\" in filter &&\n\t\t\t\tfilter.categories !== undefined &&\n\t\t\t\tfilter.categories.length > 0\n\t\t\t) {\n\t\t\t\tconst doesFilterCategoriesMatch = filter.categories.find(\n\t\t\t\t\t(category) => category === event.category,\n\t\t\t\t);\n\n\t\t\t\t// This filter specified no namespaces but it has a category match.\n\t\t\t\t// Since filters are ordered by most specific first, we know that no previous\n\t\t\t\t// filters with namespaces matched so we can return true.\n\t\t\t\tif (doesFilterCategoriesMatch) {\n\t\t\t\t\treturn true;\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Checks an array of telemetry filters for any issues, merges redundant filters, and returns a fully validated array.\n\t *\n\t * @throws An Error if there are two filters with duplicate namespace patterns or a filter with a pattern exception that is not a child of the parent pattern.\n\t */\n\tprivate validateFilters(filters: TelemetryFilter[]): void {\n\t\tconst uniqueFilterNamespaces = new Set<string>();\n\n\t\tfor (const filter of filters) {\n\t\t\tif (\"namespacePattern\" in filter && filter.namespacePattern !== undefined) {\n\t\t\t\tif (uniqueFilterNamespaces.has(filter.namespacePattern)) {\n\t\t\t\t\tthrow new Error(\"Cannot have duplicate namespace pattern filters\");\n\t\t\t\t} else {\n\t\t\t\t\tuniqueFilterNamespaces.add(filter.namespacePattern);\n\t\t\t\t}\n\n\t\t\t\tfor (const patternException of filter.namespacePatternExceptions ?? []) {\n\t\t\t\t\tif (!patternException.startsWith(filter.namespacePattern)) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\"Cannot have a namespace pattern exception that is not a child of the parent namespace\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (\"categories\" in filter && filter.categories !== undefined) {\n\t\t\t\t// These are filters that only contain \"categories\". For the purpose of this validation logic, we are treating filters\n\t\t\t\t// that does not contain a defined namespace as the the same as a blank \"\" namespace pattern (which will match any event).\n\t\t\t\tif (uniqueFilterNamespaces.has(\"\")) {\n\t\t\t\t\tthrow new Error(\"Cannot have multiple filters that only define categories\");\n\t\t\t\t}\n\t\t\t\tuniqueFilterNamespaces.add(\"\");\n\t\t\t} else {\n\t\t\t\tthrow new Error(\"Invalid filter does not have either a namespace or a category.\");\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Creates an {@link @fluidframework/core-interfaces#ITelemetryBaseLogger}\n * that routes Fluid telemetry events to Azure App Insights using the App Insights trackEvent API.\n *\n * The provided ApplicationInsights instance MUST be initialized with client.loadAppInsights(),\n * or else logging will not occur.\n *\n * @beta\n */\nexport function createLogger(\n\tclient: ApplicationInsights,\n\tconfig?: FluidAppInsightsLoggerConfig,\n): ITelemetryBaseLogger {\n\treturn new FluidAppInsightsLogger(client, config);\n}\n"]}
|
package/dist/public.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluid-tools/build-cli.
|
|
8
|
+
* Generated by "flub generate entrypoints --resolutionConditions require --outDir ./dist" in @fluid-tools/build-cli.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/**
|
package/eslint.config.mts
CHANGED
|
@@ -4,8 +4,18 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { Linter } from "eslint";
|
|
7
|
-
import { strict } from "
|
|
7
|
+
import { strict } from "@fluidframework/eslint-config-fluid/flat.mts";
|
|
8
8
|
|
|
9
|
-
const config: Linter.Config[] = [
|
|
9
|
+
const config: Linter.Config[] = [
|
|
10
|
+
...strict,
|
|
11
|
+
{
|
|
12
|
+
files: ["src/test/**/*.spec.ts"],
|
|
13
|
+
rules: {
|
|
14
|
+
// Allow named functions in mocha hooks (before, beforeEach, etc.) so that
|
|
15
|
+
// the function name appears in error output and stack traces.
|
|
16
|
+
"prefer-arrow-callback": ["error", { allowNamedFunctions: true }],
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
];
|
|
10
20
|
|
|
11
21
|
export default config;
|
package/internal.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluid-tools/build-cli.
|
|
8
|
+
* Generated by "flub generate entrypoints --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
export * from "./lib/index.js";
|
package/lib/beta.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluid-tools/build-cli.
|
|
8
|
+
* Generated by "flub generate entrypoints --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fluidAppInsightsLogger.d.ts","sourceRoot":"","sources":["../src/fluidAppInsightsLogger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAEX,oBAAoB,EACpB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"fluidAppInsightsLogger.d.ts","sourceRoot":"","sources":["../src/fluidAppInsightsLogger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAEX,oBAAoB,EACpB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAE9E;;;;;;;;;GASG;AACH,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;AAEzE;;;GAGG;AACH,MAAM,WAAW,4BAA4B;IAC5C;;;OAGG;IACH,SAAS,EAAE;QACV;;;;;;WAMG;QACH,IAAI,EAAE,WAAW,GAAG,WAAW,CAAC;QAChC;;;;;;;;;;WAUG;QACH,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;KAC5B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B;;OAEG;IACH,UAAU,EAAE,sBAAsB,EAAE,CAAC;CACrC;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B;;;;;;OAMG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,0BAA0B,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,MAAM,eAAe,GACxB,cAAc,GACd,eAAe,GACf,CAAC,cAAc,GAAG,eAAe,CAAC,CAAC;AA6LtC;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC3B,MAAM,EAAE,mBAAmB,EAC3B,MAAM,CAAC,EAAE,4BAA4B,GACnC,oBAAoB,CAEtB"}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import structuredClone from "@ungap/structured-clone";
|
|
6
5
|
/**
|
|
7
6
|
* An implementation of {@link @fluidframework/core-interfaces#ITelemetryBaseLogger}
|
|
8
7
|
* that routes Fluid telemetry events to Azure App Insights using the App Insights trackEvent API.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fluidAppInsightsLogger.js","sourceRoot":"","sources":["../src/fluidAppInsightsLogger.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tITelemetryBaseEvent,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport type { ApplicationInsights } from \"@microsoft/applicationinsights-web\";\nimport structuredClone from \"@ungap/structured-clone\";\n\n/**\n * The categories FF uses when instrumenting the code.\n *\n * generic - Informational log event\n *\n * error - Error log event, ideally 0 of these are logged during a session\n *\n * performance - Includes duration, and often has _start, _end, or _cancel suffixes for activity tracking\n * @beta\n */\nexport type TelemetryEventCategory = \"generic\" | \"error\" | \"performance\";\n\n/**\n * The configuration object for creating the logger via {@link createLogger}.\n * @beta\n */\nexport interface FluidAppInsightsLoggerConfig {\n\t/**\n\t * This Configuration defines how filtering will be applied to Fluid telemetry events flowing through the logger.\n\t * This determines which events will be sent to Azure App Insights.\n\t */\n\tfiltering: {\n\t\t/**\n\t\t * Determines whether all telemetry events are sent or not sent by default and whether filters will exclude matching telemetry events or include them.\n\t\t *\n\t\t * \"inclusive\" mode means all logs are NOT SENT by default and only the events that match at least one or more specified filters WILL be sent (included).\n\t\t *\n\t\t * \"exclusive\" mode means all logs ARE SENT by default and only the events that match at least one or more specified filters WILL NOT be sent (excluded).\n\t\t */\n\t\tmode: \"inclusive\" | \"exclusive\";\n\t\t/**\n\t\t * Controls the filtering of log events.\n\t\t *\n\t\t * @remarks Leaving this undefined will be treated as an empty array.\n\t\t *\n\t\t * In order for the filters to be valid they must meet the following conditions:\n\t\t *\n\t\t * 1. There must not be any two filters with the same `namespacePattern`.\n\t\t *\n\t\t * 2. All {@link NamespaceFilter} must not have any defined `namespacePatternException` that is not a child of the parent `namespacePattern`\n\t\t */\n\t\tfilters?: TelemetryFilter[];\n\t};\n}\n\n/**\n * A filter used to match against the category of a telemetry event\n * @beta\n */\nexport interface CategoryFilter {\n\t/**\n\t * The categories of telemetry events that this filter applies to\n\t */\n\tcategories: TelemetryEventCategory[];\n}\n\n/**\n * A filter used to match against the namespaces of a telemetry event\n * @beta\n */\nexport interface NamespaceFilter {\n\t/**\n\t * The namespace pattern to filter telemetry events.\n\t *\n\t * @remarks This will match namespaces that start with the given string. It is not a Regex pattern.\n\t * @example\n\t * \"perf:latency\" will match any namespace starting with \"perf:latency\"\n\t */\n\tnamespacePattern: string;\n\t/**\n\t * A list of namespace patterns to explicitly exclude from the filter.\n\t *\n\t * @example\n\t * If you have a namespacePattern of \"perf:latency\" but want to exclude\n\t * events from \"perf:latency:ops\", you would add \"perf:latency:ops\" to this list.\n\t */\n\tnamespacePatternExceptions?: Set<string>;\n}\n\n/**\n * Object used with an {@link FluidAppInsightsLoggerConfig}\n * to define a filter with logic for matching it to telemetry events.\n * Filters can include either a category, namespace or both types of filters; a valid filter must have at least one defined.\n * Not definining the `categories` filter array is the same as providing an array with all possible categories.\n *\n * Events must satisify the following rules for a telemetry filter:\n *\n * 1. The event must match the requirements of the most specific relevant filter to it. This takes precedence over a more generic filter.\n * The less categories and longer the namespace within a filter, the more specific it is. Definining no categories is equivalant to defining all categories.\n *\n * 2. If a {@link TelemetryFilter} specifies both `categories` and a `namespace`, the event must match both.\n *\n * 3. If only `categories` or a `namespace` is provided, the event should just match the with whatever was defined.\n *\n * 4. If a `namespace` pattern exception is specified in the {@link TelemetryFilter}, the event should not match the exception pattern.\n * @example\n * With the following configuration, an event `{ namespace: \"A.B.C\", categories: [\"generic\"] }` will not be sent despite matching the first, less specific filter because it did not match the second filter which was the most relevant and specific\n * ```\n * const logger = new FluidAppInsightsLogger(appInsightsClient, {\n *\t\t\tfiltering: {\n *\t\t\t\tmode: \"inclusive\",\n *\t\t\t\tfilters: [\n *\t\t\t\t\t{\n *\t\t\t\t\t\tnamespacePattern: \"A:B\",\n *\t\t\t\t\t\tcategories: [\"generic\", \"error\"],\n *\t\t\t\t\t},\n *\t\t\t\t\t{\n *\t\t\t\t\t\tnamespacePattern: \"A:B:C\",\n *\t\t\t\t\t\tcategories: [\"error\"],\n *\t\t\t\t\t},\n *\t\t\t\t],\n *\t\t\t},\n *\t\t});\n * ```\n * @beta\n */\nexport type TelemetryFilter =\n\t| CategoryFilter\n\t| NamespaceFilter\n\t| (CategoryFilter & NamespaceFilter);\n\n/**\n * An implementation of {@link @fluidframework/core-interfaces#ITelemetryBaseLogger}\n * that routes Fluid telemetry events to Azure App Insights using the App Insights trackEvent API.\n * The provided ApplicationInsights instance MUST be initialized with client.loadAppInsights()\n * or else logging will not occur.\n *\n * @sealed\n */\nclass FluidAppInsightsLogger implements ITelemetryBaseLogger {\n\t/**\n\t * The Azure ApplicationInsights client utilized by this logger.\n\t * The ApplicationInsights instance MUST be initialized with client.loadAppInsights()\n\t * or else logging will not occur.\n\t */\n\tprivate readonly baseLoggingClient: ApplicationInsights;\n\tprivate readonly config: FluidAppInsightsLoggerConfig;\n\tpublic constructor(client: ApplicationInsights, config?: FluidAppInsightsLoggerConfig) {\n\t\tthis.baseLoggingClient = client;\n\t\t// Deep copy config to prevent issues if user mutates the object they passed in\n\t\tthis.config = config\n\t\t\t? structuredClone(config)\n\t\t\t: {\n\t\t\t\t\tfiltering: {\n\t\t\t\t\t\tmode: \"exclusive\",\n\t\t\t\t\t\tfilters: [],\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\tif (this.config.filtering.filters) {\n\t\t\tthis.validateFilters(this.config.filtering.filters);\n\t\t\t// Sort filters by longest namespace first.\n\t\t\tthis.config.filtering.filters.sort((a, b) => {\n\t\t\t\tconst namespaceALength =\n\t\t\t\t\t\"namespacePattern\" in a && a.namespacePattern !== undefined\n\t\t\t\t\t\t? a.namespacePattern.length\n\t\t\t\t\t\t: 0;\n\t\t\t\tconst namespaceBLength =\n\t\t\t\t\t\"namespacePattern\" in b && b.namespacePattern !== undefined\n\t\t\t\t\t\t? b.namespacePattern.length\n\t\t\t\t\t\t: 0;\n\t\t\t\treturn namespaceBLength - namespaceALength;\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Routes Fluid telemetry events to the trackEvent App Insights API.\n\t * This method also uses the provided {@link FluidAppInsightsLoggerConfig} to\n\t * determine whether an event should be sent or not.\n\t */\n\tpublic send(event: ITelemetryBaseEvent): void {\n\t\tif (this.shouldSendEvent(event)) {\n\t\t\tthis.baseLoggingClient.trackEvent({\n\t\t\t\tname: event.eventName,\n\t\t\t\tproperties: event,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate shouldSendEvent(event: ITelemetryBaseEvent): boolean {\n\t\t// No events should be sent by default in \"inclusive\" mode, and all events should be\n\t\t// sent by default in \"exclusive\" mode.\n\t\tlet shouldSendEvent = this.config.filtering.mode === \"inclusive\" ? false : true;\n\t\tif (this.doesEventMatchFilter(event)) {\n\t\t\t// If the event does match a filter, in \"inclusive\" filter mode that means it should\n\t\t\t// be sent (included). In \"exclusive\" mode the opposite is true.\n\t\t\tshouldSendEvent = this.config.filtering.mode === \"inclusive\" ? true : false;\n\t\t}\n\t\treturn shouldSendEvent;\n\t}\n\n\t/**\n\t * Checks if a given telemetry event conforms to any of the provided {@link TelemetryFilter} rules.\n\t *\n\t * 1. The event must match the requirements of the most specific relevant filter to it. This takes precedence over a more generic filter.\n\t * The less categories and longer the namespace within a filter, the more specific it is. Definining no categories is equivalant to defining all categories.\n\t *\n\t * 2. If a {@link TelemetryFilter} specifies both `categories` and a `namespace`, the event must match both.\n\t *\n\t * 3. If only `categories` or a `namespace` is provided, the event should match either one of them.\n\t *\n\t * 4. If a `namespace` pattern exception is specified in the {@link TelemetryFilter}, the event should not match the exception pattern.\n\t *\n\t * @param event - The telemetry event to check against the filters.\n\t *\n\t * @returns `true` if the event matches any filter, otherwise `false`.\n\t */\n\tprivate doesEventMatchFilter(event: ITelemetryBaseEvent): boolean {\n\t\tfor (const filter of this.config.filtering.filters ?? []) {\n\t\t\tif (\"namespacePattern\" in filter && filter.namespacePattern !== undefined) {\n\t\t\t\tif (event.eventName.startsWith(filter.namespacePattern)) {\n\t\t\t\t\t// Found matching namespace pattern, since filters are ordered in most specific first,\n\t\t\t\t\t// this is the most specific, relevant matching filter for the event.\n\n\t\t\t\t\t// By default, if no categories are defined then any category is a valid match.\n\t\t\t\t\tlet doesFilterCategoriesMatch = true;\n\t\t\t\t\tif (\n\t\t\t\t\t\t\"categories\" in filter &&\n\t\t\t\t\t\tfilter.categories !== undefined &&\n\t\t\t\t\t\tfilter.categories.length > 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tdoesFilterCategoriesMatch = false;\n\t\t\t\t\t\tconst matchingCategory = filter.categories.find(\n\t\t\t\t\t\t\t(category) => category === event.category,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tdoesFilterCategoriesMatch = matchingCategory ? true : false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (doesFilterCategoriesMatch) {\n\t\t\t\t\t\t// The most specific, relevant filter matches so no need to attempt to evaluate against other filters\n\t\t\t\t\t\t// as long as the events namespace does not match any defined namespace exception.\n\t\t\t\t\t\tif (filter.namespacePatternExceptions !== undefined) {\n\t\t\t\t\t\t\tfor (const patternException of filter.namespacePatternExceptions) {\n\t\t\t\t\t\t\t\tif (event.eventName.startsWith(patternException)) {\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Filter only has categories defined\n\t\t\telse if (\n\t\t\t\t\"categories\" in filter &&\n\t\t\t\tfilter.categories !== undefined &&\n\t\t\t\tfilter.categories.length > 0\n\t\t\t) {\n\t\t\t\tconst doesFilterCategoriesMatch = filter.categories.find(\n\t\t\t\t\t(category) => category === event.category,\n\t\t\t\t);\n\n\t\t\t\t// This filter specified no namespaces but it has a category match.\n\t\t\t\t// Since filters are ordered by most specific first, we know that no previous\n\t\t\t\t// filters with namespaces matched so we can return true.\n\t\t\t\tif (doesFilterCategoriesMatch) {\n\t\t\t\t\treturn true;\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Checks an array of telemetry filters for any issues, merges redundant filters, and returns a fully validated array.\n\t *\n\t * @throws An Error if there are two filters with duplicate namespace patterns or a filter with a pattern exception that is not a child of the parent pattern.\n\t */\n\tprivate validateFilters(filters: TelemetryFilter[]): void {\n\t\tconst uniqueFilterNamespaces = new Set<string>();\n\n\t\tfor (const filter of filters) {\n\t\t\tif (\"namespacePattern\" in filter && filter.namespacePattern !== undefined) {\n\t\t\t\tif (uniqueFilterNamespaces.has(filter.namespacePattern)) {\n\t\t\t\t\tthrow new Error(\"Cannot have duplicate namespace pattern filters\");\n\t\t\t\t} else {\n\t\t\t\t\tuniqueFilterNamespaces.add(filter.namespacePattern);\n\t\t\t\t}\n\n\t\t\t\tfor (const patternException of filter.namespacePatternExceptions ?? []) {\n\t\t\t\t\tif (!patternException.startsWith(filter.namespacePattern)) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\"Cannot have a namespace pattern exception that is not a child of the parent namespace\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (\"categories\" in filter && filter.categories !== undefined) {\n\t\t\t\t// These are filters that only contain \"categories\". For the purpose of this validation logic, we are treating filters\n\t\t\t\t// that does not contain a defined namespace as the the same as a blank \"\" namespace pattern (which will match any event).\n\t\t\t\tif (uniqueFilterNamespaces.has(\"\")) {\n\t\t\t\t\tthrow new Error(\"Cannot have multiple filters that only define categories\");\n\t\t\t\t}\n\t\t\t\tuniqueFilterNamespaces.add(\"\");\n\t\t\t} else {\n\t\t\t\tthrow new Error(\"Invalid filter does not have either a namespace or a category.\");\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Creates an {@link @fluidframework/core-interfaces#ITelemetryBaseLogger}\n * that routes Fluid telemetry events to Azure App Insights using the App Insights trackEvent API.\n *\n * The provided ApplicationInsights instance MUST be initialized with client.loadAppInsights(),\n * or else logging will not occur.\n *\n * @beta\n */\nexport function createLogger(\n\tclient: ApplicationInsights,\n\tconfig?: FluidAppInsightsLoggerConfig,\n): ITelemetryBaseLogger {\n\treturn new FluidAppInsightsLogger(client, config);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"fluidAppInsightsLogger.js","sourceRoot":"","sources":["../src/fluidAppInsightsLogger.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tITelemetryBaseEvent,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport type { ApplicationInsights } from \"@microsoft/applicationinsights-web\";\n\n/**\n * The categories FF uses when instrumenting the code.\n *\n * generic - Informational log event\n *\n * error - Error log event, ideally 0 of these are logged during a session\n *\n * performance - Includes duration, and often has _start, _end, or _cancel suffixes for activity tracking\n * @beta\n */\nexport type TelemetryEventCategory = \"generic\" | \"error\" | \"performance\";\n\n/**\n * The configuration object for creating the logger via {@link createLogger}.\n * @beta\n */\nexport interface FluidAppInsightsLoggerConfig {\n\t/**\n\t * This Configuration defines how filtering will be applied to Fluid telemetry events flowing through the logger.\n\t * This determines which events will be sent to Azure App Insights.\n\t */\n\tfiltering: {\n\t\t/**\n\t\t * Determines whether all telemetry events are sent or not sent by default and whether filters will exclude matching telemetry events or include them.\n\t\t *\n\t\t * \"inclusive\" mode means all logs are NOT SENT by default and only the events that match at least one or more specified filters WILL be sent (included).\n\t\t *\n\t\t * \"exclusive\" mode means all logs ARE SENT by default and only the events that match at least one or more specified filters WILL NOT be sent (excluded).\n\t\t */\n\t\tmode: \"inclusive\" | \"exclusive\";\n\t\t/**\n\t\t * Controls the filtering of log events.\n\t\t *\n\t\t * @remarks Leaving this undefined will be treated as an empty array.\n\t\t *\n\t\t * In order for the filters to be valid they must meet the following conditions:\n\t\t *\n\t\t * 1. There must not be any two filters with the same `namespacePattern`.\n\t\t *\n\t\t * 2. All {@link NamespaceFilter} must not have any defined `namespacePatternException` that is not a child of the parent `namespacePattern`\n\t\t */\n\t\tfilters?: TelemetryFilter[];\n\t};\n}\n\n/**\n * A filter used to match against the category of a telemetry event\n * @beta\n */\nexport interface CategoryFilter {\n\t/**\n\t * The categories of telemetry events that this filter applies to\n\t */\n\tcategories: TelemetryEventCategory[];\n}\n\n/**\n * A filter used to match against the namespaces of a telemetry event\n * @beta\n */\nexport interface NamespaceFilter {\n\t/**\n\t * The namespace pattern to filter telemetry events.\n\t *\n\t * @remarks This will match namespaces that start with the given string. It is not a Regex pattern.\n\t * @example\n\t * \"perf:latency\" will match any namespace starting with \"perf:latency\"\n\t */\n\tnamespacePattern: string;\n\t/**\n\t * A list of namespace patterns to explicitly exclude from the filter.\n\t *\n\t * @example\n\t * If you have a namespacePattern of \"perf:latency\" but want to exclude\n\t * events from \"perf:latency:ops\", you would add \"perf:latency:ops\" to this list.\n\t */\n\tnamespacePatternExceptions?: Set<string>;\n}\n\n/**\n * Object used with an {@link FluidAppInsightsLoggerConfig}\n * to define a filter with logic for matching it to telemetry events.\n * Filters can include either a category, namespace or both types of filters; a valid filter must have at least one defined.\n * Not definining the `categories` filter array is the same as providing an array with all possible categories.\n *\n * Events must satisify the following rules for a telemetry filter:\n *\n * 1. The event must match the requirements of the most specific relevant filter to it. This takes precedence over a more generic filter.\n * The less categories and longer the namespace within a filter, the more specific it is. Definining no categories is equivalant to defining all categories.\n *\n * 2. If a {@link TelemetryFilter} specifies both `categories` and a `namespace`, the event must match both.\n *\n * 3. If only `categories` or a `namespace` is provided, the event should just match the with whatever was defined.\n *\n * 4. If a `namespace` pattern exception is specified in the {@link TelemetryFilter}, the event should not match the exception pattern.\n * @example\n * With the following configuration, an event `{ namespace: \"A.B.C\", categories: [\"generic\"] }` will not be sent despite matching the first, less specific filter because it did not match the second filter which was the most relevant and specific\n * ```\n * const logger = new FluidAppInsightsLogger(appInsightsClient, {\n *\t\t\tfiltering: {\n *\t\t\t\tmode: \"inclusive\",\n *\t\t\t\tfilters: [\n *\t\t\t\t\t{\n *\t\t\t\t\t\tnamespacePattern: \"A:B\",\n *\t\t\t\t\t\tcategories: [\"generic\", \"error\"],\n *\t\t\t\t\t},\n *\t\t\t\t\t{\n *\t\t\t\t\t\tnamespacePattern: \"A:B:C\",\n *\t\t\t\t\t\tcategories: [\"error\"],\n *\t\t\t\t\t},\n *\t\t\t\t],\n *\t\t\t},\n *\t\t});\n * ```\n * @beta\n */\nexport type TelemetryFilter =\n\t| CategoryFilter\n\t| NamespaceFilter\n\t| (CategoryFilter & NamespaceFilter);\n\n/**\n * An implementation of {@link @fluidframework/core-interfaces#ITelemetryBaseLogger}\n * that routes Fluid telemetry events to Azure App Insights using the App Insights trackEvent API.\n * The provided ApplicationInsights instance MUST be initialized with client.loadAppInsights()\n * or else logging will not occur.\n *\n * @sealed\n */\nclass FluidAppInsightsLogger implements ITelemetryBaseLogger {\n\t/**\n\t * The Azure ApplicationInsights client utilized by this logger.\n\t * The ApplicationInsights instance MUST be initialized with client.loadAppInsights()\n\t * or else logging will not occur.\n\t */\n\tprivate readonly baseLoggingClient: ApplicationInsights;\n\tprivate readonly config: FluidAppInsightsLoggerConfig;\n\tpublic constructor(client: ApplicationInsights, config?: FluidAppInsightsLoggerConfig) {\n\t\tthis.baseLoggingClient = client;\n\t\t// Deep copy config to prevent issues if user mutates the object they passed in\n\t\tthis.config = config\n\t\t\t? structuredClone(config)\n\t\t\t: {\n\t\t\t\t\tfiltering: {\n\t\t\t\t\t\tmode: \"exclusive\",\n\t\t\t\t\t\tfilters: [],\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\tif (this.config.filtering.filters) {\n\t\t\tthis.validateFilters(this.config.filtering.filters);\n\t\t\t// Sort filters by longest namespace first.\n\t\t\tthis.config.filtering.filters.sort((a, b) => {\n\t\t\t\tconst namespaceALength =\n\t\t\t\t\t\"namespacePattern\" in a && a.namespacePattern !== undefined\n\t\t\t\t\t\t? a.namespacePattern.length\n\t\t\t\t\t\t: 0;\n\t\t\t\tconst namespaceBLength =\n\t\t\t\t\t\"namespacePattern\" in b && b.namespacePattern !== undefined\n\t\t\t\t\t\t? b.namespacePattern.length\n\t\t\t\t\t\t: 0;\n\t\t\t\treturn namespaceBLength - namespaceALength;\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Routes Fluid telemetry events to the trackEvent App Insights API.\n\t * This method also uses the provided {@link FluidAppInsightsLoggerConfig} to\n\t * determine whether an event should be sent or not.\n\t */\n\tpublic send(event: ITelemetryBaseEvent): void {\n\t\tif (this.shouldSendEvent(event)) {\n\t\t\tthis.baseLoggingClient.trackEvent({\n\t\t\t\tname: event.eventName,\n\t\t\t\tproperties: event,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate shouldSendEvent(event: ITelemetryBaseEvent): boolean {\n\t\t// No events should be sent by default in \"inclusive\" mode, and all events should be\n\t\t// sent by default in \"exclusive\" mode.\n\t\tlet shouldSendEvent = this.config.filtering.mode === \"inclusive\" ? false : true;\n\t\tif (this.doesEventMatchFilter(event)) {\n\t\t\t// If the event does match a filter, in \"inclusive\" filter mode that means it should\n\t\t\t// be sent (included). In \"exclusive\" mode the opposite is true.\n\t\t\tshouldSendEvent = this.config.filtering.mode === \"inclusive\" ? true : false;\n\t\t}\n\t\treturn shouldSendEvent;\n\t}\n\n\t/**\n\t * Checks if a given telemetry event conforms to any of the provided {@link TelemetryFilter} rules.\n\t *\n\t * 1. The event must match the requirements of the most specific relevant filter to it. This takes precedence over a more generic filter.\n\t * The less categories and longer the namespace within a filter, the more specific it is. Definining no categories is equivalant to defining all categories.\n\t *\n\t * 2. If a {@link TelemetryFilter} specifies both `categories` and a `namespace`, the event must match both.\n\t *\n\t * 3. If only `categories` or a `namespace` is provided, the event should match either one of them.\n\t *\n\t * 4. If a `namespace` pattern exception is specified in the {@link TelemetryFilter}, the event should not match the exception pattern.\n\t *\n\t * @param event - The telemetry event to check against the filters.\n\t *\n\t * @returns `true` if the event matches any filter, otherwise `false`.\n\t */\n\tprivate doesEventMatchFilter(event: ITelemetryBaseEvent): boolean {\n\t\tfor (const filter of this.config.filtering.filters ?? []) {\n\t\t\tif (\"namespacePattern\" in filter && filter.namespacePattern !== undefined) {\n\t\t\t\tif (event.eventName.startsWith(filter.namespacePattern)) {\n\t\t\t\t\t// Found matching namespace pattern, since filters are ordered in most specific first,\n\t\t\t\t\t// this is the most specific, relevant matching filter for the event.\n\n\t\t\t\t\t// By default, if no categories are defined then any category is a valid match.\n\t\t\t\t\tlet doesFilterCategoriesMatch = true;\n\t\t\t\t\tif (\n\t\t\t\t\t\t\"categories\" in filter &&\n\t\t\t\t\t\tfilter.categories !== undefined &&\n\t\t\t\t\t\tfilter.categories.length > 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tdoesFilterCategoriesMatch = false;\n\t\t\t\t\t\tconst matchingCategory = filter.categories.find(\n\t\t\t\t\t\t\t(category) => category === event.category,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tdoesFilterCategoriesMatch = matchingCategory ? true : false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (doesFilterCategoriesMatch) {\n\t\t\t\t\t\t// The most specific, relevant filter matches so no need to attempt to evaluate against other filters\n\t\t\t\t\t\t// as long as the events namespace does not match any defined namespace exception.\n\t\t\t\t\t\tif (filter.namespacePatternExceptions !== undefined) {\n\t\t\t\t\t\t\tfor (const patternException of filter.namespacePatternExceptions) {\n\t\t\t\t\t\t\t\tif (event.eventName.startsWith(patternException)) {\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Filter only has categories defined\n\t\t\telse if (\n\t\t\t\t\"categories\" in filter &&\n\t\t\t\tfilter.categories !== undefined &&\n\t\t\t\tfilter.categories.length > 0\n\t\t\t) {\n\t\t\t\tconst doesFilterCategoriesMatch = filter.categories.find(\n\t\t\t\t\t(category) => category === event.category,\n\t\t\t\t);\n\n\t\t\t\t// This filter specified no namespaces but it has a category match.\n\t\t\t\t// Since filters are ordered by most specific first, we know that no previous\n\t\t\t\t// filters with namespaces matched so we can return true.\n\t\t\t\tif (doesFilterCategoriesMatch) {\n\t\t\t\t\treturn true;\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Checks an array of telemetry filters for any issues, merges redundant filters, and returns a fully validated array.\n\t *\n\t * @throws An Error if there are two filters with duplicate namespace patterns or a filter with a pattern exception that is not a child of the parent pattern.\n\t */\n\tprivate validateFilters(filters: TelemetryFilter[]): void {\n\t\tconst uniqueFilterNamespaces = new Set<string>();\n\n\t\tfor (const filter of filters) {\n\t\t\tif (\"namespacePattern\" in filter && filter.namespacePattern !== undefined) {\n\t\t\t\tif (uniqueFilterNamespaces.has(filter.namespacePattern)) {\n\t\t\t\t\tthrow new Error(\"Cannot have duplicate namespace pattern filters\");\n\t\t\t\t} else {\n\t\t\t\t\tuniqueFilterNamespaces.add(filter.namespacePattern);\n\t\t\t\t}\n\n\t\t\t\tfor (const patternException of filter.namespacePatternExceptions ?? []) {\n\t\t\t\t\tif (!patternException.startsWith(filter.namespacePattern)) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\"Cannot have a namespace pattern exception that is not a child of the parent namespace\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (\"categories\" in filter && filter.categories !== undefined) {\n\t\t\t\t// These are filters that only contain \"categories\". For the purpose of this validation logic, we are treating filters\n\t\t\t\t// that does not contain a defined namespace as the the same as a blank \"\" namespace pattern (which will match any event).\n\t\t\t\tif (uniqueFilterNamespaces.has(\"\")) {\n\t\t\t\t\tthrow new Error(\"Cannot have multiple filters that only define categories\");\n\t\t\t\t}\n\t\t\t\tuniqueFilterNamespaces.add(\"\");\n\t\t\t} else {\n\t\t\t\tthrow new Error(\"Invalid filter does not have either a namespace or a category.\");\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Creates an {@link @fluidframework/core-interfaces#ITelemetryBaseLogger}\n * that routes Fluid telemetry events to Azure App Insights using the App Insights trackEvent API.\n *\n * The provided ApplicationInsights instance MUST be initialized with client.loadAppInsights(),\n * or else logging will not occur.\n *\n * @beta\n */\nexport function createLogger(\n\tclient: ApplicationInsights,\n\tconfig?: FluidAppInsightsLoggerConfig,\n): ITelemetryBaseLogger {\n\treturn new FluidAppInsightsLogger(client, config);\n}\n"]}
|
package/lib/public.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluid-tools/build-cli.
|
|
8
|
+
* Generated by "flub generate entrypoints --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/**
|
package/lib/tsdoc-metadata.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/app-insights-logger",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.93.0",
|
|
4
4
|
"description": "Contains a Fluid logging client that sends telemetry events to Azure App Insights",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -47,23 +47,21 @@
|
|
|
47
47
|
"main": "lib/index.js",
|
|
48
48
|
"types": "lib/public.d.ts",
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@fluidframework/core-interfaces": "~2.
|
|
51
|
-
"@microsoft/applicationinsights-web": "^2.8.11"
|
|
52
|
-
"@ungap/structured-clone": "^1.2.0"
|
|
50
|
+
"@fluidframework/core-interfaces": "~2.93.0",
|
|
51
|
+
"@microsoft/applicationinsights-web": "^2.8.11"
|
|
53
52
|
},
|
|
54
53
|
"devDependencies": {
|
|
55
54
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
56
55
|
"@biomejs/biome": "~2.4.5",
|
|
57
|
-
"@fluid-internal/mocha-test-setup": "~2.
|
|
58
|
-
"@fluid-tools/build-cli": "^0.
|
|
59
|
-
"@fluidframework/app-insights-logger-previous": "npm:@fluidframework/app-insights-logger@2.
|
|
56
|
+
"@fluid-internal/mocha-test-setup": "~2.93.0",
|
|
57
|
+
"@fluid-tools/build-cli": "^0.64.0",
|
|
58
|
+
"@fluidframework/app-insights-logger-previous": "npm:@fluidframework/app-insights-logger@2.92.0",
|
|
60
59
|
"@fluidframework/build-common": "^2.0.3",
|
|
61
|
-
"@fluidframework/build-tools": "^0.
|
|
62
|
-
"@microsoft/api-extractor": "7.
|
|
60
|
+
"@fluidframework/build-tools": "^0.64.0",
|
|
61
|
+
"@microsoft/api-extractor": "7.58.1",
|
|
63
62
|
"@types/mocha": "^10.0.10",
|
|
64
|
-
"@types/node": "~
|
|
63
|
+
"@types/node": "~22.19.17",
|
|
65
64
|
"@types/sinon": "^17.0.3",
|
|
66
|
-
"@types/ungap__structured-clone": "^1.2.0",
|
|
67
65
|
"concurrently": "^9.2.1",
|
|
68
66
|
"copyfiles": "^2.4.1",
|
|
69
67
|
"cross-env": "^10.1.0",
|
|
@@ -89,31 +87,22 @@
|
|
|
89
87
|
}
|
|
90
88
|
}
|
|
91
89
|
},
|
|
92
|
-
"fluidBuild": {
|
|
93
|
-
"tasks": {
|
|
94
|
-
"build:esnext": [
|
|
95
|
-
"...",
|
|
96
|
-
"typetests:gen"
|
|
97
|
-
],
|
|
98
|
-
"tsc": [
|
|
99
|
-
"...",
|
|
100
|
-
"typetests:gen"
|
|
101
|
-
]
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
90
|
"typeValidation": {
|
|
105
91
|
"broken": {},
|
|
106
92
|
"entrypoint": "internal"
|
|
107
93
|
},
|
|
108
94
|
"scripts": {
|
|
109
95
|
"api": "fluid-build . --task api",
|
|
110
|
-
"api-extractor:commonjs": "flub generate entrypoints --outDir ./dist",
|
|
96
|
+
"api-extractor:commonjs": "flub generate entrypoints --resolutionConditions require --outDir ./dist",
|
|
111
97
|
"api-extractor:esnext": "flub generate entrypoints --outDir ./lib --node10TypeCompat",
|
|
112
98
|
"build": "fluid-build . --task build",
|
|
113
99
|
"build:commonjs": "fluid-build . --task commonjs",
|
|
114
100
|
"build:compile": "fluid-build . --task compile",
|
|
115
101
|
"build:docs": "api-extractor run --local",
|
|
116
102
|
"build:esnext": "tsc --project ./tsconfig.json",
|
|
103
|
+
"build:test": "npm run build:test:esm && npm run build:test:cjs",
|
|
104
|
+
"build:test:cjs": "fluid-tsc commonjs --project ./src/test/tsconfig.cjs.json",
|
|
105
|
+
"build:test:esm": "tsc --project ./src/test/tsconfig.json",
|
|
117
106
|
"check:are-the-types-wrong": "attw --pack .",
|
|
118
107
|
"check:biome": "biome check .",
|
|
119
108
|
"check:exports": "concurrently \"npm:check:exports:*\"",
|
|
@@ -139,7 +128,6 @@
|
|
|
139
128
|
"test:mocha:esm": "mocha",
|
|
140
129
|
"test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
|
|
141
130
|
"tsc": "fluid-tsc commonjs --project ./tsconfig.cjs.json && copyfiles -f ../../../../common/build/build-common/src/cjs/package.json ./dist",
|
|
142
|
-
"typetests:gen": "flub generate typetests --dir . -v"
|
|
143
|
-
"typetests:prepare": "flub typetests --dir . --reset --previous --normalize"
|
|
131
|
+
"typetests:gen": "flub generate typetests --dir . -v"
|
|
144
132
|
}
|
|
145
133
|
}
|
|
@@ -8,7 +8,6 @@ import type {
|
|
|
8
8
|
ITelemetryBaseLogger,
|
|
9
9
|
} from "@fluidframework/core-interfaces";
|
|
10
10
|
import type { ApplicationInsights } from "@microsoft/applicationinsights-web";
|
|
11
|
-
import structuredClone from "@ungap/structured-clone";
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
* The categories FF uses when instrumenting the code.
|
package/tsconfig.json
CHANGED