<commit_before>import setConfig from './config';
import Report from './report';
import { COLDSTART, VERSION } from './globals';
import { getDnsPromise } from './dns';
import { getHook } from './hooks';
import { convertToString } from './util';
import setupPlugins from './util/setupPlugins';
import getFileUploadMeta from './fileUploadMeta';
import {
  set as setInvocationContext,
  get as getInvocationContext
} from './invocationContext';

/*eslint-disable no-console*/

function setupTimeoutCapture(wrapperInstance) {
  const { context, sendReport, config } = wrapperInstance;
  const { getRemainingTimeInMillis = () => 0 } = context;

  // if getRemainingTimeInMillis returns a very small number, it's probably a local invoke (sls framework perhaps)
  if (config.timeoutWindow < 1 || getRemainingTimeInMillis() < 10) {
    return undefined;
  }

  const maxEndTime = 899900; /* Maximum execution: 100ms short of 15 minutes */
  const configEndTime = Math.max(
    0,
    getRemainingTimeInMillis.call(context) - config.timeoutWindow
  );

  const endTime = Math.min(configEndTime, maxEndTime);

  return setTimeout(() => {
    context.iopipe.label('@iopipe/timeout');
    sendReport.call(wrapperInstance, new Error('Timeout Exceeded.'), () => {});
  }, endTime);
}

process.on('unhandledRejection', error => {
  const ctx = getInvocationContext();
  if (ctx && ctx.iopipe && ctx.iopipe.label) {
    // default node behavior is to log these types of errors
    console.error(error);
    ctx.iopipe.label('@iopipe/unhandled-promise-rejection');
    ctx.iopipe.label('@iopipe/error');
  }
});

//TODO: refactor to abide by max-params rule*/
/*eslint-disable max-params*/

class IOpipeWrapperClass {
  constructor(
    originalIdentity,
    libFn,
    plugins = [],
    dnsPromise,
    config,
    userFunc,
    originalEvent,
    originalContext,
    originalCallback
  ) {
    this.startTime = process.hrtime();
    this.startTimestamp = Date.now();
    this.config = config;
    this.metrics = [];
    this.labels = new Set();
    this.originalIdentity = originalIdentity;
    this.event = originalEvent;
    this.originalContext = originalContext;
    this.originalCallback = originalCallback;
    this.userFunc = userFunc;
    this.hasSentReport = false;

    this.plugins = setupPlugins(this, plugins);

    this.runHook('pre:setup');

    // support deprecated iopipe.log
    libFn.log = (...logArgs) => {
      console.warn(
        'iopipe.log is deprecated and will be removed in a future version, please use context.iopipe.metric'
      );
      this.log(...logArgs);
    };

    if (COLDSTART) {
      this.dnsPromise = dnsPromise;
    } else {
      // assign a new dnsPromise if it's not a coldstart because dns could have changed
      this.dnsPromise = getDnsPromise(this.config.host);
    }

    this.setupContext();

    // assign modified methods and objects here
    this.context = Object.assign(this.originalContext, {
      // need to use .bind, otherwise, the this ref inside of each fn is NOT IOpipeWrapperClass
      succeed: this.succeed.bind(this),
      fail: this.fail.bind(this),
      done: this.done.bind(this),
      iopipe: {
        label: this.label.bind(this),
        log: this.log.bind(this),
        metric: this.metric.bind(this),
        version: VERSION,
        config: this.config
      }
    });

    setInvocationContext(this.context);

    this.callback = (err, data) => {
      this.sendReport(err, () => {
        typeof this.originalCallback === 'function' &&
          this.originalCallback(err, data);
      });
    };

    this.timeout = setupTimeoutCapture(this);
    this.report = new Report(this);

    this.runHook('post:setup');

    return this;
  }
  setupContext(reset) {
    // preserve original functions via a property name change
    ['succeed', 'fail', 'done'].forEach(method => {
      const descriptor = Object.getOwnPropertyDescriptor(
        this.originalContext,
        reset ? `original_${method}` : method
      );
      if (descriptor) {
        Object.defineProperty(
          this.originalContext,
          reset ? method : `original_${method}`,
          descriptor
        );
      }
      delete this.originalContext[reset ? `original_${method}` : method];
    });
  }
  debugLog(message, level = 'warn') {
    if (this.config.debug) {
      console[level](message);
    }
  }
  invoke() {
    this.runHook('pre:invoke');
    try {
      return this.userFunc.call(
        this.originalIdentity,
        this.event,
        this.context,
        this.callback
      );
    } catch (err) {
      this.sendReport(err, () => this.originalCallback(err));
      return err;<commit_msg>feat(promises): Support monitoring for functions that don't invoke IOpipe callback<commit_after>import setConfig from './config';
import Report from './report';
import { COLDSTART, VERSION } from './globals';
import { getDnsPromise } from './dns';
import { getHook } from './hooks';
import { convertToString } from './util';
import setupPlugins from './util/setupPlugins';
import getFileUploadMeta from './fileUploadMeta';
import {
  set as setInvocationContext,
  get as getInvocationContext
} from './invocationContext';

/*eslint-disable no-console*/

function setupTimeoutCapture(wrapperInstance) {
  const { context, sendReport, config } = wrapperInstance;
  const { getRemainingTimeInMillis = () => 0 } = context;

  // if getRemainingTimeInMillis returns a very small number, it's probably a local invoke (sls framework perhaps)
  if (config.timeoutWindow < 1 || getRemainingTimeInMillis() < 10) {
    return undefined;
  }

  const maxEndTime = 899900; /* Maximum execution: 100ms short of 15 minutes */
  const configEndTime = Math.max(
    0,
    getRemainingTimeInMillis.call(context) - config.timeoutWindow
  );

  const endTime = Math.min(configEndTime, maxEndTime);

  return setTimeout(() => {
    context.iopipe.label('@iopipe/timeout');
    sendReport.call(wrapperInstance, new Error('Timeout Exceeded.'), () => {});
  }, endTime);
}

process.on('unhandledRejection', error => {
  const ctx = getInvocationContext();
  if (ctx && ctx.iopipe && ctx.iopipe.label) {
    // default node behavior is to log these types of errors
    console.error(error);
    ctx.iopipe.label('@iopipe/unhandled-promise-rejection');
    ctx.iopipe.label('@iopipe/error');
  }
});

//TODO: refactor to abide by max-params rule*/
/*eslint-disable max-params*/

class IOpipeWrapperClass {
  constructor(
    originalIdentity,
    libFn,
    plugins = [],
    dnsPromise,
    config,
    userFunc,
    originalEvent,
    originalContext,
    originalCallback
  ) {
    this.startTime = process.hrtime();
    this.startTimestamp = Date.now();
    this.config = config;
    this.metrics = [];
    this.labels = new Set();
    this.originalIdentity = originalIdentity;
    this.event = originalEvent;
    this.originalContext = originalContext;
    this.originalCallback = originalCallback;
    this.userFunc = userFunc;
    this.hasSentReport = false;

    this.plugins = setupPlugins(this, plugins);

    this.runHook('pre:setup');

    // support deprecated iopipe.log
    libFn.log = (...logArgs) => {
      console.warn(
        'iopipe.log is deprecated and will be removed in a future version, please use context.iopipe.metric'
      );
      this.log(...logArgs);
    };

    if (COLDSTART) {
      this.dnsPromise = dnsPromise;
    } else {
      // assign a new dnsPromise if it's not a coldstart because dns could have changed
      this.dnsPromise = getDnsPromise(this.config.host);
    }

    this.setupContext();

    // assign modified methods and objects here
    this.context = Object.assign(this.originalContext, {
      // need to use .bind, otherwise, the this ref inside of each fn is NOT IOpipeWrapperClass
      succeed: this.succeed.bind(this),
      fail: this.fail.bind(this),
      done: this.done.bind(this),
      iopipe: {
        label: this.label.bind(this),
        log: this.log.bind(this),
        metric: this.metric.bind(this),
        version: VERSION,
        config: this.config
      }
    });

    setInvocationContext(this.context);

    this.callback = (err, data) => {
      this.sendReport(err, () => {
        typeof this.originalCallback === 'function' &&
          this.originalCallback(err, data);
      });
    };

    this.timeout = setupTimeoutCapture(this);
    this.report = new Report(this);

    this.runHook('post:setup');

    return this;
  }
  setupContext(reset) {
    // preserve original functions via a property name change
    ['succeed', 'fail', 'done'].forEach(method => {
      const descriptor = Object.getOwnPropertyDescriptor(
        this.originalContext,
        reset ? `original_${method}` : method
      );
      if (descriptor) {
        Object.defineProperty(
          this.originalContext,
          reset ? method : `original_${method}`,
          descriptor
        );
      }
      delete this.originalContext[reset ? `original_${method}` : method];
    });
  }
  debugLog(message, level = 'warn') {
    if (this.config.debug) {
      console[level](message);
    }
  }
  invoke() {
    this.runHook('pre:invoke');
    try {
      const result = this.userFunc.call(
        this.originalIdentity,
        this.event,
        this.context,
        this.callback
      );
      if (result && result.then && result.catch) {
        return new Promise(() => this.callback(null, () => result))
          .then(value => value)
          .catch(err => {
            this.sendReport(err, () => this.originalCallback(err));
            return err;
          });
      }
      return result;
    } catch (err) {
      this.sendReport(err, () => this.originalCallback(err));
      return err;
{'fraction_non_alphanumeric': 0.12861405494392428, 'fraction_numerical': 0.0032925198065644613, 'mean_word_length': 2.8510301109350236, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '172165', 'n_tokens_mistral': 2892, 'n_tokens_neox': 2839, 'n_words': 681}