apminsight
Version:
monitor nodejs applications
338 lines (304 loc) • 9.9 kB
JavaScript
var fs = require("fs");
var path = require("path");
var constants = require("../constants");
var crypto = require("crypto");
const ini = require('ini');
var algorithm = "aes-256-cbc"; //For encryption and decryption
const os = require("os");
function isEmpty(string) {
return string === undefined || string === null || string === "";
}
function isNonEmptyString(str) {
return typeof str === "string" && !isEmpty(str) && /\S/.test(str);
}
function isPositiveNumber(num) {
// Use the existing isNumber function to check validity
if (!isNumber(num)) {
return false;
}
// If it's a valid number, just check if it's >= 0
return num >= 0;
}
function isNumber(value) {
if (value === null || value === undefined || value === '') {
return false;
}
// If it's already a number, just check for NaN
if (typeof value === 'number') {
return !isNaN(value);
}
if (typeof value === 'string') {
const trimmed = value.trim();
if (trimmed === '') {
return false;
}
// Match valid integer or float, positive/negative
return /^-?\d+(\.\d+)?$/.test(trimmed);
}
return false;
}
function isTypeNumber(num) {
if (typeof num === "number") {
return true;
}
return false;
}
function isLetter(str) {
return str.length === 1 && str.match(/[a-z]/i) != null;
}
function isFunction(fn) {
return typeof fn === "function";
}
function isObject(obj) {
return typeof obj === "object";
}
function isBoolean(boolean) {
return typeof boolean === "boolean";
}
function isEmptyObject(obj) {
return Object.keys(obj).length === 0;
}
function convertToString(value) {
if (value && typeof value !== "string") {
return String(value);
}
return value;
}
/*eslint no-empty: "error"*/
function loadInfoFileSync(configInstance) {
if (isEmpty(configInstance.getBaseDir())) {
return {};
}
try {
var baseDirectory = configInstance.getBaseDir();
var appDirectoryName = configInstance.getApplicationName() + "_" + configInstance.getApplicationPort();
var appDirectoryPath = path.join(baseDirectory, appDirectoryName);
var newFilePath = path.join(appDirectoryPath, "apminsight.json");
if (!fs.existsSync(newFilePath)) {
return {};
}
return JSON.parse(fs.readFileSync(newFilePath));
} catch (e) {
console.error("[APM] Error while reading apminsight.json file: ", e);
}
return {};
}
function createInfoFileFolder() {
try {
var configDetails = apmInsightAgentInstance.getConfig();
var baseDirectory = configDetails.getBaseDir();
if (isEmpty(baseDirectory)) {
console.log("[APM] Base directory is empty, cannot create info file folder");
return;
}
var appDirectoryName = configDetails.getApplicationName() + "_" + configDetails.getApplicationPort();
var appDirectoryPath = path.join(baseDirectory, appDirectoryName);
if (!fs.existsSync(appDirectoryPath)) {
fs.mkdir(appDirectoryPath, { recursive: true }, (err) => {
if (err) {
console.log('[APM] Error creating app directory:', err);
return;
}
})
}
}
catch (err) {
console.error("[APM] Error while creating app directory : ", err);
}
}
function writeStream() {
return process.stdout;
}
function checkAndCreateBaseDir(options) {
var agentDataPath;
if (
isNonEmptyString(options.logsDir) &&
isNonEmptyString(options.appName)
) {
var dirName = "apminsightdata_" + options.appName + "_" + options.port;
agentDataPath = path.join(options.logsDir, dirName);
}
else if (isNonEmptyString(process.env.APMINSIGHT_AGENT_HOMEPATH)) {
// One agent requirement
agentDataPath = path.join(process.env.APMINSIGHT_AGENT_HOMEPATH, constants.oneAgentNodeSpecificDir);
}
else {
agentDataPath = path.join(process.cwd(), "apminsightdata");
}
try {
if (!fs.existsSync(agentDataPath)) {
fs.mkdirSync(agentDataPath, { recursive: true });
}
} catch (err) {
console.error(
`[APM] Failed to create logs directory at ${agentDataPath}: ${err.message || err}`,
err
);
// Fallback: If creation fails, try temporary directory as last resort
try {
agentDataPath = path.join(os.tmpdir(), "apminsightdata");
if (!fs.existsSync(agentDataPath)) {
fs.mkdirSync(agentDataPath, { recursive: true });
}
console.log(`[APM] Using temporary directory for agent data: ${agentDataPath}`);
} catch (fallbackErr) {
console.error(`[APM] Failed to create fallback directory: ${fallbackErr.message || fallbackErr}`);
return;
}
}
return agentDataPath;
}
function getGenericThreshold(txnName) {
var threshold;
try {
if (isNonEmptyString(txnName)) {
const genericThreshold = apmInsightAgentInstance.getThreshold();
if (genericThreshold) {
const keyTxnList = genericThreshold.getKeyTxnList();
if (keyTxnList && keyTxnList.includes(txnName)) {
threshold = apmInsightAgentInstance.getKeyTxnThreshold()[txnName];
if (isEmpty(threshold)) {
console.warn(`[APM] threshold object was empty for txnName ${txnName} and assigned with getThreshold`);
threshold = apmInsightAgentInstance.getThreshold();
}
} else {
threshold = apmInsightAgentInstance.getThreshold();
}
}
}
} catch (err) {
console.error(`[APM] error while getting genericThreshold ${err}`);
threshold = apmInsightAgentInstance.getThreshold();
}
if (isEmpty(threshold)) {
threshold = apmInsightAgentInstance.getThreshold();
}
return threshold;
}
function checkpm2(pm2Id, options) {
var agentDataPath = path.join(options.agentBaseDir, String(pm2Id));
try {
if (!fs.existsSync(agentDataPath)) {
fs.mkdirSync(agentDataPath, { recursive: true });
}
} catch (e) {
console.log(
"[APM] Error while creating apminsight agent logs in " +
agentDataPath
);
return;
}
return agentDataPath;
}
function isValidLicenseKey(lKey) {
if (isEmpty(lKey)) {
return false;
} else {
var licenseKeySplit = lKey.split("_").pop();
if (
licenseKeySplit.length == 64 &&
lKey.match(constants.appManagerLicenseRegex)
) {
return true;
}
if (
licenseKeySplit.length <= 40 &&
lKey.match(constants.site24x7LicenseRegex)
) {
return true;
}
return false;
}
}
function toEncryptKey(lKey) {
try {
// the cipher function
var cipher = crypto.createCipheriv(
algorithm,
constants.securitykey,
constants.initVector
);
// encrypt the message
var encryptedData = cipher.update(lKey, "utf-8", "base64");
encryptedData += cipher.final("base64");
return encryptedData;
} catch (err) {
return false;
}
}
function toDecryptKey(lKey, securityKey, iV) {
try {
// the decipher function
var decipher = crypto.createDecipheriv(
algorithm,
securityKey || constants.securitykey,
iV || constants.initVector
);
// decrypt the message
let decryptedData = decipher.update(lKey, "base64", "utf-8");
decryptedData += decipher.final("utf8");
return decryptedData;
} catch (err) {
return false;
}
}
function fetchAppname(configInstance) {
try {
var filePath = path.join(process.cwd(), "package.json");
var packageJson = JSON.parse(fs.readFileSync(filePath));
if ((!configInstance.getApplicationName()) && packageJson && packageJson.name) {
configInstance.setApplicationName(packageJson.name);
}
}
catch (e) {
if (!configInstance.getApplicationName()) {
configInstance.setApplicationName(constants.defaultAppName);
}
}
}
function parseIniFile(filePath) {
if (isEmpty(filePath)) {
return null;
}
try {
const fileContent = fs.readFileSync(filePath, 'utf8');
const parsedData = ini.parse(fileContent);
return parsedData;
} catch (err) {
console.error(`[APM] error parsing INI file at ${filePath}: ${err}`);
return null;
}
}
function isValidURL(url) {
try {
new URL(url); // Attempt to parse the URL
return true; // If no error, it's valid
} catch (err) {
return false; // Invalid URL
}
}
module.exports = {
isEmpty: isEmpty,
isNumber: isNumber,
isTypeNumber: isTypeNumber,
isPositiveNumber: isPositiveNumber,
isNonEmptyString: isNonEmptyString,
isLetter: isLetter,
isFunction: isFunction,
isObject: isObject,
isBoolean: isBoolean,
loadInfoFileSync: loadInfoFileSync,
checkAndCreateBaseDir: checkAndCreateBaseDir,
writeStream: writeStream,
getGenericThreshold: getGenericThreshold,
checkpm2: checkpm2,
isValidLicenseKey: isValidLicenseKey,
isEmptyObject: isEmptyObject,
toEncryptKey: toEncryptKey,
toDecryptKey: toDecryptKey,
convertToString: convertToString,
fetchAppname: fetchAppname,
createInfoFileFolder: createInfoFileFolder,
parseIniFile: parseIniFile,
isValidURL: isValidURL
};