Krzysztof Platis
Krzysztof Platis

Reputation: 1221

How to log the time of http requests in Spartacus SSR, even after the SSR timeout

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...

Upvotes: 2

Views: 390

Answers (1)

Krzysztof Platis
Krzysztof Platis

Reputation: 1221

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:

  • we inject RESPONSE InjectionToken from @nguniversal/express-engine/tokens
  • the 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 incorrect
  • We inject RESPONSE with @Optional() decorator as it is not available in the browser, but only in SSR
  • we lookup the property this.response.headersSent, which indicates whether the ExpressJS already sent a response to a client. For more, see docs of ExpressJS Response.headersSent

Note: 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.

Upvotes: 2

Related Questions