Diagnostics
SSR Diagnostics
By enabling SSR tracing on the Next.js server you can observe the rendering of the widgets and the sequence of requests, their count and duration and verify any performance hits that could occur when rendering your pages.
We provide @progress/sitefinity-nextjs-sdk/diagnostics/dev module with sample implementation for tracing widget performance utilizing the Next.js experimental implementation and OpenTelemetry.
By default the module that is required in the nextjs-sdk is the @progress/sitefinity-nextjs-sdk/diagnostics/empty which is an API mock with no dependencies that does not carry and side effects when deployed in production.
IMPORTANT: The Next.js instrumentation implementation is at an experimental stage at the moment and both their and our API can be subject to changes.
IMPORTANT: The OpenTelemetry implementation is currently only supported for SSR components and server code. For performance analytics on the Front end, please refer to the Next.JS usage of
useReportWebVitals.
Enabling tracing in your development application
-
Install the needed OpenTelemetry npm packages to your local development setup:
-
Enable tracing for Next.js in the next.config.js and change the module resolution in the webpack config:
JavaScriptmodule.exports = { // ... webpack: (config, options) => { config.resolve['alias']['@progress/sitefinity-nextjs-sdk/diagnostics/empty'] = '@progress/sitefinity-nextjs-sdk/diagnostics/dev'; config.resolve['alias']['@widgetregistry'] = path.resolve(__dirname, 'src/app/widget-registry'); // <- this should be present by default in your project return config; }, serverExternalPackages:[ "@opentelemetry/sdk-node", ] // ... } -
Include the
instrumentation.tsfile for telemetry initialization in your project. Use theregisterfunction to dynamically import a module only when the Next.js application is running in the Node.js runtime environment:TypeScriptexport async function register() { if (process.env.NEXT_RUNTIME === 'nodejs') { await import('./instrumentation.node.ts') } } -
Include the
instrumentation.node.tsfile in your project:TypeScriptimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http' import { Resource } from '@opentelemetry/resources' import { NodeSDK } from '@opentelemetry/sdk-node' import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node' import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions' const sdk = new NodeSDK({ resource: resourceFromAttributes({ [ATTR_SERVICE_NAME]: 'next-app', }), spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()), }) sdk.start()
For more information, see Next.js' documentaion on Manual OpenTelemetry configuration.
Consuming and reading the trace data
We suggest using the dev Docker setup provided by Next.js in the following repository: OpenTelemetry Collector Demo.
Filtering the precise page requests can be achieved in Jaeger and Zipkin by the http.route, http.target, next.route tags assigned to the traces by Next.js.
NOTE: The Jaeger, Zipkin, and Prometheus dashboards open under http, make sure your browser allows for that.
SSR Widget tracing
Import the @progress/sitefinity-nextjs-sdk/diagnostics/empty package to make sure that your widget works and is not reporting data if you disable the tracing and remove the module alias in the webpack config.
import { RestClient } from '@progress/sitefinity-nextjs-sdk/rest-sdk';
import { Tracer } from '@progress/sitefinity-nextjs-sdk/diagnostics/empty';
export async function CustomWidget(props: WidgetContext<CustomWidgetEntity>) {
const {span, ctx} = Tracer.traceWidget(props, true);
// ...
const serverData = RestClient.getItems({
type: //...,
traceContext: ctx // <- passing this context to the RestClient request would associate the request to the current widget via the open telemetry context created by the Tracer.traceWidget, otherwise the request's span will be logged as a child of the page render root span
});
// ...
return (
<>
{/* view implementation */}
{Tracer.endSpan(span) /* <- make sure you close the span; this method returns null regardless of whether the diagnostics is enabled or not and would not affect the output of the widget */}
</>
);
}
Other tracing
Tracing server-to-server http requests
`await RestClient.sendRequest({url, traceContext});
await RestClient.getItems({/... getAllArgs/, traceContext})`
Obtaining trace context
You can obtain an optional trace context in several ways. Not providing such context logs the request in the root of the Next.js route render span.
- First method:
TypeScript
import { context } from '@opentelemetry/api'; const ctx = context.active(); - Second method:
TypeScript
import { Tracer } from '@progress/sitefinity-nextjs-sdk/diagnostics/empty'; const {span, ctx} = Tracer.startSpan(key, startNewSubContextToUseLater?, currentContext?); // the ctx will be either a new context for the created span or the context.active() depending on the second parameter // ... Tracer.endSpan(span); - Third method:
TypeScript
import { Tracer } from '@progress/sitefinity-nextjs-sdk/diagnostics/empty'; Tracer.startTrace(key, (span) => { // code to trace with its own current context Tracer.endSpan(span); })
Furthermore, you can use any functionality that the NodeSDK for Open Telemetry provides.