Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 9: How show with a HttpInterceptor the stacktrace of a request?

I have a HttpInterceptor and I want for developing purpose print the stack trace of the functions that have made the request:

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class HttpInterceptorService implements HttpInterceptor {

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log('Who has made this request?', new Error().stack);
    return next.handle(request);
  }
}

The output of the console log is:

at HttpInterceptorService.intercept (:4200/main.js:1344) [angular]
    at HttpInterceptorHandler.handle (:4200/vendor.js:30718) [angular]
    at HttpXsrfInterceptor.intercept (:4200/vendor.js:31484) [angular]
    at HttpInterceptorHandler.handle (:4200/vendor.js:30718) [angular]
    at HttpInterceptingHandler.handle (:4200/vendor.js:31549) [angular]
    at MergeMapSubscriber.project (:4200/vendor.js:30457) [angular]
    at MergeMapSubscriber._tryNext (:4200/vendor.js:112207) [angular]
    at MergeMapSubscriber._next (:4200/vendor.js:112197) [angular]
    at MergeMapSubscriber.next (:4200/vendor.js:107493) [angular]
    at Observable._subscribe (:4200/vendor.js:116912) [angular]
    at Observable._trySubscribe (:4200/vendor.js:106949) [angular]
    at Observable.subscribe (:4200/vendor.js:106935) [angular]
    at MergeMapOperator.call (:4200/vendor.js:112182) [angular]
    at Observable.subscribe (:4200/vendor.js:106930) [angular]

The output don't show any useful information about what component or service has made the request.

There are some tips for show a useful information for find the stack trace of services and components?

like image 703
Simone Nigro Avatar asked Apr 23 '20 07:04

Simone Nigro


People also ask

What is Httpinterceptor in angular?

HTTP Interceptors is a special type of angular service that we can implement. It's used to apply custom logic to the central point between the client-side and server-side outgoing/incoming HTTP request and response. Keep in mind that the interceptor wants only HTTP requests.

Can angular have multiple HTTP interceptors?

After providing HTTP_INTERCEPTORS we need to inform the class we are going to implement our interceptor into by using useClass. Setting multi to true, makes sure that you can have multiple interceptors in your project.

How do you use interceptors?

Angular applies interceptors in the order that you provide them. If you provide interceptors A, then B, then C, requests will flow in A->B->C, and responses will flow out C->B->A. In the example app, we have all the interceptors provided, but we only use one at a time. This is done by checking the path.


2 Answers

The trace inside the interceptor is already messed up. You can also think about using a custom HttpClient. This is untested code though. So if you remove your interceptor provider and replace it with:

{ provide: HttpClient, useClass: TraceHttpClient }

And your TraceHttpClient would look like this:

@Injectable()
export class TraceHttpClient extends HttpClient {
  constructor(handler: HttpHandler) {
     super(handler);
  }

  request(...args: [ any ]): Observable<any> {
    console.trace('Who has made this request?');

    return super.request(...args);
  }
}

You can see a working version here. You can see the stack trace having the different button method calls. You should open the browser console though, because the stackblitz console does not show the console.trace logs.

The HttpClient calls request for every GET/POST/etc.... So it's enough to just extend that method, and put a trace there, and delegate back to the base HttpClient class

like image 63
Poul Kruijt Avatar answered Oct 21 '22 11:10

Poul Kruijt


Here is an alternative to the accepted answer. I don't want the noise of emitting a stack for every http call.

Once in the HttpClient error handler, the stack trace is lost so, console.trace is ineffective. Errors are expensive so I don't want this in production.

/**
 * Extended HttpClient that generates a stack trace on error when not in a production build.
 */
@Injectable()
export class TraceHttpClient extends HttpClient {
  constructor(handler: HttpHandler) {
    super(handler);
  }

  request(...args: [ any ]): Observable<any> {

    const stack = environment.production ? null : (Error()).stack;
    return super.request(...args).pipe(catchError((err) => {
      // tslint:disable-next-line:no-console
      if(stack) console.error('Cloud UI - HTTP Client error stack\n', stack);
      return throwError(err);
    }));
  }
}
like image 1
jenson-button-event Avatar answered Oct 21 '22 10:10

jenson-button-event