@microsoft/omnichannel-chat-sdk
Version:
Microsoft Omnichannel Chat SDK
368 lines (367 loc) • 17.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* AWTLogger.ts
* @author Abhilash Panwar (abpanwar)
* @copyright Microsoft 2017
*/
var Enums_1 = require("../common/Enums");
var Enums_2 = require("./Enums");
var AWTEventProperties_1 = require("./AWTEventProperties");
var Utils = require("../common/Utils");
var AWTStatsManager_1 = require("../common/AWTStatsManager");
var AWTNotificationManager_1 = require("../common/AWTNotificationManager");
var AWTTransmissionManagerCore_1 = require("./AWTTransmissionManagerCore");
var AWTLogManagerSettings_1 = require("./AWTLogManagerSettings");
var Version = require("./Version");
var AWTSemanticContext_1 = require("./AWTSemanticContext");
var AWTAutoCollection_1 = require("./AWTAutoCollection");
/**
* The AWTLogger class defines a logger.
*/
var AWTLogger = /** @class */ (function () {
/**
* The AWTLogger class constructor.
* @constructor
* @param {string} _apiKey - The API key (also known as application key, and tenant token).
*/
function AWTLogger(_apiKey) {
this._apiKey = _apiKey;
this._contextProperties = new AWTEventProperties_1.default();
this._semanticContext = new AWTSemanticContext_1.default(false, this._contextProperties);
this._sessionStartTime = 0;
this._createInitId();
}
/**
* Sets the context sent with every event from this logger.
* @param {string} name - The name of the context property.
* @param {string|number|boolean} value - The context property's value.
* @param {enum} type - [Optional] The type of context property, as one of the AWTPropertyType enumeration values.
*/
AWTLogger.prototype.setContext = function (name, value, type) {
if (type === void 0) { type = Enums_1.AWTPropertyType.Unspecified; }
this._contextProperties.setProperty(name, value, type);
};
/**
* Sets context that will be sent with every event from this logger, and tags it as PII.
* @param {string} name - The name of the context property.
* @param {string|number|boolean} value - The context property's value.
* @param {enum} pii - The kind of PII for the context property, as one of the AWTPiiKind enumeration values.
* @param {enum} type - [Optional] The type of context property, as one of the AWTPropertyType enumeration values.
*/
AWTLogger.prototype.setContextWithPii = function (name, value, pii, type) {
if (type === void 0) { type = Enums_1.AWTPropertyType.Unspecified; }
this._contextProperties.setPropertyWithPii(name, value, pii, type);
};
/**
* Sets the context that sent with every event from this logger, and tags it as customer content.
* @param {string} name - The name of the context property.
* @param {string|number|boolean} value - The context property's value.
* @param {enum} customerContent - The customer content kind, as one of the AWTCustomerContentKind enumeration values.
* @param {enum} type - [Optional] The type of context property, as one of the AWTPropertyType enumeration values.
*/
AWTLogger.prototype.setContextWithCustomerContent = function (name, value, customerContent, type) {
if (type === void 0) { type = Enums_1.AWTPropertyType.Unspecified; }
this._contextProperties.setPropertyWithCustomerContent(name, value, customerContent, type);
};
/**
* Gets the logger semantic context.
* <b>Note:</b> Device properties are not permitted at the logger level, but you can set them
* at the global level using the AWTLogManager class.
*
* @return A AWTSemanticContext object that you can use to set common semantic properties.
*/
AWTLogger.prototype.getSemanticContext = function () {
return this._semanticContext;
};
/**
* Logs a custom event with the specified name and fields - to track information
* such as how a particular feature is used.
* @param {Object} event - Can be either an AWTEventProperties object or an AWTEventData object or an event name.
*/
AWTLogger.prototype.logEvent = function (event) {
if (AWTLogManagerSettings_1.default.loggingEnabled) {
if (!this._apiKey) {
this._apiKey = AWTLogManagerSettings_1.default.defaultTenantToken;
this._createInitId();
}
var sanitizeProperties = true;
if (Utils.isString(event)) {
event = {
name: event
};
}
else if (event instanceof AWTEventProperties_1.default) {
event = event.getEvent();
//AWTEventProperties will already sanitize properties
sanitizeProperties = false;
}
AWTStatsManager_1.default.eventReceived(this._apiKey);
AWTLogger._logEvent(AWTLogger._getInternalEvent(event, this._apiKey, sanitizeProperties), this._contextProperties);
}
};
/**
* Logs the session state.
* <b>Note:</b> Calling Logging session <i>start</i> while a session already exists will produce a no-op. Similarly, calling logging
* session <i>end</i> while a session does not exist will also produce a no-op.
* @param {enum} state - The session's state.
* @param {obbject} properties - [Optional] Properties of the session event as either a AWTEventProperties object,
* or a AWTEventData object.
*/
AWTLogger.prototype.logSession = function (state, properties) {
if (AWTLogManagerSettings_1.default.sessionEnabled) {
var sessionEvent = {
name: 'session',
type: 'session',
properties: {}
};
AWTLogger._addPropertiesToEvent(sessionEvent, properties);
sessionEvent.priority = Enums_1.AWTEventPriority.High;
if (state === Enums_2.AWTSessionState.Started) {
if (this._sessionStartTime > 0) {
//Session start called out of order. Session start time being non zero indicates an ongoing session.
return;
}
this._sessionStartTime = (new Date()).getTime();
this._sessionId = Utils.newGuid();
this.setContext('Session.Id', this._sessionId);
sessionEvent.properties['Session.State'] = 'Started';
}
else if (state === Enums_2.AWTSessionState.Ended) {
if (this._sessionStartTime === 0) {
//Session end called out of order. Session start time being zero indicates no ongoing session.
return;
}
var sessionDurationSec = Math.floor(((new Date()).getTime() - this._sessionStartTime) / 1000);
sessionEvent.properties['Session.Id'] = this._sessionId;
sessionEvent.properties['Session.State'] = 'Ended';
sessionEvent.properties['Session.Duration'] = sessionDurationSec.toString();
sessionEvent.properties['Session.DurationBucket'] =
AWTLogger._getSessionDurationFromTime(sessionDurationSec);
this._sessionStartTime = 0;
this.setContext('Session.Id', null);
this._sessionId = undefined;
}
else {
return;
}
sessionEvent.properties['Session.FirstLaunchTime'] = AWTAutoCollection_1.default.firstLaunchTime;
this.logEvent(sessionEvent);
}
};
/**
* Gets the session ID for the ongoing session.
* @return {string} A string that contains the session ID for the ongoing session. Returns undefined if there is
* no ongoing session.
*/
AWTLogger.prototype.getSessionId = function () {
return this._sessionId;
};
/**
* Logs a failure event, such as an application exception.
* @param {string} signature - A string that identifies the bucket of the failure.
* @param {string} detail - A string that contains the a description of the failure.
* @param {string} category - [Optional] A string that identifies the category of the failure, such as an application error,
* a hang, or a crash.
* @param {string} id - [Optional] A string that that uniquely identifies this failure.
* @param {object} properties - [Optional] Properties of the failure event, as either an AWTEventProperties object or an
* AWTEventData object. This value can also be null.
*/
AWTLogger.prototype.logFailure = function (signature, detail, category, id, properties) {
if (!signature || !detail) {
return;
}
var failureEvent = {
name: 'failure',
type: 'failure',
properties: {}
};
AWTLogger._addPropertiesToEvent(failureEvent, properties);
failureEvent.properties['Failure.Signature'] = signature;
failureEvent.properties['Failure.Detail'] = detail;
if (category) {
failureEvent.properties['Failure.Category'] = category;
}
if (id) {
failureEvent.properties['Failure.Id'] = id;
}
failureEvent.priority = Enums_1.AWTEventPriority.High;
this.logEvent(failureEvent);
};
/**
* Logs a page view event which is normally a result of a user action on a UI page - such as search query,
* a content request, or a page navigation.
*
* @param {string} id - A string that uniquely identifies this page.
* @param {string} pageName - The name of the page.
* @param {string} category - [Optional] A string that contains the category to which this page belongs.
* @param {string} uri - [Optional] A string that contains the URI of this page.
* @param {string} referrerUri - [Optional] A string that contains the URI that refers to this page.
* @param {object} properties - [Optional] Properties of the page view event, as an AWTEventProperties object.
* This value can also be null.
*/
AWTLogger.prototype.logPageView = function (id, pageName, category, uri, referrerUri, properties) {
if (!id || !pageName) {
return;
}
var pageViewEvent = {
name: 'pageview',
type: 'pageview',
properties: {}
};
AWTLogger._addPropertiesToEvent(pageViewEvent, properties);
pageViewEvent.properties['PageView.Id'] = id;
pageViewEvent.properties['PageView.Name'] = pageName;
if (category) {
pageViewEvent.properties['PageView.Category'] = category;
}
if (uri) {
pageViewEvent.properties['PageView.Uri'] = uri;
}
if (referrerUri) {
pageViewEvent.properties['PageView.ReferrerUri'] = referrerUri;
}
this.logEvent(pageViewEvent);
};
AWTLogger.prototype._createInitId = function () {
// If no init ID for this tenant token exists, create one
if (!AWTLogger._initIdMap[this._apiKey] && this._apiKey) {
AWTLogger._initIdMap[this._apiKey] = Utils.newGuid();
}
};
AWTLogger._addPropertiesToEvent = function (event, propertiesEvent) {
if (propertiesEvent) {
if (propertiesEvent instanceof AWTEventProperties_1.default) {
propertiesEvent = propertiesEvent.getEvent();
}
if (propertiesEvent.name) {
event.name = propertiesEvent.name;
}
if (propertiesEvent.priority) {
event.priority = propertiesEvent.priority;
}
for (var name_1 in propertiesEvent.properties) {
if (propertiesEvent.properties.hasOwnProperty(name_1)) {
event.properties[name_1] = propertiesEvent.properties[name_1];
}
}
}
};
AWTLogger._getSessionDurationFromTime = function (timeInSec) {
if (timeInSec < 0) {
return 'Undefined';
}
else if (timeInSec <= 3) {
return 'UpTo3Sec';
}
else if (timeInSec <= 10) {
return 'UpTo10Sec';
}
else if (timeInSec <= 30) {
return 'UpTo30Sec';
}
else if (timeInSec <= 60) {
return 'UpTo60Sec';
}
else if (timeInSec <= 180) {
return 'UpTo3Min';
}
else if (timeInSec <= 600) {
return 'UpTo10Min';
}
else if (timeInSec <= 1800) {
return 'UpTo30Min';
}
return 'Above30Min';
};
AWTLogger._logEvent = function (eventWithMetaData, contextProperties) {
if (!eventWithMetaData.name || !Utils.isString(eventWithMetaData.name)) {
AWTNotificationManager_1.default.eventsRejected([eventWithMetaData], Enums_1.AWTEventsRejectedReason.InvalidEvent);
return;
}
eventWithMetaData.name = eventWithMetaData.name.toLowerCase();
//Check if name is a string and replace . with _ if it is. Drop otherwise.
eventWithMetaData.name = eventWithMetaData.name.replace(Utils.EventNameDotRegex, '_');
if (!eventWithMetaData.type || !Utils.isString(eventWithMetaData.type)) {
eventWithMetaData.type = 'custom';
}
else {
eventWithMetaData.type = eventWithMetaData.type.toLowerCase();
}
//Validate name and type and drop if invalid
if (!Utils.EventNameAndTypeRegex.test(eventWithMetaData.name) || !Utils.EventNameAndTypeRegex.test(eventWithMetaData.type)) {
AWTNotificationManager_1.default.eventsRejected([eventWithMetaData], Enums_1.AWTEventsRejectedReason.InvalidEvent);
return;
}
//Add the timestamp if the timestamp is not set or is negative.
if (!Utils.isNumber(eventWithMetaData.timestamp) || eventWithMetaData.timestamp < 0) {
eventWithMetaData.timestamp = (new Date()).getTime();
}
//If no properties create one for EventInfo and context
if (!eventWithMetaData.properties) {
eventWithMetaData.properties = {};
}
// Logger ContextProperties
this._addContextIfAbsent(eventWithMetaData, contextProperties.getPropertyMap());
// LogManager ContextProperties
this._addContextIfAbsent(eventWithMetaData, AWTLogManagerSettings_1.default.logManagerContext.getPropertyMap());
//Add event info
this._setDefaultProperty(eventWithMetaData, 'EventInfo.InitId', this._getInitId(eventWithMetaData.apiKey));
this._setDefaultProperty(eventWithMetaData, 'EventInfo.Sequence', this._getSequenceId(eventWithMetaData.apiKey));
this._setDefaultProperty(eventWithMetaData, 'EventInfo.SdkVersion', Version.FullVersionString);
this._setDefaultProperty(eventWithMetaData, 'EventInfo.Name', eventWithMetaData.name);
this._setDefaultProperty(eventWithMetaData, 'EventInfo.Time', (new Date(eventWithMetaData.timestamp)).toISOString());
if (!Utils.isPriority(eventWithMetaData.priority)) {
eventWithMetaData.priority = Enums_1.AWTEventPriority.Normal;
}
this._sendEvent(eventWithMetaData);
};
AWTLogger._addContextIfAbsent = function (event, contextProperties) {
if (contextProperties) {
for (var name_2 in contextProperties) {
if (contextProperties.hasOwnProperty(name_2)) {
if (!event.properties[name_2]) {
event.properties[name_2] = contextProperties[name_2];
}
}
}
}
};
AWTLogger._setDefaultProperty = function (event, name, value) {
event.properties[name] = { value: value, pii: Enums_1.AWTPiiKind.NotSet, type: Enums_1.AWTPropertyType.String };
};
AWTLogger._sendEvent = function (event) {
AWTTransmissionManagerCore_1.default.sendEvent(event);
};
AWTLogger._getInternalEvent = function (event, apiKey, sanitizeProperties) {
event.properties = event.properties || {};
if (sanitizeProperties) {
// Event Properties
for (var name_3 in event.properties) {
if (event.properties.hasOwnProperty(name_3)) {
event.properties[name_3] = Utils.sanitizeProperty(name_3, event.properties[name_3]);
if (event.properties[name_3] === null) {
delete event.properties[name_3];
}
}
}
}
var internalEvent = event;
internalEvent.id = Utils.newGuid();
internalEvent.apiKey = apiKey;
return internalEvent;
};
AWTLogger._getInitId = function (apiKey) {
return AWTLogger._initIdMap[apiKey];
};
AWTLogger._getSequenceId = function (apiKey) {
if (AWTLogger._sequenceIdMap[apiKey] === undefined) {
AWTLogger._sequenceIdMap[apiKey] = 0;
}
return (++AWTLogger._sequenceIdMap[apiKey]).toString();
};
AWTLogger._sequenceIdMap = {};
AWTLogger._initIdMap = {};
return AWTLogger;
}());
exports.default = AWTLogger;