How to log the time of http requests made in the Spartacus Angular SSR app, even after the SSR timeout (which sent the CSR fallback to a client)?
Context:
In the the monitoring tool like dynatrace
you can see a waterfall chart showing the duration of the rendered request, including also the http calls made by the rendered app to external services (e.g. OCC). However, when the Spartacus SSR returns a CSR fallback (due to a SSR request timeout), dynatrace
stops showing the http calls that the rendered app is making. It's important to emphasize, that even after sending a CSR fallback by the ExpressJS server, the Angular SSR app keeps being rendered in the background and can still make http calls. When those http calls take too long, it would be good to debug which of those http calls took so long. How to debug duration of those http calls? Ideally, knowing whether the CSR fallback was already sent to a client...
For debugging purposes, you can provide an Angular HttpInteceptor
that logs time of every http request made by the Angular app. Btw. it can also indicate if the response was already sent to the client by the ExpressJS engine (e.g. due to a SSR request timeout).
See the example implementation:
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { Inject, InjectionToken, Optional } from '@angular/core';
import { RESPONSE } from '@nguniversal/express-engine/tokens';
import { Response } from 'express';
export class LoggingInterceptor implements HttpInterceptor {
constructor(@Optional() @Inject(RESPONSE) private response: Response) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const started = Date.now();
return next.handle(request).pipe(
tap(
_event => {
console.log(
`Request for ${request.urlWithParams} took ${Date.now() - started} ms. ` +
`Was ExpressJS Response already sent?: ${this.response?.headersSent}`
);
},
_error => {
console.log(
`Request for ${request.urlWithParams} failed after ${Date.now() - started} ms. ` +
`Was ExpressJS Response already sent?: ${this.response?.headersSent}`
);
}
)
);
}
}
Explanation:
RESPONSE
InjectionToken from @nguniversal/express-engine/tokens
RESPONSE
object has a type of Response
from ExpressJS. Please mind to write: import {Response} from 'express'
. Otherwise the global type Response
of Node.js will be implicitly used, which would be incorrectRESPONSE
with @Optional()
decorator as it is not available in the browser, but only in SSRthis.response.headersSent
, which indicates whether the ExpressJS already sent a response to a client. For more, see docs of ExpressJS Response.headersSentNote: If you want to also console.log the URL of the currently rendered page in SSR, you can inject WindowRef
from @spartacus/core
and log it’s property windowRef.location.href
.