Home Reference Source

lib/helpers.js

const fs = require('fs');

/**
 * Replace any characters that can't be sent on with an underscore
 * @ignore
 */
function sanitizeTags(value, telegraf) {
  const blacklist = telegraf ? /:|\|/g : /:|\||@|,/g;
  // Replace reserved chars with underscores.
  return String(value).replace(blacklist, '_');
}

/**
 * Format tags properly before sending on
 * @ignore
 */
function formatTags(tags, telegraf) {
  if (Array.isArray(tags)) {
    return tags;

  } else {
    return Object.keys(tags).map(key => {
      return `${sanitizeTags(key, telegraf)}:${sanitizeTags(tags[key], telegraf)}`;
    });
  }
}

/**
 * Overrides tags in parent with tags from child with the same name (case sensitive) and return the result as new
 * array. parent and child are not mutated.
 * @ignore
 */
function overrideTags (parent, child, telegraf) {
  const childCopy = {};
  const toAppend = [];
  formatTags(child, telegraf).forEach(tag => {
    const idx = typeof tag === 'string' ? tag.indexOf(':') : -1;
    if (idx < 1) { // Not found or first character
      toAppend.push(tag);
    } else {
      childCopy[tag.substring(0, idx)] = tag.substring(idx + 1);
    }
  });
  const result = parent.map(tag => {
    const idx = typeof tag === 'string' ? tag.indexOf(':') : -1;
    if (idx < 1) { // Not found or first character
      return tag;
    }
    const key = tag.substring(0, idx);
    if (childCopy.hasOwnProperty(key)) {
      const value = childCopy[key];
      delete childCopy[key];
      return `${key}:${value}`;
    }
    return tag;
  });
  Object.keys(childCopy).forEach(key => {
    result.push(`${key}:${childCopy[key]}`);
  });
  return result.concat(toAppend);
}

/**
 * Formats a date for use with DataDog
 * @ignore
 */
function formatDate(date) {
  let timestamp;
  if (date instanceof Date) {
    // Datadog expects seconds.
    timestamp = Math.round(date.getTime() / 1000);
  } else if (date instanceof Number) {
    // Make sure it is an integer, not a float.
    timestamp = Math.round(date);
  }
  return timestamp;
}

/**
 * Converts int to a string IP
 * @ignore
 */
function intToIP(int) {
  const part1 = int & 255;
  const part2 = ((int >> 8) & 255);
  const part3 = ((int >> 16) & 255);
  const part4 = ((int >> 24) & 255);

  return `${part4}.${part3}.${part2}.${part1}`;
}

/**
 * Returns the system default interface on Linux
 * @ignore
 */
function getDefaultRoute() {
  try {
    const fileContents = fs.readFileSync('/proc/net/route', 'utf8'); // eslint-disable-line no-sync
    const routes = fileContents.split('\n');
    for (const routeIdx in routes) {
      const fields = routes[routeIdx].trim().split('\t');
      if (fields[1] === '00000000') {
        const address = fields[2];
        // Convert to little endian by splitting every 2 digits and reversing that list
        const littleEndianAddress = address.match(/.{2}/g).reverse().join('');
        return intToIP(parseInt(littleEndianAddress, 16));
      }
    }
  } catch (e) {
    console.error('Could not get default route from /proc/net/route');
  }
  return null;
}

/**
 * High-resolution timer
 * @ignore
 */
function createHrTimer() {
  const start = process.hrtime();

  return () => {
    const durationComponents = process.hrtime(start);
    const seconds = durationComponents[0];
    const nanoseconds = durationComponents[1];
    const duration = (seconds * 1000) + (nanoseconds / 1E6);
    return duration;
  };
}

module.exports = {
  formatTags,
  overrideTags,
  formatDate,
  getDefaultRoute,
  createHrTimer
};