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
Short summary on functionality and used technologies.
[picture of the solution in action, if possible]
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.
## Used SharePoint Framework Version
@ -22,11 +35,10 @@ Short summary on functionality and used technologies.
Application Insight Service on Azure
Add the connection stirng of this Service to the the variable ```AIConnectionString``` at ```src/EnvProps.ts```
## Solution
| Solution | Author(s) |
| ----------- | ------------------------------------------------------- |
| folder name | Author details (name, company, twitter alias with link) |
## Contributors
* [Peter Paul Kirschner](https://github.com/petkir)
## Version history
@ -44,6 +56,8 @@ Add the connection stirng of this Service to the the variable ```AIConnectionStr
- Clone this repository
- 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:
- **npm install**
- **gulp serve**
@ -63,8 +77,7 @@ This extension illustrates the following concepts:
- Logging
- PnP JS Logger
- Logging with PnPJS
- Custom Logger
- Logging with PnPJS
# Sample Router WebPart
@ -115,6 +128,10 @@ customEvents
```
![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.
> 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)
- [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
- [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-property-pane": "1.18.2",
"@microsoft/sp-webpart-base": "1.18.2",
"@pnp/logging": "^4.0.1",
"react": "17.0.1",
"react-dom": "17.0.1",
"tslib": "2.3.1"
@ -4758,6 +4759,26 @@
"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": {
"version": "2.0.0",
"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-property-pane": "1.18.2",
"@microsoft/sp-webpart-base": "1.18.2",
"@pnp/logging": "^4.0.1",
"react": "17.0.1",
"react-dom": "17.0.1",
"tslib": "2.3.1"

View File

@ -11,6 +11,10 @@ import { IReadonlyTheme } from '@microsoft/sp-component-base';
import * as strings from 'PnPjsLoggerWebPartStrings';
import PnPjsLogger from './components/PnPjsLogger';
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 {
description: string;
@ -20,6 +24,7 @@ export default class PnPjsLoggerWebPart extends BaseClientSideWebPart<IPnPjsLogg
private _isDarkTheme: boolean = false;
private _environmentMessage: string = '';
private _appInsights: ApplicationInsights;
public render(): void {
const element: React.ReactElement<IPnPjsLoggerProps> = React.createElement(
@ -37,11 +42,57 @@ export default class PnPjsLoggerWebPart extends BaseClientSideWebPart<IPnPjsLogg
}
protected onInit(): Promise<void> {
return this._getEnvironmentMessage().then(message => {
const allAsynCalls = []
allAsynCalls.push(this._getEnvironmentMessage().then(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> {

View File

@ -2,9 +2,17 @@ import * as React from 'react';
import styles from './PnPjsLogger.module.scss';
import type { IPnPjsLoggerProps } from './IPnPjsLoggerProps';
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, {}> {
constructor(props: IPnPjsLoggerProps) {
super(props);
Logger.writeJSON(this.props, LogLevel.Info);
}
public render(): React.ReactElement<IPnPjsLoggerProps> {
Logger.write("PnPjsLogger:Render", LogLevel.Info);
const {
description,
isDarkTheme,
@ -22,21 +30,23 @@ export default class PnPjsLogger extends React.Component<IPnPjsLoggerProps, {}>
<div>Web part property value: <strong>{escape(description)}</strong></div>
</div>
<div>
<h3>Welcome to SharePoint Framework!</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>
<h3>Logging Actions</h3>
<ul className={styles.links}>
<li><a href="https://aka.ms/spfx" target="_blank" rel="noreferrer">SharePoint Framework Overview</a></li>
<li><a href="https://aka.ms/spfx-yeoman-graph" target="_blank" rel="noreferrer">Use Microsoft Graph in your solution</a></li>
<li><a href="https://aka.ms/spfx-yeoman-teams" target="_blank" rel="noreferrer">Build for Microsoft Teams using SharePoint Framework</a></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><a href="https://aka.ms/spfx-yeoman-store" target="_blank" rel="noreferrer">Publish SharePoint Framework applications to the marketplace</a></li>
<li><a href="https://aka.ms/spfx-yeoman-api" target="_blank" rel="noreferrer">SharePoint Framework API reference</a></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_Verbose", LogLevel.Verbose)}>Log Verbose</ActionButton>
</li>
<li>
<ActionButton onClick={() => Logger.write("PnPjsLogger:ActionButtonClick_Info", LogLevel.Info)}>Log Info</ActionButton>
</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>
</div>
</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 });
}
}