├── config ├── runtime.json ├── doc │ ├── assets │ │ └── css │ │ │ ├── sprite.png │ │ │ ├── cssgrids-min.css │ │ │ └── combo-min.css │ ├── partials │ │ ├── files.handlebars │ │ ├── index.handlebars │ │ ├── props.handlebars │ │ ├── events.handlebars │ │ └── method.handlebars │ ├── README │ └── layouts │ │ └── main.handlebars ├── external.js └── default.js ├── .gitignore ├── .npmignore ├── doc ├── assets │ ├── css │ │ ├── logo.png │ │ ├── sprite.png │ │ ├── external-small.png │ │ ├── cssgrids-min.css │ │ └── combo-min.css │ ├── img │ │ └── spinner.gif │ ├── index.html │ ├── js │ │ ├── yui-prettify.js │ │ ├── tabs.js │ │ ├── api-filter.js │ │ ├── api-search.js │ │ └── api-list.js │ └── vendor │ │ └── prettify │ │ ├── prettify-min.css │ │ ├── CHANGES.html │ │ └── README.html ├── api.js ├── index.html └── files │ ├── lib_probes_LogProbe.js.html │ ├── lib_probes_StatProbe.js.html │ ├── test_ServerTest.js.html │ └── test_ConnectionTest.js.html ├── .travis.yml ├── README.md ├── yuidoc.json ├── LICENSE ├── package.json ├── lib ├── index.js ├── probes │ ├── StatProbe.js │ ├── LogProbe.js │ ├── PollingProbe.js │ ├── StreamProbe.js │ ├── ProcessProbe.js │ ├── InspectProbe.js │ ├── SyncProbe.js │ └── ReplProbe.js ├── Probe.js └── Log.js ├── History.md ├── monitor.js ├── test ├── ServerTest.js ├── ConnectionTest.js ├── InspectTest.js ├── ProbeTest.js ├── MonitorTest.js ├── LogTest.js └── FileProbeTest.js └── grunt.js /config/runtime.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /config/doc 3 | -------------------------------------------------------------------------------- /doc/assets/css/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lorenwest/monitor-min/master/doc/assets/css/logo.png -------------------------------------------------------------------------------- /doc/assets/css/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lorenwest/monitor-min/master/doc/assets/css/sprite.png -------------------------------------------------------------------------------- /doc/assets/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lorenwest/monitor-min/master/doc/assets/img/spinner.gif -------------------------------------------------------------------------------- /config/doc/assets/css/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lorenwest/monitor-min/master/config/doc/assets/css/sprite.png -------------------------------------------------------------------------------- /doc/assets/css/external-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lorenwest/monitor-min/master/doc/assets/css/external-small.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | - "0.8" 5 | - "0.6" 6 | before_script: 7 | - npm install -g grunt@0.3.17 8 | -------------------------------------------------------------------------------- /config/doc/partials/files.handlebars: -------------------------------------------------------------------------------- 1 |

File: {{fileName}}

2 | 3 |
4 |
5 | {{fileData}}
6 |     
7 |
8 | -------------------------------------------------------------------------------- /doc/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redirector 5 | 6 | 7 | 8 | Click here to redirect 9 | 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Repo Moved 2 | ========== 3 | 4 | This repository has moved to the [Node Monitor](https://github.com/lorenwest/node-monitor) project. 5 | 6 | Monitor-Min is kept here for commit histories. 7 | 8 | [![Build Status](https://secure.travis-ci.org/lorenwest/monitor-min.png?branch=master)](https://travis-ci.org/lorenwest/monitor-min) 9 | -------------------------------------------------------------------------------- /config/external.js: -------------------------------------------------------------------------------- 1 | // Configuration overrides when NODE_ENV=external 2 | 3 | // This configuration allows incoming connections from remote systems. 4 | // It should be used only after assuring the network firewall prevents 5 | // untrusted connections on the service port range (usually 42000+). 6 | module.exports = { 7 | MonitorMin: { 8 | allowExternalConnections: true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /yuidoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "monitor-min", 3 | "description": "Monitor Min", 4 | "version": "0.0.0", 5 | "year": "2013", 6 | "url": "http://lorenwest.github.com/monitor-min", 7 | "logo": "", 8 | "themedir": "./config/doc", 9 | "options": { 10 | "external": { 11 | }, 12 | "linkNatives": "true", 13 | "attributesEmit": "true", 14 | "paths": [ 15 | "./lib", 16 | "./test" 17 | ], 18 | "outdir": "./doc" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /doc/assets/js/yui-prettify.js: -------------------------------------------------------------------------------- 1 | YUI().use('node', function(Y) { 2 | var code = Y.all('.prettyprint.linenums'); 3 | if (code.size()) { 4 | code.each(function(c) { 5 | var lis = c.all('ol li'), 6 | l = 1; 7 | lis.each(function(n) { 8 | n.prepend(''); 9 | l++; 10 | }); 11 | }); 12 | var h = location.hash; 13 | location.hash = ''; 14 | h = h.replace('LINE_', 'LINENUM_'); 15 | location.hash = h; 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /doc/assets/vendor/prettify/prettify-min.css: -------------------------------------------------------------------------------- 1 | .str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun{color:#660}.pln{color:#000}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec{color:#606}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}@media print{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun{color:#440}.pln{color:#000}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}} -------------------------------------------------------------------------------- /config/doc/README: -------------------------------------------------------------------------------- 1 | These override from the default yuidoc templates installed globally: 2 | 3 | /usr/local/lib/node_modules/yuidocjs/themes/default 4 | 5 | In order to load locally vs. requiring a network connection (required for developing on the train): 6 | 7 | * Download yui-min.js into assets/js/yui-min.js 8 | * Remove the reference to http://yui.yahooapis.com/ 9 | * Download all combo* .js files that it grabs from yahoo -> into assets/js/combo-min.js 10 | * Download all combo* .css files -> into assets/css/combo-min.css 11 | * Download sprite.png -> into assets/css/sprite.png 12 | * Change all sprite.png references from url(http...sprite.png) to url(sprite.png) in combo-min.css 13 | * Edit the main.handlebars to include assets/js/combo-min.js and assets/css/combo-min.css 14 | 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2013 Loren West and other contributors 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /config/doc/partials/index.handlebars: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

Monitor-Min

5 |

Remote monitoring and control for your node.js app

6 | 7 |

8 | This contains both API and implementation documentation for the monitor package. 9 |

10 | 11 |

12 | Class and method interfaces are documented in the modules below, with links to 13 | the underlying implementation. 14 |

15 | 16 |

Monitor Core

17 |

18 | Classes in this module represent baseline monitor functionality. They can 19 | be loaded and run in a node.js container as well as within a browser. 20 |

21 | 22 |

Baseline Probes

23 |

24 | The probes in this module offer baseline functionality, and provide examples 25 | for building custom probes. 26 |

27 | 28 |

Core Unit Tests

29 |

30 | This module contains unit test classes for each of the core classes, and 31 | some unit tests for baseline probes. 32 |

33 | 34 |
35 |
36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "monitor-min", 3 | "description": "Runtime monitoring for node.js applications", 4 | "version": "0.5.13", 5 | "main": "./lib/index.js", 6 | "author": { 7 | "name": "Loren West", 8 | "email": "open_source@lorenwest.com", 9 | "url": "https://github.com/lorenwest" 10 | }, 11 | "homepage": "http://lorenwest.github.com/monitor-min/", 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/lorenwest/monitor-min.git" 15 | }, 16 | "licenses": [ 17 | { 18 | "type": "MIT", 19 | "url": "https://github.com/lorenwest/monitor-min/blob/master/LICENSE" 20 | } 21 | ], 22 | "dependencies": { 23 | "config": ">=0.4.32 <0.5.0", 24 | "cron": ">=0.1.3 <0.2.0", 25 | "backbone": "0.9.9", 26 | "underscore": ">=1.4.3 <1.5.0", 27 | "backbone-callbacks": ">=0.1.4 <0.2.0", 28 | "socket.io-client": ">=0.9.11 <0.10.0", 29 | "socket.io": ">=0.9.10 <0.10.0" 30 | }, 31 | "devDependencies": { 32 | "grunt": "0.3.17" 33 | }, 34 | "engines": { "node": ">= 0.6.0" }, 35 | "scripts": { 36 | "test": "grunt test", 37 | "start": "node monitor" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /doc/api.js: -------------------------------------------------------------------------------- 1 | YUI.add("yuidoc-meta", function(Y) { 2 | Y.YUIDoc = { meta: { 3 | "classes": [ 4 | "Connection", 5 | "ConnectionTest", 6 | "FileProbe", 7 | "FileProbeTest", 8 | "FileSyncProbe", 9 | "InspectProbe", 10 | "InspectTest", 11 | "Log", 12 | "LogProbe", 13 | "LogTest", 14 | "Monitor", 15 | "MonitorTest", 16 | "PollingProbe", 17 | "Probe", 18 | "ProbeTest", 19 | "ProcessProbe", 20 | "ReplProbe", 21 | "Router", 22 | "RouterTest", 23 | "Server", 24 | "ServerTest", 25 | "Stat", 26 | "StatProbe", 27 | "StatTest", 28 | "StreamProbe", 29 | "Sync", 30 | "SyncProbe", 31 | "SyncProbeTest" 32 | ], 33 | "modules": [ 34 | "Monitor" 35 | ], 36 | "allModules": [ 37 | { 38 | "displayName": "Monitor", 39 | "name": "Monitor", 40 | "description": "Core monitor classes\n\nClasses in this module represent baseline monitor functionality. They can\nbe loaded and run in a node.js container as well as within a browser." 41 | } 42 | ] 43 | } }; 44 | }); -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | // index.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | /* 8 | * Entry point for commonJS style loading 9 | * 10 | * This file coordinates the loading of modules in a consistent order 11 | * in a commonJS environment. 12 | */ 13 | 14 | var commonJS = (typeof exports !== 'undefined'); 15 | if (commonJS) { 16 | 17 | // Only load once 18 | if (!global.Monitor) { 19 | 20 | // Export the Monitor class to module and global scope to assure 21 | // a single load, and to match the browser-side global Monitor. 22 | var Monitor = global.Monitor = module.exports = require('./Monitor'); 23 | 24 | // Attach backbone callbacks 25 | require('backbone-callbacks').attach(Monitor.Backbone); 26 | 27 | // Grunt.js contains the module definition files 28 | var MODULE_DEF = require('../grunt.js').MODULE_DEF; 29 | 30 | // Load local library files, then server-only probes 31 | var allFiles = MODULE_DEF.lib.concat(MODULE_DEF.probes); 32 | allFiles.forEach(function(file) {require('../' + file);}); 33 | } 34 | } 35 | 36 | }(this)); 37 | -------------------------------------------------------------------------------- /doc/assets/css/cssgrids-min.css: -------------------------------------------------------------------------------- 1 | /* 2 | YUI 3.4.0 (build 3928) 3 | Copyright 2011 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | http://yuilibrary.com/license/ 6 | */ 7 | .yui3-g{letter-spacing:-0.31em;*letter-spacing:normal;word-spacing:-0.43em}.yui3-u,.yui3-u-1,.yui3-u-1-2,.yui3-u-1-3,.yui3-u-2-3,.yui3-u-1-4,.yui3-u-3-4,.yui3-u-1-5,.yui3-u-2-5,.yui3-u-3-5,.yui3-u-4-5,.yui3-u-1-6,.yui3-u-5-6,.yui3-u-1-8,.yui3-u-3-8,.yui3-u-5-8,.yui3-u-7-8,.yui3-u-1-12,.yui3-u-5-12,.yui3-u-7-12,.yui3-u-11-12,.yui3-u-1-24,.yui3-u-5-24,.yui3-u-7-24,.yui3-u-11-24,.yui3-u-13-24,.yui3-u-17-24,.yui3-u-19-24,.yui3-u-23-24{display:inline-block;zoom:1;*display:inline;letter-spacing:normal;word-spacing:normal;vertical-align:top}.yui3-u-1{display:block}.yui3-u-1-2{width:50%}.yui3-u-1-3{width:33.33333%}.yui3-u-2-3{width:66.66666%}.yui3-u-1-4{width:25%}.yui3-u-3-4{width:75%}.yui3-u-1-5{width:20%}.yui3-u-2-5{width:40%}.yui3-u-3-5{width:60%}.yui3-u-4-5{width:80%}.yui3-u-1-6{width:16.656%}.yui3-u-5-6{width:83.33%}.yui3-u-1-8{width:12.5%}.yui3-u-3-8{width:37.5%}.yui3-u-5-8{width:62.5%}.yui3-u-7-8{width:87.5%}.yui3-u-1-12{width:8.3333%}.yui3-u-5-12{width:41.6666%}.yui3-u-7-12{width:58.3333%}.yui3-u-11-12{width:91.6666%}.yui3-u-1-24{width:4.1666%}.yui3-u-5-24{width:20.8333%}.yui3-u-7-24{width:29.1666%}.yui3-u-11-24{width:45.8333%}.yui3-u-13-24{width:54.1666%}.yui3-u-17-24{width:70.8333%}.yui3-u-19-24{width:79.1666%}.yui3-u-23-24{width:95.8333%} -------------------------------------------------------------------------------- /config/doc/assets/css/cssgrids-min.css: -------------------------------------------------------------------------------- 1 | /* 2 | YUI 3.4.0 (build 3928) 3 | Copyright 2011 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | http://yuilibrary.com/license/ 6 | */ 7 | .yui3-g{letter-spacing:-0.31em;*letter-spacing:normal;word-spacing:-0.43em}.yui3-u,.yui3-u-1,.yui3-u-1-2,.yui3-u-1-3,.yui3-u-2-3,.yui3-u-1-4,.yui3-u-3-4,.yui3-u-1-5,.yui3-u-2-5,.yui3-u-3-5,.yui3-u-4-5,.yui3-u-1-6,.yui3-u-5-6,.yui3-u-1-8,.yui3-u-3-8,.yui3-u-5-8,.yui3-u-7-8,.yui3-u-1-12,.yui3-u-5-12,.yui3-u-7-12,.yui3-u-11-12,.yui3-u-1-24,.yui3-u-5-24,.yui3-u-7-24,.yui3-u-11-24,.yui3-u-13-24,.yui3-u-17-24,.yui3-u-19-24,.yui3-u-23-24{display:inline-block;zoom:1;*display:inline;letter-spacing:normal;word-spacing:normal;vertical-align:top}.yui3-u-1{display:block}.yui3-u-1-2{width:50%}.yui3-u-1-3{width:33.33333%}.yui3-u-2-3{width:66.66666%}.yui3-u-1-4{width:25%}.yui3-u-3-4{width:75%}.yui3-u-1-5{width:20%}.yui3-u-2-5{width:40%}.yui3-u-3-5{width:60%}.yui3-u-4-5{width:80%}.yui3-u-1-6{width:16.656%}.yui3-u-5-6{width:83.33%}.yui3-u-1-8{width:12.5%}.yui3-u-3-8{width:37.5%}.yui3-u-5-8{width:62.5%}.yui3-u-7-8{width:87.5%}.yui3-u-1-12{width:8.3333%}.yui3-u-5-12{width:41.6666%}.yui3-u-7-12{width:58.3333%}.yui3-u-11-12{width:91.6666%}.yui3-u-1-24{width:4.1666%}.yui3-u-5-24{width:20.8333%}.yui3-u-7-24{width:29.1666%}.yui3-u-11-24{width:45.8333%}.yui3-u-13-24{width:54.1666%}.yui3-u-17-24{width:70.8333%}.yui3-u-19-24{width:79.1666%}.yui3-u-23-24{width:95.8333%} -------------------------------------------------------------------------------- /doc/assets/js/tabs.js: -------------------------------------------------------------------------------- 1 | YUI({ 2 | insertBefore: 'site_styles' 3 | }).use('tabview', function(Y) { 4 | var classdocs = Y.one('#classdocs'), 5 | tabviewIndexTable = {}; 6 | if (classdocs) { 7 | if (classdocs.all('li').size()) { 8 | var tabview = new Y.TabView({ srcNode: classdocs }); 9 | tabview.render(); 10 | classdocs.all('li a').each(function (item, index) { 11 | var hash = item.get(['hash']); 12 | type = hash.substring(1); 13 | if (!tabviewIndexTable[type]) { 14 | tabviewIndexTable[type] = index; 15 | } 16 | }) 17 | Y.all('.sidebox.on-page').each(function (item, index) { 18 | var children = item.all('li a'); 19 | children.each(function (cItem, cIndex) { 20 | return function () { 21 | var handleClick = function (e) { 22 | var node = Y.one(this), 23 | hash = node.get(['hash']), 24 | hashValue = hash.substring(1).split('_'), 25 | type = hashValue.shift(), 26 | ogKey = hashValue.join('_'); // in case the hash had other underscores 27 | if (tabviewIndexTable[type] > -1 && tabviewIndexTable[type] !== currentTab) { 28 | currentTab = tabviewIndexTable[type]; 29 | tabview.selectChild(tabviewIndexTable[type]); 30 | } 31 | } 32 | Y.on('click', handleClick, cItem) 33 | }() 34 | }) 35 | }); 36 | } 37 | } 38 | }); 39 | -------------------------------------------------------------------------------- /config/default.js: -------------------------------------------------------------------------------- 1 | // Default configurations. 2 | module.exports = { 3 | MonitorMin: { 4 | 5 | // This is the running applicaiton name. It should be overridden 6 | // in applications that embed the monitor package. 7 | appName: 'MonitorMin', 8 | 9 | // The base port to use for monitor connections. If this is changed, 10 | // it must be changed on all processes in the monitor network as it 11 | // is used by both client and server processes. Clients use this as 12 | // the starting port to scan. Servers attempt to listen on this port, 13 | // and will continue with higher ports if other processes are listening 14 | // on the port. 15 | serviceBasePort: 42000, 16 | 17 | // When attempting to connect to a remote server, scan this number of 18 | // ports on the remote machine (starting at the serviceBasePort) to 19 | // discover monitor processes. 20 | portsToScan: 20, 21 | 22 | // Only allow connections from this machine by default. This reduces 23 | // accidental security breaches by requiring you to consider your network 24 | // security policies before allowing external connections. 25 | // See the external.js file in this directory for more information. 26 | allowExternalConnections: false, 27 | 28 | // Configure the built-in console log output 29 | consoleLogListener: { 30 | pattern: "{trace,warn,error,fatal}.*" 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /doc/assets/js/api-filter.js: -------------------------------------------------------------------------------- 1 | YUI.add('api-filter', function (Y) { 2 | 3 | Y.APIFilter = Y.Base.create('apiFilter', Y.Base, [Y.AutoCompleteBase], { 4 | // -- Initializer ---------------------------------------------------------- 5 | initializer: function () { 6 | this._bindUIACBase(); 7 | this._syncUIACBase(); 8 | }, 9 | getDisplayName: function(name) { 10 | 11 | Y.each(Y.YUIDoc.meta.allModules, function(i) { 12 | if (i.name === name && i.displayName) { 13 | name = i.displayName; 14 | } 15 | }); 16 | 17 | return name; 18 | } 19 | 20 | }, { 21 | // -- Attributes ----------------------------------------------------------- 22 | ATTRS: { 23 | resultHighlighter: { 24 | value: 'phraseMatch' 25 | }, 26 | 27 | // May be set to "classes" or "modules". 28 | queryType: { 29 | value: 'classes' 30 | }, 31 | 32 | source: { 33 | valueFn: function() { 34 | var self = this; 35 | return function(q) { 36 | var data = Y.YUIDoc.meta[self.get('queryType')]; 37 | var out = []; 38 | Y.each(data, function(v) { 39 | if (v.toLowerCase().indexOf(q.toLowerCase()) > -1) { 40 | out.push(v); 41 | } 42 | }); 43 | return out; 44 | } 45 | } 46 | } 47 | } 48 | }); 49 | 50 | }, '3.4.0', {requires: [ 51 | 'autocomplete-base', 'autocomplete-highlighters', 'autocomplete-sources' 52 | ]}); 53 | -------------------------------------------------------------------------------- /doc/assets/css/combo-min.css: -------------------------------------------------------------------------------- 1 | /* 2 | YUI 3.4.0 (build 3928) 3 | Copyright 2011 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | http://yuilibrary.com/license/ 6 | */ 7 | .yui3-widget-hidden{display:none}.yui3-widget-content{overflow:hidden}.yui3-widget-content-expanded{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;height:100%}.yui3-widget-tmp-forcesize{overflow:hidden!important} 8 | /* 9 | YUI 3.4.0 (build 3928) 10 | Copyright 2011 Yahoo! Inc. All rights reserved. 11 | Licensed under the BSD License. 12 | http://yuilibrary.com/license/ 13 | */ 14 | .yui3-tab-panel{display:none}.yui3-tab-panel-selected{display:block}.yui3-tabview-list,.yui3-tab{margin:0;padding:0;list-style:none}.yui3-tabview{position:relative}.yui3-tabview,.yui3-tabview-list,.yui3-tabview-panel,.yui3-tab,.yui3-tab-panel{zoom:1}.yui3-tab{display:inline-block;*display:inline;vertical-align:bottom;cursor:pointer}.yui3-tab-label{display:block;display:inline-block;padding:6px 10px;position:relative;text-decoration:none;vertical-align:bottom}.yui3-skin-sam .yui3-tabview-list{border:solid #2647a0;border-width:0 0 5px;zoom:1}.yui3-skin-sam .yui3-tab{margin:0 .2em 0 0;padding:1px 0 0;zoom:1}.yui3-skin-sam .yui3-tab-selected{margin-bottom:-1px}.yui3-skin-sam .yui3-tab-label{background:#d8d8d8 url(sprite.png) repeat-x;border:solid #a3a3a3;border-width:1px 1px 0 1px;color:#000;cursor:hand;font-size:85%;padding:.3em .75em;text-decoration:none}.yui3-skin-sam .yui3-tab-label:hover,.yui3-skin-sam .yui3-tab-label:focus{background:#bfdaff url(sprite.png) repeat-x left -1300px;outline:0}.yui3-skin-sam .yui3-tab-selected .yui3-tab-label,.yui3-skin-sam .yui3-tab-selected .yui3-tab-label:focus,.yui3-skin-sam .yui3-tab-selected .yui3-tab-label:hover{background:#2647a0 url(sprite.png) repeat-x left -1400px;color:#fff}.yui3-skin-sam .yui3-tab-selected .yui3-tab-label{padding:.4em .75em}.yui3-skin-sam .yui3-tab-selected .yui3-tab-label{border-color:#243356}.yui3-skin-sam .yui3-tabview-panel{background:#edf5ff}.yui3-skin-sam .yui3-tabview-panel{border:1px solid #808080;border-top-color:#243356;padding:.25em .5em} 15 | -------------------------------------------------------------------------------- /config/doc/assets/css/combo-min.css: -------------------------------------------------------------------------------- 1 | /* 2 | YUI 3.4.0 (build 3928) 3 | Copyright 2011 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | http://yuilibrary.com/license/ 6 | */ 7 | .yui3-widget-hidden{display:none}.yui3-widget-content{overflow:hidden}.yui3-widget-content-expanded{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;height:100%}.yui3-widget-tmp-forcesize{overflow:hidden!important} 8 | /* 9 | YUI 3.4.0 (build 3928) 10 | Copyright 2011 Yahoo! Inc. All rights reserved. 11 | Licensed under the BSD License. 12 | http://yuilibrary.com/license/ 13 | */ 14 | .yui3-tab-panel{display:none}.yui3-tab-panel-selected{display:block}.yui3-tabview-list,.yui3-tab{margin:0;padding:0;list-style:none}.yui3-tabview{position:relative}.yui3-tabview,.yui3-tabview-list,.yui3-tabview-panel,.yui3-tab,.yui3-tab-panel{zoom:1}.yui3-tab{display:inline-block;*display:inline;vertical-align:bottom;cursor:pointer}.yui3-tab-label{display:block;display:inline-block;padding:6px 10px;position:relative;text-decoration:none;vertical-align:bottom}.yui3-skin-sam .yui3-tabview-list{border:solid #2647a0;border-width:0 0 5px;zoom:1}.yui3-skin-sam .yui3-tab{margin:0 .2em 0 0;padding:1px 0 0;zoom:1}.yui3-skin-sam .yui3-tab-selected{margin-bottom:-1px}.yui3-skin-sam .yui3-tab-label{background:#d8d8d8 url(sprite.png) repeat-x;border:solid #a3a3a3;border-width:1px 1px 0 1px;color:#000;cursor:hand;font-size:85%;padding:.3em .75em;text-decoration:none}.yui3-skin-sam .yui3-tab-label:hover,.yui3-skin-sam .yui3-tab-label:focus{background:#bfdaff url(sprite.png) repeat-x left -1300px;outline:0}.yui3-skin-sam .yui3-tab-selected .yui3-tab-label,.yui3-skin-sam .yui3-tab-selected .yui3-tab-label:focus,.yui3-skin-sam .yui3-tab-selected .yui3-tab-label:hover{background:#2647a0 url(sprite.png) repeat-x left -1400px;color:#fff}.yui3-skin-sam .yui3-tab-selected .yui3-tab-label{padding:.4em .75em}.yui3-skin-sam .yui3-tab-selected .yui3-tab-label{border-color:#243356}.yui3-skin-sam .yui3-tabview-panel{background:#edf5ff}.yui3-skin-sam .yui3-tabview-panel{border:1px solid #808080;border-top-color:#243356;padding:.25em .5em} 15 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 0.5.13 / 2013-11-06 2 | =================== 3 | 4 | * Moved repository to node-monitor 5 | 6 | 0.5.12 / 2013-10-23 7 | =================== 8 | 9 | * Updated config dependency to not freak out if the config directory is absent 10 | 11 | 0.5.11 / 2013-10-22 12 | =================== 13 | 14 | * Added TRACE to default console logging output 15 | * Better server listen error handling and debug output 16 | * Better error message on probe failure 17 | 18 | 0.5.10 / 2013-10-15 19 | =================== 20 | 21 | * Better console logging 22 | * Can chain require().start() 23 | * Travis test 24 | 25 | 0.5.9 / 2013-10-04 26 | ================== 27 | 28 | * Better probe instantiation error message 29 | 30 | 0.5.8 / 2013-09-15 31 | ================== 32 | 33 | * Use a gateway if available 34 | * More efficient localhost processing 35 | * Don't restart if already started 36 | * Fixed lint issues 37 | 38 | 0.5.7 / 2013-08-28 39 | ================== 40 | 41 | * Allow socket.io to connect any way it can 42 | * Fixed process.uptime 43 | * Detect and prevent stat & log recursion 44 | * Improved log usage 45 | 46 | 0.5.6 / 2013-07-22 47 | ================== 48 | 49 | * Changed log/stat probe timestamp from integer to ISO 50 | 51 | 0.5.6 / 2013-07-19 52 | ================== 53 | 54 | * Added a timestamp to logProbe/statProbe bundles 55 | 56 | 0.5.5 / 2013-07-18 57 | ================== 58 | 59 | * Added Log & Stat classes 60 | * Tests for Stat & Log 61 | * Added LogProbe & StatProbe 62 | * Added Log.console for console logging 63 | * Added log statements & stats gathering 64 | 65 | 0.5.4 / 2013-05-23 66 | ================== 67 | 68 | * Exported documentation to a public site 69 | * Updated links in README.txt 70 | 71 | 0.5.3 / 2013-05-16 72 | ================== 73 | 74 | * Fixed a dependency issue in the monitor.js bootstrap 75 | 76 | 0.5.2 / 2013-04-17 77 | ================== 78 | 79 | * Revved the major version to match node-monitor major version 80 | * Added Stats and Logs 81 | 82 | 0.1.1 / 2013-03-21 83 | ================== 84 | 85 | * Initial checkin after montior re-org 86 | -------------------------------------------------------------------------------- /config/doc/layouts/main.handlebars: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{htmlTitle}} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 |

{{projectDescription}} v{{projectVersion}}

19 |
20 |
21 |
22 | 23 |
24 | 27 |
28 |
29 | {{>options}} 30 |
31 |
32 |
33 | {{>layout_content}} 34 |
35 |
36 |
37 |
38 |
39 |
40 | 43 | 46 |
47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /lib/probes/StatProbe.js: -------------------------------------------------------------------------------- 1 | // StatProbe.js (c) 2010-2013 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/monitor-min 5 | (function(root) { 6 | 7 | // Module loading - this runs server-side only 8 | var Monitor = root.Monitor || require('../Monitor'), 9 | _ = Monitor._, 10 | StreamProbe = Monitor.StreamProbe, 11 | Stat = Monitor.Stat; 12 | 13 | // Constants 14 | var DEFAULT_PATTERN = '*'; 15 | 16 | /** 17 | * Remote application statistics monitoring 18 | * 19 | * This probe forwards application statistics to the monitor. 20 | * 21 | * @class StatProbe 22 | * @extends StreamProbe 23 | * @constructor 24 | * @param [initParams] {Object} Probe initialization parameters 25 | * @param [initParams.pattern=*] {String} Stat name pattern to monitor (see Stat) 26 | * @param [initParams.interval=1000] {Numeric} Queue interval (see StreamProbe) 27 | * @param model {Object} Monitor data model elements 28 | * @param model.bundle {Stat array} Array of Stat elements. 29 | * @param model.bundle.timestamp {String} Timestamp of the stat entry 30 | * @param model.bundle.module {String} Stat module 31 | * @param model.bundle.name {String} Stat name 32 | * @param model.bundle.value {Numeric} Stat value 33 | * @param model.bundle.type {String} 'c'ounter, 'g'ague, or 'ms'timer 34 | * @param model.sequence {Integer} A numeric incrementer causing a change event 35 | */ 36 | var StatProbe = Monitor.StatProbe = StreamProbe.extend({ 37 | 38 | probeClass: 'Stat', 39 | 40 | defaults: _.extend({}, StreamProbe.prototype.defaults, { 41 | pattern: DEFAULT_PATTERN 42 | }), 43 | 44 | initialize: function(){ 45 | var t = this; 46 | 47 | // Call parent constructor 48 | StreamProbe.prototype.initialize.apply(t, arguments); 49 | 50 | // The watcher just forwards all args to queueItem as an array 51 | t.watcher = function() { 52 | // Add timestamp as the first element 53 | var logElems = _.toArray(arguments); 54 | logElems.splice(0,0,JSON.stringify(new Date()).substr(1,24)); 55 | t.queueItem.call(t, logElems); 56 | }; 57 | Stat.on(t.get('pattern'), t.watcher); 58 | }, 59 | 60 | release: function() { 61 | var t = this; 62 | Stat.off(t.get('pattern'), t.watcher); 63 | } 64 | 65 | }); 66 | 67 | }(this)); 68 | -------------------------------------------------------------------------------- /lib/probes/LogProbe.js: -------------------------------------------------------------------------------- 1 | // LogProbe.js (c) 2010-2013 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/monitor-min 5 | (function(root) { 6 | 7 | // Module loading - this runs server-side only 8 | var Monitor = root.Monitor || require('../Monitor'), 9 | _ = Monitor._, 10 | StreamProbe = Monitor.StreamProbe, 11 | Log = Monitor.Log; 12 | 13 | // Constants 14 | var DEFAULT_PATTERN = '*'; 15 | 16 | /** 17 | * Remote application log monitoring 18 | * 19 | * This probe forwards application logs to the monitor. 20 | * 21 | * @class LogProbe 22 | * @extends StreamProbe 23 | * @constructor 24 | * @param [initParams] {Object} Probe initialization parameters 25 | * @param [initParams.pattern=*] {String} Log name pattern to monitor (see Log) 26 | * @param [initParams.interval=1000] {Numeric} Queue interval (see StreamProbe) 27 | * @param model {Object} Monitor data model elements 28 | * @param model.bundle {Log array} Array of Log elements. 29 | * @param model.bundle.timestamp {String} Timestamp of the log statement 30 | * @param model.bundle.logType {String} Log type (error, info, etc) 31 | * @param model.bundle.module {String} Module that emitted the log 32 | * @param model.bundle.name {String} Log entry name 33 | * @param model.bundle.args {any[]} Arguments to the log statement 34 | * @param model.sequence {Integer} A numeric incrementer causing a change event 35 | */ 36 | var LogProbe = Monitor.LogProbe = StreamProbe.extend({ 37 | 38 | probeClass: 'Log', 39 | 40 | defaults: _.extend({}, StreamProbe.prototype.defaults, { 41 | pattern: DEFAULT_PATTERN 42 | }), 43 | 44 | initialize: function(){ 45 | var t = this; 46 | 47 | // Call parent constructor 48 | StreamProbe.prototype.initialize.apply(t, arguments); 49 | 50 | // The watcher just forwards all args to queueItem as an array 51 | t.watcher = function() { 52 | // Add timestamp as the first element 53 | var logElems = _.toArray(arguments); 54 | logElems.splice(0,0,JSON.stringify(new Date()).substr(1,24)); 55 | t.queueItem.call(t, logElems); 56 | }; 57 | Log.on(t.get('pattern'), t.watcher); 58 | }, 59 | 60 | release: function() { 61 | var t = this; 62 | Log.off(t.get('pattern'), t.watcher); 63 | } 64 | 65 | }); 66 | 67 | }(this)); 68 | -------------------------------------------------------------------------------- /monitor.js: -------------------------------------------------------------------------------- 1 | // monitor.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | // Load dependencies 8 | var Monitor = require('./lib/index'), 9 | log = Monitor.getLogger('monitor'), 10 | stat = Monitor.getStatLogger('monitor'), 11 | OS = require('os'); 12 | 13 | /** 14 | * Bootstrap for a standalone monitor server 15 | * 16 | * @static 17 | * @class server 18 | */ 19 | 20 | console.log(""); 21 | console.log(" __________"); 22 | console.log("_______ ___________________(_)_ /______________ _______ ______(_)______ "); 23 | console.log("__ __ `__ \\ __ \\_ __ \\_ /_ __/ __ \\_ ___/________ __ `__ \\_ /__ __ \\"); 24 | console.log("_ / / / / / /_/ / / / / / / /_ / /_/ / / _/_____/ / / / / / / _ / / /"); 25 | console.log("/_/ /_/ /_/\\____//_/ /_//_/ \\__/ \\____//_/ /_/ /_/ /_//_/ /_/ /_/ "); 26 | console.log(""); 27 | 28 | // Boot the monitor server. 29 | // This accepts websocket connections on the configured port. 30 | var server = new Monitor.Server(); 31 | server.start(function(error) { 32 | if (error) { 33 | log.error('monitor-min.start', error); 34 | return; 35 | } 36 | 37 | var connectTo = Monitor.Config.MonitorMin.allowExternalConnections ? OS.hostname() : 'localhost'; 38 | console.log('Headless monitor service started on host: ' + connectTo); 39 | 40 | // Output security concerns 41 | if (!Monitor.Config.MonitorMin.allowExternalConnections) { 42 | console.log(""); 43 | console.log("External connections disabled."); 44 | console.log("See " + process.cwd() + "/config/external.js for more information."); 45 | } 46 | 47 | }); 48 | 49 | // Process uncaught exceptions. 50 | process.on('uncaughtException', function(err){ 51 | 52 | // On laptop sleep/startup the DNS servers aren't immediately available, 53 | // resulting in a flood of these for socket.io until DNS services are back up. 54 | if (err.message === 'ECONNREFUSED, Could not contact DNS servers') { 55 | return; 56 | } 57 | 58 | // Don't allow the process to continue in an unknown state. 59 | log.fatal('moniotor-min.uncaught', 'Uncaught Exception: ' + err.message); 60 | log.fatal('moniotor-min.uncaught', err.stack); 61 | server.stop(function(){ 62 | process.exit(1); 63 | }); 64 | 65 | // Don't wait around if the server is hung. 66 | setTimeout(function(){process.exit(1);}, 2000); 67 | }); 68 | 69 | }(this)); 70 | -------------------------------------------------------------------------------- /test/ServerTest.js: -------------------------------------------------------------------------------- 1 | // ServerTest.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | // Dependencies 8 | var Monitor = require('../lib/index'), 9 | Server = Monitor.Server, Backbone = Monitor.Backbone; 10 | 11 | /** 12 | * Unit tests for the Server class. 13 | * @class ServerTest 14 | */ 15 | 16 | /** 17 | * Test group for baseline Server functionality 18 | * 19 | * @method Server 20 | */ 21 | module.exports['Server'] = { 22 | 23 | setUp: function(callback) {callback();}, 24 | tearDown: function(callback) {callback();}, 25 | 26 | /** 27 | * Tests that Server classes are in place 28 | * @method Server-Classes 29 | */ 30 | Classes: function(test) { 31 | test.ok(Server.prototype instanceof Backbone.Model, 'The Server data model is in place'); 32 | test.ok(Server.List.prototype instanceof Backbone.Collection, 'The Server.List collection is in place'); 33 | test.done(); 34 | }, 35 | 36 | /** 37 | * Start and Stop a server 38 | * @method Server-StartStop 39 | */ 40 | StartStop: function(test) { 41 | var server = new Monitor.Server(); 42 | server.on('start', function() { 43 | test.ok(server.get('port') > 0, 'The server started accepting connections on a port'); 44 | server.stop(function(){ 45 | test.ok(true, 'The server has stopped'); 46 | test.done(); 47 | }); 48 | }); 49 | server.start(); 50 | }, 51 | 52 | /** 53 | * Verify multiple servers start on different ports 54 | * @method Server-MultipleStartStop 55 | */ 56 | MultipleStartStop: function(test) { 57 | var server1 = new Monitor.Server(), port1, port2; 58 | server1.on('start', function() { 59 | port1 = server1.get('port'); 60 | test.ok(port1 >= Monitor.Config.MonitorMin.serviceBasePort, 'The server started in the correct port range'); 61 | var server2 = new Monitor.Server(); 62 | server2.on('start', function() { 63 | port2 = server2.get('port'); 64 | test.notEqual(port1, port2, 'Two servers started on two different ports'); 65 | server1.stop(function(){ 66 | server2.stop(function(){ 67 | test.ok(true, 'Both servers have stopped'); 68 | test.done(); 69 | }); 70 | }); 71 | }); 72 | server2.start(); 73 | }); 74 | server1.start(); 75 | } 76 | 77 | }; 78 | 79 | }(this)); 80 | -------------------------------------------------------------------------------- /test/ConnectionTest.js: -------------------------------------------------------------------------------- 1 | // ConnectionTest.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | // Dependencies 8 | var Monitor = require('../lib/index'), 9 | Connection = Monitor.Connection, Backbone = Monitor.Backbone, 10 | server, serverPort; 11 | 12 | /** 13 | * Unit tests for the Connection class. 14 | * @class ConnectionTest 15 | */ 16 | 17 | /** 18 | * Test group for connection functionality 19 | * @method Connection 20 | */ 21 | module.exports['Connection'] = { 22 | 23 | /** 24 | * Create a Server to test connections with 25 | * @method Connection-setUp 26 | */ 27 | setUp: function(callback) { 28 | server = new Monitor.Server(); 29 | server.start(callback); 30 | }, 31 | 32 | /** 33 | * Tests that the Connection classes are available 34 | * @method Connection-Classes 35 | */ 36 | Classes: function(test) { 37 | test.ok(Connection.prototype instanceof Backbone.Model, 'The Connection data model is in place'); 38 | test.ok(Connection.List.prototype instanceof Backbone.Collection, 'The Connection.List collection is in place'); 39 | test.done(); 40 | }, 41 | 42 | /** 43 | * Assure that a connect / disconnect to the server host/port works 44 | * @method Connection-ConnectDisconnect 45 | */ 46 | ConnectDisconnect: function(test) { 47 | var port = server.get('port'), conn = new Monitor.Connection({hostName:'localhost', hostPort:port}); 48 | conn.on('connect', function() { 49 | test.ok(conn.get('remoteHostName'), 'The remote host name is known'); 50 | conn.on('disconnect', test.done); 51 | conn.disconnect(); 52 | }); 53 | }, 54 | 55 | /** 56 | * Test pinging the remote connection 57 | * @method Connection-PingPong 58 | */ 59 | PingPong: function(test) { 60 | var port = server.get('port'), conn = new Monitor.Connection({hostName:'localhost', hostPort:port}); 61 | conn.on('connect', function() { 62 | test.ok(conn.get('remoteHostName'), 'The remote host name is known'); 63 | conn.ping(function(){ 64 | test.ok(true, 'Ping made its way to and from the remote server'); 65 | conn.on('disconnect', test.done); 66 | conn.disconnect(); 67 | }); 68 | }); 69 | }, 70 | 71 | /** 72 | * Tear down the test Server 73 | * @method Connection-tearDown 74 | */ 75 | tearDown: function(callback) { 76 | server.stop(callback); 77 | } 78 | 79 | }; 80 | 81 | }(this)); 82 | -------------------------------------------------------------------------------- /doc/assets/js/api-search.js: -------------------------------------------------------------------------------- 1 | YUI.add('api-search', function (Y) { 2 | 3 | var Lang = Y.Lang, 4 | Node = Y.Node, 5 | YArray = Y.Array; 6 | 7 | Y.APISearch = Y.Base.create('apiSearch', Y.Base, [Y.AutoCompleteBase], { 8 | // -- Public Properties ---------------------------------------------------- 9 | RESULT_TEMPLATE: 10 | '
  • ' + 11 | '' + 12 | '

    {name}

    ' + 13 | '{resultType}' + 14 | '
    {description}
    ' + 15 | '{class}' + 16 | '
    ' + 17 | '
  • ', 18 | 19 | // -- Initializer ---------------------------------------------------------- 20 | initializer: function () { 21 | this._bindUIACBase(); 22 | this._syncUIACBase(); 23 | }, 24 | 25 | // -- Protected Methods ---------------------------------------------------- 26 | _apiResultFilter: function (query, results) { 27 | // Filter components out of the results. 28 | return YArray.filter(results, function (result) { 29 | return result.raw.resultType === 'component' ? false : result; 30 | }); 31 | }, 32 | 33 | _apiResultFormatter: function (query, results) { 34 | return YArray.map(results, function (result) { 35 | var raw = Y.merge(result.raw), // create a copy 36 | desc = raw.description || ''; 37 | 38 | // Convert description to text and truncate it if necessary. 39 | desc = Node.create('
    ' + desc + '
    ').get('text'); 40 | 41 | if (desc.length > 65) { 42 | desc = Y.Escape.html(desc.substr(0, 65)) + ' …'; 43 | } else { 44 | desc = Y.Escape.html(desc); 45 | } 46 | 47 | raw['class'] || (raw['class'] = ''); 48 | raw.description = desc; 49 | 50 | // Use the highlighted result name. 51 | raw.name = result.highlighted; 52 | 53 | return Lang.sub(this.RESULT_TEMPLATE, raw); 54 | }, this); 55 | }, 56 | 57 | _apiTextLocator: function (result) { 58 | return result.displayName || result.name; 59 | } 60 | }, { 61 | // -- Attributes ----------------------------------------------------------- 62 | ATTRS: { 63 | resultFormatter: { 64 | valueFn: function () { 65 | return this._apiResultFormatter; 66 | } 67 | }, 68 | 69 | resultFilters: { 70 | valueFn: function () { 71 | return this._apiResultFilter; 72 | } 73 | }, 74 | 75 | resultHighlighter: { 76 | value: 'phraseMatch' 77 | }, 78 | 79 | resultListLocator: { 80 | value: 'data.results' 81 | }, 82 | 83 | resultTextLocator: { 84 | valueFn: function () { 85 | return this._apiTextLocator; 86 | } 87 | }, 88 | 89 | source: { 90 | value: '/api/v1/search?q={query}&count={maxResults}' 91 | } 92 | } 93 | }); 94 | 95 | }, '3.4.0', {requires: [ 96 | 'autocomplete-base', 'autocomplete-highlighters', 'autocomplete-sources', 97 | 'escape' 98 | ]}); 99 | -------------------------------------------------------------------------------- /test/InspectTest.js: -------------------------------------------------------------------------------- 1 | // InspectTest.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | // Dependencies 8 | var Monitor = require('../lib/index'), 9 | InspectProbe = Monitor.InspectProbe, 10 | Backbone = Monitor.Backbone, _ = Monitor._; 11 | 12 | /** 13 | * Unit tests for the Inspect probe. 14 | * @class InspectTest 15 | */ 16 | 17 | /** 18 | * Test group for baseline Inspect probe functionality 19 | * 20 | * @method Inspect 21 | */ 22 | module.exports['Inspect'] = { 23 | 24 | /** 25 | * Tests that classes are in correct 26 | * @method Inspect-Classes 27 | */ 28 | Classes: function(test) { 29 | test.ok(InspectProbe.prototype instanceof Backbone.Model, 'The data model is in place'); 30 | test.ok(InspectProbe.prototype instanceof Monitor.Probe, 'It is a probe'); 31 | test.ok(InspectProbe.prototype instanceof Monitor.PollingProbe, 'It is a polling probe'); 32 | test.done(); 33 | }, 34 | 35 | /** 36 | * Tests the no-param constructor 37 | * @method Inspect-NoParams 38 | */ 39 | NoParams: function(test) { 40 | var monitor = new Monitor({ 41 | probeClass:'Inspect' 42 | }); 43 | monitor.connect(function(error) { 44 | test.ok(!error, "Able to construct a top level inspector"); 45 | var globalValue = monitor.get('value'); 46 | test.ok(typeof globalValue.Monitor !== 'undefined', 'Global object returned'); 47 | monitor.disconnect(function(error){ 48 | test.ok(!error, 'Properly disconnected'); 49 | test.done(); 50 | }); 51 | }); 52 | }, 53 | 54 | /** 55 | * Tests the key parameter as a global variable 56 | * @method Inspect-KeyVariable 57 | */ 58 | KeyVariable: function(test) { 59 | var monitor = new Monitor({ 60 | probeClass:'Inspect', 61 | initParams: { 62 | key: 'Monitor' 63 | } 64 | }); 65 | monitor.connect(function(error) { 66 | test.ok(!error, "Able to inspect a global variable"); 67 | var value = monitor.get('value'); 68 | test.ok(typeof value.Probe !== 'undefined', 'The monitor object was returned'); 69 | monitor.disconnect(function(error){ 70 | test.ok(!error, 'Properly disconnected'); 71 | test.done(); 72 | }); 73 | }); 74 | }, 75 | 76 | /** 77 | * Tests the key parameter as an expression 78 | * @method Inspect-KeyExpression 79 | */ 80 | KeyExpression: function(test) { 81 | var monitor = new Monitor({ 82 | probeClass:'Inspect', 83 | initParams: { 84 | key: 'Monitor.getRouter()' 85 | } 86 | }); 87 | monitor.connect(function(error) { 88 | test.ok(!error, "Able to inspect an expression"); 89 | var value = monitor.get('value'); 90 | test.ok(typeof value.firewall !== 'undefined', 'The expression returned the correct object'); 91 | monitor.disconnect(function(error){ 92 | test.ok(!error, 'Properly disconnected'); 93 | test.done(); 94 | }); 95 | }); 96 | } 97 | 98 | }; 99 | 100 | }(this)); 101 | -------------------------------------------------------------------------------- /lib/probes/PollingProbe.js: -------------------------------------------------------------------------------- 1 | // PollingProbe.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | // Module loading 8 | var Monitor = root.Monitor || require('../Monitor'), Probe = Monitor.Probe, 9 | Cron = Monitor.Cron, _ = Monitor._, Backbone = Monitor.Backbone; 10 | 11 | // Constants 12 | var DEFAULT_POLL_INTERVAL = 1000; 13 | var DEFAULT_CRON_PATTERN = "* * * * * *"; 14 | 15 | /** 16 | * ## Base class for probes that require polling to detect and set model changes. 17 | * 18 | * The probe wakes up every polling interval and executes the poll() method 19 | * in the derived class. 20 | * 21 | * PollingProbes are instantiated with either a polling interval (in milliseconds) 22 | * or a cron pattern. If the polling interval is set, that's what will be used. 23 | * 24 | * The cronPattern isn't available in browser-side probes. 25 | * 26 | * To disable polling, set the pollInterval to 0. 27 | * 28 | * More about cron formats, with examples 29 | * 34 | * 35 | * @class PollingProbe 36 | * @extends Probe 37 | * @constructor 38 | * @param [initParams] {Object} Probe initialization parameters 39 | * @param [initParams.pollInterval] {Integer} Polling interval in milliseconds. Default: null 40 | * @param [initParams.cronPattern] {String} Crontab syle polling pattern. Default once per second: "* * * * * *" 41 | * 42 | * The format is: [second] [minute] [hour] [day of month] [month] [day of week].
    43 | */ 44 | var PollingProbe = Monitor.PollingProbe = Probe.extend({ 45 | defaults: _.extend({}, Probe.prototype.defaults, { 46 | pollInterval: null, 47 | cronPattern: DEFAULT_CRON_PATTERN 48 | }), 49 | initialize: function(){ 50 | var t = this, 51 | pollInterval = t.get('pollInterval'), 52 | cronPattern = t.get('cronPattern'), 53 | poll = function(){t.poll();}; 54 | Probe.prototype.initialize.apply(t, arguments); 55 | 56 | // Override cron for the default 1-second interval 57 | // (this allows the default to work when Cron isn't available) 58 | if (pollInterval == null && cronPattern === DEFAULT_CRON_PATTERN) { 59 | pollInterval = DEFAULT_POLL_INTERVAL; 60 | } 61 | 62 | // Poll once, then set up the interval 63 | t.poll(); 64 | if (pollInterval !== 0) { 65 | if (pollInterval) { 66 | t.timer = setInterval(poll, pollInterval); 67 | } else { 68 | if (!Cron) { 69 | throw new Error("Cron is not available in this client"); 70 | } 71 | t.cronJob = new Cron.CronJob(cronPattern, poll); 72 | } 73 | } 74 | }, 75 | release: function(){ 76 | var t = this, timer = (t.cronJob ? t.cronJob.timer : t.timer); 77 | if (t.cronJob && !t.cronJob.initiated) { 78 | // If cron isn't initiated we've been asked to shut down within the 79 | // first second, and the timer hasn't been set (but will be soon). 80 | setTimeout(function(){clearInterval(t.cronJob.timer);}, 1000); 81 | } else if (t.timer) { 82 | clearInterval(timer); 83 | } 84 | t.timer = t.cron = null; 85 | Probe.prototype.release.apply(t, arguments); 86 | } 87 | 88 | }); 89 | 90 | }(this)); 91 | -------------------------------------------------------------------------------- /lib/probes/StreamProbe.js: -------------------------------------------------------------------------------- 1 | // StreamProbe.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | // Module loading 8 | var Monitor = root.Monitor || require('../Monitor'), 9 | Probe = Monitor.Probe, 10 | _ = Monitor._; 11 | 12 | // Constants 13 | var DEFAULT_BUNDLE_INTERVAL = 1000; 14 | 15 | /** 16 | * Base class for probes that stream data 17 | * 18 | * Offering real time data streaming can result in degraded performance due 19 | * to the I/O overhead of sending individual stream elements to remote monitors. 20 | * 21 | * This class eases that overhead by bundling stream elements, and sending those 22 | * bundles in scheduled intervals. The monitor gets to decide the interval based 23 | * on the stream volume, and their needs. 24 | * 25 | * Derived classes output their stream data as elements of the ```bundle``` 26 | * attribute. 27 | * 28 | * A ```sequence``` attribute is incremented sequentially to assure change 29 | * events are fired, and to allow clients to insure stream ordering and 30 | * completeness. 31 | * 32 | * @class StreamProbe 33 | * @extends Probe 34 | * @constructor 35 | * @param [initParams] {Object} Probe initialization parameters 36 | * @param [initParams.interval=1000] {Numeric} Number of milliseconds 37 | * to wait between bundles. 38 | */ 39 | var StreamProbe = Monitor.StreamProbe = Probe.extend({ 40 | 41 | 42 | defaults: _.extend({}, Probe.prototype.defaults, { 43 | bundle: [], 44 | interval: DEFAULT_BUNDLE_INTERVAL, 45 | sequence: 0 46 | }), 47 | 48 | initialize: function(){ 49 | var t = this; 50 | 51 | // Initialize parent 52 | Probe.prototype.initialize.apply(t, arguments); 53 | 54 | // Moving the interval into an instance variable for performance 55 | t.interval = t.get('interval'); 56 | 57 | // Set up for the first bundle 58 | t.queue = []; 59 | t.timer = null; 60 | t.lastSendTime = 0; 61 | }, 62 | 63 | /** 64 | * Queue an item in the stream 65 | * 66 | * This method places the item into the stream and outputs it to the 67 | * monitor, or queues it up for the next bundle. 68 | * 69 | * @method queueItem 70 | * @param item {Any} Item to place into the queue 71 | */ 72 | queueItem: function(item) { 73 | var t = this, 74 | now = Date.now(), 75 | msSinceLastSend = now - t.lastSendTime; 76 | 77 | // Queue the item 78 | t.queue.push(item); 79 | 80 | // Send the bundle? 81 | if (msSinceLastSend > t.interval) { 82 | // It's been a while since the last send. Send it now. 83 | t._send(); 84 | } 85 | else { 86 | // Start the timer if it's not already running 87 | if (!t.timer) { 88 | t.timer = setTimeout(function(){ 89 | t._send(); 90 | }, t.interval - msSinceLastSend); 91 | } 92 | } 93 | }, 94 | 95 | /** 96 | * Send the bundle to the montitor 97 | * 98 | * @private 99 | * @method _send 100 | */ 101 | _send: function() { 102 | var t = this, 103 | now = Date.now(); 104 | 105 | // This kicks off the send 106 | t.lastSendTime = now; 107 | t.set({ 108 | bundle: t.queue, 109 | sequence: t.get('sequence') + 1 110 | }); 111 | 112 | // Reset 113 | t.queue = []; 114 | if (t.timer) { 115 | clearTimeout(t.timer); 116 | t.timer = null; 117 | } 118 | } 119 | 120 | }); 121 | 122 | }(this)); 123 | -------------------------------------------------------------------------------- /grunt.js: -------------------------------------------------------------------------------- 1 | // grunt.js (c) 2010-2013 Loren West and other contributors 2 | // May be freely distributed under the MIT license. 3 | // For all details and documentation: 4 | // http://lorenwest.github.com/monitor-min 5 | 6 | var exec = require('child_process').exec; 7 | 8 | // This is used in the build automation tasks, and on the server 9 | // when running in dev mode to serve individual files for debugging. 10 | var MODULE_DEF = { 11 | lib: [ 12 | "lib/Monitor.js", 13 | "lib/Stat.js", 14 | "lib/Log.js", 15 | "lib/Probe.js", 16 | "lib/Connection.js", 17 | "lib/Server.js", 18 | "lib/Router.js", 19 | "lib/Sync.js", 20 | "lib/probes/PollingProbe.js", 21 | "lib/probes/StreamProbe.js", 22 | "lib/probes/InspectProbe.js", 23 | "lib/probes/StatProbe.js", 24 | "lib/probes/LogProbe.js" 25 | ], 26 | ext: [ 27 | "node_modules/underscore/underscore.js", 28 | "node_modules/backbone/backbone.js", 29 | "node_modules/backbone-callbacks/backbone-callbacks.js", 30 | "node_modules/socket.io-client/dist/socket.io.js" 31 | ], 32 | probes: [ 33 | "lib/probes/FileProbe.js", 34 | "lib/probes/ReplProbe.js", 35 | "lib/probes/ProcessProbe.js", 36 | "lib/probes/SyncProbe.js", 37 | "lib/probes/FileSyncProbe.js" 38 | ] 39 | }; 40 | 41 | // Build automation tasks 42 | module.exports = function(grunt) { 43 | 44 | // Project configuration. 45 | grunt.initConfig({ 46 | pkg: '', 47 | monitor: MODULE_DEF, 48 | meta: { 49 | banner: '/* <%= pkg.name %> - v<%= pkg.version %> - ' + 50 | '<%= grunt.template.today("yyyy-mm-dd") %> */' 51 | }, 52 | lint: { 53 | files: ['grunt.js', '', '', 'test/*.js'] 54 | }, 55 | test: { 56 | files: ['test/*.js'] 57 | }, 58 | watch: { 59 | files: ['grunt.js', 'yuidoc.json', '', '', 'config/doc/**', 'test/*.js'], 60 | tasks: 'doc lint test' 61 | }, 62 | concat: { 63 | lib: { 64 | src: ['', ''], 65 | dest: './dist/monitor-min.js' 66 | }, 67 | all: { 68 | src: ['', '', ''], 69 | dest: './dist/monitor-min-all.js' 70 | } 71 | }, 72 | min: { 73 | lib: { 74 | src: ['', './dist/monitor-min.js'], 75 | dest: './dist/monitor-min.min.js' 76 | 77 | }, 78 | all: { 79 | src: ['', './dist/monitor-min-all.js'], 80 | dest: './dist/monitor-min-all.min.js' 81 | } 82 | }, 83 | jshint: { 84 | options: { 85 | strict: false, 86 | curly: true, 87 | eqeqeq: true, 88 | immed: true, 89 | latedef: true, 90 | newcap: true, 91 | noarg: true, 92 | sub: true, 93 | undef: true, 94 | boss: true, 95 | eqnull: true, 96 | node: true 97 | }, 98 | globals: { 99 | exports: true 100 | } 101 | } 102 | }); 103 | 104 | grunt.registerTask('doc', 'Generate documentation files', function() { 105 | var t = this, done = t.async(), child, version = grunt.config.get('pkg').version; 106 | var cmd = 'yuidoc --project-version ' + version; 107 | console.log(cmd); 108 | child = exec(cmd, function (error, stdout, stderr) { 109 | console.log(stderr); 110 | console.log(stdout); 111 | cmd = 'cp -R doc/* ../lorenwest.github.com/monitor-min'; 112 | console.log(cmd); 113 | child = exec(cmd, function (error, stdout, stderr) { 114 | console.log(stderr); 115 | console.log(stdout); 116 | done(); 117 | }); 118 | }); 119 | }); 120 | 121 | grunt.registerTask('rm_dist', 'Remove distribution files', function() { 122 | var t = this, done = t.async(), child; 123 | child = exec('rm -f dist/*', function (error, stdout, stderr) { 124 | console.log(stderr); 125 | console.log(stdout); 126 | done(); 127 | }); 128 | }); 129 | 130 | // Default task. 131 | grunt.registerTask('default', 'doc lint test dist'); 132 | grunt.registerTask('dist', 'rm_dist concat:lib concat:all min:lib min:all'); 133 | 134 | }; 135 | 136 | // Expose externally 137 | module.exports.MODULE_DEF = MODULE_DEF; 138 | -------------------------------------------------------------------------------- /config/doc/partials/props.handlebars: -------------------------------------------------------------------------------- 1 |
    2 |

    3 | {{name}} 4 |

    5 | {{#crossLink type}}{{/crossLink}} 6 | 7 | {{#if deprecated}} 8 | deprecated 9 | {{/if}} 10 | 11 | {{#if access}} 12 | {{access}} 13 | {{/if}} 14 | 15 | {{#if final}} 16 | final 17 | {{/if}} 18 | 19 | {{#if static}} 20 | static 21 | {{/if}} 22 | 23 |
    24 | {{#if overwritten_from}} 25 |

    Inherited from 26 | 27 | {{overwritten_from/class}} 28 | 29 | {{#if foundAt}} 30 | but overwritten in 31 | {{/if}} 32 | {{else}} 33 | {{#if extended_from}} 34 |

    Inherited from 35 | {{extended_from}}: 36 | {{else}} 37 | {{#providedBy}} 38 |

    Provided by the {{.}} module.

    39 | {{/providedBy}} 40 |

    41 | {{/if}} 42 | {{/if}} 43 |

    44 | 45 | {{#if deprecationMessage}} 46 |

    Deprecated: {{deprecationMessage}}

    47 | {{/if}} 48 | 49 | {{#if since}} 50 |

    Available since {{since}}

    51 | {{/if}} 52 |
    53 | 54 |
    55 | {{{propertyDescription}}} 56 |
    57 | 58 | {{#if default}} 59 |

    Default: {{default}}

    60 | {{/if}} 61 | 62 | {{#example}} 63 |
    64 |

    Example:

    65 | 66 |
    67 | {{{.}}} 68 |
    69 |
    70 | {{/example}} 71 | 72 | {{#if subprops}} 73 |

    Sub-properties:

    74 | 75 |
      76 | {{#subprops}} 77 |
    • 78 | {{#if optional}} 79 | [{{name}}{{#if optdefault}}={{optdefault}}{{/if}}] 80 | {{#crossLink type}}{{/crossLink}} 81 | optional 82 | {{else}} 83 | {{name}} 84 | {{#crossLink type}}{{/crossLink}} 85 | {{/if}} 86 | 87 |
      88 | {{{description}}} 89 |
      90 | 91 | {{#if subprops}} 92 |
        93 | {{#subprops}} 94 |
      • 95 | {{#if optional}} 96 | [{{name}}{{#if optdefault}}={{optdefault}}{{/if}}] 97 | {{#crossLink type}}{{/crossLink}} 98 | optional 99 | {{else}} 100 | {{name}} 101 | {{#crossLink type}}{{/crossLink}} 102 | {{/if}} 103 | 104 |
        105 | {{{description}}} 106 |
        107 |
      • 108 | {{/subprops}} 109 |
      110 | {{/if}} 111 |
    • 112 | {{/subprops}} 113 |
    114 | {{/if}} 115 |
    116 | -------------------------------------------------------------------------------- /test/ProbeTest.js: -------------------------------------------------------------------------------- 1 | // ProbeTest.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | // Dependencies 8 | var Monitor = require('../lib/index'), 9 | Probe = Monitor.Probe, PollingProbe = Monitor.PollingProbe, 10 | Backbone = Monitor.Backbone, _ = Monitor._; 11 | 12 | /** 13 | * Unit tests for the Probe class. 14 | * @class ProbeTest 15 | */ 16 | 17 | /** 18 | * Tests for Probe functionality 19 | * 20 | * @method ProbeTest 21 | */ 22 | // Test that important namespaces are available 23 | var probeTests = module.exports['ProbeTest'] = { 24 | 25 | /** 26 | * Tests that Probe classes are in place 27 | * @method ProbeTest-Classes 28 | */ 29 | Classes: function(test) { 30 | test.ok(Probe.prototype instanceof Backbone.Model, 'The Probe data model is in place'); 31 | test.ok(Probe.List.prototype instanceof Backbone.Collection, 'The Probe.List collection is in place'); 32 | test.ok(PollingProbe.prototype instanceof Probe, 'The PollingProbe base constructor is in place'); 33 | test.done(); 34 | }, 35 | 36 | /** 37 | * Tests Probe instantiation 38 | * @method ProbeTest-Instantiate 39 | */ 40 | Instantiate: function(test) { 41 | var process = probeTests.processMonitor = new Monitor({probeClass:'Process', initParams:{a:'b', pollInterval:100}}); 42 | process.connect(function(err) { 43 | test.ifError(err); 44 | test.notEqual(process.get('probeId'), null, "Probe ID isn't null"); 45 | test.done(); 46 | }); 47 | }, 48 | 49 | /** 50 | * Test the same ID on subsequent probe instantiation with similar init params 51 | * @method ProbeTest-SameProbe 52 | */ 53 | SameProbe: function(test) { 54 | var process = new Monitor({probeClass:'Process', initParams:{pollInterval:100, a:'b'}}); 55 | process.connect(function(err) { 56 | test.ifError(err); 57 | test.notEqual(process.get('probeId'), null, "Probe ID isn't null"); 58 | test.equal(probeTests.processMonitor.get('probeId'), process.get('probeId'), "Probes are the same with similar init params."); 59 | process.disconnect(); 60 | test.done(); 61 | }); 62 | }, 63 | 64 | /** 65 | * Test that different init params result in a different probe 66 | * @method ProbeTest-DifferentProbe 67 | */ 68 | DifferentProbe: function(test) { 69 | var process = new Monitor({probeClass:'Process', initParams:{pollInterval:1000, a:'b'}}); 70 | process.connect(function(err) { 71 | test.ifError(err); 72 | test.notEqual(process.get('probeId'), null, "Probe ID isn't null"); 73 | test.notEqual(probeTests.processMonitor.get('probeId'), process.get('probeId'), "Probes are different with different init params."); 74 | process.disconnect(); 75 | test.done(); 76 | }); 77 | }, 78 | 79 | /** 80 | * Tests remote control functionality 81 | * @method ProbeTest-RemoteControl 82 | */ 83 | RemoteControl: function(test) { 84 | var monitor = probeTests.processMonitor; 85 | monitor.control('ping', function(error, result) { 86 | test.ifError(error); 87 | test.equals(result, 'pong', 'Ping returned pong'); 88 | test.done(); 89 | }); 90 | }, 91 | 92 | /** 93 | * Test remote control failure (no control method) 94 | * @method ProbeTest-RemoteControlFail 95 | */ 96 | RemoteControlFail: function(test) { 97 | var monitor = probeTests.processMonitor; 98 | monitor.control('pingPong', function(error, result) { 99 | test.ok(error != null, 'Correctly errored on un-available control method'); 100 | test.done(); 101 | }); 102 | }, 103 | 104 | /** 105 | * Test the change event 106 | * @method ProbeTest-ChangeEvent 107 | */ 108 | ChangeEvent: function(test) { 109 | var monitor = probeTests.processMonitor; 110 | var onChange = function(){ 111 | monitor.off('change', onChange); 112 | var changes = monitor.changedAttributes(); 113 | test.ok(_.size(changes) > 0, 'Attribute changes came through'); 114 | test.done(); 115 | }; 116 | monitor.on('change', onChange); 117 | }, 118 | 119 | /** 120 | * Tests that Probe clean up works 121 | * @method ProbeTest-Cleanup 122 | */ 123 | Cleanup: function(test) { 124 | var monitor = probeTests.processMonitor; 125 | monitor.disconnect(function(error) { 126 | test.ifError(error); 127 | test.done(); 128 | }); 129 | } 130 | 131 | }; 132 | 133 | }(this)); 134 | -------------------------------------------------------------------------------- /config/doc/partials/events.handlebars: -------------------------------------------------------------------------------- 1 |
    2 |

    3 | {{name}} 4 |

    5 | {{#crossLink type}}{{/crossLink}} 6 | 7 | {{#if deprecated}} 8 | deprecated 9 | {{/if}} 10 | 11 | {{#if access}} 12 | {{access}} 13 | {{/if}} 14 | 15 | {{#if final}} 16 | final 17 | {{/if}} 18 | 19 | {{#if static}} 20 | static 21 | {{/if}} 22 | 23 |
    24 | {{#if overwritten_from}} 25 |

    Inherited from 26 | 27 | {{overwritten_from/class}} 28 | 29 | {{#if foundAt}} 30 | but overwritten in 31 | {{/if}} 32 | {{else}} 33 | {{#if extended_from}} 34 |

    Inherited from 35 | {{extended_from}}: 36 | {{else}} 37 | {{#providedBy}} 38 |

    Provided by the {{.}} module.

    39 | {{/providedBy}} 40 |

    41 | {{/if}} 42 | {{/if}} 43 |

    44 | 45 | {{#if deprecationMessage}} 46 |

    Deprecated: {{deprecationMessage}}

    47 | {{/if}} 48 | 49 | {{#if since}} 50 |

    Available since {{since}}

    51 | {{/if}} 52 |
    53 | 54 |
    55 | {{{eventDescription}}} 56 |
    57 | 58 | {{#if params}} 59 |
    60 |

    Event Payload:

    61 | 62 |
      63 | {{#params}} 64 |
    • 65 | {{#if optional}} 66 | [{{name}}{{#if optdefault}}={{optdefault}}{{/if}}] 67 | {{#crossLink type}}{{/crossLink}} 68 | optional 69 | {{else}} 70 | {{name}} 71 | {{#crossLink type}}{{/crossLink}} 72 | {{/if}} 73 | 74 | {{#if multiple}} 75 | Multiple 76 | {{/if}} 77 | 78 |
      79 | {{{description}}} 80 |
      81 | 82 | {{#if props}} 83 |
        84 | {{#props}} 85 |
      • 86 | {{name}} 87 | {{#crossLink type}}{{/crossLink}} 88 | 89 |
        90 | {{{description}}} 91 |
        92 | 93 | {{#if props}} 94 |
          95 | {{#props}} 96 |
        • 97 | {{name}} 98 | {{#crossLink type}}{{/crossLink}} 99 | 100 |
          101 | {{{description}}} 102 |
          103 |
        • 104 | {{/props}} 105 |
        106 | {{/if}} 107 |
      • 108 | {{/props}} 109 |
      110 | {{/if}} 111 |
    • 112 | {{/params}} 113 |
    114 |
    115 | {{/if}} 116 | 117 | 118 | {{#example}} 119 |
    120 |

    Example:

    121 | 122 |
    123 | {{{.}}} 124 |
    125 |
    126 | {{/example}} 127 |
    128 | -------------------------------------------------------------------------------- /lib/probes/ProcessProbe.js: -------------------------------------------------------------------------------- 1 | // ProcessProbe.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | // Module loading - this runs server-side only 8 | var util = require('util'), OS = require('os'), 9 | Monitor = root.Monitor || require('../Monitor'), _ = Monitor._, 10 | logger = Monitor.getLogger('ProcessProbe'), 11 | PollingProbe = Monitor.PollingProbe; 12 | 13 | /** 14 | * Probe for attaining process and O/S information 15 | * 16 | * @class ProcessProbe 17 | * @extends PollingProbe 18 | * @constructor 19 | * @param [initParams] {Object} Probe initialization parameters (from PollingProbe) 20 | * @param [initParams.pollInterval] {Integer} Polling interval in milliseconds. Default: null 21 | * @param [initParams.cronPattern] {String} Crontab syle polling pattern. Default once per second: "* * * * * *" 22 | * @param model {Object} Monitor data model elements 23 | * @param model.platform {String} O/S Platform 24 | * @param model.version {String} Node.js compiled-in version 25 | * @param model.installPrefix {String} Node.js installation directory 26 | * @param model.title {String} The current process title (as reported in ps) 27 | * @param model.execPath {String} The path to the current node.js executable 28 | * @param model.argv {Array(String)} Arguments passed on the command line to this process 29 | * @param model.env {Object} Current environment (inherited) 30 | * @param model.cwd {String} Current working directory 31 | * @param model.uptime {Integer} Number of seconds the process has been up (if available) 32 | * @param model.versions {String} Versions of V8 and dependent libraries (if available) 33 | * @param model.arch {String} Processor architecture (if available) 34 | * @param model.gid {Integer} Process group ID 35 | * @param model.uid {Integer} Process user ID 36 | * @param model.pid {Integer} Unique process ID 37 | * @param model.umask {Integer} The process file mode creation mask 38 | * @param model.memoryUsage {Object} An object describing memory usage of the node.js process 39 | * @param model.memoryUsage.rss {Integer} As defined by process.memoryUsage 40 | * @param model.memoryUsage.vsize {Integer} As defined by process.memoryUsage 41 | * @param model.memoryUsage.heapTotal {Integer} As defined by process.memoryUsage 42 | * @param model.memoryUsage.heapUsed {Integer} As defined by process.memoryUsage 43 | * @param model.os {Object} An object containing O/S information 44 | * @param model.os.hostname {String} Name of the host operating system 45 | * @param model.os.type {String} Operating system type 46 | * @param model.os.release {String} O/S Release version 47 | * @param model.os.uptime {String} O/S Uptime in seconds 48 | * @param model.os.loadavg {Array(Number)} An array containing the 1, 5, and 15 minute load averages 49 | * @param model.os.freemem {Integer} Free O/S memory (in bytes) 50 | * @param model.os.totalmem {Integer} Total O/S memory capacity (in bytes) 51 | * @param model.os.cpus {Array(Object)} An array of objects containing information about each CPU/core installed 52 | */ 53 | var ProcessProbe = Monitor.ProcessProbe = PollingProbe.extend({ 54 | 55 | // These are required for Probes 56 | probeClass: 'Process', 57 | 58 | /* not required 59 | initialize: function(){ 60 | var t = this; 61 | PollingProbe.prototype.initialize.apply(t, arguments); 62 | ... 63 | }, 64 | release: function() { 65 | var t = this; 66 | PollingProbe.prototype.release.apply(t, arguments); 67 | ... // release any resources held 68 | }) 69 | */ 70 | 71 | /** 72 | * Poll the probe for changes 73 | * 74 | * This method is called by the parent PollingProbe on the interval specified by the client Monitor. 75 | * 76 | * It polls for process information, and updates the data model with any changes. 77 | * 78 | * @method poll 79 | */ 80 | poll: function() { 81 | var t = this, 82 | attrs = _.extend({ 83 | platform: process.platform, 84 | version: process.version, 85 | installPrefix: process.installPrefix, 86 | title: process.title, 87 | execPath: process.execPath, 88 | argv: process.argv, 89 | env: process.env, 90 | cwd: process.cwd(), 91 | gid: process.getgid ? process.getgid() : 0, 92 | uid: process.getuid ? process.getuid() : 0, 93 | pid: process.pid, 94 | umask: process.umask(), 95 | hostname: OS.hostname(), 96 | type: OS.type(), 97 | release: OS.release(), 98 | osUptime: OS.uptime(), 99 | loadavg: OS.loadavg(), 100 | freemem: OS.freemem(), 101 | totalmem: OS.totalmem(), 102 | cpus: OS.cpus() 103 | }, process.memoryUsage()); 104 | if (process.uptime) {attrs.uptime = process.uptime();} 105 | if (process.versions) {attrs.versions = process.versions;} 106 | if (process.arch) {attrs.arch = process.arch;} 107 | t.set(attrs); 108 | } 109 | }); 110 | 111 | }(this)); 112 | -------------------------------------------------------------------------------- /lib/probes/InspectProbe.js: -------------------------------------------------------------------------------- 1 | // InspectProbe.js (c) 2010-2013 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/monitor-min 5 | 6 | /* This class is evil. You probably shouldn't use it. Or drink. Or drink while using it. */ 7 | /*jslint evil: true */ 8 | 9 | (function(root){ 10 | 11 | // Module loading - this runs server-side only 12 | var Monitor = root.Monitor || require('../Monitor'), 13 | _ = Monitor._, 14 | Backbone = Monitor.Backbone, 15 | PollingProbe = Monitor.PollingProbe; 16 | 17 | // Constants 18 | var DEFAULT_DEPTH = 2; 19 | 20 | /** 21 | * Inspect and manipulate variables on the monitored server. 22 | * 23 | * This class monitors the variable specified by the key. 24 | * 25 | * The key is evaluated to determine the variable to monitor, so it may 26 | * be a complex key starting at global scope. If the key isn't 27 | * specified, it monitors all variables in the global scope. 28 | * 29 | * If the key points to an object of type Backbone.Model, this probe 30 | * will update the value in real time, triggered on the *change* event. 31 | * Otherwise it will update the value as it notices changes, while polling 32 | * on the specified polling interval (default: 1 second). 33 | * 34 | * @class InspectProbe 35 | * @extends PollingProbe 36 | * @constructor 37 | * @param [initParams] - Initialization parameters 38 | * @param [initParams.key=null] {String} A global variable name or expression 39 | * @param [initParams.depth=2] {Integer} If the key points to an object, this 40 | * is the depth to traverse the object for changes. Default=2, or 1 if 41 | * key='window'. 42 | * @param [initParams.pollInterval] {Integer} (from PollingProbe) Polling interval in milliseconds. Default: null 43 | * @param [initParams.cronPattern] {String} (from PollingProbe) Crontab syle polling pattern. Default once per second: "* * * * * *" 44 | * @param model - Monitor data model elements 45 | * @param model.value - The value of the element being inspected 46 | * @param model.isModel - Is the value a Backbone.Model? 47 | */ 48 | var InspectProbe = Monitor.InspectProbe = PollingProbe.extend({ 49 | 50 | // These are required for Probes 51 | probeClass: 'Inspect', 52 | 53 | initialize: function(initParams){ 54 | var t = this; 55 | 56 | // Get the global object if the key isn't specified 57 | t.key = initParams.key; 58 | if (typeof initParams.key === 'undefined') { 59 | t.key = typeof window === 'undefined' ? 'global' : 'window'; 60 | } 61 | 62 | // Get a good depth default. Default unless key = window. 63 | if (typeof initParams.depth === 'undefined') { 64 | if (!initParams.key && t.key === 'window') { 65 | t.depth = 1; 66 | } else { 67 | t.depth = DEFAULT_DEPTH; 68 | } 69 | } else { 70 | t.depth = initParams.depth; 71 | } 72 | 73 | // Evaluate the expression to see if it's a Backbone.Model 74 | // This will throw an exception if the key is a bad expression 75 | t.value = t._evaluate(t.key); 76 | t.isModel = t.value instanceof Backbone.Model; 77 | 78 | // Set the initial values 79 | t.set({ 80 | value: Monitor.deepCopy(t.value, t.depth), 81 | isModel: t.isModel 82 | }); 83 | 84 | // Watch for backbone model changes, or initialize the polling probe 85 | if (t.isModel) { 86 | t.value.on('change', t.poll, t); 87 | } else { 88 | PollingProbe.prototype.initialize.apply(t, arguments); 89 | } 90 | }, 91 | 92 | // Stop watching for change events or polling 93 | release: function() { 94 | var t = this; 95 | if (t.isModel) { 96 | t.value.off('change', t.poll, t); 97 | } else { 98 | PollingProbe.prototype.release.apply(t, arguments); 99 | } 100 | }, 101 | 102 | /** 103 | * Evaluate an expression, returning the depth-limited results 104 | * 105 | * @method eval_control 106 | * @param expression {String} Expression to evaluate 107 | * @param [depth=2] {Integer} Depth of the object to return 108 | * @return value {Mixed} Returns the depth-limited value 109 | */ 110 | eval_control: function(expression, depth){ 111 | var t = this; 112 | 113 | // Determine a default depth 114 | depth = typeof depth === 'undefined' ? DEFAULT_DEPTH : depth; 115 | 116 | // Get the raw value 117 | var value = t._evaluate(expression); 118 | 119 | // Return the depth limited results 120 | return Monitor.deepCopy(value, depth); 121 | }, 122 | 123 | /** 124 | * Evaluate an expression, returning the raw results 125 | * 126 | * @protected 127 | * @method _evaluate 128 | * @param expression {String} Expression to evaluate 129 | * @return value {Mixed} Returns the expression value 130 | */ 131 | _evaluate: function(expression){ 132 | var t = this, 133 | value = null; 134 | 135 | // Evaluate the expression 136 | try { 137 | value = eval(expression); 138 | } catch (e) { 139 | throw new Error('Unable to evaluate: ' + expression); 140 | } 141 | 142 | // Return the value 143 | return value; 144 | }, 145 | 146 | /** 147 | * Poll for changes in the evaluation 148 | * 149 | * @method poll 150 | */ 151 | poll: function() { 152 | var t = this, 153 | newValue = t.eval_control(t.key, t.depth); 154 | 155 | // Set the new value if it has changed from the current value 156 | if (!_.isEqual(newValue, t.get('value'))) { 157 | t.set({value: newValue}); 158 | } 159 | } 160 | }); 161 | 162 | }(this)); 163 | -------------------------------------------------------------------------------- /doc/assets/vendor/prettify/CHANGES.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Change Log 5 | 6 | 7 | README 8 | 9 |

    Known Issues

    10 |
      11 |
    • Perl formatting is really crappy. Partly because the author is lazy and 12 | partly because Perl is 13 | hard to parse. 14 |
    • On some browsers, <code> elements with newlines in the text 15 | which use CSS to specify white-space:pre will have the newlines 16 | improperly stripped if the element is not attached to the document at the time 17 | the stripping is done. Also, on IE 6, all newlines will be stripped from 18 | <code> elements because of the way IE6 produces 19 | innerHTML. Workaround: use <pre> for code with 20 | newlines. 21 |
    22 | 23 |

    Change Log

    24 |

    29 March 2007

    25 |
      26 |
    • Added tests for PHP support 27 | to address 28 | issue 3. 30 |
    • Fixed 31 | bug: prettyPrintOne was not halting. This was not 33 | reachable through the normal entry point. 34 |
    • Fixed 35 | bug: recursing into a script block or PHP tag that was not properly 37 | closed would not silently drop the content. 38 | (test) 39 |
    • Fixed 40 | bug: was eating tabs 42 | (test) 43 |
    • Fixed entity handling so that the caveat 44 |
      45 |

      Caveats: please properly escape less-thans. x&lt;y 46 | instead of x<y, and use " instead of 47 | &quot; for string delimiters.

      48 |
      49 | is no longer applicable. 50 |
    • Added noisefree's C# 51 | patch 53 |
    • Added a distribution that has comments and 54 | whitespace removed to reduce download size from 45.5kB to 12.8kB. 55 |
    56 |

    4 Jul 2008

    57 |
      58 |
    • Added language specific formatters that are triggered by the presence 59 | of a lang-<language-file-extension>
    • 60 |
    • Fixed bug: python handling of '''string''' 61 |
    • Fixed bug: / in regex [charsets] should not end regex 62 |
    63 |

    5 Jul 2008

    64 |
      65 |
    • Defined language extensions for Lisp and Lua 66 |
    67 |

    14 Jul 2008

    68 |
      69 |
    • Language handlers for F#, OCAML, SQL 70 |
    • Support for nocode spans to allow embedding of line 71 | numbers and code annotations which should not be styled or otherwise 72 | affect the tokenization of prettified code. 73 | See the issue 22 74 | testcase. 75 |
    76 |

    6 Jan 2009

    77 |
      78 |
    • Language handlers for Visual Basic, Haskell, CSS, and WikiText
    • 79 |
    • Added .mxml extension to the markup style handler for 80 | Flex MXML files. See 81 | issue 37. 84 |
    • Added .m extension to the C style handler so that Objective 85 | C source files properly highlight. See 86 | issue 58. 89 |
    • Changed HTML lexer to use the same embedded source mechanism as the 90 | wiki language handler, and changed to use the registered 91 | CSS handler for STYLE element content. 92 |
    93 |

    21 May 2009

    94 |
      95 |
    • Rewrote to improve performance on large files. 96 | See benchmarks.
    • 97 |
    • Fixed bugs with highlighting of Haskell line comments, Lisp 98 | number literals, Lua strings, C preprocessor directives, 99 | newlines in Wiki code on Windows, and newlines in IE6.
    • 100 |
    101 |

    14 August 2009

    102 |
      103 |
    • Fixed prettifying of <code> blocks with embedded newlines. 104 |
    105 |

    3 October 2009

    106 |
      107 |
    • Fixed prettifying of XML/HTML tags that contain uppercase letters. 108 |
    109 |

    19 July 2010

    110 |
      111 |
    • Added support for line numbers. Bug 112 | 22
    • 114 |
    • Added YAML support. Bug 115 | 123
    • 117 |
    • Added VHDL support courtesy Le Poussin.
    • 118 |
    • IE performance improvements. Bug 119 | 102 courtesy jacobly.
    • 121 |
    • A variety of markup formatting fixes courtesy smain and thezbyg.
    • 122 |
    • Fixed copy and paste in IE[678]. 123 |
    • Changed output to use &#160; instead of 124 | &nbsp; so that the output works when embedded in XML. 125 | Bug 126 | 108.
    • 128 |
    129 | 130 | 131 | -------------------------------------------------------------------------------- /lib/probes/SyncProbe.js: -------------------------------------------------------------------------------- 1 | // SyncProbe.js (c) 2010-2013 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 | 7 | // Module loading - this runs server-side only 8 | var Monitor = root.Monitor || require('../Monitor'), 9 | _ = Monitor._, Probe = Monitor.Probe; 10 | 11 | /** 12 | * Probe for exposing backbone data models from server-side persistence 13 | * 14 | * This probe is used by the client-side Sync class 15 | * to connect a local backbone model with server-side storage. 16 | * 17 | * It delegates to a specialized SyncProbe defined by the server for the 18 | * specific data class. For example, the server may determine that one class 19 | * type uses FileSyncProbe, and another class uses a different persistence 20 | * mechanism. 21 | * 22 | * For security purposes, the server must configure specific SyncProbes for 23 | * classes, or a default sync probe before this will operate. 24 | * 25 | * @class SyncProbe 26 | * @extends Probe 27 | * @constructor 28 | * @param className {String} Name of the class to synchronize with 29 | * @param [modelId] {String} Id of the data model for live synchronization 30 | * If not set, a non-live probe is set up for control access only. 31 | * @param [model] {Object} If this is a liveSync probe, this contains 32 | * the attributes of the current model object. 33 | */ 34 | var SyncProbe = Monitor.SyncProbe = Probe.extend({ 35 | 36 | probeClass: 'Sync', 37 | defaults: { 38 | className: null, 39 | modelId: null, 40 | model: null 41 | }, 42 | 43 | initialize: function(attributes, options){ 44 | var t = this; 45 | Probe.prototype.initialize.apply(t, arguments); 46 | 47 | // Determine the probe name based on the class, and coerce this 48 | // object into one of those by copying all prototype methods. 49 | var className = t.get('className'), 50 | config = SyncProbe.Config, 51 | probeClassName = config.classMap[className] || config.defaultProbe, 52 | probeClass = SyncProbe[probeClassName]; 53 | _.each(_.functions(probeClass.prototype), function(methodName) { 54 | t[methodName] = probeClass.prototype[methodName]; 55 | }); 56 | t.probeClass = probeClass.prototype.probeClass; 57 | 58 | // Forward class initialization to the coerced initialize method 59 | return t.initialize.apply(t, arguments); 60 | }, 61 | 62 | release: function() { 63 | var t = this; 64 | Probe.prototype.release.apply(t, arguments); 65 | }, 66 | 67 | /** 68 | * Create and save a new instance of the class into storage 69 | * 70 | * This probe control requests a new instance of a data model to be 71 | * persisted onto storage. It is invoked when a data model that has 72 | * the Sync probe attached calls ```save()``` on a new object. 73 | * 74 | * @method create_control 75 | * @param model {Object} Full data model to save. This must contain 76 | * the id element. 77 | * @param callback {Function(error, result)} Callback when complete 78 | * @param callback.error {Mixed} Set if an error occurs during creation. 79 | * @param callback.result {Object} An object containing any differing 80 | * parameters from the model sent in. Normally a blank object. 81 | */ 82 | create_control: function(args, callback) { 83 | callback({msg: 'not implemented'}); 84 | }, 85 | 86 | /** 87 | * Read an instance from storage 88 | * 89 | * This probe control reads the instance with the specified id 90 | * from storage, and returns it in the callback. 91 | * 92 | * @method read_control 93 | * @param id {String} ID of the object to read 94 | * @param callback {Function(error, result)} Callback when complete 95 | * @param callback.error {Mixed} Set if an error occurs during read. 96 | * if error.code === 'NOTFOUND' then the requested object wasn't found. 97 | * if error.code === 'PARSE' then the document was poorly formatted JSON. 98 | * @param callback.result {Object} The full object. 99 | */ 100 | read_control: function(args, callback) { 101 | callback({msg: 'not implemented'}); 102 | }, 103 | 104 | /** 105 | * Update a data model in storage 106 | * 107 | * This acts like a REST PUT, meaning it can create a new object, or 108 | * update an existing object. 109 | * 110 | * Backbone has only a save() method. If the client sets the ID 111 | * of the object before save(), Backbone thinks the object exists and 112 | * will call update vs. create. 113 | * 114 | * @method update_control 115 | * @param model {Object} Full data model to save. This must contain 116 | * the id element. 117 | * @param callback {Function(error, result)} Callback when complete 118 | * @param callback.error {Mixed} Set if an error occurs during save. 119 | * @param callback.result {Object} An object containing any differing 120 | * parameters from the model sent in. Normally a blank object. 121 | */ 122 | update_control: function(args, callback) { 123 | callback({msg: 'not implemented'}); 124 | }, 125 | 126 | /** 127 | * Delete an instance from storage 128 | * 129 | * This probe control deletes the instance with the specified id 130 | * from storage. 131 | * 132 | * @method delete_control 133 | * @param id {String} ID of the object to read 134 | * @param callback {Function(error)} Callback when complete 135 | * @param callback.error {Mixed} Set if an error occurs during read. 136 | */ 137 | delete_control: function(args, callback) { 138 | callback({msg: 'not implemented'}); 139 | } 140 | 141 | }); 142 | 143 | /** 144 | * Static Configurations 145 | * 146 | * These can be set onto the Monitor.SyncProbe class after it's loaded. 147 | * 148 | * The SyncProbe will *not* work until the defaultProbe is defined. 149 | * 150 | * Example: 151 | * 152 | * var syncConfig = Monitor.SyncProbe.Config; 153 | * syncConfig.defaultProbe = 'FileSyncProbe'; 154 | * syncConfig.classMap = { 155 | * Book: 'MongoDbSync', 156 | * Author: 'MongoDbSync' 157 | * } 158 | * 159 | * @static 160 | * @property Config 161 | * @type <Object> 162 | *
      163 | *
    • defaultProbe (String) Name of the sync probe to use if the class isn't listed in the classMap
    • 164 | *
    • classMap (Object) Map of className to sync probe name to use instead of the default for that class
    • 165 | *
    166 | */ 167 | var defaultConfig = { 168 | defaultProbe: '', 169 | classMap: {} 170 | }; 171 | 172 | // Expose default configurations to the config package 173 | SyncProbe.Config = _.extend({}, defaultConfig); 174 | 175 | }(this)); 176 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | monitor-min 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |
    18 |

    Monitor Min v0.5.12

    19 |
    20 |
    21 |
    22 | 23 |
    24 | 108 |
    109 |
    110 |
    111 | Show: 112 | 116 | 117 | 121 | 122 | 126 |
    127 | 128 | 129 |
    130 |
    131 |
    132 |
    133 |
    134 | 135 |

    Monitor-Min

    136 |

    Remote monitoring and control for your node.js app

    137 | 138 |

    139 | This contains both API and implementation documentation for the monitor package. 140 |

    141 | 142 |

    143 | Class and method interfaces are documented in the modules below, with links to 144 | the underlying implementation. 145 |

    146 | 147 |

    Monitor Core

    148 |

    149 | Classes in this module represent baseline monitor functionality. They can 150 | be loaded and run in a node.js container as well as within a browser. 151 |

    152 | 153 |

    Baseline Probes

    154 |

    155 | The probes in this module offer baseline functionality, and provide examples 156 | for building custom probes. 157 |

    158 | 159 |

    Core Unit Tests

    160 |

    161 | This module contains unit test classes for each of the core classes, and 162 | some unit tests for baseline probes. 163 |

    164 | 165 |
    166 |
    167 | 168 |
    169 |
    170 |
    171 |
    172 |
    173 |
    174 | 177 | 180 |
    181 |
    182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /config/doc/partials/method.handlebars: -------------------------------------------------------------------------------- 1 |
    2 |

    3 | {{name}} 4 |

    5 | 6 | {{#if params}} 7 |
    8 | (
      9 | {{#params}} 10 |
    • 11 | {{#if optional}} 12 | [{{name}}{{#if optdefault}}={{optdefault}}{{/if}}] 13 | {{else}} 14 | {{name}} 15 | {{/if}} 16 |
    • 17 | {{/params}} 18 |
    ) 19 |
    20 | {{else}} 21 | () 22 | {{/if}} 23 | 24 | {{#if return}} 25 | 26 | {{#crossLink returnType}}{{/crossLink}} 27 | 28 | {{/if}} 29 | 30 | {{#if deprecated}} 31 | deprecated 32 | {{/if}} 33 | 34 | {{#if access}} 35 | {{access}} 36 | {{/if}} 37 | 38 | {{#if final}} 39 | final 40 | {{/if}} 41 | 42 | {{#if static}} 43 | static 44 | {{/if}} 45 | 46 | {{#if chainable}} 47 | chainable 48 | {{/if}} 49 | 50 |
    51 | {{#if overwritten_from}} 52 |

    Inherited from 53 | 54 | {{overwritten_from/class}} 55 | 56 | {{#if foundAt}} 57 | but overwritten in 58 | {{/if}} 59 | {{else}} 60 | {{#if extended_from}} 61 |

    Inherited from 62 | {{extended_from}}: 63 | {{else}} 64 | {{#providedBy}} 65 |

    Provided by the {{.}} module.

    66 | {{/providedBy}} 67 |

    68 | {{/if}} 69 | {{/if}} 70 |

    71 | 72 | 73 | {{#if deprecationMessage}} 74 |

    Deprecated: {{deprecationMessage}}

    75 | {{/if}} 76 | 77 | {{#if since}} 78 |

    Available since {{since}}

    79 | {{/if}} 80 |
    81 | 82 |
    83 | {{{methodDescription}}} 84 |
    85 | 86 | {{#if params}} 87 |
    88 |

    Parameters:

    89 | 90 |
      91 | {{#params}} 92 |
    • 93 | {{#if optional}} 94 | [{{name}}{{#if optdefault}}={{optdefault}}{{/if}}] 95 | {{#crossLink type}}{{/crossLink}} 96 | optional 97 | {{else}} 98 | {{name}} 99 | {{#crossLink type}}{{/crossLink}} 100 | {{/if}} 101 | 102 | {{#if multiple}} 103 | multiple 104 | {{/if}} 105 | 106 |
      107 | {{{description}}} 108 |
      109 | 110 | {{#if props}} 111 |
        112 | {{#props}} 113 |
      • 114 | {{#if optional}} 115 | [{{name}}{{#if optdefault}}={{optdefault}}{{/if}}] 116 | {{#crossLink type}}{{/crossLink}} 117 | optional 118 | {{else}} 119 | {{name}} 120 | {{#crossLink type}}{{/crossLink}} 121 | {{/if}} 122 | 123 |
        124 | {{{description}}} 125 |
        126 | 127 | {{#if props}} 128 |
          129 | {{#props}} 130 |
        • 131 | {{#if optional}} 132 | [{{name}}{{#if optdefault}}={{optdefault}}{{/if}}] 133 | {{#crossLink type}}{{/crossLink}} 134 | optional 135 | {{else}} 136 | {{name}} 137 | {{#crossLink type}}{{/crossLink}} 138 | {{/if}} 139 | 140 |
          141 | {{{description}}} 142 |
          143 |
        • 144 | {{/props}} 145 |
        146 | {{/if}} 147 |
      • 148 | {{/props}} 149 |
      150 | {{/if}} 151 |
    • 152 | {{/params}} 153 |
    154 |
    155 | {{/if}} 156 | 157 | {{#return}} 158 |
    159 |

    Returns:

    160 | 161 |
    162 | {{#if description}} 163 | {{#if type}} 164 | {{#crossLink type}}{{/crossLink}}: 165 | {{/if}} 166 | {{{description}}} 167 | {{else}} 168 | {{#if type}} 169 | {{#crossLink type}}{{/crossLink}}: 170 | {{/if}} 171 | {{/if}} 172 |
    173 |
    174 | {{/return}} 175 | 176 | {{#example}} 177 |
    178 |

    Example:

    179 | 180 |
    181 | {{{.}}} 182 |
    183 |
    184 | {{/example}} 185 |
    186 | -------------------------------------------------------------------------------- /doc/assets/js/api-list.js: -------------------------------------------------------------------------------- 1 | YUI.add('api-list', function (Y) { 2 | 3 | var Lang = Y.Lang, 4 | YArray = Y.Array, 5 | 6 | APIList = Y.namespace('APIList'), 7 | 8 | classesNode = Y.one('#api-classes'), 9 | inputNode = Y.one('#api-filter'), 10 | modulesNode = Y.one('#api-modules'), 11 | tabviewNode = Y.one('#api-tabview'), 12 | 13 | tabs = APIList.tabs = {}, 14 | 15 | filter = APIList.filter = new Y.APIFilter({ 16 | inputNode : inputNode, 17 | maxResults: 1000, 18 | 19 | on: { 20 | results: onFilterResults 21 | } 22 | }), 23 | 24 | search = APIList.search = new Y.APISearch({ 25 | inputNode : inputNode, 26 | maxResults: 100, 27 | 28 | on: { 29 | clear : onSearchClear, 30 | results: onSearchResults 31 | } 32 | }), 33 | 34 | tabview = APIList.tabview = new Y.TabView({ 35 | srcNode : tabviewNode, 36 | panelNode: '#api-tabview-panel', 37 | render : true, 38 | 39 | on: { 40 | selectionChange: onTabSelectionChange 41 | } 42 | }), 43 | 44 | focusManager = APIList.focusManager = tabviewNode.plug(Y.Plugin.NodeFocusManager, { 45 | circular : true, 46 | descendants: '#api-filter, .yui3-tab-panel-selected .api-list-item a, .yui3-tab-panel-selected .result a', 47 | keys : {next: 'down:40', previous: 'down:38'} 48 | }).focusManager, 49 | 50 | LIST_ITEM_TEMPLATE = 51 | '
  • ' + 52 | '{displayName}' + 53 | '
  • '; 54 | 55 | // -- Init --------------------------------------------------------------------- 56 | 57 | // Duckpunch FocusManager's key event handling to prevent it from handling key 58 | // events when a modifier is pressed. 59 | Y.before(function (e, activeDescendant) { 60 | if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { 61 | return new Y.Do.Prevent(); 62 | } 63 | }, focusManager, '_focusPrevious', focusManager); 64 | 65 | Y.before(function (e, activeDescendant) { 66 | if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { 67 | return new Y.Do.Prevent(); 68 | } 69 | }, focusManager, '_focusNext', focusManager); 70 | 71 | // Create a mapping of tabs in the tabview so we can refer to them easily later. 72 | tabview.each(function (tab, index) { 73 | var name = tab.get('label').toLowerCase(); 74 | 75 | tabs[name] = { 76 | index: index, 77 | name : name, 78 | tab : tab 79 | }; 80 | }); 81 | 82 | // Switch tabs on Ctrl/Cmd-Left/Right arrows. 83 | tabviewNode.on('key', onTabSwitchKey, 'down:37,39'); 84 | 85 | // Focus the filter input when the `/` key is pressed. 86 | Y.one(Y.config.doc).on('key', onSearchKey, 'down:83'); 87 | 88 | // Keep the Focus Manager up to date. 89 | inputNode.on('focus', function () { 90 | focusManager.set('activeDescendant', inputNode); 91 | }); 92 | 93 | // Update all tabview links to resolved URLs. 94 | tabview.get('panelNode').all('a').each(function (link) { 95 | link.setAttribute('href', link.get('href')); 96 | }); 97 | 98 | // -- Private Functions -------------------------------------------------------- 99 | function getFilterResultNode() { 100 | return filter.get('queryType') === 'classes' ? classesNode : modulesNode; 101 | } 102 | 103 | // -- Event Handlers ----------------------------------------------------------- 104 | function onFilterResults(e) { 105 | var frag = Y.one(Y.config.doc.createDocumentFragment()), 106 | resultNode = getFilterResultNode(), 107 | typePlural = filter.get('queryType'), 108 | typeSingular = typePlural === 'classes' ? 'class' : 'module'; 109 | 110 | if (e.results.length) { 111 | YArray.each(e.results, function (result) { 112 | frag.append(Lang.sub(LIST_ITEM_TEMPLATE, { 113 | rootPath : APIList.rootPath, 114 | displayName : filter.getDisplayName(result.highlighted), 115 | name : result.text, 116 | typePlural : typePlural, 117 | typeSingular: typeSingular 118 | })); 119 | }); 120 | } else { 121 | frag.append( 122 | '
  • ' + 123 | 'No ' + typePlural + ' found.' + 124 | '
  • ' 125 | ); 126 | } 127 | 128 | resultNode.empty(true); 129 | resultNode.append(frag); 130 | 131 | focusManager.refresh(); 132 | } 133 | 134 | function onSearchClear(e) { 135 | 136 | focusManager.refresh(); 137 | } 138 | 139 | function onSearchKey(e) { 140 | var target = e.target; 141 | 142 | if (target.test('input,select,textarea') 143 | || target.get('isContentEditable')) { 144 | return; 145 | } 146 | 147 | e.preventDefault(); 148 | 149 | inputNode.focus(); 150 | focusManager.refresh(); 151 | } 152 | 153 | function onSearchResults(e) { 154 | var frag = Y.one(Y.config.doc.createDocumentFragment()); 155 | 156 | if (e.results.length) { 157 | YArray.each(e.results, function (result) { 158 | frag.append(result.display); 159 | }); 160 | } else { 161 | frag.append( 162 | '
  • ' + 163 | 'No results found. Maybe you\'ll have better luck with a ' + 164 | 'different query?' + 165 | '
  • ' 166 | ); 167 | } 168 | 169 | 170 | focusManager.refresh(); 171 | } 172 | 173 | function onTabSelectionChange(e) { 174 | var tab = e.newVal, 175 | name = tab.get('label').toLowerCase(); 176 | 177 | tabs.selected = { 178 | index: tab.get('index'), 179 | name : name, 180 | tab : tab 181 | }; 182 | 183 | switch (name) { 184 | case 'classes': // fallthru 185 | case 'modules': 186 | filter.setAttrs({ 187 | minQueryLength: 0, 188 | queryType : name 189 | }); 190 | 191 | search.set('minQueryLength', -1); 192 | 193 | // Only send a request if this isn't the initially-selected tab. 194 | if (e.prevVal) { 195 | filter.sendRequest(filter.get('value')); 196 | } 197 | break; 198 | 199 | case 'everything': 200 | filter.set('minQueryLength', -1); 201 | search.set('minQueryLength', 1); 202 | 203 | if (search.get('value')) { 204 | search.sendRequest(search.get('value')); 205 | } else { 206 | inputNode.focus(); 207 | } 208 | break; 209 | 210 | default: 211 | // WTF? We shouldn't be here! 212 | filter.set('minQueryLength', -1); 213 | search.set('minQueryLength', -1); 214 | } 215 | 216 | if (focusManager) { 217 | setTimeout(function () { 218 | focusManager.refresh(); 219 | }, 1); 220 | } 221 | } 222 | 223 | function onTabSwitchKey(e) { 224 | var currentTabIndex = tabs.selected.index; 225 | 226 | if (!(e.ctrlKey || e.metaKey)) { 227 | return; 228 | } 229 | 230 | e.preventDefault(); 231 | 232 | switch (e.keyCode) { 233 | case 37: // left arrow 234 | if (currentTabIndex > 0) { 235 | tabview.selectChild(currentTabIndex - 1); 236 | inputNode.focus(); 237 | } 238 | break; 239 | 240 | case 39: // right arrow 241 | if (currentTabIndex < (Y.Object.size(tabs) - 2)) { 242 | tabview.selectChild(currentTabIndex + 1); 243 | inputNode.focus(); 244 | } 245 | break; 246 | } 247 | } 248 | 249 | }, '3.4.0', {requires: [ 250 | 'api-filter', 'api-search', 'event-key', 'node-focusmanager', 'tabview' 251 | ]}); 252 | -------------------------------------------------------------------------------- /lib/Probe.js: -------------------------------------------------------------------------------- 1 | // Probe.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | // Module loading 8 | var Monitor = root.Monitor || require('./Monitor'), 9 | log = Monitor.getLogger('Probe'), 10 | stat = Monitor.getStatLogger('Probe'), 11 | Cron = Monitor.Cron, _ = Monitor._, Backbone = Monitor.Backbone; 12 | 13 | /** 14 | * A software device used to expose real time data to monitors 15 | * 16 | * This is the base class from which all probe implementations extend. 17 | * 18 | * In order to send probe data to monitors, probe implementations simply set 19 | * their model data using ```set()```. Those changes are detected and propagated 20 | * to all monitors of this probe, firing their change events. 21 | * 22 | * In order to allow remote probe control, probes need only provide a method 23 | * called ```{name}_control()```. See the ```ping_control()``` method as an example, 24 | * and the ```Probe.onControl()``` method for more information. 25 | * 26 | * @class Probe 27 | * @extends Backbone.Model 28 | * @constructor 29 | * @param model - Initial data model. Can be a JS object or another Model. 30 | * @param model.id {String} The probe id. 31 | * Assigned by the Router on probe instantiation. 32 | */ 33 | var Probe = Monitor.Probe = Backbone.Model.extend({ 34 | 35 | defaults: { 36 | id: null 37 | }, 38 | 39 | /** 40 | * Initialize the probe 41 | * 42 | * This is called on the probe during construction. It contains 43 | * the probe initialization attributes and an option to make probe 44 | * construction asynchronous. 45 | * 46 | * Probe implementations can defer the initial response to the monitor until 47 | * the initial state is loaded. This allows the callback on 48 | * ```Monitor.connect()``` 49 | * to have the complete initial state of the probe when called. 50 | * 51 | * If the initial probe state cannot be determined in ```initialize```, it should 52 | * set the ```options.asyncInit``` option to ```true```, and call the 53 | * ```options.callback(error)``` once the initial state is determined. 54 | * 55 | * // Asynchronous initialization 56 | * options.asyncInit = true; 57 | * var callback = options.callback 58 | * 59 | * If ```asyncInit``` is set to true, the ```callback``` must be called once 60 | * the initial state of the probe is known (or in an error condition). 61 | * 62 | * // Set the initial state, and call the callback 63 | * this.set(...); 64 | * callback(null); 65 | * 66 | * See the ```initialize``` 67 | * method of the FileProbe probe for an example. It defers 68 | * returning the probe to the monitor until the initial file contents are loaded. 69 | * 70 | * @method initialize 71 | * @param attributes {Object} Initial probe attributes sent in from the Monitor 72 | * @param options {Object} Initialization options 73 | * @param options.asyncInit {boolean} Set this to TRUE if the initial probe 74 | * state can't be known immediately. 75 | * @param options.callback {function(error)} The callback to call 76 | * if asyncInit is set to true. If an error is passed, the probe 77 | * will not be used. 78 | */ 79 | initialize: function(attributes, options) { 80 | var t = this; 81 | log.info('init', t.toJSON(), options); 82 | }, 83 | 84 | /** 85 | * Release any resources consumed by this probe. 86 | * 87 | * This can be implemented by derived classes that need to be informed when 88 | * they are to be shut down. 89 | * 90 | * Probes that listen to events should use this method to remove their 91 | * event listeners. 92 | * 93 | * @method release 94 | */ 95 | release: function(){ 96 | var t = this; 97 | log.info('release', t.toJSON()); 98 | }, 99 | 100 | /** 101 | * Dispatch a control message to the appropriate control function. 102 | * 103 | * This is called when the 104 | * ```control()``` 105 | * method of a monitor is called. 106 | * The name determines the method name called on the probe. 107 | * 108 | * The probe must implement a method with the name ```{name}_control()```, 109 | * and that method must accept two parameters - an input params and a callback. 110 | * The callback must be called, passing an optional error and response object. 111 | * 112 | * For example, if the probe supports a control with the name ```go```, then 113 | * all it needs to do is implement the ```go_control()``` method with the 114 | * proper signature. See ```ping_control()``` for an example. 115 | * 116 | * @method onControl 117 | * @param name {String} Name of the control message. 118 | * @param [params] {Any} Input parameters specific to the control message. 119 | * @param [callback] {Function(error, response)} Called to send the message (or error) response. 120 | *
      121 | *
    • error (Any) An object describing an error (null if no errors)
    • 122 | *
    • response (Any) Response parameters specific to the control message. 123 | *
    124 | */ 125 | onControl: function(name, params, callback) { 126 | var t = this, 127 | controlFn = t[name + '_control'], 128 | startTime = Date.now(), 129 | errMsg, 130 | logId = 'onControl.' + t.probeClass + '.' + name; 131 | 132 | params = params || {}; 133 | callback = callback || function(){}; 134 | log.info(logId, t.get('id'), params); 135 | 136 | if (!controlFn) { 137 | errMsg = 'No control function: ' + name; 138 | log.error(logId, errMsg); 139 | return callback({msg: errMsg}); 140 | } 141 | 142 | var whenDone = function(error) { 143 | if (error) { 144 | log.error(logId, error); 145 | return callback(error); 146 | } 147 | var duration = Date.now() - startTime; 148 | log.info(logId, params); 149 | stat.time(t.logId, duration); 150 | callback.apply(null, arguments); 151 | }; 152 | 153 | try { 154 | controlFn.call(t, params, whenDone); 155 | } catch (e) { 156 | errMsg = 'Error calling control: ' + t.probeClass + ':' + name; 157 | whenDone({msg:errMsg, err: e.toString()}); 158 | } 159 | }, 160 | 161 | /** 162 | * Respond to a ping control sent from a monitor 163 | * 164 | * @method ping_control 165 | * @param params {Object} Input parameters (not used) 166 | * @param callback {Function(error, response)} Called to send the message (or error) response. 167 | *
      168 | *
    • error (Any) An object describing an error
    • 169 | *
    • response (String) The string 'pong' is returned as the response
    • 170 | *
    171 | */ 172 | ping_control: function(params, callback) { 173 | return callback(null, 'pong'); 174 | } 175 | 176 | }); 177 | 178 | // Register probe classes when loaded 179 | Probe.classes = {}; // key = name, data = class definition 180 | Probe.extend = function(params) { 181 | var t = this, probeClass = Backbone.Model.extend.apply(t, arguments); 182 | if (params.probeClass) {Probe.classes[params.probeClass] = probeClass;} 183 | return probeClass; 184 | }; 185 | 186 | /** 187 | * Constructor for a list of Probe objects 188 | * 189 | * var myList = new Probe.List(initialElements); 190 | * 191 | * @static 192 | * @method List 193 | * @param [items] {Array} Initial list items. These can be raw JS objects or Probe data model objects. 194 | * @return {Backbone.Collection} Collection of Probe data model objects 195 | */ 196 | Probe.List = Backbone.Collection.extend({model: Probe}); 197 | 198 | }(this)); 199 | -------------------------------------------------------------------------------- /doc/assets/vendor/prettify/README.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Javascript code prettifier 7 | 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | Languages : CH 20 |

    Javascript code prettifier

    21 | 22 |

    Setup

    23 |
      24 |
    1. Download a distribution 25 |
    2. Include the script and stylesheets in your document 26 | (you will need to make sure the css and js file are on your server, and 27 | adjust the paths in the script and link tag) 28 |
       29 | <link href="prettify.css" type="text/css" rel="stylesheet" />
       30 | <script type="text/javascript" src="prettify.js"></script>
      31 |
    3. Add onload="prettyPrint()" to your 32 | document's body tag. 33 |
    4. Modify the stylesheet to get the coloring you prefer
    5. 34 |
    35 | 36 |

    Usage

    37 |

    Put code snippets in 38 | <pre class="prettyprint">...</pre> 39 | or <code class="prettyprint">...</code> 40 | and it will automatically be pretty printed. 41 | 42 | 43 | 44 | 47 |
    The original 45 | Prettier 46 |
    class Voila {
     49 | public:
     50 |   // Voila
     51 |   static const string VOILA = "Voila";
     52 | 
     53 |   // will not interfere with embedded tags.
     54 | }
    55 | 56 |
    class Voila {
     57 | public:
     58 |   // Voila
     59 |   static const string VOILA = "Voila";
     60 | 
     61 |   // will not interfere with embedded tags.
     62 | }
    63 |
    64 | 65 |

    FAQ

    66 |

    Which languages does it work for?

    67 |

    The comments in prettify.js are authoritative but the lexer 68 | should work on a number of languages including C and friends, 69 | Java, Python, Bash, SQL, HTML, XML, CSS, Javascript, and Makefiles. 70 | It works passably on Ruby, PHP, VB, and Awk and a decent subset of Perl 71 | and Ruby, but, because of commenting conventions, doesn't work on 72 | Smalltalk, or CAML-like languages.

    73 | 74 |

    LISPy languages are supported via an extension: 75 | lang-lisp.js.

    77 |

    And similarly for 78 | CSS, 80 | Haskell, 82 | Lua, 84 | OCAML, SML, F#, 86 | Visual Basic, 88 | SQL, 90 | Protocol Buffers, and 92 | WikiText.. 94 | 95 |

    If you'd like to add an extension for your favorite language, please 96 | look at src/lang-lisp.js and file an 97 | issue including your language extension, and a testcase.

    99 | 100 |

    How do I specify which language my code is in?

    101 |

    You don't need to specify the language since prettyprint() 102 | will guess. You can specify a language by specifying the language extension 103 | along with the prettyprint class like so:

    104 |
    <pre class="prettyprint lang-html">
    106 |   The lang-* class specifies the language file extensions.
    107 |   File extensions supported by default include
    108 |     "bsh", "c", "cc", "cpp", "cs", "csh", "cyc", "cv", "htm", "html",
    109 |     "java", "js", "m", "mxml", "perl", "pl", "pm", "py", "rb", "sh",
    110 |     "xhtml", "xml", "xsl".
    111 | </pre>
    112 | 113 |

    It doesn't work on <obfuscated code sample>?

    114 |

    Yes. Prettifying obfuscated code is like putting lipstick on a pig 115 | — i.e. outside the scope of this tool.

    116 | 117 |

    Which browsers does it work with?

    118 |

    It's been tested with IE 6, Firefox 1.5 & 2, and Safari 2.0.4. 119 | Look at the test page to see if it 120 | works in your browser.

    121 | 122 |

    What's changed?

    123 |

    See the change log

    124 | 125 |

    Why doesn't Prettyprinting of strings work on WordPress?

    126 |

    Apparently wordpress does "smart quoting" which changes close quotes. 127 | This causes end quotes to not match up with open quotes. 128 |

    This breaks prettifying as well as copying and pasting of code samples. 129 | See 130 | WordPress's help center for info on how to stop smart quoting of code 132 | snippets.

    133 | 134 |

    How do I put line numbers in my code?

    135 |

    You can use the linenums class to turn on line 136 | numbering. If your code doesn't start at line number 1, you can 137 | add a colon and a line number to the end of that class as in 138 | linenums:52. 139 | 140 |

    For example 141 |

    <pre class="prettyprint linenums:4"
    142 | >// This is line 4.
    143 | foo();
    144 | bar();
    145 | baz();
    146 | boo();
    147 | far();
    148 | faz();
    149 | <pre>
    150 | produces 151 |
    // This is line 4.
    153 | foo();
    154 | bar();
    155 | baz();
    156 | boo();
    157 | far();
    158 | faz();
    159 | 
    160 | 161 |

    How do I prevent a portion of markup from being marked as code?

    162 |

    You can use the nocode class to identify a span of markup 163 | that is not code. 164 |

    <pre class=prettyprint>
    165 | int x = foo();  /* This is a comment  <span class="nocode">This is not code</span>
    166 |   Continuation of comment */
    167 | int y = bar();
    168 | </pre>
    169 | produces 170 |
    171 | int x = foo();  /* This is a comment  This is not code
    172 |   Continuation of comment */
    173 | int y = bar();
    174 | 
    175 | 176 |

    For a more complete example see the issue22 177 | testcase.

    178 | 179 |

    I get an error message "a is not a function" or "opt_whenDone is not a function"

    180 |

    If you are calling prettyPrint via an event handler, wrap it in a function. 181 | Instead of doing 182 |

    183 | addEventListener('load', prettyPrint, false); 185 |
    186 | wrap it in a closure like 187 |
    188 | addEventListener('load', function (event) { prettyPrint() }, false); 190 |
    191 | so that the browser does not pass an event object to prettyPrint which 192 | will confuse it. 193 | 194 |


    195 | 196 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /lib/Log.js: -------------------------------------------------------------------------------- 1 | /*jslint browser: true */ 2 | // Log.js (c) 2010-2013 Loren West and other contributors 3 | // May be freely distributed under the MIT license. 4 | // For further details and documentation: 5 | // http://lorenwest.github.com/monitor-min 6 | (function(root){ 7 | 8 | // Module loading 9 | var Monitor = root.Monitor || require('./Monitor'), 10 | // Raw events on the server (for speed), backbone events on the browser (for functionality) 11 | EventEmitter = Monitor.commonJS ? require('events').EventEmitter.prototype : Monitor.Backbone.Events, 12 | Stat = Monitor.Stat, 13 | stat = new Stat('Log'), 14 | _ = Monitor._, 15 | emittingNow = false; 16 | 17 | /** 18 | * A lightweight component for gathering and emitting application logs 19 | * 20 | * It's designed with low development and runtime cost in mind, encouraging 21 | * usage with minimum concern for overhead. Runtime monitoring can be as chatty 22 | * as desired, outputting every log statement of every type, or finely tuned 23 | * with regular expressions to monitor specific log statements. 24 | * 25 | * Log Collector 26 | * ------------- 27 | * 28 | * As a collector, it's a place to send application logs. 29 | * 30 | * Example for outputting a log in your application: 31 | * 32 | * var log = require('monitor-min').getLogger('myModule'); 33 | * ... 34 | * log.info('Credit limit accepted', limit, requestedAmount); 35 | * 36 | * The above is a request to output an ```info``` log for ```myModule``` named 37 | * ```Credit limit accepted```. The log entry includes all additional parameters, 38 | * in this case the customer credit limit and the reqeusted amount. 39 | * 40 | * The full name for this log entry is: ```"info.myModule.Credit limit accepted"``` 41 | * The name is important, as monitors can be configured to output logs based 42 | * on this name. 43 | * 44 | * Best practices are to include dynamic parameters in extra arguments 45 | * vs. concatenating strings. This reduces logging overhead, especially 46 | * for log statements that aren't currently being watched. 47 | * 48 | * Log Emitter 49 | * ----------- 50 | * As an emitter, the Log module is a place to capture logging output. 51 | * 52 | * When listening for log entries, wildcards can be used to register for 53 | * particular log types and entries. 54 | * 55 | * var Log = require('monitor-min').Log; 56 | * ... 57 | * Log.on('info.myModule.*', myFunction); 58 | * 59 | * Will call ```myFunction``` when all ```info.myModule.*``` logs are emitted. 60 | * 61 | * Listeners are invoked with the following arguments: 62 | * 63 | * - type - The log type (trace, debug, info, warn, error, or fatal) 64 | * - module - The logger module name 65 | * - name - The log entry name 66 | * - args... - Additional arguments passed into the log entry are passed on 67 | * as additional args to the event listener. 68 | * 69 | * Wildcards 70 | * --------- 71 | * A flexible and user-oriented wildcard pattern is used for monitoring 72 | * logs. The pattern is described in the Wildcard secttion of the Stats class. 73 | * 74 | * Choosing Good Names 75 | * ------------------- 76 | * It's a good idea to pick a good naming scheme with each dot-delimited segment 77 | * having a consistent, well-defined purpose. Volatile segments should be as deep 78 | * into the hierarchy (furthest right) as possible. Keeping the names less 79 | * volatile makes it easier to turn statistics recording on for all logs. 80 | * 81 | * @class Log 82 | * @constructor 83 | */ 84 | var Log = Monitor.Log = function(module) { 85 | var t = this; 86 | t.module = module; 87 | }; 88 | var proto = Log.prototype; 89 | 90 | // This is a map of registered event names to compiled regexs, for 91 | // quickly testing if a log needs to be emitted. 92 | Log.eventRegex = {}; 93 | 94 | /** 95 | * Output a ```trace``` log entry 96 | * 97 | * @method trace 98 | * @param name {String} Log entry name 99 | * @param [...] {Any} Subsequent arguments to add to the log 100 | */ 101 | 102 | /** 103 | * Output a ```debug``` log entry 104 | * 105 | * @method debug 106 | * @param name {String} Log entry name 107 | * @param [...] {Any} Subsequent arguments to add to the log 108 | */ 109 | 110 | /** 111 | * Output a ```info``` log entry 112 | * 113 | * @method info 114 | * @param name {String} Log entry name 115 | * @param [...] {Any} Subsequent arguments to add to the log 116 | */ 117 | 118 | /** 119 | * Output a ```warn``` log entry 120 | * 121 | * @method warn 122 | * @param name {String} Log entry name 123 | * @param [...] {Any} Subsequent arguments to add to the log 124 | */ 125 | 126 | /** 127 | * Output a ```error``` log entry 128 | * 129 | * @method error 130 | * @param name {String} Log entry name 131 | * @param [...] {Any} Subsequent arguments to add to the log 132 | */ 133 | 134 | /** 135 | * Output a ```fatal``` log entry 136 | * 137 | * @method fatal 138 | * @param name {String} Log entry name 139 | * @param [...] {Any} Subsequent arguments to add to the log 140 | */ 141 | 142 | // Add a method for each log type 143 | ['trace','debug','info','warn','error','fatal'].forEach(function(method) { 144 | proto[method] = function(name) { 145 | Log._emit(method, this.module, name, arguments); 146 | }; 147 | }); 148 | 149 | /** 150 | * Send the log to all registered listeners 151 | * 152 | * @private 153 | * @static 154 | * @method emit 155 | * @param type {string} The log type (trace, debug, info, etc) 156 | * @param module {String} The log module name 157 | * @param name {String} The log entry name 158 | * @param args {any[]} Arguments to the log entry 159 | */ 160 | Log._emit = function(type, module, name, args) { 161 | var eventName, 162 | fullName = type + '.' + module + '.' + name; 163 | 164 | // Prevent log recursion. This has the effect of disabling all logging 165 | // for log handlers (and their downstream effect), but is necessary to 166 | // prevent infinite recursion. If it's desired to log the output of 167 | // log handlers, then delay that processing until nextTick. 168 | if (emittingNow) { 169 | return; 170 | } 171 | emittingNow = true; 172 | 173 | // Output a counter stat for this log 174 | stat.increment(fullName); 175 | 176 | // Test the name against all registered events 177 | for (eventName in Log._events) { 178 | 179 | // Get the regex associated with the name (using the Stat package) 180 | var regex = Log.eventRegex[eventName]; 181 | if (!regex) { 182 | regex = Log.eventRegex[eventName] = Stat._buildRegex(eventName); 183 | } 184 | 185 | // Test the long name with the regex, and emit if it matches 186 | if (regex.test(fullName)) { 187 | 188 | // Build the arguments as event name, log type, module, name, [other args...] 189 | var allArgs = _.toArray(args), 190 | emitFn = Log.emit || Log.trigger; // NodeJS/server=emit, Backbone/browser=trigger 191 | allArgs.splice(0, 1, eventName, type, module, name); 192 | emitFn.apply(Log, allArgs); 193 | } 194 | } 195 | 196 | // Turn off recursion prevention 197 | emittingNow = false; 198 | }; 199 | 200 | // Mixin event processing for the Log class 201 | _.extend(Log, EventEmitter); 202 | 203 | // Expose this class from the Monitor module 204 | Monitor.setLoggerClass(Log); 205 | 206 | /** 207 | * Output log statements to the console 208 | * 209 | * This method can be used as a listener to send logs to the console. 210 | * 211 | * It uses console.error() for error and fatal log types, and console.log() 212 | * for all other log types. 213 | * 214 | * Example: 215 | * 216 | * var Log = Monitor.Log; 217 | * Log.on('*.MyModule.*', Log.console); 218 | * 219 | * @static 220 | * @method consoleLogger 221 | * @param type {string} The log type (trace, debug, info, etc) 222 | * @param module {String} The log module name 223 | * @param name {String} The log entry name 224 | * @param args {any...} All original, starting with the short name 225 | */ 226 | Log.console = function(type, module, name, args) { 227 | 228 | // Build the string to log, in log4js format 229 | var nowStr = JSON.stringify(new Date()).substr(1,22), 230 | allArgs = _.toArray(arguments), 231 | logStr = nowStr + ' [' + type + '] ' + module + '.' + name + ' '; 232 | allArgs.splice(0,3); 233 | try { 234 | logStr += JSON.stringify(allArgs); 235 | } catch(e) { 236 | logStr += Monitor.stringify(allArgs); 237 | } 238 | 239 | // Log or error 240 | if (type === 'error' || type === 'fatal') { 241 | console.error(logStr); 242 | } 243 | else { 244 | console.log(logStr); 245 | } 246 | 247 | }; 248 | 249 | // Attach the console log listener 250 | var pattern = Monitor.Config.MonitorMin.consoleLogListener.pattern; 251 | if (pattern) { 252 | Log.on(pattern, Log.console); 253 | } 254 | 255 | }(this)); 256 | -------------------------------------------------------------------------------- /lib/probes/ReplProbe.js: -------------------------------------------------------------------------------- 1 | // ReplProbe.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | // Module loading - this runs server-side only 8 | var Monitor = root.Monitor || require('../Monitor'), 9 | _ = Monitor._, 10 | Probe = Monitor.Probe, 11 | REPL = require('repl'), 12 | Stream = require('stream'), 13 | util = require('util'), 14 | events = require('events'), 15 | ChildProcess = require('child_process'); 16 | 17 | // Statics 18 | var CONSOLE_PROMPT = '> '; 19 | var NEW_REPL = (typeof REPL.disableColors === 'undefined'); 20 | 21 | /** 22 | * A probe based Read-Execute-Print-Loop console for node.js processes 23 | * 24 | * @class ReplProbe 25 | * @extends Probe 26 | * @constructor 27 | * @param initParams {Object} Probe initialization parameters 28 | * @param initParams.uniqueInstance - Usually specified to obtain a unique REPL probe instance 29 | * @param model {Object} Monitor data model elements 30 | * @param model.output {String} Last (current) REPL output line 31 | * @param model.sequence {Integer} Increasing sequence number - to enforce unique line output 32 | */ 33 | var ReplProbe = Monitor.ReplProbe = Probe.extend({ 34 | 35 | probeClass: 'Repl', 36 | description: 'A socket.io based Read-Execute-Print-Loop console for node.js processes.', 37 | defaults: { 38 | // This assures output events are sent, even if the 39 | // data is the same as the prior output. 40 | sequence: 0, 41 | output: '' 42 | }, 43 | 44 | initialize: function(attributes, options){ 45 | var t = this; 46 | Probe.prototype.initialize.apply(t, arguments); 47 | 48 | // Don't send change events before connected 49 | process.nextTick(function(){ 50 | t.stream = new ReplStream(t); 51 | if (NEW_REPL) { 52 | t.repl = require('repl').start({ 53 | prompt: CONSOLE_PROMPT, 54 | input: t.stream, 55 | output: t.stream 56 | }); 57 | } else { 58 | t.repl = REPL.start(CONSOLE_PROMPT, t.stream); 59 | } 60 | t.htmlConsole = new HtmlConsole(t); 61 | t.shellCmd = null; 62 | t.repl.context.console = t.htmlConsole; 63 | }); 64 | }, 65 | 66 | /** 67 | * Send output to the terminal 68 | * 69 | * This forces the change event even if the last output is the same 70 | * as this output. 71 | * 72 | * @protected 73 | * @method output 74 | * @param str {String} String to output to the repl console 75 | */ 76 | _output: function(str) { 77 | var t = this; 78 | t.set({ 79 | output: str, 80 | sequence: t.get('sequence') + 1 81 | }); 82 | }, 83 | 84 | /** 85 | * Release any resources consumed by this probe. 86 | * 87 | * Stop the REPL console. Consoles live 1-1 with a UI counterpart, so stop 88 | * requests exit the underlying repl console. If the probe is re-started it 89 | * will get a new repl stream and console. 90 | * 91 | * @method release 92 | */ 93 | release: function(){ 94 | var t = this; 95 | t.stream = null; 96 | t.repl = null; 97 | }, 98 | 99 | /** 100 | * Process an autocomplete request from the client 101 | * 102 | * @method autocomplete 103 | * @param {Object} params Named parameters 104 | * @param {Function(error, returnParams)} callback Callback function 105 | */ 106 | autocomplete_control: function(params, callback) { 107 | var t = this; 108 | if (typeof(params) !== 'string' || params.length < 1) { 109 | callback("Autocomplete paramter must be a nonzero string"); 110 | } 111 | 112 | // Forward to the completion mechanism if it can be completed 113 | if (params.substr(-1).match(/([0-9])|([a-z])|([A-Z])|([_])/)) { 114 | t.repl.complete(params, callback); 115 | } else { 116 | // Return a no-op autocomplete 117 | callback(null, [[],'']); 118 | } 119 | }, 120 | 121 | /** 122 | * Handle user input from the console line 123 | * 124 | * @method input 125 | * @param {Object} params Named parameters 126 | * @param {Function(error, returnParams)} callback Callback function 127 | */ 128 | input_control: function(params, callback) { 129 | var t = this; 130 | if (params === '.break' && t.shellCmd) { 131 | t.shellCmd.kill(); 132 | } 133 | if (NEW_REPL) { 134 | t.stream.emit('data', params + "\n"); 135 | } else { 136 | t.stream.emit('data', params); 137 | } 138 | return callback(null); 139 | }, 140 | 141 | /** 142 | * Execute a shell command 143 | * 144 | * @method sh 145 | * @param {Object} params Named parameters 146 | * @param {Function(error, returnParams)} callback Callback function 147 | */ 148 | sh_control: function(params, callback) { 149 | var t = this; 150 | return callback(null, t._runShellCmd(params)); 151 | }, 152 | 153 | /** 154 | * Run a shell command and emit the output to the browser. 155 | * 156 | * @private 157 | * @method _runShellCmd 158 | * @param {String} command - The shell command to invoke 159 | */ 160 | _runShellCmd: function(command) { 161 | var t = this; 162 | t.shellCmd = ChildProcess.exec(command, function(err, stdout, stderr) { 163 | if (err) { 164 | var outstr = 'exit'; 165 | if (err.code) { 166 | outstr += ' (' + err.code + ')'; 167 | } 168 | if (err.signal) { 169 | outstr += ' ' + err.signal; 170 | } 171 | t._output(outstr); 172 | return null; 173 | } 174 | if (stdout.length) { 175 | t._output(stdout); 176 | } 177 | if (stderr.length) { 178 | t._output(stderr); 179 | } 180 | t.shellCmd = null; 181 | t._output(CONSOLE_PROMPT); 182 | }); 183 | return null; 184 | } 185 | 186 | }); 187 | 188 | // Define an internal stream class for the probe 189 | var ReplStream = function(probe){ 190 | var t = this; 191 | t.probe = probe; 192 | events.EventEmitter.call(t); 193 | if (t.setEncoding) { 194 | t.setEncoding('utf8'); 195 | } 196 | }; 197 | util.inherits(ReplStream, events.EventEmitter); 198 | // util.inherits(ReplStream, require('stream')); 199 | ReplStream.prototype.readable = true; 200 | ReplStream.prototype.writable = true; 201 | ['pause','resume','destroySoon','pipe', 'end'] 202 | .forEach(function(fnName){ 203 | ReplStream.prototype[fnName] = function(){ 204 | console.log("REPL Stream function unexpected: " + fnName); 205 | }; 206 | }); 207 | ['resume'] 208 | .forEach(function(fnName){ 209 | ReplStream.prototype[fnName] = function(){ 210 | // Handled 211 | }; 212 | }); 213 | ReplStream.prototype.write = function(data) { 214 | var t = this; 215 | t.probe._output(data); 216 | }; 217 | ReplStream.prototype.destroy = function(data) { 218 | var t = this; 219 | console.log("REPL stream destroy " + t.probe.get('id')); 220 | t.probe.stop(); 221 | }; 222 | 223 | // Define format if it's not in util. 224 | var formatRegExp = /%[sdj]/g; 225 | var format = util.format || function (f) { 226 | if (typeof f !== 'string') { 227 | var objects = []; 228 | for (var i = 0; i < arguments.length; i++) { 229 | objects.push(util.inspect(arguments[i])); 230 | } 231 | return objects.join(' '); 232 | } 233 | var j = 1; 234 | var args = arguments; 235 | var str = String(f).replace(formatRegExp, function(x) { 236 | switch (x) { 237 | case '%s': return String(args[j++]); 238 | case '%d': return Number(args[j++]); 239 | case '%j': return JSON.stringify(args[j++]); 240 | default: 241 | return x; 242 | } 243 | }); 244 | for (var len = args.length, x = args[j]; j < len; x = args[++j]) { 245 | if (x === null || typeof x !== 'object') { 246 | str += ' ' + x; 247 | } else { 248 | str += ' ' + util.inspect(x); 249 | } 250 | } 251 | return str; 252 | }; 253 | 254 | // Re-define the console so it goes to the HTML window 255 | var HtmlConsole = function(probe){ 256 | this.probe = probe; 257 | }; 258 | HtmlConsole.prototype.log = function(msg) { 259 | this.probe._output(format.apply(this, arguments)); 260 | }; 261 | HtmlConsole.prototype.info = HtmlConsole.prototype.log; 262 | HtmlConsole.prototype.warn = HtmlConsole.prototype.log; 263 | HtmlConsole.prototype.error = HtmlConsole.prototype.log; 264 | HtmlConsole.prototype.dir = function(object) { 265 | this.probe._output(util.inspect(object)); 266 | }; 267 | var times = {}; 268 | HtmlConsole.prototype.time = function(label) { 269 | times[label] = Date.now(); 270 | }; 271 | HtmlConsole.prototype.timeEnd = function(label) { 272 | var duration = Date.now() - times[label]; 273 | this.log('%s: %dms', label, duration); 274 | }; 275 | 276 | }(this)); 277 | -------------------------------------------------------------------------------- /doc/files/lib_probes_LogProbe.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | lib/probes/LogProbe.js - monitor-min 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |
    18 |

    Monitor Min v0.5.12

    19 |
    20 |
    21 |
    22 | 23 |
    24 | 108 |
    109 |
    110 |
    111 | Show: 112 | 116 | 117 | 121 | 122 | 126 |
    127 | 128 | 129 |
    130 |
    131 |
    132 |

    File: lib/probes/LogProbe.js

    133 | 134 |
    135 |
    136 | // LogProbe.js (c) 2010-2013 Loren West and other contributors
    137 | // May be freely distributed under the MIT license.
    138 | // For further details and documentation:
    139 | // http://lorenwest.github.com/monitor-min
    140 | (function(root) {
    141 | 
    142 |   // Module loading - this runs server-side only
    143 |   var Monitor = root.Monitor || require('../Monitor'),
    144 |       _ = Monitor._,
    145 |       StreamProbe = Monitor.StreamProbe,
    146 |       Log = Monitor.Log;
    147 | 
    148 |   // Constants
    149 |   var DEFAULT_PATTERN = '*';
    150 | 
    151 |   /**
    152 |   * Remote application log monitoring
    153 |   *
    154 |   * This probe forwards application logs to the monitor.
    155 |   *
    156 |   * @class LogProbe
    157 |   * @extends StreamProbe
    158 |   * @constructor
    159 |   * @param [initParams] {Object} Probe initialization parameters
    160 |   *     @param [initParams.pattern=*] {String} Log name pattern to monitor (see <a href="Log.html">Log</a>)
    161 |   *     @param [initParams.interval=1000] {Numeric} Queue interval (see <a href="StreamProbe.html">StreamProbe</a>)
    162 |   * @param model {Object} Monitor data model elements
    163 |   *     @param model.bundle {Log array} Array of Log elements.
    164 |   *         @param model.bundle.timestamp {String} Timestamp of the log statement
    165 |   *         @param model.bundle.logType {String} Log type (error, info, etc)
    166 |   *         @param model.bundle.module {String} Module that emitted the log
    167 |   *         @param model.bundle.name {String} Log entry name
    168 |   *         @param model.bundle.args {any[]} Arguments to the log statement
    169 |   *     @param model.sequence {Integer} A numeric incrementer causing a change event
    170 |   */
    171 |   var LogProbe = Monitor.LogProbe = StreamProbe.extend({
    172 | 
    173 |     probeClass: 'Log',
    174 | 
    175 |     defaults: _.extend({}, StreamProbe.prototype.defaults, {
    176 |       pattern: DEFAULT_PATTERN
    177 |     }),
    178 | 
    179 |     initialize: function(){
    180 |       var t = this;
    181 | 
    182 |       // Call parent constructor
    183 |       StreamProbe.prototype.initialize.apply(t, arguments);
    184 | 
    185 |       // The watcher just forwards all args to queueItem as an array
    186 |       t.watcher = function() {
    187 |         // Add timestamp as the first element
    188 |         var logElems = _.toArray(arguments);
    189 |         logElems.splice(0,0,JSON.stringify(new Date()).substr(1,24));
    190 |         t.queueItem.call(t, logElems);
    191 |       };
    192 |       Log.on(t.get('pattern'), t.watcher);
    193 |     },
    194 | 
    195 |     release: function() {
    196 |       var t = this;
    197 |       Log.off(t.get('pattern'), t.watcher);
    198 |     }
    199 | 
    200 |   });
    201 | 
    202 | }(this));
    203 | 
    204 |     
    205 |
    206 | 207 |
    208 |
    209 |
    210 |
    211 |
    212 |
    213 | 216 | 219 |
    220 |
    221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /doc/files/lib_probes_StatProbe.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | lib/probes/StatProbe.js - monitor-min 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |
    18 |

    Monitor Min v0.5.12

    19 |
    20 |
    21 |
    22 | 23 |
    24 | 108 |
    109 |
    110 |
    111 | Show: 112 | 116 | 117 | 121 | 122 | 126 |
    127 | 128 | 129 |
    130 |
    131 |
    132 |

    File: lib/probes/StatProbe.js

    133 | 134 |
    135 |
    136 | // StatProbe.js (c) 2010-2013 Loren West and other contributors
    137 | // May be freely distributed under the MIT license.
    138 | // For further details and documentation:
    139 | // http://lorenwest.github.com/monitor-min
    140 | (function(root) {
    141 | 
    142 |   // Module loading - this runs server-side only
    143 |   var Monitor = root.Monitor || require('../Monitor'),
    144 |       _ = Monitor._,
    145 |       StreamProbe = Monitor.StreamProbe,
    146 |       Stat = Monitor.Stat;
    147 | 
    148 |   // Constants
    149 |   var DEFAULT_PATTERN = '*';
    150 | 
    151 |   /**
    152 |   * Remote application statistics monitoring
    153 |   *
    154 |   * This probe forwards application statistics to the monitor.
    155 |   *
    156 |   * @class StatProbe
    157 |   * @extends StreamProbe
    158 |   * @constructor
    159 |   * @param [initParams] {Object} Probe initialization parameters
    160 |   *     @param [initParams.pattern=*] {String} Stat name pattern to monitor (see <a href="Stat.html">Stat</a>)
    161 |   *     @param [initParams.interval=1000] {Numeric} Queue interval (see <a href="StreamProbe.html">StreamProbe</a>)
    162 |   * @param model {Object} Monitor data model elements
    163 |   *     @param model.bundle {Stat array} Array of Stat elements.
    164 |   *         @param model.bundle.timestamp {String} Timestamp of the stat entry
    165 |   *         @param model.bundle.module {String} Stat module
    166 |   *         @param model.bundle.name {String} Stat name
    167 |   *         @param model.bundle.value {Numeric} Stat value
    168 |   *         @param model.bundle.type {String} 'c'ounter, 'g'ague, or 'ms'timer
    169 |   *     @param model.sequence {Integer} A numeric incrementer causing a change event
    170 |   */
    171 |   var StatProbe = Monitor.StatProbe = StreamProbe.extend({
    172 | 
    173 |     probeClass: 'Stat',
    174 | 
    175 |     defaults: _.extend({}, StreamProbe.prototype.defaults, {
    176 |       pattern: DEFAULT_PATTERN
    177 |     }),
    178 | 
    179 |     initialize: function(){
    180 |       var t = this;
    181 | 
    182 |       // Call parent constructor
    183 |       StreamProbe.prototype.initialize.apply(t, arguments);
    184 | 
    185 |       // The watcher just forwards all args to queueItem as an array
    186 |       t.watcher = function() {
    187 |         // Add timestamp as the first element
    188 |         var logElems = _.toArray(arguments);
    189 |         logElems.splice(0,0,JSON.stringify(new Date()).substr(1,24));
    190 |         t.queueItem.call(t, logElems);
    191 |       };
    192 |       Stat.on(t.get('pattern'), t.watcher);
    193 |     },
    194 | 
    195 |     release: function() {
    196 |       var t = this;
    197 |       Stat.off(t.get('pattern'), t.watcher);
    198 |     }
    199 | 
    200 |   });
    201 | 
    202 | }(this));
    203 | 
    204 |     
    205 |
    206 | 207 |
    208 |
    209 |
    210 |
    211 |
    212 |
    213 | 216 | 219 |
    220 |
    221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /test/MonitorTest.js: -------------------------------------------------------------------------------- 1 | // MonitorTest.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | /** 8 | * Unit tests for the Monitor class. 9 | * @class MonitorTest 10 | */ 11 | 12 | // Dependencies 13 | var Monitor = require('../lib/index'), 14 | Backbone = Monitor.Backbone, 15 | _ = Monitor._, 16 | testMonitorAttrs = { 17 | // Monitor attributes 18 | id: '24-2', 19 | name: 'Test monitor', 20 | probeClass: 'NoClass', 21 | initParams: {a:1}, 22 | hostName: 'some-host.com', 23 | appName: 'test', 24 | appInstance: 2 25 | }, 26 | testProbeAttrs = { 27 | // Non-monitor attributes 28 | probeId: Monitor.generateUniqueId(), 29 | probeAttr1: 'attr1 value', 30 | probeAttr2: 2, 31 | probeAttr3: {hello: 'world'} 32 | }, 33 | testAllAttrs = _.extend({}, testMonitorAttrs, testProbeAttrs), 34 | testMonitor = new Monitor(testAllAttrs); 35 | 36 | /** 37 | * Tests for verifying modules are loaded and exposed properly 38 | * 39 | * @method ModuleLoad 40 | */ 41 | module.exports.ModuleLoad = { 42 | 43 | setUp: function(callback) {callback();}, 44 | tearDown: function(callback) {callback();}, 45 | 46 | /** 47 | * Tests that externals dependencies are exposed 48 | * @method ModuleLoad-Externals 49 | */ 50 | Externals: function(test) { 51 | test.notEqual(Monitor.Config, 'undefined', 'Config package is exported'); 52 | test.notEqual(Monitor.Cron, 'undefined', 'Cron package is exported'); 53 | test.notEqual(Monitor._, 'undefined', 'Underscore package is exported'); 54 | test.notEqual(Monitor.Backbone, 'undefined', 'Backbone package is exported'); 55 | test.done(); 56 | }, 57 | 58 | /** 59 | * Tests that Monitor is exposed and of the correct type 60 | * @method ModuleLoad-Monitor 61 | */ 62 | Monitor: function(test) { 63 | test.ok(Monitor.prototype instanceof Backbone.Model, 'The Monitor data model is in place'); 64 | test.ok(Monitor.List.prototype instanceof Backbone.Collection, 'The Monitor collection is in place'); 65 | test.done(); 66 | }, 67 | 68 | /** 69 | * Tests that all Sub Modules are exposed and of the correct type 70 | * @method ModuleLoad-Submodules 71 | */ 72 | Submodules: function(test) { 73 | test.ok(Monitor.Probe.prototype instanceof Backbone.Model, 'The Probe submodule is in place'); 74 | test.ok(Monitor.Connection.prototype instanceof Backbone.Model, 'The Connection submodule is in place'); 75 | test.ok(Monitor.Server.prototype instanceof Backbone.Model, 'The Server submodule is in place'); 76 | test.ok(Monitor.Router.prototype instanceof Backbone.Model, 'The Router submodule is in place'); 77 | test.done(); 78 | } 79 | 80 | }; 81 | 82 | /** 83 | * Tests for internal (protected) methods 84 | * @method Protected 85 | */ 86 | module.exports['Protected'] = { 87 | 88 | /** 89 | * Test UUID generation 90 | * @method Protected-UUID 91 | */ 92 | UUID: function(test) { 93 | // Generate a bunch and make sure they're unique 94 | var numToTest = 100, uuids = {}; 95 | for (var i = 0; i < numToTest; i++) { 96 | var uuid = Monitor.generateUniqueId(); 97 | test.ok(uuid, "A uuid was generated"); 98 | test.ok(uuid.length === 36, "It has the correct V.4 length"); 99 | test.ok(!uuids[uuid], "It is unique within the test UUIDs"); 100 | uuids[uuid] = ''; 101 | } 102 | test.done(); 103 | }, 104 | 105 | /** 106 | * Tests that the Router is available 107 | * @method Protected-Router 108 | */ 109 | Router: function(test) { 110 | test.ok(Monitor.getRouter() instanceof Monitor.Router, "The default router is available"); 111 | test.done(); 112 | } 113 | 114 | }; 115 | 116 | /** 117 | * ## Tests for the toJSON methods 118 | * @method JSON 119 | */ 120 | module.exports['JSON'] = { 121 | 122 | /** 123 | * Tests that toJSON produces both monitor an probe attributes 124 | * 125 | * @method JSON-toJSON 126 | */ 127 | toJSON: function(test) { 128 | var json = testMonitor.toJSON(); 129 | test.deepEqual(json, testAllAttrs, 'toJSON produces the correct values'); 130 | test.done(); 131 | }, 132 | 133 | /** 134 | * Test that toMonitorJSON produces only monitor attributes 135 | * 136 | * @method JSON-toMonitorJSON 137 | */ 138 | toMonitorJSON: function(test) { 139 | var json = testMonitor.toMonitorJSON(); 140 | test.deepEqual(json, testMonitorAttrs, 'toMonitorJSON produces the correct values'); 141 | test.done(); 142 | }, 143 | 144 | /** 145 | * Test that toProbeJSON produces only monitor attributes 146 | * 147 | * @method JSON-toProbeJSON 148 | */ 149 | toProbeJSON: function(test) { 150 | var json = testMonitor.toProbeJSON(); 151 | 152 | // The probeId is moved into ID 153 | var testAttrs = _.clone(testProbeAttrs); 154 | testAttrs.id = testMonitor.get('probeId'); 155 | test.deepEqual(json, testAttrs, 'toProbeJSON produces the correct values'); 156 | test.done(); 157 | } 158 | 159 | }; 160 | 161 | /** 162 | * ## Tests for connecting and disconnecting with probes 163 | * @method Connection 164 | */ 165 | module.exports['Connection'] = { 166 | 167 | /** 168 | * Test connecting with internal probes 169 | * @method Connection-Internal 170 | */ 171 | Internal: function(test) { 172 | test.expect(6); // Make sure both callbacks and events are fired 173 | var processMonitor = new Monitor({probeClass:'Process'}); 174 | processMonitor.connect(function(error) { 175 | test.equal(error, null, 'No errors on connect'); 176 | var probeId = processMonitor.get('probeId'); 177 | test.ok(probeId, "The probeId is set"); 178 | test.ok(probeId && probeId.length === 36, "The probeId is a uuid"); 179 | }); 180 | processMonitor.on('connect', function() { 181 | 182 | // Don't disconnect right away. This allows the connect 183 | // event to be run before emitting change events. 184 | process.nextTick(function(){ 185 | processMonitor.disconnect(function(error){ 186 | test.equal(error, null, 'No errors on disconnect'); 187 | }); 188 | }); 189 | }); 190 | processMonitor.on('disconnect', function(reason) { 191 | test.equal(reason, 'manual_disconnect', 'The reason for disconnect is "manually disconnected"'); 192 | test.ok(!processMonitor.get('probeId'), 'The probe is no longer attached to the monitor'); 193 | test.done(); 194 | }); 195 | } 196 | 197 | }; 198 | 199 | /** 200 | * Test the stringify method 201 | * @method Stringify 202 | */ 203 | module.exports['Stringify'] = { 204 | Test: function(test) { 205 | var tests = [ 206 | "7", 7, true, false, 207 | {depth:1, test:7}, 208 | {depth:1, test:7, depth2:{depth:2, test:"7"}}, 209 | {depth:1, test:7, depth2:{depth:2, test:"7", depth3:{depth:3, test:"hello"}}}, 210 | {depth:1, test:7, depth2:{depth:2, test:"7", depth3:{depth:3, test:"hello", depth4:{depth:4, test:"there"}}}} 211 | ]; 212 | var expected = [ 213 | '"7"', '7', 'true', 'false', 214 | '{\n \"depth\": 1,\n \"test\": 7\n}', 215 | '{\n \"depth\": 1,\n \"test\": 7,\n \"depth2\": {\n \"depth\": 2,\n \"test\": \"7\"\n }\n}', 216 | '{\n \"depth\": 1,\n \"test\": 7,\n \"depth2\": {\n \"depth\": 2,\n \"test\": \"7\",\n \"depth3\": {\n \"depth\": 3,\n \"test\": \"hello\"\n }\n }\n}', 217 | '{\n \"depth\": 1,\n \"test\": 7,\n \"depth2\": {\n \"depth\": 2,\n \"test\": \"7\",\n \"depth3\": {\n \"depth\": 3,\n \"test\": \"hello\",\n \"depth4\": \"[Object]\"\n }\n }\n}' 218 | ]; 219 | for (var i = 0; i < tests.length; i++) { 220 | var str = Monitor.stringify(tests[i], 3); 221 | test.equal(str, expected[i]); 222 | } 223 | test.done(); 224 | } 225 | }; 226 | 227 | }(this)); 228 | 229 | /* 230 | jsunit test functions: 231 | 232 | expect(amount) - Specify how many assertions are expected to run within a test. Very useful for ensuring that all your callbacks and assertions are run. 233 | done() - Finish the current test function, and move on to the next. ALL tests should call this! 234 | 235 | ok(value, [message]) - Tests if value is a true value. 236 | equal(actual, expected, [message]) - Tests shallow, coercive equality with the equal comparison operator ( == ). 237 | notEqual(actual, expected, [message]) - Tests shallow, coercive non-equality with the not equal comparison operator ( != ). 238 | deepEqual(actual, expected, [message]) - Tests for deep equality. 239 | notDeepEqual(actual, expected, [message]) - Tests for any deep inequality. 240 | strictEqual(actual, expected, [message]) - Tests strict equality, as determined by the strict equality operator ( === ) 241 | notStrictEqual(actual, expected, [message]) - Tests strict non-equality, as determined by the strict not equal operator ( !== ) 242 | throws(block, [error], [message]) - Expects block to throw an error. 243 | doesNotThrow(block, [error], [message]) - Expects block not to throw an error. 244 | ifError(value) - Tests if value is not a false value, throws if it is a true value. Useful when testing the first argument, error in callbacks. 245 | 246 | */ 247 | -------------------------------------------------------------------------------- /doc/files/test_ServerTest.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test/ServerTest.js - monitor-min 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |
    18 |

    Monitor Min v0.5.12

    19 |
    20 |
    21 |
    22 | 23 |
    24 | 108 |
    109 |
    110 |
    111 | Show: 112 | 116 | 117 | 121 | 122 | 126 |
    127 | 128 | 129 |
    130 |
    131 |
    132 |

    File: test/ServerTest.js

    133 | 134 |
    135 |
    136 | // ServerTest.js (c) 2010-2013 Loren West and other contributors
    137 | // May be freely distributed under the MIT license.
    138 | // For further details and documentation:
    139 | // http://lorenwest.github.com/monitor-min
    140 | (function(root){
    141 | 
    142 |   // Dependencies
    143 |   var Monitor = require('../lib/index'),
    144 |       Server = Monitor.Server, Backbone = Monitor.Backbone;
    145 | 
    146 |   /**
    147 |   * Unit tests for the <a href="Server.html">Server</a> class.
    148 |   * @class ServerTest
    149 |   */
    150 | 
    151 |   /**
    152 |   * Test group for baseline Server functionality
    153 |   *
    154 |   * @method Server
    155 |   */
    156 |   module.exports['Server'] = {
    157 | 
    158 |     setUp: function(callback) {callback();},
    159 |     tearDown: function(callback) {callback();},
    160 | 
    161 |     /**
    162 |     * Tests that Server classes are in place
    163 |     * @method Server-Classes
    164 |     */
    165 |     Classes: function(test) {
    166 |       test.ok(Server.prototype instanceof Backbone.Model, 'The Server data model is in place');
    167 |       test.ok(Server.List.prototype instanceof Backbone.Collection, 'The Server.List collection is in place');
    168 |       test.done();
    169 |     },
    170 | 
    171 |     /**
    172 |     * Start and Stop a server
    173 |     * @method Server-StartStop
    174 |     */
    175 |     StartStop: function(test) {
    176 |       var server = new Monitor.Server();
    177 |       server.on('start', function() {
    178 |         test.ok(server.get('port') > 0, 'The server started accepting connections on a port');
    179 |         server.stop(function(){
    180 |           test.ok(true, 'The server has stopped');
    181 |           test.done();
    182 |         });
    183 |       });
    184 |       server.start();
    185 |     },
    186 | 
    187 |     /**
    188 |     * Verify multiple servers start on different ports
    189 |     * @method Server-MultipleStartStop
    190 |     */
    191 |     MultipleStartStop: function(test) {
    192 |       var server1 = new Monitor.Server(), port1, port2;
    193 |       server1.on('start', function() {
    194 |         port1 = server1.get('port');
    195 |         test.ok(port1 >= Monitor.Config.MonitorMin.serviceBasePort, 'The server started in the correct port range');
    196 |         var server2 = new Monitor.Server();
    197 |         server2.on('start', function() {
    198 |           port2 = server2.get('port');
    199 |           test.notEqual(port1, port2, 'Two servers started on two different ports');
    200 |           server1.stop(function(){
    201 |             server2.stop(function(){
    202 |               test.ok(true, 'Both servers have stopped');
    203 |               test.done();
    204 |             });
    205 |           });
    206 |         });
    207 |         server2.start();
    208 |       });
    209 |       server1.start();
    210 |     }
    211 | 
    212 |   };
    213 | 
    214 | }(this));
    215 | 
    216 |     
    217 |
    218 | 219 |
    220 |
    221 |
    222 |
    223 |
    224 |
    225 | 228 | 231 |
    232 |
    233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | -------------------------------------------------------------------------------- /test/LogTest.js: -------------------------------------------------------------------------------- 1 | // LogTest.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | // Dependencies 8 | var Monitor = require('../lib/index'), 9 | Log = Monitor.Log, 10 | log = Monitor.getLogger('log-test'), 11 | Backbone = Monitor.Backbone; 12 | 13 | /** 14 | * Unit tests for the Log class. 15 | * @class LogTest 16 | */ 17 | 18 | /** 19 | * Test group for baseline Log functionality 20 | * 21 | * @method Log 22 | */ 23 | module.exports['Log'] = { 24 | 25 | setUp: function(callback) {callback();}, 26 | tearDown: function(callback) {callback();}, 27 | 28 | /** 29 | * Tests that Log class is in place 30 | * @method Log-Classes 31 | */ 32 | Classes: function(test) { 33 | test.ok(Log.prototype, 'The Log model is in place'); 34 | test.done(); 35 | }, 36 | 37 | /** 38 | * Tests that registering for '*' emits all logs 39 | * @method Log-AllLogs 40 | */ 41 | AllLogs: function(test) { 42 | 43 | // Listen for all logs 44 | Log.once('*', function(log, module, name) { 45 | test.equals(log, 'info', 'The log type is correct'); 46 | test.equals(module, 'log-test', 'found the log-test module when listening to *'); 47 | test.equals(name, 'All logs test', 'found the correct log name *'); 48 | test.done(); 49 | }); 50 | log.info('All logs test', 34); 51 | }, 52 | 53 | /** 54 | * Tests for the inclusion of multiple arguments in logs 55 | * @method Log-MultiArg 56 | */ 57 | MultiArg: function(test) { 58 | 59 | // Listen for all logs 60 | Log.once('*', function(log, module, name, hello, number, obj) { 61 | test.equals(log, 'error', 'The log type is correct'); 62 | test.equals(name, 'MultiArg', 'found the correct log name *'); 63 | test.equals(hello, 'hello', 'hello arg is found'); 64 | test.equals(number, 34, 'Numeric argument is found'); 65 | test.ok(obj, 'Object argument is found'); 66 | test.equals(obj.there, 'world', 'Object elements are intact'); 67 | test.equals(obj.num, 9273, 'Object elements are intact'); 68 | test.done(); 69 | }); 70 | log.error('MultiArg', 'hello', 34, {there:'world', num: 9273}); 71 | }, 72 | 73 | /** 74 | * Tests for the trace log 75 | * @method Log-trace 76 | */ 77 | TraceLog: function(test) { 78 | 79 | // Listen for trace logs 80 | Log.once('trace.*', function(log, module, name) { 81 | test.equals(log, 'trace', 'The log type is correct'); 82 | test.equals(module, 'log-test', 'found the correct module name'); 83 | test.equals(name, 'traceLog', 'found the correct log name'); 84 | test.done(); 85 | }); 86 | log.trace('traceLog'); 87 | }, 88 | 89 | /** 90 | * Tests for the debug log 91 | * @method Log-debug 92 | */ 93 | DebugLog: function(test) { 94 | 95 | // Listen for debug logs 96 | Log.once('*.*.debugLog', function(log, module, name) { 97 | test.equals(log, 'debug', 'The log type is correct'); 98 | test.equals(module, 'log-test', 'found the correct module name'); 99 | test.equals(name, 'debugLog', 'found the correct log name'); 100 | test.done(); 101 | }); 102 | log.debug('debugLog'); 103 | }, 104 | 105 | /** 106 | * Tests for the info log 107 | * @method Log-info 108 | */ 109 | InfoLog: function(test) { 110 | 111 | // Listen for info logs 112 | Log.once('*.log-test.infoLog', function(log, module, name) { 113 | test.equals(log, 'info', 'The log type is correct'); 114 | test.equals(module, 'log-test', 'found the correct module name'); 115 | test.equals(name, 'infoLog', 'found the correct log name'); 116 | test.done(); 117 | }); 118 | log.info('infoLog'); 119 | }, 120 | 121 | /** 122 | * Tests for the warn log 123 | * @method Log-warn 124 | */ 125 | WarnLog: function(test) { 126 | 127 | // Listen for warn logs 128 | Log.once('*.log-test.*', function(log, module, name) { 129 | test.equals(log, 'warn', 'The log type is correct'); 130 | test.equals(module, 'log-test', 'found the correct module name'); 131 | test.equals(name, 'warnLog', 'found the correct log name'); 132 | test.done(); 133 | }); 134 | log.warn('warnLog'); 135 | }, 136 | 137 | /** 138 | * Tests for the error log 139 | * @method Log-error 140 | */ 141 | ErrorLog: function(test) { 142 | 143 | // Listen for error logs 144 | Log.once('error.log-test.errorLog', function(log, module, name) { 145 | test.equals(log, 'error', 'The log type is correct'); 146 | test.equals(module, 'log-test', 'found the correct module name'); 147 | test.equals(name, 'errorLog', 'found the correct log name'); 148 | test.done(); 149 | }); 150 | log.error('errorLog'); 151 | }, 152 | 153 | /** 154 | * Tests for the fatal log 155 | * @method Log-fatal 156 | */ 157 | FatalLog: function(test) { 158 | 159 | // Listen for fatal logs 160 | Log.once('{error,fatal}.*.fatal[Ll]og', function(log, module, name) { 161 | test.equals(log, 'fatal', 'The log type is correct'); 162 | test.equals(module, 'log-test', 'found the correct module name'); 163 | test.equals(name, 'fatalLog', 'found the correct log name'); 164 | test.done(); 165 | }); 166 | log.fatal('fatalLog'); 167 | }, 168 | 169 | /** 170 | * Make sure a stat is output for every log 171 | * @method Log-Stat 172 | */ 173 | Stat: function(test) { 174 | 175 | // Listen for the stat 176 | Monitor.Stat.once('*', function(module, name, value, type) { 177 | test.equals(module, 'Log', 'The stat module is correct'); 178 | test.equals(name, 'info.log-test.Checking for stat emission', 'found the correct stat name'); 179 | test.equals(value, 1, 'Correctly incremented the log stat by 1'); 180 | test.equals(type, 'c', 'Correct stat type - counter'); 181 | test.done(); 182 | }); 183 | log.info('Checking for stat emission'); 184 | }, 185 | 186 | /** 187 | * Tests the Log probe 188 | * @method Log-ProbeTest 189 | */ 190 | ProbeTest: function(test) { 191 | var logMonitor = new Monitor({probeClass:'Log', initParams:{interval:10, pattern:'*.log-test.*'}}); 192 | logMonitor.connect(function(error) { 193 | test.ok(!error, 'Log monitor error: ' + JSON.stringify(error)); 194 | logMonitor.on('change', function() { 195 | var bundle = logMonitor.get('bundle'); 196 | 197 | // Omit the initial state of the monitor 198 | if (bundle.length === 0) { 199 | return; 200 | } 201 | 202 | test.ok(bundle, 'The log bundle is available'); 203 | test.equals(bundle.length, 1, 'There is a single log in the bundle'); 204 | var logArgs = bundle[0]; 205 | test.equals(logArgs.length, 5, 'There are 5 log arguments'); 206 | test.ok(Date.now() - (new Date(logArgs[0]).getTime()) < 1000, 'The first arg is a timestamp'); 207 | test.equals(logArgs[1], 'info', 'There log type is correct'); 208 | test.equals(logArgs[2], 'log-test', 'Ther module is correct'); 209 | test.equals(logArgs[3], 'probeTest', 'There log name is correct'); 210 | test.equals(logArgs[4], 22, 'The value is correct'); 211 | logMonitor.off('change'); 212 | test.done(); 213 | }); 214 | log.info('probeTest', 22); 215 | }); 216 | }, 217 | 218 | /** 219 | * Tests the probe streams multiple items at once 220 | * @method Log-ProbeStream 221 | */ 222 | ProbeStream: function(test) { 223 | 224 | // This relies on the fact that the monitor was created in the prior 225 | // function, and it just emitted a single item. 226 | var logMonitor = new Monitor({probeClass:'Log', initParams:{interval:10, pattern:'*.log-test.*'}}); 227 | logMonitor.connect(function(error) { 228 | test.ok(!error, 'Log monitor error: ' + JSON.stringify(error)); 229 | logMonitor.on('change', function() { 230 | var bundle = logMonitor.get('bundle'); 231 | 232 | // Omit the current state of the probe (first change event) 233 | if (bundle.length < 4) { 234 | return; 235 | } 236 | 237 | test.ok(bundle, 'The log bundle is available'); 238 | test.equals(bundle.length, 4, 'There were the correct number of items in the stream'); 239 | var logArgs = bundle[2]; 240 | test.equals(logArgs.length, 7, 'There are 7 log arguments'); 241 | test.ok(Date.now() - (new Date(logArgs[0]).getTime()) < 1000, 'The first arg is a timestamp'); 242 | test.equals(logArgs[1], 'error', 'The log name is correct'); 243 | test.equals(logArgs[2], 'log-test', 'The module is correct'); 244 | test.equals(logArgs[3], 'probeTest3', 'The log name is correct'); 245 | test.equals(logArgs[4], 420, 'The value is correct'); 246 | test.equals(logArgs[5], 'hello', 'The next arg is correct'); 247 | test.equals(logArgs[6].a, 'world', 'Objects are correctly represented'); 248 | logMonitor.off('change'); 249 | test.done(); 250 | }); 251 | log.info('probeTest1'); 252 | log.warn('probeTest2'); 253 | log.error('probeTest3', 420, "hello", {a:"world"}); 254 | log.fatal('probeTest4', 2840); 255 | }); 256 | } 257 | 258 | }; 259 | 260 | }(this)); 261 | -------------------------------------------------------------------------------- /doc/files/test_ConnectionTest.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test/ConnectionTest.js - monitor-min 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |
    18 |

    Monitor Min v0.5.12

    19 |
    20 |
    21 |
    22 | 23 |
    24 | 108 |
    109 |
    110 |
    111 | Show: 112 | 116 | 117 | 121 | 122 | 126 |
    127 | 128 | 129 |
    130 |
    131 |
    132 |

    File: test/ConnectionTest.js

    133 | 134 |
    135 |
    136 | // ConnectionTest.js (c) 2010-2013 Loren West and other contributors
    137 | // May be freely distributed under the MIT license.
    138 | // For further details and documentation:
    139 | // http://lorenwest.github.com/monitor-min
    140 | (function(root){
    141 | 
    142 |   // Dependencies
    143 |   var Monitor = require('../lib/index'),
    144 |       Connection = Monitor.Connection, Backbone = Monitor.Backbone,
    145 |       server, serverPort;
    146 | 
    147 |   /**
    148 |   * Unit tests for the <a href="Connection.html">Connection</a> class.
    149 |   * @class ConnectionTest
    150 |   */
    151 | 
    152 |   /**
    153 |   * Test group for connection functionality
    154 |   * @method Connection
    155 |   */
    156 |   module.exports['Connection'] = {
    157 | 
    158 |     /**
    159 |     * Create a <a href="Server.html">Server</a> to test connections with
    160 |     * @method Connection-setUp
    161 |     */
    162 |     setUp: function(callback) {
    163 |       server = new Monitor.Server();
    164 |       server.start(callback);
    165 |     },
    166 | 
    167 |     /**
    168 |     * Tests that the Connection classes are available
    169 |     * @method Connection-Classes
    170 |     */
    171 |     Classes: function(test) {
    172 |       test.ok(Connection.prototype instanceof Backbone.Model, 'The Connection data model is in place');
    173 |       test.ok(Connection.List.prototype instanceof Backbone.Collection, 'The Connection.List collection is in place');
    174 |       test.done();
    175 |     },
    176 | 
    177 |     /**
    178 |     * Assure that a connect / disconnect to the server host/port works
    179 |     * @method Connection-ConnectDisconnect
    180 |     */
    181 |     ConnectDisconnect: function(test) {
    182 |       var port = server.get('port'), conn = new Monitor.Connection({hostName:'localhost', hostPort:port});
    183 |       conn.on('connect', function() {
    184 |         test.ok(conn.get('remoteHostName'), 'The remote host name is known');
    185 |         conn.on('disconnect', test.done);
    186 |         conn.disconnect();
    187 |       });
    188 |     },
    189 | 
    190 |     /**
    191 |     * Test pinging the remote connection
    192 |     * @method Connection-PingPong
    193 |     */
    194 |     PingPong: function(test) {
    195 |       var port = server.get('port'), conn = new Monitor.Connection({hostName:'localhost', hostPort:port});
    196 |       conn.on('connect', function() {
    197 |         test.ok(conn.get('remoteHostName'), 'The remote host name is known');
    198 |         conn.ping(function(){
    199 |           test.ok(true, 'Ping made its way to and from the remote server');
    200 |           conn.on('disconnect', test.done);
    201 |           conn.disconnect();
    202 |         });
    203 |       });
    204 |     },
    205 | 
    206 |     /**
    207 |     * Tear down the test Server
    208 |     * @method Connection-tearDown
    209 |     */
    210 |     tearDown: function(callback) {
    211 |       server.stop(callback);
    212 |     }
    213 | 
    214 |   };
    215 | 
    216 | }(this));
    217 | 
    218 |     
    219 |
    220 | 221 |
    222 |
    223 |
    224 |
    225 |
    226 |
    227 | 230 | 233 |
    234 |
    235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /test/FileProbeTest.js: -------------------------------------------------------------------------------- 1 | // FileProbeTest.js (c) 2010-2013 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/monitor-min 5 | (function(root){ 6 | 7 | // Dependencies 8 | var Monitor = require('../lib/index'), 9 | Path = require('path'), 10 | FS = require('fs'), 11 | FileProbe = Monitor.FileProbe, 12 | Backbone = Monitor.Backbone, _ = Monitor._; 13 | 14 | // Constants 15 | var TEST_ROOT_PATH = __dirname + '/fileTestData', 16 | TEST_FILE_RELATIVE_PATH = 'testdir/testfile1.json', 17 | TEST_FILE_FULL_PATH = Path.join(TEST_ROOT_PATH, TEST_FILE_RELATIVE_PATH), 18 | TEST_FILE_DIR = Path.dirname(TEST_FILE_FULL_PATH), 19 | TEST_OBJECT = { 20 | testNumber:1, 21 | testString:"two", 22 | testObject:{some:"sub_object"}, 23 | testArray:[1, "two", 3] 24 | }, 25 | JSON_CONTENT = JSON.stringify(TEST_OBJECT, null, 2); 26 | 27 | // Old style watch takes *forever* to connect 28 | var OLD_WATCHER_CONNECT_MS = 1000, 29 | NEW_WATCHER_CONNECT_MS = 10, 30 | WATCH_CONNECT_TIME = FS.watch ? NEW_WATCHER_CONNECT_MS : OLD_WATCHER_CONNECT_MS; 31 | 32 | /** 33 | * Unit tests for the File probe. 34 | * @class FileProbeTest 35 | */ 36 | 37 | /** 38 | * Test group for baseline FileProbe functionality 39 | * 40 | * @method FileProbe 41 | */ 42 | module.exports['FileProbe'] = { 43 | 44 | /** 45 | * Tests that classes are in correct 46 | * @method FileProbe-Classes 47 | */ 48 | Classes: function(test) { 49 | test.ok(FileProbe.prototype instanceof Backbone.Model, 'The data model is in place'); 50 | test.ok(FileProbe.prototype instanceof Monitor.Probe, 'It is a probe'); 51 | test.done(); 52 | }, 53 | 54 | /** 55 | * Tests that public static methods are in place 56 | * @method FileProbe-Static 57 | */ 58 | Static: function(test) { 59 | test.equal(typeof FileProbe.setRootPath, 'function'); 60 | test.equal(typeof FileProbe.getRootPath, 'function'); 61 | test.equal(typeof FileProbe.rm_rf, 'function'); 62 | test.equal(typeof FileProbe.mkdir_r, 'function'); 63 | test.equal(typeof FileProbe.watch, 'function'); 64 | test.equal(typeof FileProbe.watchLoad, 'function'); 65 | test.equal(typeof FileProbe.tail, 'function'); 66 | test.done(); 67 | } 68 | 69 | }; 70 | 71 | /** 72 | * Test group for static file/directory utilities 73 | * 74 | * @method Utils 75 | */ 76 | module.exports['Utils'] = { 77 | 78 | /** 79 | * Test the mkdir_r utility 80 | * @method Utils-Mkdir_R 81 | */ 82 | Mkdir_R: function(test) { 83 | FileProbe.mkdir_r(TEST_FILE_DIR, function(error) { 84 | test.ok(!error, 'Mkdir-r error ' + JSON.stringify(error)); 85 | var status = FS.statSync(TEST_FILE_DIR); 86 | test.ok(status.isDirectory(), "Recursive mkdir created all directories"); 87 | test.done(); 88 | }); 89 | }, 90 | 91 | /** 92 | * Test the rm_rf utility 93 | * @method Utils-Rm_Rf 94 | */ 95 | Rm_Rf: function(test) { 96 | // Make a test directory structure 97 | FileProbe.mkdir_r(TEST_FILE_DIR, function(error) { 98 | var status = FS.statSync(TEST_FILE_DIR); 99 | test.ok(status.isDirectory(), "Recursive mkdir created all directories"); 100 | 101 | // Make a bunch of files in the lowest directory 102 | for (var i = 0; i < 10; i++) { 103 | FS.writeFileSync(TEST_FILE_FULL_PATH + i, JSON_CONTENT); 104 | } 105 | 106 | // Remove everything from the test root 107 | FileProbe.rm_rf(TEST_ROOT_PATH, function(err1) { 108 | test.ok(!err1, "rm_rf error: " + err1); 109 | FS.readdir(TEST_FILE_DIR, function(err2, files) { 110 | test.ok(err2, "Readdir correctly reported an error on no directory"); 111 | test.equal(err2.code, 'ENOENT', "Directory and all sub-files removed correctly"); 112 | test.done(); 113 | }); 114 | }); 115 | }); 116 | }, 117 | 118 | /** 119 | * Tests the file watch functionality 120 | * @method Utils-Watch 121 | */ 122 | Watch: function(test) { 123 | // Create a file 124 | FileProbe.mkdir_r(TEST_FILE_DIR, function(err) { 125 | test.ok(!err, 'Made the test directory'); 126 | writeTestFile(); 127 | 128 | // Get a watcher on the file 129 | var watcher = FileProbe.watch(TEST_FILE_FULL_PATH, {persistent:true}, function(){ 130 | test.ok(true, "File change detected"); 131 | watcher.close(); 132 | FileProbe.rm_rf(TEST_ROOT_PATH, function(){ 133 | test.done(); 134 | }); 135 | }); 136 | 137 | // Wait for the O/S to start watching, then change the file 138 | writeTestFile("new", WATCH_CONNECT_TIME); 139 | }); 140 | }, 141 | 142 | /** 143 | * Tests the polling style file watching mechanism 144 | * @method Utils-PollingWatcher 145 | */ 146 | PollingWatcher: function(test) { 147 | // Create a file 148 | FileProbe.mkdir_r(TEST_FILE_DIR, function(err) { 149 | test.ok(!err, 'Made the test directory'); 150 | writeTestFile(); 151 | 152 | // Test the old-style watching 153 | var watcher = FileProbe.watch(TEST_FILE_FULL_PATH, {persistent:true, pollStyle:true}, function(){ 154 | test.ok(true, "File change detected"); 155 | watcher.close(); 156 | FileProbe.rm_rf(TEST_ROOT_PATH, function(){ 157 | test.done(); 158 | }); 159 | }); 160 | 161 | // Wait long enough for the old-style watcher to connect 162 | writeTestFile('new', OLD_WATCHER_CONNECT_MS); 163 | }); 164 | }, 165 | 166 | /** 167 | * Tests the watchLoad functionality 168 | * @method Utils-WatchLoad 169 | */ 170 | WatchLoad: function(test) { 171 | // Create a file 172 | FileProbe.mkdir_r(TEST_FILE_DIR, function(err) { 173 | test.ok(!err, 'Made the test directory'); 174 | writeTestFile(); 175 | 176 | // Test with initial preload 177 | var watchCount = 0; 178 | var watcher = FileProbe.watchLoad(TEST_FILE_FULL_PATH, {persistent:true, preload:true}, function(err1, content){ 179 | test.ok(!err1, "watchLoad error: " + err1); 180 | watchCount++; 181 | if (watchCount === 1) { 182 | test.equal(content, JSON_CONTENT, "Initial file contents preloaded"); 183 | 184 | // Test with subsequent file write 185 | writeTestFile("extra", WATCH_CONNECT_TIME); 186 | } else if (watchCount === 2) { 187 | test.equal(content, JSON_CONTENT + "extra", "Subsequent content loaded after update"); 188 | watcher.close(); 189 | FileProbe.rm_rf(TEST_ROOT_PATH, function(){ 190 | test.done(); 191 | }); 192 | } 193 | }); 194 | }); 195 | } 196 | 197 | }; 198 | 199 | /** 200 | * Test group for File based probe functionality 201 | * 202 | * @method Probe 203 | */ 204 | module.exports['Probe'] = { 205 | 206 | // Create the test directory and file 207 | setUp: function(callback) { 208 | FileProbe.mkdir_r(TEST_FILE_DIR, function(err) { 209 | writeTestFile(); 210 | callback(); 211 | }); 212 | }, 213 | 214 | // Remove the test directory 215 | tearDown: function(callback) { 216 | FileProbe.rm_rf(TEST_ROOT_PATH, function(){ 217 | callback(); 218 | }); 219 | }, 220 | 221 | /** 222 | * Tests the ROOT_PATH functionality 223 | * @method Probe-RootPath 224 | */ 225 | RootPath: function(test) { 226 | // Only perform tests if root path hasn't been set 227 | if (FileProbe.getRootPath() === null) { 228 | FileProbe.setRootPath(TEST_ROOT_PATH); 229 | test.equal(FileProbe.getRootPath(), TEST_ROOT_PATH); 230 | try { 231 | FileProbe.setRootPath('/'); 232 | test.ok(false, "This line shouldn't be reached"); 233 | } 234 | catch (e) { 235 | test.ok(true, "Root path correctly disallowed changes"); 236 | } 237 | } 238 | test.done(); 239 | }, 240 | 241 | /** 242 | * This tests the File probe initializes properly 243 | * @method Probe-Init 244 | */ 245 | Init: function(test) { 246 | 247 | // Build and connect the file monitor 248 | var fileMonitor = new Monitor({ 249 | probeClass: "File", 250 | initParams: {path: TEST_FILE_RELATIVE_PATH} 251 | }); 252 | fileMonitor.connect(function(){ 253 | 254 | // Make sure the initial content is correct 255 | test.equal(fileMonitor.get("text"), JSON_CONTENT, "File content is correct"); 256 | 257 | // Watch for file changes after first change event 258 | process.nextTick(function(){ 259 | fileMonitor.on('change', function() { 260 | test.equal(fileMonitor.get("text"), JSON_CONTENT + 'altered', "Altered file content is correct"); 261 | fileMonitor.off('change'); 262 | fileMonitor.disconnect(); 263 | test.done(); 264 | }); 265 | }); 266 | 267 | // Alter the file 268 | writeTestFile('altered', WATCH_CONNECT_TIME); 269 | }); 270 | } 271 | }; 272 | 273 | /** 274 | * Write the test file to disk, with possible appendage 275 | * 276 | * @static 277 | * @method writeTestFile 278 | * @param append {String} String to append onto the standard test file 279 | * @param wait {Integer} Number of milliseconds to wait before writing 280 | */ 281 | function writeTestFile(append, wait) { 282 | var content = append ? JSON_CONTENT + append : JSON_CONTENT; 283 | if (wait) { 284 | setTimeout(function(){ 285 | FS.writeFileSync(TEST_FILE_FULL_PATH, content); 286 | }, wait); 287 | } else { 288 | FS.writeFileSync(TEST_FILE_FULL_PATH, content); 289 | } 290 | } 291 | 292 | }(this)); 293 | --------------------------------------------------------------------------------