projects/common/lib/services/logger.service.ts
Properties |
|
Methods |
|
Accessors |
constructor(http: HttpClient)
|
||||||
Parameters :
|
Protected _log | ||||||||
_log(message: CommonLogMessage)
|
||||||||
Log a message to Splunk. This is the main way to send logs and automatically includes meta-data. You do not need to subscribe to the response, as the service already does that. The input object must have an 'event' property set, everything else is optional. Example:
Parameters :
Returns :
any
|
Protected _logError | ||||||
_logError(errorMessage: CommonLogMessage)
|
||||||
Parameters :
Returns :
any
|
Private _sendLog | ||||||||
_sendLog(message: CommonLogMessage)
|
||||||||
Internal method to send logs to Splunk, includes meta-data except that's consistent across all requests, but not specific values like severity level.
Parameters :
Returns :
any
|
Protected handleError | ||||||
handleError(error: HttpErrorResponse)
|
||||||
Parameters :
Returns :
any
|
Public log | ||||||
log(message: any)
|
||||||
Parameters :
Returns :
void
|
Public logError | ||||||
logError(errorMessage: any)
|
||||||
Parameters :
Returns :
void
|
Public logHttpError | ||||||
logHttpError(error: HttpErrorResponse)
|
||||||
Log HTTP errors, e.g. when losing network connectivity or receiving an error response code.
Parameters :
Returns :
any
|
Private setSeverity | ||||||
setSeverity(severity: SeverityLevels)
|
||||||
Parameters :
Returns :
void
|
Private setTags | ||||||
setTags(message: string)
|
||||||
The headers are easier to search in splunk, and we aren't using tags, so repurpose it to event type.
Parameters :
Returns :
void
|
Private setTimestamp |
setTimestamp()
|
Returns :
void
|
setURL | ||||||
setURL(newURL: string)
|
||||||
Parameters :
Returns :
void
|
Protected generateUUID |
generateUUID()
|
Inherited from
AbstractHttpService
|
Defined in
AbstractHttpService:64
|
Returns :
any
|
Protected get | ||||||||||||
get(url, queryParams?: HttpParams)
|
||||||||||||
Inherited from
AbstractHttpService
|
||||||||||||
Defined in
AbstractHttpService:24
|
||||||||||||
Type parameters :
|
||||||||||||
Makes a GET request to the specified URL, using headers and HTTP options specified in their respective methods.
Parameters :
Returns :
Observable<T>
|
Protected Abstract handleError | ||||||
handleError(error: HttpErrorResponse)
|
||||||
Inherited from
AbstractHttpService
|
||||||
Defined in
AbstractHttpService:61
|
||||||
Handles all failed requests that throw either a server error (400/500) or a client error (e.g. lost internet).
Parameters :
Returns :
any
|
Protected post | ||||||
post(url, body)
|
||||||
Inherited from
AbstractHttpService
|
||||||
Defined in
AbstractHttpService:32
|
||||||
Type parameters :
|
||||||
Parameters :
Returns :
Observable<T>
|
Protected setupRequest | ||||||
setupRequest(observable: Observable
|
||||||
Inherited from
AbstractHttpService
|
||||||
Defined in
AbstractHttpService:40
|
||||||
Type parameters :
|
||||||
Parameters :
Returns :
Observable<T>
|
Protected uploadAttachment | ||||||||||||
uploadAttachment(relativeUrl: string, attachment: CommonImage)
|
||||||||||||
Inherited from
AbstractHttpService
|
||||||||||||
Defined in
AbstractHttpService:75
|
||||||||||||
Uploads an individual attachment. All you need to do is set the url. Note: urls often include UUIDs, so this must be an application decision.
Parameters :
Returns :
any
|
Protected _headers |
Type : HttpHeaders
|
Default value : new HttpHeaders({
request_method: 'POST',
logsource: window.location.hostname,
http_x_forwarded_host: window.location.hostname
})
|
The HTTP Headers which go with each request. These MUST be set if you are using the logger. Fields include:
|
Private url |
Type : string
|
Default value : null
|
Protected Abstract _headers |
Type : HttpHeaders
|
Inherited from
AbstractHttpService
|
Defined in
AbstractHttpService:18
|
The headers to send along with every GET and POST. |
Protected logHTTPRequestsToConsole |
Type : boolean
|
Default value : false
|
Inherited from
AbstractHttpService
|
Defined in
AbstractHttpService:13
|
applicationId | ||||||
getapplicationId()
|
||||||
setapplicationId(id: string)
|
||||||
Parameters :
Returns :
void
|
programName | ||||||
getprogramName()
|
||||||
setprogramName(name: string)
|
||||||
Parameters :
Returns :
void
|
httpOptions |
gethttpOptions()
|
Overwrite the inherited httpOptions so we can set responseType to text. This updates Angular's parsing, and it won't error out due to the server not responding with JSON.
Returns :
any
|
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { AbstractHttpService } from './abstract-api-service';
import { throwError } from 'rxjs';
import * as moment_ from 'moment';
const moment = moment_;
enum SeverityLevels {
INFO = 'info',
ERROR = 'error',
}
export enum CommonLogEvents {
navigation = 'navigation',
error = 'error',
submission = 'submission'
}
export interface CommonLogMessage {
/** The type of event being logged. */
event: string; // Should be subclasses into multiple string literals
// We allow any other properties/values in the interface
[key: string]: any;
}
@Injectable({
providedIn: 'root'
})
export class CommonLogger extends AbstractHttpService {
/**
* The HTTP Headers which go with each request. These MUST be set if you are
* using the logger. Fields include:
*
* - program (REQUIRED, the application wide code)
* - applicationId (REQUIRED, like sessionId)
* - request_method (REQUIRED, 'POST')
* - logsource: (REQUIRED, window.location.hostname)
* - http_x_forwarded_host (REQUIRED, window.location.hostname)
*
*/
protected _headers: HttpHeaders = new HttpHeaders({
request_method: 'POST',
logsource: window.location.hostname,
http_x_forwarded_host: window.location.hostname
});
private url: string = null;
constructor(protected http: HttpClient) {
super(http);
}
set applicationId( id: string ) {
this._headers = this._headers.set( 'applicationId', id );
}
get applicationId() {
return this._headers.get( 'applicationId' );
}
set programName( name: string ) {
this._headers = this._headers.set( 'program', name );
}
get programName() {
return this._headers.get( 'name' );
}
setURL(newURL: string) {
this.url = newURL;
}
public log( message: any ) {
this._log( message as CommonLogMessage );
}
public logError( errorMessage: any ) {
this._logError( errorMessage as CommonLogMessage );
}
/**
* Log a message to Splunk. This is the main way to send logs and
* automatically includes meta-data. You do **not** need to subscribe to the
* response, as the service already does that. The input object must have an
* 'event' property set, everything else is optional.
*
* Example:
* ```
this.logService.log({
event: 'submission',
dateObj: new Date()
});
```
* @param message A JavaScript object, nesting is fine, with `event` property
* set.
*/
protected _log(message: CommonLogMessage) {
this.setSeverity(SeverityLevels.INFO);
return this._sendLog(message);
}
protected _logError(errorMessage: CommonLogMessage) {
this.setSeverity(SeverityLevels.ERROR);
return this._sendLog(errorMessage);
}
/**
* Log HTTP errors, e.g. when losing network connectivity or receiving an
* error response code.
*/
public logHttpError(error: HttpErrorResponse) {
return this._logError({
event: CommonLogEvents.error,
message: error.message,
errorName: error.name,
statusText: error.statusText
});
}
/**
* Internal method to send logs to Splunk, includes meta-data except that's
* consistent across all requests, but not specific values like severity
* level.
*
* @param message A JavaScript object or anything that can be toString()'d,
* like Date
*/
private _sendLog(message: CommonLogMessage) {
// Update headers
this.setTimestamp();
this.setTags(message.event);
if (this.url === null) {
const msg = 'Unable to send logs as URL as not been set via setURL()';
console.error(msg);
return throwError(msg);
}
// Configure request
const body = { message: message };
// We call .subscribe() here because we don't care about the response and
// we want to ensure that we never forget to call subscribe.
return this.post(this.url, body).subscribe();
}
protected handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// Client-side / network error occured
console.error('An error occured: ', error.error.message);
} else {
// The backend returned an unsuccessful response code
console.error(`Backend returned error code: ${error.status}. Error body: ${error.error}`);
}
return throwError(error);
}
/**
* Overwrite the inherited httpOptions so we can set responseType to text.
* This updates Angular's parsing, and it won't error out due to the server
* not responding with JSON.
*/
protected get httpOptions(): any {
return {
headers: this._headers,
responseType: 'text'
};
}
// TODO: Remove moment dependency
private setTimestamp() {
this._headers = this._headers.set('timestamp', moment().toISOString());
}
private setSeverity(severity: SeverityLevels) {
this._headers = this._headers.set('severity', severity);
}
/**
* The headers are easier to search in splunk, and we aren't using tags, so
* repurpose it to event type.
*/
private setTags(message: string ) {
this._headers = this._headers.set('tags', message);
}
}