<commit_before>// # Startup
// A class to encompass both dual master/worker cluster launch and installation of a
// top-level domain for the process.

// [strict mode](http://mzl.la/1fRhnam)
'use strict';

var cluster = require('cluster');
var domain = require('domain');
var path = require('path');

var winston = require('winston');

var core = require('thehelp-core');
var Graceful = require('./graceful');

/*
The `constructor` requires only one parameter `worker`, a callback which
starts a worker process. Optional parameters:

+ `logsDir` -  your logs directory, defaulting to './logs/' (can also be specified by the
THEHELP_LOGS_DIR environment variable)
+ `log` -  an object to replicate the `winston` interface
+ `masterOptions` - options to be passed to the `Master` class on construction in the
default master start callback
+ `master` - a callback to start the cluster's master process
+ `errorHandler` - an alternate handler for a top-level error. Prevents `messenger` from
being called, and prevents any kind of automatic graceful shutdown.
+ `messenger` -  a `function(err, options, cb)`, defaulting to
`thehelp-last-ditch`. Passed any top-level exceptions encountered.

*/
function Startup(options) {
  /*jshint maxcomplexity: 10 */

  options = options || {};

  this.worker = options.worker;
  if (!this.worker) {
    throw new Error('Need to provide a worker callback!');
  }

  this.logsDir = options.logsDir || process.env.THEHELP_LOGS_DIR || './logs/';
  this.log = options.log || winston;

  this.masterOptions = options.masterOptions;
  this.master = options.master || this._defaultMasterStart.bind(this);

  this.errorHandler = options.errorHandler;
  //errorHandler supercedes messenger
  if (!this.errorHandler) {
    this.messenger = options.messenger || require('thehelp-last-ditch');
  }

  this.domain = domain.create();
  this.domain.on('error', this._onError.bind(this));

  this.cluster = options.cluster || cluster;
}

module.exports = Startup;

// Public methods
// ========

// `start` checks whether the current process is the master, then calls the appropriate
// `master` or `worker` in the contxt of a top-level domain.
Startup.prototype.start = function start() {
  if (this.cluster.isMaster) {
    this.domain.run(this.master);
  }
  else {
    this.domain.run(this.worker);
  }
};

// `setupLogs` sets up colorful, formatted console logging as well as a file appropriate
// to the process type. Files are of the form 'worker-2014-04-28T03-04:03.232Z-32706.log'
// in the `logs` directory.
Startup.prototype.setupLogs = function setupLogs() {
  var type = this.cluster.isMaster ? 'master' : 'worker';
  core.logs.setupFile(path.join(
    this.logsDir,
    type + '-' + this._timestampForPath() + '-' + process.pid + '.log'
  ));
  core.logs.setupConsole();
};

// Helper methods
// ========

/*
`onError` is called when the top-level domain is sent an error. Whenever this happens
it's definitely something serious, so we log the error via `this.log`, then send it via
the `messenger` callback, and finally start the process of graceful shutdown.

If [`Graceful.instance`](./graceful.html) is found, its `shutdown()` method will be
called, preventing the `messenger()` handler from being called.

Lastly `errorHandler` can be specified for custom error-handling logic, superceding all
other behavior in this method.<commit_msg>Startup: Split out log filename gen from setupLogs<commit_after>// # Startup
// A class to encompass both dual master/worker cluster launch and installation of a
// top-level domain for the process.

// [strict mode](http://mzl.la/1fRhnam)
'use strict';

var cluster = require('cluster');
var domain = require('domain');
var path = require('path');

var winston = require('winston');

var core = require('thehelp-core');
var Graceful = require('./graceful');

/*
The `constructor` requires only one parameter `worker`, a callback which
starts a worker process. Optional parameters:

+ `logsDir` -  your logs directory, defaulting to './logs/' (can also be specified by the
THEHELP_LOGS_DIR environment variable)
+ `log` -  an object to replicate the `winston` interface
+ `masterOptions` - options to be passed to the `Master` class on construction in the
default master start callback
+ `master` - a callback to start the cluster's master process
+ `errorHandler` - an alternate handler for a top-level error. Prevents `messenger` from
being called, and prevents any kind of automatic graceful shutdown.
+ `messenger` -  a `function(err, options, cb)`, defaulting to
`thehelp-last-ditch`. Passed any top-level exceptions encountered.

*/
function Startup(options) {
  /*jshint maxcomplexity: 10 */

  options = options || {};

  this.worker = options.worker;
  if (!this.worker) {
    throw new Error('Need to provide a worker callback!');
  }

  this.logsDir = options.logsDir || process.env.THEHELP_LOGS_DIR || './logs/';
  this.log = options.log || winston;

  this.masterOptions = options.masterOptions;
  this.master = options.master || this._defaultMasterStart.bind(this);

  this.errorHandler = options.errorHandler;
  //errorHandler supercedes messenger
  if (!this.errorHandler) {
    this.messenger = options.messenger || require('thehelp-last-ditch');
  }

  this.domain = domain.create();
  this.domain.on('error', this._onError.bind(this));

  this.cluster = options.cluster || cluster;
}

module.exports = Startup;

// Public methods
// ========

// `start` checks whether the current process is the master, then calls the appropriate
// `master` or `worker` in the contxt of a top-level domain.
Startup.prototype.start = function start() {
  if (this.cluster.isMaster) {
    this.domain.run(this.master);
  }
  else {
    this.domain.run(this.worker);
  }
};

// `setupLogs` sets up `winston` with colorful, formatted console logging as well as a
// file appropriate to the process type. Files are of the form
// 'worker-2014-04-28T03-04:03.232Z-32706.log' in the `this.logsDir` directory.
Startup.prototype.setupLogs = function setupLogs() {
  core.logs.setupFile(this.getLogFilename());
  core.logs.setupConsole();
};

// `getLogFilename` might still be useful if you're not using `winston` for your logging.
Startup.prototype.getLogFilename = function getLogFilename() {
  var type = this.cluster.isMaster ? 'master' : 'worker';
  return path.join(
    this.logsDir,
    type + '-' + this._timestampForPath() + '-' + process.pid + '.log'
  );
};

// Helper methods
// ========

/*
`onError` is called when the top-level domain is sent an error. Whenever this happens
it's definitely something serious, so we log the error via `this.log`, then send it via
the `messenger` callback, and finally start the process of graceful shutdown.

If [`Graceful.instance`](./graceful.html) is found, its `shutdown()` method will be
called, preventing the `messenger()` handler from being called.

Lastly `errorHandler` can be specified for custom error-handling logic, superceding all
other behavior in this method.
{'fraction_non_alphanumeric': 0.12702045487054786, 'fraction_numerical': 0.007152052639107424, 'mean_word_length': 4.111111111111111, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '2603985', 'n_tokens_mistral': 2137, 'n_tokens_neox': 2034, 'n_words': 710}