ca-apm-probe
Version:
CA APM Node.js Agent monitors real-time health and performance of Node.js applications
212 lines (182 loc) • 6.01 kB
JavaScript
/**
* Copyright (c) 2015 CA. All rights reserved.
*
* This software and all information contained therein is confidential and proprietary and
* shall not be duplicated, used, disclosed or disseminated in any way except as authorized
* by the applicable license agreement, without the express written permission of CA. All
* authorized reproductions must be marked with this language.
*
* EXCEPT AS SET FORTH IN THE APPLICABLE LICENSE AGREEMENT, TO THE EXTENT
* PERMITTED BY APPLICABLE LAW, CA PROVIDES THIS SOFTWARE WITHOUT WARRANTY
* OF ANY KIND, INCLUDING WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL CA BE
* LIABLE TO THE END USER OR ANY THIRD PARTY FOR ANY LOSS OR DAMAGE, DIRECT OR
* INDIRECT, FROM THE USE OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, LOST
* PROFITS, BUSINESS INTERRUPTION, GOODWILL, OR LOST DATA, EVEN IF CA IS
* EXPRESSLY ADVISED OF SUCH LOSS OR DAMAGE.
*/
// module for generating correlation id
'use strict';
var guidgenerator = require('./guidgenerator');
var IsengardHashMap = require('./isengard-hashmap');
var logger = require("../logger.js");
var SEQ_SEP = ',';
var LEVEL_SEP = ':';
var NO_OPTIONAL_PARAMS = 'NoOptionalParams';
var TXN_TRACE_ID_KEY = 'TxnTraceId';
var CALLER_TIMESTAMP_KEY = 'CallerTimestamp';
function SequenceId() {
this.seqValue = '1';
this.outgoingLevel = 0;
this.getOutgoingSequenceId = function() {
return this.seqValue + LEVEL_SEP + (++this.outgoingLevel);
};
this.getCurrentOutgoingSequenceId = function() {
return this.seqValue + LEVEL_SEP + this.outgoingLevel;
};
this.setSequenceValue = function(value) {
this.seqValue = value;
}
this.getSequenceValue = function() {
return this.seqValue;
}
}
function CorrelationId() {
this.guid;
this.seqId = new SequenceId();
this.propagationFlag = '0'; // 0: no propogation, 1: propogate
this.depPropagationFlag = '0';
this.incomingCalledByNodeId = '';
this.incomingCalledByNodeType = '';
this.outgoingCallerNodeId = 'NodeJS';
this.outgoingCallerNodeType = '1';
this.txtTraceId = guidgenerator.generateGuid();
this.optionalParam = NO_OPTIONAL_PARAMS;
this.optionalParamMap = new IsengardHashMap();
this.optionalParamMap.put(TXN_TRACE_ID_KEY, this.txtTraceId);
this.getOutgoingSequenceId = function() {
return this.seqId.getOutgoingSequenceId();
};
this.getCurrentOutgoingSequenceId = function() {
return this.seqId.getCurrentOutgoingSequenceId();
};
this.getPropagationFlagValue = function() {
return this.propagationFlag;
}
this.getDeepPropagationFlagValue = function() {
return this.depPropagationFlag;
}
this.getOutgoingCallerNodeType = function() {
return this.outgoingCallerNodeType;
}
this.getOutgoingCallerNodeId = function() {
return this.outgoingCallerNodeId;
}
this.getOptionalParam = function() {
return this.optionalParam;
}
this.getTransactionTraceId = function() {
return this.txtTraceId;
}
this.getCurrentCorId = function() {
if (!this.guid) {
this.guid = guidgenerator.generateGuid();
}
// note, we use seq value only
var seqId = this.seqId.getSequenceValue();
var propFlag = this.getPropagationFlagValue();
var deepPropFlag = this.getDeepPropagationFlagValue();
var nodeID = this.getOutgoingCallerNodeId();
var nodeType = this.getOutgoingCallerNodeType();
var param = this.getOptionalParam();
var corid = this.guid + SEQ_SEP + seqId + SEQ_SEP + propFlag + SEQ_SEP +
deepPropFlag + SEQ_SEP + nodeID + SEQ_SEP + nodeType + SEQ_SEP + param;
return corid;
}
// CorID = <GUID>,<seqID>,<propagation flag>,<dep propagation flag>,
// <outgoingCallerNodeID>,<outgoingCallerNodeType>
this.getOutgoingCorId = function() {
if (!this.guid) {
this.guid = guidgenerator.generateGuid();
}
var seqId = this.getOutgoingSequenceId();
var propFlag = this.getPropagationFlagValue();
var deepPropFlag = this.getDeepPropagationFlagValue();
var nodeID = this.getOutgoingCallerNodeId();
var nodeType = this.getOutgoingCallerNodeType();
// add caller time stamp
this.optionalParamMap.put(CALLER_TIMESTAMP_KEY, Date.now());
var param = this.optionalParamMap.serialize();
var corid = this.guid + SEQ_SEP + seqId + SEQ_SEP + propFlag + SEQ_SEP +
deepPropFlag + SEQ_SEP + nodeID + SEQ_SEP + nodeType + SEQ_SEP + param;
return corid;
}
this.parseAndSet = function(corid) {
if (corid) {
var tokens = corid.split(SEQ_SEP);
var len = tokens.length;
// tokens to look for
var correlationId = null;
var newSeqString = null;
var propagationFlag = null;
var depPropagationFlag = null;
var callerName = null;
var callerNodeType = null;
var optionalParam = null;
if (len.length < 7) {
logger.debug('Received an older cross process data on wire.');
}
if (len > 0) {
correlationId = tokens[0];
}
if (len > 1) {
newSeqString = tokens[1];
}
if (len > 2) {
propagationFlag = tokens[2];
}
if (len > 3) {
depPropagationFlag = tokens[3];
}
if (len > 4) {
callerName = tokens[4];
}
if (len > 5) {
callerNodeType = tokens[5];
}
if (len > 6) {
optionalParam = tokens[6];
}
// set values for properties
if (correlationId) {
this.guid = correlationId;
}
if (newSeqString) {
// TODO: do we need to create new object
// this.seqId = new SequenceId();
this.seqId.setSequenceValue(newSeqString);
}
if (propagationFlag) {
this.propagationFlag = propagationFlag;
}
if (depPropagationFlag) {
this.depPropagationFlag = depPropagationFlag;
}
if (callerName) {
this.incomingCalledByNodeId = callerName;
}
if (callerNodeType) {
this.incomingCalledByNodeType = callerNodeType;
}
if (optionalParam) {
this.optionalParam = optionalParam;
}
}
}
}
function CorrelationIdGenerator() {
this.generateCorIdObj = function() {
return new CorrelationId();
}
}
module.exports = new CorrelationIdGenerator();