lib/Probe.js - monitor

Node Monitor v0.6.5

Show:

File: lib/Probe.js

  1. // Probe.js (c) 2010-2014 Loren West and other contributors
  2. // May be freely distributed under the MIT license.
  3. // For further details and documentation:
  4. // http://lorenwest.github.com/node-monitor
  5. (function(root){

  6.   // Module loading
  7.   var Monitor = root.Monitor || require('./Monitor'),
  8.       log = Monitor.getLogger('Probe'),
  9.       stat = Monitor.getStatLogger('Probe'),
  10.       Cron = Monitor.Cron, _ = Monitor._, Backbone = Monitor.Backbone;

  11.   /**
  12.   * A software device used to expose real time data to monitors
  13.   *
  14.   * This is the base class from which all probe implementations extend.
  15.   *
  16.   * In order to send probe data to monitors, probe implementations simply set
  17.   * their model data using ```set()```.  Those changes are detected and propagated
  18.   * to all monitors of this probe, firing their change events.
  19.   *
  20.   * In order to allow remote probe control, probes need only provide a method
  21.   * called ```{name}_control()```.  See the ```ping_control()``` method as an example,
  22.   * and the ```Probe.onControl()``` method for more information.
  23.   *
  24.   * @class Probe
  25.   * @extends Backbone.Model
  26.   * @constructor
  27.   * @param model - Initial data model.  Can be a JS object or another Model.
  28.   *     @param model.id {String} The probe id.
  29.   *       Assigned by the <a href="Router.html">Router</a> on probe instantiation.
  30.   */
  31.   var Probe = Monitor.Probe = Backbone.Model.extend({

  32.     defaults: {
  33.       id:  null
  34.     },

  35.     /**
  36.     * Initialize the probe
  37.     *
  38.     * This is called on the probe during construction.  It contains
  39.     * the probe initialization attributes and an option to make probe
  40.     * construction asynchronous.
  41.     *
  42.     * Probe implementations can defer the initial response to the monitor until
  43.     * the initial state is loaded.  This allows the callback on
  44.     * <a href="Monitor.html#method_connect">```Monitor.connect()```</a>
  45.     * to have the complete initial state of the probe when called.
  46.     *
  47.     * If the initial probe state cannot be determined in ```initialize```, it should
  48.     * set the ```options.asyncInit``` option to ```true```, and call the
  49.     * ```options.callback(error)``` once the initial state is determined.
  50.     *
  51.     *     // Asynchronous initialization
  52.     *     options.asyncInit = true;
  53.     *     var callback = options.callback
  54.     *
  55.     * If ```asyncInit``` is set to true, the ```callback``` must be called once
  56.     * the initial state of the probe is known (or in an error condition).
  57.     *
  58.     *     // Set the initial state, and call the callback
  59.     *     this.set(...);
  60.     *     callback(null);
  61.     *
  62.     * See the <a href="../files/lib_probes_FileProbe.js.html#l47">```initialize```</a>
  63.     * method of the <a href="FileProbe.html">FileProbe</a> probe for an example.  It defers
  64.     * returning the probe to the monitor until the initial file contents are loaded.
  65.     *
  66.     * @method initialize
  67.     * @param attributes {Object} Initial probe attributes sent in from the Monitor
  68.     * @param options {Object} Initialization options
  69.     *     @param options.asyncInit {boolean} Set this to TRUE if the initial probe
  70.     *         state can't be known immediately.
  71.     *     @param options.callback {function(error)} The callback to call
  72.     *         if asyncInit is set to true.  If an error is passed, the probe
  73.     *         will not be used.
  74.     */
  75.     initialize: function(attributes, options) {
  76.       var t = this;
  77.       log.info('init', t.toJSON(), options);
  78.     },

  79.     /**
  80.     * Release any resources consumed by this probe.
  81.     *
  82.     * This can be implemented by derived classes that need to be informed when
  83.     * they are to be shut down.
  84.     *
  85.     * Probes that listen to events should use this method to remove their
  86.     * event listeners.
  87.     *
  88.     * @method release
  89.     */
  90.     release: function(){
  91.       var t = this;
  92.       log.info('release', t.toJSON());
  93.     },

  94.     /**
  95.     * Dispatch a control message to the appropriate control function.
  96.     *
  97.     * This is called when the
  98.     * <a href="Monitor.html#method_control">```control()```</a>
  99.     * method of a monitor is called.
  100.     * The name determines the method name called on the probe.
  101.     *
  102.     * The probe must implement a method with the name ```{name}_control()```,
  103.     * and that method must accept two parameters - an input params and a callback.
  104.     * The callback must be called, passing an optional error and response object.
  105.     *
  106.     * For example, if the probe supports a control with the name ```go```, then
  107.     * all it needs to do is implement the ```go_control()``` method with the
  108.     * proper signature.  See ```ping_control()``` for an example.
  109.     *
  110.     * @method onControl
  111.     * @param name {String} Name of the control message.
  112.     * @param [params] {Any} Input parameters specific to the control message.
  113.     * @param [callback] {Function(error, response)} Called to send the message (or error) response.
  114.     * <ul>
  115.     *   <li>error (Any) An object describing an error (null if no errors)</li>
  116.     *   <li>response (Any) Response parameters specific to the control message.
  117.     * </ul>
  118.     */
  119.     onControl: function(name, params, callback) {
  120.       var t = this,
  121.           controlFn = t[name + '_control'],
  122.           startTime = Date.now(),
  123.           errMsg,
  124.           logId = 'onControl.' + t.probeClass + '.' + name;

  125.       params = params || {};
  126.       callback = callback || function(){};
  127.       log.info(logId, t.get('id'), params);

  128.       if (!controlFn) {
  129.         errMsg = 'No control function: ' + name;
  130.         log.error(logId, errMsg);
  131.         return callback({msg: errMsg});
  132.       }

  133.       var whenDone = function(error) {
  134.         if (error) {
  135.           log.error(logId, error);
  136.           return callback(error);
  137.         }
  138.         var duration = Date.now() - startTime;
  139.         log.info(logId, params);
  140.         stat.time(t.logId, duration);
  141.         callback.apply(null, arguments);
  142.       };

  143.       try {
  144.         controlFn.call(t, params, whenDone);
  145.       } catch (e) {
  146.         errMsg = 'Error calling control: ' + t.probeClass + ':' + name;
  147.         whenDone({msg:errMsg, err: e.toString()});
  148.       }
  149.     },

  150.     /**
  151.     * Respond to a ping control sent from a monitor
  152.     *
  153.     * @method ping_control
  154.     * @param params {Object} Input parameters (not used)
  155.     * @param callback {Function(error, response)} Called to send the message (or error) response.
  156.     * <ul>
  157.     *   <li>error (Any) An object describing an error</li>
  158.     *   <li>response (String) The string 'pong' is returned as the response</li>
  159.     * </ul>
  160.     */
  161.     ping_control: function(params, callback) {
  162.       return callback(null, 'pong');
  163.     }

  164.   });

  165.   // Register probe classes when loaded
  166.   Probe.classes = {}; // key = name, data = class definition
  167.   Probe.extend = function(params) {
  168.     var t = this, probeClass = Backbone.Model.extend.apply(t, arguments);
  169.     if (params.probeClass) {Probe.classes[params.probeClass] = probeClass;}
  170.     return probeClass;
  171.   };

  172.   /**
  173.   * Constructor for a list of Probe objects
  174.   *
  175.   *     var myList = new Probe.List(initialElements);
  176.   *
  177.   * @static
  178.   * @method List
  179.   * @param [items] {Array} Initial list items.  These can be raw JS objects or Probe data model objects.
  180.   * @return {Backbone.Collection} Collection of Probe data model objects
  181.   */
  182.   Probe.List = Backbone.Collection.extend({model: Probe});

  183. }(this));

  184.