Usando o OpenReplay com Angular
É importante ter em mente que o tracker deve ser executado fora dos hooks do Zone.js do Angular, para evitar sobreposição e verificações desnecessárias.
Veja um exemplo simples de configuração do tracker:
import { Injectable, NgZone } from '@angular/core';
import Tracker from '@openreplay/tracker';
import trackerAssist from '@openreplay/tracker-assist';
@Injectable({
providedIn: 'root',
})
export class OpenReplayService {
public tracker?: Tracker | null;
constructor(private zone: NgZone) {
this.zone.runOutsideAngular(() => {
this.tracker = new Tracker({
projectKey: 'abc123',
ingestPoint: 'https://someurl/',
});
this.tracker.use(
trackerAssist({
confirmText: `You have an incoming call from <Company> Support. Do you want to answer?`,
})
);
});
}
public async start() {
this.zone.runOutsideAngular(() => {
if (this.tracker) {
return this.tracker.start();
} else {
return {
sessionID: null,
sessionToken: null,
userUUID: null,
};
}
});
}
public setUserData(user: { id: string }): void {
this.zone.runOutsideAngular(() => {
if (this.tracker && user.id) {
this.tracker.setUserID(String(user.id));
}
});
}
}
Rastreando as requisições HTTP
Section titled Rastreando as requisições HTTPSe você quiser rastrear as requisições enviadas pelo seu aplicativo Angular, o OpenReplay não oferece um plugin como faz para Fetch ou Axios.
Dito isso, você ainda pode configurá-lo para rastrear as suas requisições com as informações que desejar usando um HTTPInterceptor.
Neste tutorial, vou mostrar como criar um HTTPInterceptor capaz de gravar tanto as requisições quanto as respostas enviadas pelo seu HTTPClient.
Criando o interceptor
Section titled Criando o interceptorO interceptor é um tipo especial de objeto que você pode injetar no código do seu aplicativo para capturar cada requisição enviada com o cliente HTTP padrão do Angular, além de capturar a resposta.
Com essa lógica, vamos aproveitar os eventos personalizados do OpenReplay, que permitem enviar qualquer evento que você quiser para ser capturado dentro da sua sessão, de modo que reproduziremos o que o plugin de Fetch ou Axios faria em outras configurações.
O código do interceptor é o seguinte:
import { Injectable } from '@angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpEvent,
HttpResponse,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { ReplaySessionService } from '../replay-session.service';
@Injectable({providedIn: 'root'})
export class HttpConfigInterceptor implements HttpInterceptor {
constructor(
private replaySessionService: ReplaySessionService,
) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
//This function will be called with the response a few lines below
const handleResponse = (request: HttpRequest<any>, response: HttpResponse<any>, event: string) => {
//we forward our data to the service, which will create the custom event and send it
this.replaySessionService.sendEventToReplaySession(event, { request, response })
}
return next.handle(request).pipe(
//filter out events that aren't http reponses
filter( (event: any) => event instanceof HttpResponse),
map( (resp: HttpResponse<any>) => { //for each response, call handleResponse
handleResponse(request, resp, `${request.url}`)
return resp
}),
map((event: HttpEvent<any>) => {
return event;
})
);
}
}
Veremos o serviço de replay em instantes, mas por enquanto assuma que ele já existe. Salve este arquivo dentro da sua pasta app.
Em seguida, edite o arquivo app.module para adicionar o seguinte dentro da diretiva @ngModule:
providers: [
{provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true}
]
Assim, o arquivo app.module deve ficar parecido com isto:
import { NgModule } from '@angular/core';
/*
imports...
*/
import { HttpConfigInterceptor } from './interceptor/index';
@NgModule({
imports: [
/*...*/
],
providers: [
{provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true}
],
declarations: [
/*...*/
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Com isso resolvido, o seu aplicativo agora sabe que deve injetar o seu interceptor em cada requisição HTTP realizada.
Agora vamos dar uma olhada no serviço de session replay propriamente dito.
Criando o SessionReplayService
Section titled Criando o SessionReplayServicePrimeiro, adicione o seu novo serviço com o seguinte comando:
$ ng generate service replay-session
Isso criará um novo serviço Angular na raiz do seu aplicativo chamado replay-session.service.ts
O conteúdo desse arquivo deve ser parecido com isto:
import { Injectable } from '@angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpResponse,
} from '@angular/common/http';
import OpenReplay from '@openreplay/tracker'
type ReqRespType = {
request: HttpRequest<any>,
response: HttpResponse<any>
}
@Injectable({
providedIn: 'root'
})
export class ReplaySessionService {
tracker: OpenReplay|null = null
constructor() {
this.tracker = new OpenReplay({
projectKey: "<YOUR PROJECT KEY>",
})
//you can set up any other OR plugins here as well
this.tracker.start()
}
sendEventToReplaySession(event: string, params: ReqRespType): void {
const {request, response} = params
this.tracker?.event(event + "[request]", {
method: request.method,
url: request.url,
params: request.params
})
this.tracker?.event(event + "[response]", {
body: response.body,
status: response.status,
headers: response.headers
})
}
}
O construtor da classe, que, por se tratar de um serviço, sabemos que será chamado apenas uma vez, cuida de instanciar o tracker e iniciá-lo.
Em seguida, no nosso método sendEventToReplaySession, usamos o método event para enviar dois eventos personalizados.
Se você voltar à classe do interceptor, notará que o “evento” (o primeiro parâmetro que recebemos neste método) é, na verdade, a URL, então estou anexando as palavras “[response]” e “[request]” a ela para identificar o que é gravado em cada lugar. Depois, crio os payloads de cada evento, salvando apenas as informações que quero guardar.
Na verdade, você pode até pegar esse código e sanitizar qualquer campo da requisição ou da resposta que você não queira que fique visível dentro do replay antes de chamar o método event.
Você pode conferir este repositório para ver o código-fonte completo de um aplicativo baseado em Angular funcionando com o Tracker.
Tem dúvidas?
Section titled Tem dúvidas?Se você tiver algum problema ao configurar o Tracker no seu projeto Angular, entre em contato conosco na nossa comunidade no Slack e fale diretamente com os nossos devs!