Skip to content

Commit

Permalink
refactor: move datadog rum methods to service (DEV-190) (#572)
Browse files Browse the repository at this point in the history
* refactor: moves datadog rum methods to a service

* cleanup: remove console warning

* refactor(datadog-rum): moves service init to app-init service and checks if datadog has been initialized before adding or removing a user session

* refactor: further refactoring of datadog rum init
  • Loading branch information
mdelez committed Nov 5, 2021
1 parent ff9d097 commit 77191cb
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 49 deletions.
29 changes: 27 additions & 2 deletions src/app/app-init.service.spec.ts
@@ -1,7 +1,8 @@
import { TestBed } from '@angular/core/testing';
import { AppInitService } from './app-init.service';
import { IConfig } from './main/declarations/app-config';
import { APP_CONFIG } from './main/declarations/dsp-api-tokens';
import { APP_CONFIG, DspInstrumentationToken } from './main/declarations/dsp-api-tokens';
import { DspDataDogConfig, DspInstrumentationConfig } from './main/declarations/dsp-instrumentation-config';

describe('TestService', () => {
let service: AppInitService;
Expand Down Expand Up @@ -34,10 +35,34 @@ describe('TestService', () => {
}
};

const dspDatadogSpy = new DspDataDogConfig(false, '', '', '', '');

const instrumentationConfig: DspInstrumentationConfig = {
environment: 'dev',
dataDog: {
enabled: false,
applicationId: 'app_id',
clientToken: 'client_token',
site: 'site',
service: 'dsp-app'
},
rollbar: {
enabled: false,
accessToken: 'rollbar_token'
}
};

beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{ provide: APP_CONFIG, useValue: config }
{
provide: APP_CONFIG,
useValue: config
},
{
provide: DspInstrumentationToken,
useValue: instrumentationConfig
},
]
});
service = TestBed.inject(AppInitService);
Expand Down
2 changes: 1 addition & 1 deletion src/app/app-init.service.ts
Expand Up @@ -36,7 +36,7 @@ export class AppInitService {
}

constructor(
@Inject(APP_CONFIG) private _config: IConfig
@Inject(APP_CONFIG) private _config: IConfig,
) {
// check for presence of apiProtocol and apiHost
if (typeof this._config.apiProtocol !== 'string' || typeof this._config.apiHost !== 'string') {
Expand Down
4 changes: 3 additions & 1 deletion src/app/app.component.spec.ts
Expand Up @@ -12,14 +12,16 @@ import { TranslateModule } from '@ngx-translate/core';
import { TestConfig } from 'test.config';
import { AppInitService } from './app-init.service';
import { AppComponent } from './app.component';
import { DspApiConfigToken, DspApiConnectionToken } from './main/declarations/dsp-api-tokens';
import { DspApiConfigToken, DspApiConnectionToken, DspInstrumentationToken } from './main/declarations/dsp-api-tokens';
import { DspDataDogConfig, DspInstrumentationConfig } from './main/declarations/dsp-instrumentation-config';
import { HeaderComponent } from './main/header/header.component';
import { SelectLanguageComponent } from './main/select-language/select-language.component';
import { UserMenuComponent } from './user/user-menu/user-menu.component';

describe('AppComponent', () => {

beforeEach(waitForAsync(() => {

TestBed.configureTestingModule({
declarations: [
AppComponent,
Expand Down
1 change: 0 additions & 1 deletion src/app/app.component.ts
Expand Up @@ -19,7 +19,6 @@ export class AppComponent implements OnInit {

// set the page title
this._titleService.setTitle('DaSCH Service Platform');

}

ngOnInit() {
Expand Down
2 changes: 2 additions & 0 deletions src/app/app.module.ts
Expand Up @@ -48,6 +48,7 @@ import { LinkifyPipe } from './main/pipes/string-transformation/linkify.pipe';
import { StringifyStringLiteralPipe } from './main/pipes/string-transformation/stringify-string-literal.pipe';
import { TruncatePipe } from './main/pipes/string-transformation/truncate.pipe';
import { SelectLanguageComponent } from './main/select-language/select-language.component';
import { DatadogRumService } from './main/services/datadog-rum.service';
import { MaterialModule } from './material-module';
import { AddressTemplateComponent } from './project/board/address-template/address-template.component';
import { AttributionTabViewComponent } from './project/board/attribution-tab-view/attribution-tab-view.component';
Expand Down Expand Up @@ -345,6 +346,7 @@ export function httpLoaderFactory(httpClient: HttpClient) {
],
providers: [
AppInitService,
DatadogRumService,
{
provide: DspApiConfigToken,
useFactory: (appInitService: AppInitService) => appInitService.dspApiConfig,
Expand Down
26 changes: 6 additions & 20 deletions src/app/main/action/login-form/login-form.component.spec.ts
Expand Up @@ -17,6 +17,7 @@ import { AppInitService } from 'src/app/app-init.service';
import { TestConfig } from 'test.config';
import { DspApiConfigToken, DspApiConnectionToken, DspInstrumentationToken } from '../../declarations/dsp-api-tokens';
import { DspDataDogConfig, DspInstrumentationConfig } from '../../declarations/dsp-instrumentation-config';
import { DatadogRumService } from '../../services/datadog-rum.service';
import { Session, SessionService } from '../../services/session.service';
import { LoginFormComponent } from './login-form.component';

Expand Down Expand Up @@ -57,23 +58,6 @@ describe('LoginFormComponent', () => {

beforeEach(waitForAsync(() => {

const dspDatadogSpy = new DspDataDogConfig(false, '', '', '', '');

const instrumentationConfig: DspInstrumentationConfig = {
environment: 'dev',
dataDog: {
enabled: false,
applicationId: 'app_id',
clientToken: 'client_token',
site: 'site',
service: 'dsp-app'
},
rollbar: {
enabled: false,
accessToken: 'rollbar_token'
}
};

const authEndpointSpyObj = {
admin: {
usersEndpoint: jasmine.createSpyObj('usersEndpoint', ['getUser'])
Expand All @@ -83,6 +67,8 @@ describe('LoginFormComponent', () => {
}
};

const datadogRumServiceSpy = jasmine.createSpyObj('datadogRumService', ['initializeRum', 'setActiveUser', 'removeActiveUser']);

TestBed.configureTestingModule({
declarations: [
LoginFormComponent,
Expand All @@ -106,9 +92,9 @@ describe('LoginFormComponent', () => {
useValue: authEndpointSpyObj
},
{
provide: DspInstrumentationToken,
useValue: instrumentationConfig
},
provide: DatadogRumService,
useValue: datadogRumServiceSpy
}
]
})
.compileComponents();
Expand Down
28 changes: 4 additions & 24 deletions src/app/main/action/login-form/login-form.component.ts
Expand Up @@ -4,6 +4,7 @@ import { ApiResponseData, ApiResponseError, KnoraApiConnection, LoginResponse, L
import { datadogRum, RumFetchResourceEventDomainContext } from '@datadog/browser-rum';
import { DspApiConnectionToken, DspInstrumentationToken } from '../../declarations/dsp-api-tokens';
import { DspInstrumentationConfig } from '../../declarations/dsp-instrumentation-config';
import { DatadogRumService } from '../../services/datadog-rum.service';
import { NotificationService } from '../../services/notification.service';
import { Session, SessionService } from '../../services/session.service';

Expand Down Expand Up @@ -105,7 +106,7 @@ export class LoginFormComponent implements OnInit {

constructor(
@Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection,
@Inject(DspInstrumentationToken) private _dspInstrumentationConfig: DspInstrumentationConfig,
private _datadogRumService: DatadogRumService,
private _notification: NotificationService,
private _sessionService: SessionService,
private _fb: FormBuilder
Expand Down Expand Up @@ -156,29 +157,7 @@ export class LoginFormComponent implements OnInit {
this.session = this._sessionService.getSession();
this.loginSuccess.emit(true);
this.loading = false;
if (this._dspInstrumentationConfig.dataDog.enabled) {
datadogRum.init({
applicationId: this._dspInstrumentationConfig.dataDog.applicationId,
clientToken: this._dspInstrumentationConfig.dataDog.clientToken,
site: this._dspInstrumentationConfig.dataDog.site,
service: this._dspInstrumentationConfig.dataDog.service,
env: this._dspInstrumentationConfig.environment,
version: appVersion,
sampleRate: 100,
trackInteractions: true,
beforeSend: (event, context) => {
// collect a RUM resource's response headers
if (event.type === 'resource' && event.resource.type === 'xhr') {
event.context = { ...event.context, responseHeaders: (context as RumFetchResourceEventDomainContext).response.body };
}
},
});

datadogRum.setUser({
id: identifier,
identifierType: identifierType
});
}
this._datadogRumService.setActiveUser(identifier, identifierType);
}
);
},
Expand Down Expand Up @@ -215,6 +194,7 @@ export class LoginFormComponent implements OnInit {
(response: ApiResponseData<LogoutResponse>) => {
this.logoutSuccess.emit(true);
this._sessionService.destroySession();
this._datadogRumService.removeActiveUser();
this.loading = false;
this.buildLoginForm();
this.session = undefined;
Expand Down
39 changes: 39 additions & 0 deletions src/app/main/services/datadog-rum.service.spec.ts
@@ -0,0 +1,39 @@
import { TestBed } from '@angular/core/testing';

import { DatadogRumService } from './datadog-rum.service';

describe('DatadogRumService', () => {
let service: DatadogRumService;
const mockdatadogRumService = jasmine.createSpyObj('datadogRumService', ['initializeRum', 'setActiveUser', 'removeActiveUser']);

beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{ provide: DatadogRumService, useValue: mockdatadogRumService }
]
});
service = TestBed.inject(DatadogRumService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});

describe('setActiveUser', () => {
it('should set the active user', () => {
const identifier = 'test';
const identifierType = 'email';
mockdatadogRumService.setActiveUser.and.callThrough();
service.setActiveUser(identifier, identifierType);
expect(service.setActiveUser).toHaveBeenCalledOnceWith(identifier, identifierType);
});
});

describe('removeActiveUser', () => {
it('should remove the active user', () => {
mockdatadogRumService.removeActiveUser.and.callThrough();
service.removeActiveUser();
expect(service.removeActiveUser).toHaveBeenCalled();
});
});
});
50 changes: 50 additions & 0 deletions src/app/main/services/datadog-rum.service.ts
@@ -0,0 +1,50 @@
import { Inject, Injectable } from '@angular/core';
import { datadogRum, RumFetchResourceEventDomainContext } from '@datadog/browser-rum';
import { DspInstrumentationToken } from '../declarations/dsp-api-tokens';
import { DspInstrumentationConfig } from '../declarations/dsp-instrumentation-config';

const { version: appVersion } = require('../../../../package.json');

@Injectable({
providedIn: 'root'
})
export class DatadogRumService {

constructor(
@Inject(DspInstrumentationToken) private _dspInstrumentationConfig: DspInstrumentationConfig
) {
if (this._dspInstrumentationConfig.dataDog.enabled) {
datadogRum.init({
applicationId: this._dspInstrumentationConfig.dataDog.applicationId,
clientToken: this._dspInstrumentationConfig.dataDog.clientToken,
site: this._dspInstrumentationConfig.dataDog.site,
service: this._dspInstrumentationConfig.dataDog.service,
env: this._dspInstrumentationConfig.environment,
version: appVersion,
sampleRate: 100,
trackInteractions: true,
beforeSend: (event, context) => {
// collect a RUM resource's response headers
if (event.type === 'resource' && event.resource.type === 'xhr') {
event.context = { ...event.context, responseHeaders: (context as RumFetchResourceEventDomainContext).response.body };
}
},
});
}
}

setActiveUser(identifier: any, identifierType: 'iri' | 'email' | 'username'): void {
if(datadogRum.getInternalContext().application_id) {
datadogRum.setUser({
id: identifier,
identifierType: identifierType
});
}
}

removeActiveUser(): void {
if(datadogRum.getInternalContext().application_id) {
datadogRum.removeUser();
}
}
}

0 comments on commit 77191cb

Please sign in to comment.