Name

global.VAClickMetrics

Description

A helper for VA Click Metrics

Script

var VAClickMetrics = Class.create();

/**
* Creates a new click metrics URL for the given link
* @param vaSystem : VA runtime context object
* @param originalLink : the original link. This is the final destination the user will be redirected to.
* @param scrachPad : Any runtime info to be used when inserting attributes into the ETL table.
* @param eventType It should be one of "ai_search", "contextual_search" or "bot_output". 
*                   If omitted, VAClickMetricsConstants.EVENT_TYPE_BOT_OUTPUT will be used.
* @return a fully qualified Click Metrics URL 
*/
VAClickMetrics.createClickMetricsURL = function(vaSystem, originalLink, scratchPad, eventType) {

  if(gs.nil(vaSystem) || gs.nil(originalLink))
  	throw 'Invalid input parmeters';
  
  var scratchPadStr = null;
  
  if(typeof scratchPad === 'string')
  	scratchPadStr = scratchPad;	
  else 
  	scratchPadStr = gs.nil(scratchPad) ? '' : JSON.stringify(scratchPad);
  
  return vaSystem.createClickMetricsURL(originalLink, scratchPadStr, eventType);
};

/**
* Fires an event for AI search 
* @param payload
*/
VAClickMetrics.queueAISearchEvent = function(conversationId, taskId, payload) {	
  VAClickMetrics.queueSearchEvent(conversationId, taskId, VAClickMetricsConstants.EVENT_TYPE_AI_SEARCH, payload);
};

/**
* Fires an event for contextual search. 
* @param payload
*/
VAClickMetrics.queueContextualSearchEvent = function(conversationId, taskId, payload) {
  VAClickMetrics.queueSearchEvent(conversationId, taskId, VAClickMetricsConstants.EVENT_TYPE_CONTEXTUAL_SEARCH, payload);
};

/**
* Fires an event for search. The type of search can be either AI search or Contextual Search.
*
* @param eventType  Either VAClickMetricsConstants.EVENT_TYPE_AI_SEARCH  or VAClickMetricsConstants.EVENT_TYPE_CONTEXTUAL_SEARCH
* @param payload
*/
VAClickMetrics.queueSearchEvent = function(conversationId, taskId, eventType, payload) {
  
  var logger = global.VAClickMetrics.getLogger(conversationId, taskId);
  
  if(gs.nil(eventType) || gs.nil(payload)) {
  	logger.error('Event can not be fired. Invalid parameters');
  	throw 'Invalid parameters';
  }
  
  var payloadObj;
  
  if (typeof payload ==='string') 
  	payloadObj = JSON.parse(payload);
  else 
  	payloadObj = payload;
  
  // add the current timestamp to the payload, so that this timestamp can be used when the event gets processed.
  payloadObj[global.VAClickMetricsConstants.EVENT_TIMESTAMP_NAME] = new GlideDateTime().getNumericValue()+'';
  sn_cs.VASystemObject.queueClickMetricsLifeCycleEvent(conversationId, taskId, eventType, JSON.stringify(payloadObj));
};

/**
* Extracts the token from the provided request and processes the data
*/
VAClickMetrics.processLink = function(request) {
  
  // read the token from the request.
  var token = request.getParameter('token');
  var targetURL = request.getParameter('target_url');
  
  return sn_cs.VASystemObject.processToken(token, targetURL);
};

/**
* Retuns the current timestamp
*/
VAClickMetrics.getCurrentTime = function() {
  return new GlideDateTime().getValue();
};

VAClickMetrics.isAISearchClickMetricsAllowed = function() {
  return global.VAClickMetrics.isFeatureEanbled(VAClickMetricsConstants.EVENT_TYPE_AI_SEARCH);
};

VAClickMetrics.isContextualSearchClickMetricsAllowed = function() {
  return global.VAClickMetrics.isFeatureEanbled(VAClickMetricsConstants.EVENT_TYPE_CONTEXTUAL_SEARCH);
};

VAClickMetrics.isBotOutputClickMetricsAllowed = function() {
  return global.VAClickMetrics.isFeatureEanbled(VAClickMetricsConstants.EVENT_TYPE_BOT_OUTPUT);
};

/**
* Tests if Click Metrics for the passed even type is enabled or not. 
* @param evenType - the value should be one of VAClickMetricsConstants.EVENT_TYPE_BOT_OUTPUT, VAClickMetricsConstants.EVENT_TYPE_AI_SEARCH,
*				    VAClickMetricsConstants.EVENT_TYPE_CONTEXTUAL_SEARCH
*/
VAClickMetrics.isFeatureEanbled = function(eventType) {
  
  if(gs.nil(eventType))
  	eventType = global.VAClickMetricsConstants.EVENT_TYPE_DEFAULT;
  
  var propName = global.VAClickMetrics.getFeatureSwitchProperty(eventType);
  var propVal = gs.getProperty(propName, 'false');
  return propVal && propVal==='true';
};

/**
*  Returns always a new unique ID
*/
VAClickMetrics.createGUID = function() {
  return gs.generateGUID();
};

/**
* Creates a ScriptableGlideLogger instance with the passed conversationId and taskId
* @param conversationId. pass null if not avaialble.
* @param taskId. pass null if not available.
* @returns {sn_log.GlideLogger}
*/
VAClickMetrics.getLogger = function(conversationId, taskId) {
  
  var context = global.VAClickMetricsConstants.LOGGING_CONTEXT;
  
  if (!gs.nil(conversationId))
  	context.conversation = conversationId;
  
  if (!gs.nil(taskId))
  	context.conversation_task = taskId;
  
  return getVALogger(context);
};

VAClickMetrics.getTimeDifferenceInMilliseconds = function(timestamp) {
  var currntTime = new GlideDateTime().getNumericValue();
  return currntTime - timestamp; 
};

VAClickMetrics.getFeatureSwitchProperty = function(eventType) {
  return 'com.glide.cs.click_metrics.' + eventType;
};

/**
* Creates a URL that contains metrics and target URL for Genius Search Result.
* This URL will be clicked by the User and sent to the processor for signal processing.
* @return a fully qalified URL . eg:  contain https://instance/va_link_processor.do?metrics=<metrics>&target_url=<target_url>
*/
VAClickMetrics.createGeniusSearchEventMetricsURL = function(searchMetadata, geniusSearchResults, vaSystem, vaInputs, vaVars, url, index) {
  
  var collector = new global.VAAISearchGeniusResultEventMetricCollector(searchMetadata, vaSystem, vaInputs, vaVars);
  collector.collect(geniusSearchResults, index);
  collector.sendOutMetrics();
  return global.VAClickMetrics.createClickMetricsURL(vaSystem, url, collector.getPayload(), global.VAClickMetricsConstants.EVENT_TYPE_AI_SEARCH);
};

/**
* Creates a URL that contains metrics and target URL for non-Genius Search Result.
* This URL will be clicked by the User and sent to the processor for signal processing.
* @return a fully qalified URL . eg:  contain https://instance/va_link_processor.do?metrics=<metrics>&target_url=<target_url>
*/
VAClickMetrics.createSearchResultEventMetricsURL = function(searchMetadata, searchResults, vaSystem, vaInputs, vaVars, url, signalType, signalValue) {

  var collector = new global.VAAISearchSearchResultEventMetricCollector(searchMetadata, vaSystem, vaInputs, vaVars);
  collector.collect(searchResults, signalType, signalValue);
  collector.sendOutMetrics();
  return global.VAClickMetrics.createClickMetricsURL(vaSystem, url, collector.getPayload(), global.VAClickMetricsConstants.EVENT_TYPE_AI_SEARCH);
};


/**
* Creates a URL that contains metrics and target URL for Genius Search Result.
* This URL will be clicked by the User and sent to the processor for signal processing.
* @return a fully qalified URL . eg:  contain https://instance/va_link_processor.do?metrics=<metrics>&target_url=<target_url>
*/
VAClickMetrics.createGeniusSearchEventMetricsURL = function(searchMetadata, geniusSearchResults, vaSystem, vaInputs, vaVars, url, index) {
  
  // If signal-operation is not allowed, don't need to create a special URL.
  if (!global.VAClickMetrics.isAISearchClickMetricsAllowed()) 
  	return VAClickMetrics.createClickMetricsURL(vaSystem, url, {}, VAClickMetricsConstants.EVENT_TYPE_AI_SEARCH);
  
  var collector = new global.VAAIGeniusResultEventMetricCollector(searchMetadata, vaSystem, vaInputs, vaVars);
  
  collector.collect(geniusSearchResults, index);
  collector.sendOutMetrics(true);
  
  return VAClickMetrics.createClickMetricsURL(vaSystem, url, collector.getPayload(), VAClickMetricsConstants.EVENT_TYPE_AI_SEARCH);
};

/**
* Creates a URL that contains metrics and target URL for regular search results.
* This URL will be clicked by the User and sent to the processor for signal processing.
* @return a fully qualified URL. eg:  contain https://instance/va_link_processor.do?metrics=<metrics>&target_url=<target_url>
*/
VAClickMetrics.createSearchResultEventMetricsURL = function(searchMetadata, searchResults, vaSystem, vaInputs, vaVars, url, itemIndex) {

  // If the signal operation is not allowed, don't need to create a special URL
  if (!global.VAClickMetrics.isAISearchClickMetricsAllowed())
  	return global.VAClickMetrics.createClickMetricsURL(vaSystem, url, {}, global.VAClickMetricsConstants.EVENT_TYPE_AI_SEARCH);

  var collector = new global.VAAISearchResultEventMetricCollector(searchMetadata, vaSystem, vaInputs, vaVars);
  collector.collect(searchResults, itemIndex);
  collector.sendOutMetrics();
  
  return global.VAClickMetrics.createClickMetricsURL(vaSystem, url, collector.getPayload(), global.VAClickMetricsConstants.EVENT_TYPE_AI_SEARCH);
};


/**
* Sends the signals to GlideSignals API
*/
VAClickMetrics.sendToGlideSignalsAPI = function(conversationId, taskId, eventType, payload) {
  
  var logger = global.VAClickMetrics.getLogger(conversationId, taskId);
  var apiName = global.VAClickMetricsConstants.GLIDE_SINALS_API;
  
  if (gs.nil(eventType)) {
  	logger.error('Event Type must exist to send VA AI Search result metrics to {0}:{1}', apiName, eventType);
  	return {};
  }
  
  if (gs.nil(payload)) {
  	logger.error('Payload must exist to send VA AI Search result metrics to {0}:{1}', apiName, eventType);
  	return {};
  }
  
  var timestamp = new GlideDateTime().getNumericValue();
  var userId = payload.userId;
  var sessionId = payload.sessionId;
  
  try {
  	
  	var signal = new global.GlideSignalsService();
  	signal.trackEventAsync(eventType, "INFO", payload);
  	logger.info("Sent VA AI search result metrics to {0}:{1}. It took {2} ms. user_id:{3}, session_id:{4}", 
  				apiName, eventType, VAClickMetrics.getTimeDifferenceInMilliseconds(timestamp)+'', userId, sessionId);

  	return payload;
  } catch(e) {
  	// log the issue and let the flow continues..
  	// the payload won't be logged here to avoid any possible privacy issue.
  	var LOG_ID = apiName+':'+eventType;
  	logger.error("An error occurred while sending VA AI search result metrics to {0}. It took {1} ms. user_id:{2}, session_id:{3} \nError:{4}", 
  				LOG_ID, global.VAClickMetrics.getTimeDifferenceInMilliseconds(timestamp)+'', userId, sessionId, e);
  	return {};
  }
};

VAClickMetrics.updateClickMetricsScheduleJobTriggerType = function(eventEnabled) {
  // find all click-Metrics scheduled jobs and change the trigger type based on the flag.
  // When event handling is set to true, the trigger type needs to be set to "Repeat"
  // When event handling is set to false, the trigger type needs to be set to "Disabled"
  var names = global.VAClickMetricsConstants.SCHEDULED_JOB_NAMES;

  var gr = new GlideRecord('sys_trigger');
  gr.addQuery('name', 'IN', names.join());  
  
  // 1 - Repeat.
  // 2 - Disabled.
  var triggerType = (eventEnabled) ? '1' : '2';
  gr.setValue('trigger_type',triggerType);

  gr.updateMultiple();
};

function getVALogger(context) {
  return new sn_log.GlideLogger(global.VAClickMetricsConstants.LOGGER_NAME, context, Object.keys(context));
}

Sys ID

dab13a7153303010c440ddeeff7b1265

Offical Documentation

Official Docs: