UNPKG

ca-apm-probe

Version:

CA APM Node.js Agent monitors real-time health and performance of Node.js applications

216 lines (200 loc) 6.76 kB
/** * 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 APM Isengard serialization of hashmap. // Only String keys and values are allowed. // // Following is reverse engineered encoding sample, that is used as spec for this module. // //Isengard encoding of map { a=b } // //[2, kCurrentVersion //0, 0, 0, 84, - fCurrentObjectGraphLength (buffer length - header) //72, - kControlObjectStart // 66, - code = kSerializableByValue // 0, 0, 0, 1, - key // 70, - kClassByValue // 0, 0, 0, 1, - id // 0, 0, - class loader name = "", len = 0 // 0, 17, 106, 97, 118, 97, 46, 117, 116, 105, 108, 46, 72, 97, 115, 104, 77, 97, 112, - classname = java.util.HashMap, len = 16 // 0, 0, 0, 1, - hashmap size // - entry 1 // 72, - kControlObjectStart for key // 66, - code = kSerializableByValue // 0, 0, 0, 2, - key // 70, - code = kClassByValue // 0, 0, 0, 2, - id // 0, 0, - class loader name = "", len = 0 // 0, 16, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, - classname = java.lang.String // 0, 1, 97, - key = "a", len = 1 // 72, - kControlObjectStart for value // 66, - code = kSerializableByValue // 0, 0, 0, 3, - key // 69, - code = kClassByID // 0, 0, 0, 2, - id // 0, 1, 98 - value = "b", len = 1] // // //base64 encoding of this: // //AgAAAFRIQgAAAAFGAAAAAQAAABFqYXZhLnV0aWwuSGFzaE1hcAAAAAFIQgAAAAJGAAAAAgAAABBqYXZhLmxhbmcuU3RyaW5nAAFhSEIAAAADRQAAAAIAAWI= 'use strict'; var logger = require("../logger.js"); var isengardVersion = 2; var kControlObjectStart = 72; var kSerializableByValue = 66; var kClassByValue = 70; var kClassByID = 69 var kJavaHashMapClassName = 'java.util.HashMap'; var kJavaHashMapId = 1; var kJavaStringClassName = 'java.lang.String'; var kJavaStringId = 2; function buildIsengardHeader(size) { var buffer = new Buffer(5); buffer[0] = 2; buffer.writeUInt32BE(size, 1); return buffer; }; function buildUtfString(str) { var len = str.length; var buffer = new Buffer(2 + len); buffer.writeUInt16BE(len, 0); buffer.write(str, 2); return buffer; } function buildHashMapHeader(numEntries, objectKey) { var classNameBuf = buildUtfString(kJavaHashMapClassName); var pos = 0; var size = 1 + // kControlObjectStart 1 + // kSerializableByValue 4 + // objectKey 1 + // kClassByValue 4 + // kJavaHashMapId 2 + // class loader "" classNameBuf.length + 4; // numEntries var buffer = new Buffer(size); buffer[pos++] = kControlObjectStart; buffer[pos++] = kSerializableByValue buffer.writeUInt32BE(objectKey, pos); pos += 4; buffer[pos++] = kClassByValue; buffer.writeUInt32BE(kJavaHashMapId, pos); pos += 4; buffer.writeUInt16BE(0, pos); pos += 2 classNameBuf.copy(buffer, pos); pos += classNameBuf.length; buffer.writeUInt32BE(numEntries, pos); return buffer; }; function buildStringInstance(value, objectKey, first) { var valueBuf = buildUtfString(value); var pos = 0; if (first == true) { var classNameBuf = buildUtfString(kJavaStringClassName); var size = 1 + // kControlObjectStart 1 + // kSerializableByValue 4 + // objectKey 1 + // kClassByValue 4 + // kJavaStringId 2 + // class loader "" classNameBuf.length + // class name valueBuf.length; // value var buffer = new Buffer(size); buffer[pos++] = kControlObjectStart; buffer[pos++] = kSerializableByValue buffer.writeUInt32BE(objectKey, pos); pos += 4; buffer[pos++] = kClassByValue; buffer.writeUInt32BE(kJavaStringId, pos); pos += 4; buffer.writeUInt16BE(0, pos, 2); pos += 2 classNameBuf.copy(buffer, pos); pos += classNameBuf.length; } else { var size = 1 + // kControlObjectStart 1 + // kSerializableByValue 4 + // objectKey 1 + // kClassById 4 + // kJavaStringId valueBuf.length; // value var buffer = new Buffer(size); buffer[pos++] = kControlObjectStart; buffer[pos++] = kSerializableByValue buffer.writeUInt32BE(objectKey, pos); pos += 4; buffer[pos++] = kClassByID; buffer.writeUInt32BE(kJavaStringId, pos); pos += 4; } valueBuf.copy(buffer, pos); return buffer; }; function IsengardHashMap() { this.entries = new Object(); this.serialize = function() { var objectKeyCount = 0; var firstStringEncoding = true; var objectLen = 0; var keys = Object.keys(this.entries); if (logger.isDebug()) { logger.debug('serializing map with %d entries', keys.length); } var bufferCount = 2 + 2 * keys.length; var bufferCounter = 1; var buffers = new Array(bufferCount); objectKeyCount++; buffers[bufferCounter] = buildHashMapHeader(keys.length, objectKeyCount); objectLen = buffers[bufferCounter++].length; for (var i = 0; i < keys.length; i++) { if (logger.isDebug()) { logger.debug('processing %s:%s', keys[i], this.entries[keys[i]]); } objectKeyCount++; buffers[bufferCounter] = buildStringInstance(keys[i], objectKeyCount, firstStringEncoding); objectLen += buffers[bufferCounter++].length; firstStringEncoding = false; objectKeyCount++; buffers[bufferCounter] = buildStringInstance(this.entries[keys[i]], objectKeyCount, firstStringEncoding); objectLen += buffers[bufferCounter++].length; } buffers[0] = buildIsengardHeader(objectLen); var result = Buffer.concat(buffers, buffers[0].length + objectLen); var base64str = result.toString('base64'); if (logger.isDebug()) { logger.debug('json: %s', JSON.stringify(result)); logger.debug('base64: %s', base64str); } return base64str; }; this.put = function(key, value) { if (typeof value == 'string') { this.entries[key] = value; } else { this.entries[key] = '' + value; } }; this.size = function() { var keys = Object.keys(this.entries); return keys.length; }; }; module.exports = IsengardHashMap;