Readme an PnPJS

This commit is contained in:
Peter Paul Kirschner 2024-05-27 10:26:15 +02:00
parent cb8956a86e
commit aa70fe957d
8 changed files with 261 additions and 25 deletions

View File

@ -1,10 +1,23 @@
# app-insights-spfx-webparts ---
page_type: sample
products:
- office-sp
languages:
- typescript
extensions:
contentType: samples
technologies:
- SharePoint Framework
platforms:
- react
createdDate: 5/26/2024 12:00:00 AM
---
# Application Insights usage
## Summary ## Summary
Short summary on functionality and used technologies. Application Insights provides telemetry data to monitor and improve application performance and user experience, while AB Testing, user flow analysis, and logging help in optimizing and debugging applications by comparing different versions, mapping user paths, and recording significant events. The 3 Sample Webpart demonstrates webpart functionalities to aid developers in integrating customizable components effectively.
[picture of the solution in action, if possible]
## Used SharePoint Framework Version ## Used SharePoint Framework Version
@ -22,11 +35,10 @@ Short summary on functionality and used technologies.
Application Insight Service on Azure Application Insight Service on Azure
Add the connection stirng of this Service to the the variable ```AIConnectionString``` at ```src/EnvProps.ts``` Add the connection stirng of this Service to the the variable ```AIConnectionString``` at ```src/EnvProps.ts```
## Solution
| Solution | Author(s) | ## Contributors
| ----------- | ------------------------------------------------------- |
| folder name | Author details (name, company, twitter alias with link) | * [Peter Paul Kirschner](https://github.com/petkir)
## Version history ## Version history
@ -44,6 +56,8 @@ Add the connection stirng of this Service to the the variable ```AIConnectionStr
- Clone this repository - Clone this repository
- Ensure that you are at the solution folder - Ensure that you are at the solution folder
- Create or use Existing Azure Application Insights
- Update ```src/EnvProps.ts``` and Set AIConnectionString
- in the command-line run: - in the command-line run:
- **npm install** - **npm install**
- **gulp serve** - **gulp serve**
@ -63,8 +77,7 @@ This extension illustrates the following concepts:
- Logging - Logging
- PnP JS Logger - PnP JS Logger
- Logging with PnPJS - Logging with PnPJS
- Custom Logger
- Logging with PnPJS
# Sample Router WebPart # Sample Router WebPart
@ -115,6 +128,10 @@ customEvents
``` ```
![AB Evaluation](assets/ABEvaluation.png) ![AB Evaluation](assets/ABEvaluation.png)
# PnPJS Logger WebPart
![Logoutput with Browser Log Level Filter](assets/PNPJSLogger.png)
> Notice that better pictures and documentation will increase the sample usage and the value you are providing for others. Thanks for your submissions advance. > Notice that better pictures and documentation will increase the sample usage and the value you are providing for others. Thanks for your submissions advance.
> Share your web part with others through Microsoft 365 Patterns and Practices program to get visibility and exposure. More details on the community, open-source projects and other activities from http://aka.ms/m365pnp. > Share your web part with others through Microsoft 365 Patterns and Practices program to get visibility and exposure. More details on the community, open-source projects and other activities from http://aka.ms/m365pnp.
@ -126,3 +143,5 @@ customEvents
- [Use Microsoft Graph in your solution](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/using-microsoft-graph-apis) - [Use Microsoft Graph in your solution](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/using-microsoft-graph-apis)
- [Publish SharePoint Framework applications to the Marketplace](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/publish-to-marketplace-overview) - [Publish SharePoint Framework applications to the Marketplace](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/publish-to-marketplace-overview)
- [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) - Guidance, tooling, samples and open-source controls for your Microsoft 365 development - [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) - Guidance, tooling, samples and open-source controls for your Microsoft 365 development
- [PnPJS/Logging](https://pnp.github.io/pnpjs/logging/)
- [Application Insights](https://learn.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview) Application Insights provides many experiences to enhance the performance, reliability, and quality of your applications.

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

@ -0,0 +1,112 @@
[
{
"name": "pnp-sp-dev-spfx-web-parts-react-appinsights-usage",
"source": "pnp",
"title": "React AppInsights Usage WebParts",
"shortDescription": "This web parts shows different use cases for capuring data in your application and store it into the Azure Application Insights service.",
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-appinsights-usage",
"longDescription": [
"This web parts shows different use cases for capuring data in your application. Azure Application Insights is more than only Logging and Tracing. It can be used to analyse data and display them in a graphical representation."
],
"creationDateTime": "2024-05-26",
"updateDateTime": "2024-05-26",
"products": [
"SharePoint"
],
"metadata": [
{
"key": "CLIENT-SIDE-DEV",
"value": "React"
},
{
"key": "SPFX-VERSION",
"value": "1.18.2"
},
{
"key": "SPFX-FULLPAGEAPP",
"value": "true"
},
{
"key": "PNPCONTROLS",
"value": ""
}
],
"thumbnails": [
{
"type": "image",
"order": 100,
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-appinsights-dashboard/assets/AppInsights_Dashboard.gif",
"alt": "React AppInsights Dashboard"
},
{
"type": "image",
"order": 101,
"url": "https://github.com/pnp/sp-dev-fx-webparts/blob/main/samples/react-appinsights-usage/assets/ABEvaluation.png?raw=true",
"alt": "AppInsights AB Test Chart"
},
{
"type": "image",
"order": 102,
"url": "https://github.com/pnp/sp-dev-fx-webparts/blob/main/samples/react-appinsights-usage/assets/ABTextUI.png?raw=true",
"alt": "AppInsights AB Test UI"
},
{
"type": "image",
"order": 103,
"url": "https://github.com/pnp/sp-dev-fx-webparts/blob/main/samples/react-appinsights-usage/assets/PNPJSLogger.png?raw=true",
"alt": "Logger in Terminal"
},
{
"type": "image",
"order": 104,
"url": "https://github.com/pnp/sp-dev-fx-webparts/blob/main/samples/react-appinsights-usage/assets/SampleRouterDurationEvaluation.png?raw=true",
"alt": "AppInsights Page visit average duration Chart"
},
{
"type": "image",
"order": 105,
"url": "https://github.com/pnp/sp-dev-fx-webparts/blob/main/samples/react-appinsights-usage/assets/SampleRouterEvaluation.png?raw=true",
"alt": "AppInsights Page visit count Chart"
},
{
"type": "image",
"order": 105,
"url": "https://github.com/pnp/sp-dev-fx-webparts/blob/main/samples/react-appinsights-usage/assets/SampleRouterUserFlow.png?raw=true",
"alt": "AppInsights User Flow"
}
],
"authors": [
{
"gitHubAccount": "petkir",
"company": "ACP CUBIDO Digital Solutions GmbH",
"pictureUrl": "https://github.com/petkir.png",
"name": "Peter Paul Kirschner",
"twitter": "petkir_at"
}
],
"references": [
{
"name": "Build your first SharePoint client-side web part",
"description": "Client-side web parts are client-side components that run in the context of a SharePoint page. Client-side web parts can be deployed to SharePoint environments that support the SharePoint Framework. You can also use modern JavaScript web frameworks, tools, and libraries to build them.",
"url": "https://learn.microsoft.com/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part"
},
{
"name": "Using single part app pages in SharePoint Online",
"description": "Single part app pages provide a capability to host SharePoint Framework web parts or Microsoft Teams applications in SharePoint Online with a locked layout. End users cannot modify or configure the page that is using the Single Part App Page layout.",
"url": "https://learn.microsoft.com/sharepoint/dev/spfx/web-parts/single-part-app-pages?tabs=pnpposh"
},
{
"name": "PNPJS Understanding the Logging Framework",
"description": "The logging framework is centered on the Logger class to which any number of listeners can be subscribed. Each of these listeners will receive each of the messages logged. Each listener must implement the ILogListener interface",
"url": "https://pnp.github.io/pnpjs/logging/"
},
{
"name": "Application Insights",
"description": "Application Insights provides many experiences to enhance the performance, reliability, and quality of your applications.",
"url": "https://learn.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview"
}
]
}
]

View File

@ -17,6 +17,7 @@
"@microsoft/sp-office-ui-fabric-core": "1.18.2", "@microsoft/sp-office-ui-fabric-core": "1.18.2",
"@microsoft/sp-property-pane": "1.18.2", "@microsoft/sp-property-pane": "1.18.2",
"@microsoft/sp-webpart-base": "1.18.2", "@microsoft/sp-webpart-base": "1.18.2",
"@pnp/logging": "^4.0.1",
"react": "17.0.1", "react": "17.0.1",
"react-dom": "17.0.1", "react-dom": "17.0.1",
"tslib": "2.3.1" "tslib": "2.3.1"
@ -4758,6 +4759,26 @@
"node": ">=8.0.0" "node": ">=8.0.0"
} }
}, },
"node_modules/@pnp/logging": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@pnp/logging/-/logging-4.0.1.tgz",
"integrity": "sha512-+HVb3EFvSuEis2Wn7kHVhReEyFsB8Vtb2PfRWGcHQiCXGuje9y2oJb8HLxpV5+IdS2qoqpktrZa6ADf8+EkOVQ==",
"dependencies": {
"tslib": "2.6.2"
},
"engines": {
"node": ">=18.12.0"
},
"funding": {
"type": "individual",
"url": "https://github.com/sponsors/patrick-rodgers/"
}
},
"node_modules/@pnp/logging/node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/@pnpm/crypto.base32-hash": { "node_modules/@pnpm/crypto.base32-hash": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/@pnpm/crypto.base32-hash/-/crypto.base32-hash-2.0.0.tgz", "resolved": "https://registry.npmjs.org/@pnpm/crypto.base32-hash/-/crypto.base32-hash-2.0.0.tgz",

View File

@ -21,6 +21,7 @@
"@microsoft/sp-office-ui-fabric-core": "1.18.2", "@microsoft/sp-office-ui-fabric-core": "1.18.2",
"@microsoft/sp-property-pane": "1.18.2", "@microsoft/sp-property-pane": "1.18.2",
"@microsoft/sp-webpart-base": "1.18.2", "@microsoft/sp-webpart-base": "1.18.2",
"@pnp/logging": "^4.0.1",
"react": "17.0.1", "react": "17.0.1",
"react-dom": "17.0.1", "react-dom": "17.0.1",
"tslib": "2.3.1" "tslib": "2.3.1"

View File

@ -11,6 +11,10 @@ import { IReadonlyTheme } from '@microsoft/sp-component-base';
import * as strings from 'PnPjsLoggerWebPartStrings'; import * as strings from 'PnPjsLoggerWebPartStrings';
import PnPjsLogger from './components/PnPjsLogger'; import PnPjsLogger from './components/PnPjsLogger';
import { IPnPjsLoggerProps } from './components/IPnPjsLoggerProps'; import { IPnPjsLoggerProps } from './components/IPnPjsLoggerProps';
import { ApplicationInsights, DistributedTracingModes, ITelemetryItem } from '@microsoft/applicationinsights-web';
import { ConsoleListener, LogLevel, Logger } from '@pnp/logging';
import { AppInsightListener } from './listener/appinsight-loglistener';
import { AIConnectionString } from '../../EnvProps';
export interface IPnPjsLoggerWebPartProps { export interface IPnPjsLoggerWebPartProps {
description: string; description: string;
@ -20,6 +24,7 @@ export default class PnPjsLoggerWebPart extends BaseClientSideWebPart<IPnPjsLogg
private _isDarkTheme: boolean = false; private _isDarkTheme: boolean = false;
private _environmentMessage: string = ''; private _environmentMessage: string = '';
private _appInsights: ApplicationInsights;
public render(): void { public render(): void {
const element: React.ReactElement<IPnPjsLoggerProps> = React.createElement( const element: React.ReactElement<IPnPjsLoggerProps> = React.createElement(
@ -37,11 +42,57 @@ export default class PnPjsLoggerWebPart extends BaseClientSideWebPart<IPnPjsLogg
} }
protected onInit(): Promise<void> { protected onInit(): Promise<void> {
return this._getEnvironmentMessage().then(message => { const allAsynCalls = []
allAsynCalls.push(this._getEnvironmentMessage().then(message => {
this._environmentMessage = message; this._environmentMessage = message;
})
)
const userId: string = this.context.pageContext.user.loginName.replace(/([\\|:;=])/g, '');
// App Insights JS Documentation: https://github.com/microsoft/applicationinsights-js
this._appInsights = new ApplicationInsights({
config: {
connectionString: AIConnectionString,
accountId: userId,
disableFetchTracking: false,
enableRequestHeaderTracking: true,
enableResponseHeaderTracking: true,
enableAjaxErrorStatusText: true,
enableAjaxPerfTracking: true,
enableUnhandledPromiseRejectionTracking: true,
enableCorsCorrelation: true,
disableExceptionTracking: false,
distributedTracingMode: DistributedTracingModes.AI
}
});
this._appInsights.loadAppInsights();
this._appInsights.addTelemetryInitializer(this._appInsightsInitializer);
this._appInsights.setAuthenticatedUserContext(userId, userId, true);
this._appInsights.trackPageView();
Logger.subscribe(new AppInsightListener(this._appInsights));
Logger.subscribe( ConsoleListener("pnpjs"));
Logger.activeLogLevel = LogLevel.Info;
return Promise.all(allAsynCalls).then(() => {
return super.onInit();
}); });
} }
private _appInsightsInitializer = (telemetryItem: ITelemetryItem): boolean | void => {
if (telemetryItem) {
if (!telemetryItem.tags) telemetryItem.tags = {};
telemetryItem.tags['ai.cloud.role'] = "app-insights-spfx-webparts";
telemetryItem.tags['ai.cloud.roleInstance'] = "PnPjsLoggerWebPart";
if (telemetryItem.baseType === 'RemoteDependencyData' && telemetryItem.baseData?.target) {
const isExcluded = telemetryItem.baseData.target.toLowerCase().indexOf('my_un_monitored_api ') !== -1;
if (isExcluded) return false; // don't track
}
}
}
private _getEnvironmentMessage(): Promise<string> { private _getEnvironmentMessage(): Promise<string> {

View File

@ -2,9 +2,17 @@ import * as React from 'react';
import styles from './PnPjsLogger.module.scss'; import styles from './PnPjsLogger.module.scss';
import type { IPnPjsLoggerProps } from './IPnPjsLoggerProps'; import type { IPnPjsLoggerProps } from './IPnPjsLoggerProps';
import { escape } from '@microsoft/sp-lodash-subset'; import { escape } from '@microsoft/sp-lodash-subset';
import { LogLevel, Logger } from '@pnp/logging';
import { ActionButton } from '@fluentui/react';
export default class PnPjsLogger extends React.Component<IPnPjsLoggerProps, {}> { export default class PnPjsLogger extends React.Component<IPnPjsLoggerProps, {}> {
constructor(props: IPnPjsLoggerProps) {
super(props);
Logger.writeJSON(this.props, LogLevel.Info);
}
public render(): React.ReactElement<IPnPjsLoggerProps> { public render(): React.ReactElement<IPnPjsLoggerProps> {
Logger.write("PnPjsLogger:Render", LogLevel.Info);
const { const {
description, description,
isDarkTheme, isDarkTheme,
@ -22,21 +30,23 @@ export default class PnPjsLogger extends React.Component<IPnPjsLoggerProps, {}>
<div>Web part property value: <strong>{escape(description)}</strong></div> <div>Web part property value: <strong>{escape(description)}</strong></div>
</div> </div>
<div> <div>
<h3>Welcome to SharePoint Framework!</h3> <h3>Logging Actions</h3>
<p>
The SharePoint Framework (SPFx) is a extensibility model for Microsoft Viva, Microsoft Teams and SharePoint. It&#39;s the easiest way to extend Microsoft 365 with automatic Single Sign On, automatic hosting and industry standard tooling.
</p>
<h4>Learn more about SPFx development:</h4>
<ul className={styles.links}> <ul className={styles.links}>
<li><a href="https://aka.ms/spfx" target="_blank" rel="noreferrer">SharePoint Framework Overview</a></li> <li>
<li><a href="https://aka.ms/spfx-yeoman-graph" target="_blank" rel="noreferrer">Use Microsoft Graph in your solution</a></li> <ActionButton onClick={() => Logger.write("PnPjsLogger:ActionButtonClick_Verbose", LogLevel.Verbose)}>Log Verbose</ActionButton>
<li><a href="https://aka.ms/spfx-yeoman-teams" target="_blank" rel="noreferrer">Build for Microsoft Teams using SharePoint Framework</a></li> </li>
<li><a href="https://aka.ms/spfx-yeoman-viva" target="_blank" rel="noreferrer">Build for Microsoft Viva Connections using SharePoint Framework</a></li> <li>
<li><a href="https://aka.ms/spfx-yeoman-store" target="_blank" rel="noreferrer">Publish SharePoint Framework applications to the marketplace</a></li> <ActionButton onClick={() => Logger.write("PnPjsLogger:ActionButtonClick_Info", LogLevel.Info)}>Log Info</ActionButton>
<li><a href="https://aka.ms/spfx-yeoman-api" target="_blank" rel="noreferrer">SharePoint Framework API reference</a></li> </li>
<li><a href="https://aka.ms/m365pnp" target="_blank" rel="noreferrer">Microsoft 365 Developer Community</a></li> <li>
<ActionButton onClick={() => Logger.write("PnPjsLogger:ActionButtonClick_Warning", LogLevel.Warning)}>Log Warning</ActionButton>
</li>
<li>
<ActionButton onClick={() => Logger.write("PnPjsLogger:ActionButtonClick_Error", LogLevel.Error)}>Log Error</ActionButton>
</li>
</ul> </ul>
</div> </div>
</section> </section>
); );
} }

View File

@ -0,0 +1,22 @@
import { ApplicationInsights, SeverityLevel } from "@microsoft/applicationinsights-web";
import { ILogEntry, ILogListener, LogLevel } from "@pnp/logging";
export class AppInsightListener implements ILogListener {
private appInsights: ApplicationInsights;
constructor(appInsights: ApplicationInsights) {
this.appInsights = appInsights;
}
log(entry: ILogEntry): void {
if (entry.level === LogLevel.Error)
this.appInsights.trackException({ error: new Error(entry.message), severityLevel: SeverityLevel.Error });
else if (entry.level === LogLevel.Warning)
this.appInsights.trackException({ error: new Error(entry.message), severityLevel: SeverityLevel.Warning });
else if (entry.level === LogLevel.Info)
this.appInsights.trackException({ error: new Error(entry.message), severityLevel: SeverityLevel.Information });
else
this.appInsights.trackException({ error: new Error(entry.message), severityLevel: SeverityLevel.Verbose });
}
}