lorenwest / monitor-dashboard

Dashboards for the Node.js monitor project
https://lorenwest.github.com/monitor-dashboard
MIT License
204 stars 28 forks source link

Help with node-monitor and monitor-dashboard #15

Open sanchezih opened 10 years ago

sanchezih commented 10 years ago

Hi Loren, I'd like to know if you can help me with node-monitor and monitor-dashboard. I need to monitoring a node app, specifically http requests and the node server cluster status (freemem, cpu status) and be able to see this information in monitor-dashboard. I tried to do this by reading your code, but I can't.

Hope you help me. Thanks! Ignacio.

lorenwest commented 10 years ago

Hello Ignacio,

If you've used Java, you can think of node-monitor as JMX beans. You install node-monitor on the system you want to monitor, and the remote system can view and interact with node-monitor.

It's best to start simple - with node-monitor (less the dashboard). Have you gone through the README and seen the process stats (freemem, cpu stats) using node-monitor only?

-Loren

sanchezih commented 10 years ago

Thanks for your response Loren. Yes, I've already read the example, that works very good, but now I need to know how can count the http requests that my node app receives, but I don't know how do this. I've tried with StatProbe and InspectProbe, but I don't understand how it works. There is a possibility that you show some example?

Thanks for your time. Ignacio.

lorenwest commented 10 years ago

For http requests, the question is - how do you want your data aggregated. The stats probe is good for viewing all stats as they're fired, but it doesn't yet do aggregation.

The quickest (and dirtiest) way to get this done is to create a handful of variables off the global namespace to contain the aggregations you care about (5 minute, 1 hour, by http method, by endpoint, etc.). Add to these variables in your http request pipeline, and clear them on a timer if they're periodic aggregations.

Then use the InspectProbe to inspect these variables.

Let me know if that makes any sense :) -Loren

sanchezih commented 10 years ago

Great. I have the following:

var inspectOptions = { hostName: 'localhost', probeClass: 'Inspect', initParams: { key:global.http_requests, pollInterval: 10000 } } var inspectMonitor = new Monitor(inspectOptions); inspectMonitor.on('change', function() { var xxx =inspectMonitor.get('value'); console.log(xxx); }); inspectMonitor.connect(function(error) { if (error) { console.error('Error connecting with the process probe: ', error); process.exit(1); } });

I want to get the value of http_requests variable, defined in my app, but I can't. Can you help me?

lorenwest commented 10 years ago

So your app (running in a different process, maybe a different server) has a global variable called global.http_requests, and it also has node-monitor linked in and started.

From the other app (running on the same machine or on another machine), you have to connect to the correct node process. Everything looks good except your key variable is global.http_requests, which, if evaluated locally is likely to return undefined. Place quotes around the key:'global.http_requests' and see if that works better.

sanchezih commented 10 years ago

You're right Loren, when I put the quotes around the key, I get undefined. Is that because the hostName is localhost?

lorenwest commented 10 years ago

It's because both processes are on localhost, and it connected with the closest inspector probe, which happened to be running in your client. To verify, set global.http_requests in the client to something like "hello world", and run again.

If that's the case, you have to differentiate the two processes - either by running them on different machines, or by naming the processes.

To configure your app with a name, add the following to your config/default.json configuration file in your server app:

{ 
  Monitor: {
    appName: 'YourAppServerName'
  }
}

Then when you connect from your client, do this:

var inspectOptions = {
  hostName: 'localhost',
  appName: 'YourAppServerName',
  probeClass: 'Inspect',
...
sanchezih commented 10 years ago

Now I'm trying to run your Monitoring example from another machine into the LAN, but Isn't work. I added node-config to my app and my script.

var options = { hostName: '192.168.0.1:9000', appName: 'YourAppServerName', probeClass: 'Process', initParams: { pollInterval: 10000 } }

lorenwest commented 10 years ago

The :9000 shouldn't be specified, as node-monitor uses other ports by default (in the 42,000 range).

The other thing about connecting one machine to another is security. By default, node-monitor only accepts incoming connections on localhost. In order to allow it to connect from another machine, you have to configure this in your config/default.json file:

{ 
  Monitor: {
    appName: 'YourAppServerName',
    allowExternalConnections: true
  }
}

The reason it's disabled by default is to have you think about your network security before allowing external connections. Generally your network isn't exposing ports in the 42,000 range to the outside world, but it's good to think about security before opening up your servers for external monitoring & control.

sanchezih commented 10 years ago

Great! I have seen the freemem from another machine using your example. But now I wish I could see a global variable in my app.

--config/default.json { "Monitor": { "appName": "YourAppServerName", "allowExternalConnections": "true" } }

--monitorScript.js

var Monitor = require('monitor'); var options = { hostName: '192.168.0.1', appName: 'YourAppServerName', probeClass: 'Inspect', initParams: { key:'global.http_requests', pollInterval: 10000 } }

var inspectMonitor = new Monitor(inspectOptions);

// Attach the change listener inspectMonitor.on('change', function() { console.log(inspectMonitor.get('value')); });

// Now connect the monitor inspectMonitor.connect(function(error) { if (error) { console.error('Error connecting with the Inspect probe: ', error); process.exit(1); } });

Thank you very much Loren.

lorenwest commented 10 years ago

Everything looks right. You're monitoring the variable every 10 seconds, and triggering console.log when the value changes. Is that value changing in your server?

sanchezih commented 10 years ago

Yes, the value changes. When I evaluate if isModel I get false

console.log(inspectMonitor.get('isModel'));

Should I get true?

lorenwest commented 10 years ago

Unless global.http_requests is a backbone data model, you should be getting false returned from inspectMonitor.get('isModel').

What do you see when you do console.log(inspectMonitor.toJSON()) ?

sanchezih commented 10 years ago

{ hostName: '10.10.10.212', appName: 'YourAppServerName', probeClass: 'Inspect', initParams: { key: undefined, pollInterval: 10000 }, id: '', name: '', probeName: '', appInstance: '', probeId: '3cef7531-1d1b-8137-ad1c-edcba1a7fa5d', writableAttributes: [ 'value' ], pollInterval: 10000, cronPattern: '* * * * * *', value: { ArrayBuffer: '[Function]', Int8Array: { constructor: '[Function]', BYTES_PER_ELEMENT: 1 }, Uint8Array: { constructor: '[Function]', BYTES_PER_ELEMENT: 1 }, Uint8ClampedArray: { constructor: '[Function]', BYTES_PER_ELEMENT: 1 }, Int16Array: { constructor: '[Function]', BYTES_PER_ELEMENT: 2 }, Uint16Array: { constructor: '[Function]', BYTES_PER_ELEMENT: 2 }, Int32Array: { constructor: '[Function]', BYTES_PER_ELEMENT: 4 }, Uint32Array: { constructor: '[Function]', BYTES_PER_ELEMENT: 4 }, Float32Array: { constructor: '[Function]', BYTES_PER_ELEMENT: 4 }, Float64Array: { constructor: '[Function]', BYTES_PER_ELEMENT: 8 }, DataView: '[Function]', global: { ArrayBuffer: '[Function]', Int8Array: '[Function]', Uint8Array: '[Function]', Uint8ClampedArray: '[Function]', Int16Array: '[Function]', Uint16Array: '[Function]', Int32Array: '[Function]', Uint32Array: '[Function]', Float32Array: '[Function]', Float64Array: '[Function]', DataView: '[Function]', global: '[Object]', process: '[Object]', GLOBAL: '[Object]', root: '[Object]', Buffer: '[Function]', setTimeout: '[Function]', setInterval: '[Function]', clearTimeout: '[Function]', clearInterval: '[Function]', setImmediate: '[Function]', clearImmediate: '[Function]', console: '[Object]', NODE_CONFIG: '[Object]', Monitor: '[Function]', empresa: '[Object]', local: '[Object]' }, process: { title: 'node', version: 'v0.10.25', moduleLoadList: '[Array]', versions: '[Object]', arch: 'x64', platform: 'linux', argv: '[Array]', execArgv: '[Array]', env: '[Object]', pid: 5951, features: '[Object]', _needImmediateCallback: false, execPath: '/usr/bin/nodejs', debugPort: 5858, _getActiveRequests: '[Function]', _getActiveHandles: '[Function]', _needTickCallback: '[Function]', reallyExit: '[Function]', abort: '[Function]', chdir: '[Function]', cwd: '[Function]', umask: '[Function]', getuid: '[Function]', setuid: '[Function]', setgid: '[Function]', getgid: '[Function]', getgroups: '[Function]', setgroups: '[Function]', initgroups: '[Function]', _kill: '[Function]', _debugProcess: '[Function]', _debugPause: '[Function]', _debugEnd: '[Function]', hrtime: '[Function]', dlopen: '[Function]', uptime: '[Function]', memoryUsage: '[Function]', binding: '[Function]', _usingDomains: '[Function]', _tickInfoBox: '[Object]', _events: '[Object]', domain: '[Object]', _maxListeners: 10, EventEmitter: '[Function]', _fatalException: '[Function]', _exiting: false, assert: '[Function]', config: '[Object]', nextTick: '[Function]', _nextDomainTick: '[Function]', _tickCallback: '[Function]', _tickDomainCallback: '[Function]', _tickFromSpinner: '[Function]', maxTickDepth: 1000, stdout: '[Object]', stderr: '[Object]', stdin: '[Object]', openStdin: '[Function]', exit: '[Function]', kill: '[Function]', addListener: '[Function]', on: '[Function]', removeListener: '[Function]', mainModule: '[Object]', _errno: 'EOF' }, GLOBAL: { ArrayBuffer: '[Function]', Int8Array: '[Function]', Uint8Array: '[Function]', Uint8ClampedArray: '[Function]', Int16Array: '[Function]', Uint16Array: '[Function]', Int32Array: '[Function]', Uint32Array: '[Function]', Float32Array: '[Function]', Float64Array: '[Function]', DataView: '[Function]', global: '[Object]', process: '[Object]', GLOBAL: '[Object]', root: '[Object]', Buffer: '[Function]', setTimeout: '[Function]', setInterval: '[Function]', clearTimeout: '[Function]', clearInterval: '[Function]', setImmediate: '[Function]', clearImmediate: '[Function]', console: '[Object]', NODE_CONFIG: '[Object]', Monitor: '[Function]', empresa: '[Object]', local: '[Object]' }, root: { ArrayBuffer: '[Function]', Int8Array: '[Function]', Uint8Array: '[Function]', Uint8ClampedArray: '[Function]', Int16Array: '[Function]', Uint16Array: '[Function]', Int32Array: '[Function]', Uint32Array: '[Function]', Float32Array: '[Function]', Float64Array: '[Function]', DataView: '[Function]', global: '[Object]', process: '[Object]', GLOBAL: '[Object]', root: '[Object]', Buffer: '[Function]', setTimeout: '[Function]', setInterval: '[Function]', clearTimeout: '[Function]', clearInterval: '[Function]', setImmediate: '[Function]', clearImmediate: '[Function]', console: '[Object]', NODE_CONFIG: '[Object]', Monitor: '[Function]', empresa: '[Object]', local: '[Object]' }, Buffer: { constructor: '[Function]', isEncoding: '[Function]', poolSize: 8192, isBuffer: '[Function]', byteLength: '[Function]', concat: '[Function]', _charsWritten: 261 }, setTimeout: '[Function]', setInterval: '[Function]', clearTimeout: '[Function]', clearInterval: '[Function]', setImmediate: '[Function]', clearImmediate: '[Function]', console: { log: '[Function]', info: '[Function]', warn: '[Function]', error: '[Function]', dir: '[Function]', time: '[Function]', timeEnd: '[Function]', trace: '[Function]', assert: '[Function]', Console: '[Function]' }, NODE_CONFIG: { Monitor: '[Object]', watch: '[Function]', setModuleDefaults: '[Function]', makeHidden: '[Function]', makeImmutable: '[Function]', watchForConfigFileChanges: '[Function]', safeWriteFile: '[Function]', getConfigSources: '[Function]', _persistConfigsOnChange: '[Function]', _loadFileConfigs: '[Function]', _loadOldStyleEnv: '[Function]', _parseFile: '[Function]', _attachProtoDeep: '[Function]', _cloneDeep: '[Function]', _equalsDeep: '[Function]', _diffDeep: '[Function]', _extendDeep: '[Function]', _stripYamlComments: '[Function]', _stripComments: '[Function]', _isObject: '[Function]', getOriginalConfig: '[Function]', resetRuntime: '[Function]', _initParam: '[Function]', getCmdLineArg: '[Function]' }, Monitor: { constructor: '[Function]', extend: '[Function]', super: '[Object]', generateUniqueId: '[Function]', generateUniqueCollectionId: '[Function]', getRouter: '[Function]', start: '[Function]', stop: '[Function]', toServerString: '[Function]', deepCopy: '[Function]', stringify: '[Function]', setStatLoggerClass: '[Function]', setLoggerClass: '[Function]', List: '[Function]', Config: '[Object]', : '[Function]', Backbone: '[Object]', Cron: '[Object]', commonJS: true, Stat: '[Function]', getStatLogger: '[Function]', Log: '[Function]', getLogger: '[Function]', Probe: '[Function]', Connection: '[Function]', Server: '[Function]', Router: '[Function]', Sync: '[Function]', DataModelProbe: '[Function]', RecipeProbe: '[Function]', PollingProbe: '[Function]', StreamProbe: '[Function]', InspectProbe: '[Function]', StatProbe: '[Function]', LogProbe: '[Function]', FileProbe: '[Function]', ReplProbe: '[Function]', ProcessProbe: '[Function]', SyncProbe: '[Function]', defaultServer: '[Object]', defaultRouter: '[Object]' }, empresa: { INCIADA: 0, INCOMPLETA: 1, ERROR: 2, COMPLETA: 3, CERRADA: 4 }, local: { ABIERTO: 0, COMPLETO: 1, CERRADO: 2, MODIFICADO: 3, VALIDADO: 4 } }, isModel: false }

lorenwest commented 10 years ago

The fact that key: undefined is in your initParams tells me that you've forgotten to put quotes around global.http_requests. The value you're seeing is your entire global namespace (!).

lorenwest commented 10 years ago

If you are putting quotes around global.http_requests in your init params, it could be that global.http_requests really is undefined in your server.

sanchezih commented 10 years ago

Can you show me a little example how I should define my variable to see its value using Inspect?

Thank you in advance :)

lorenwest commented 10 years ago

Yes:

var inspectOptions = {
  hostName: '10.10.10.212',
  appName: 'YourAppServerName',  
  probeClass: 'Inspect',
  initParams: {
    key: 'global.http_requests',
    pollInterval: 10000
  }
}
var inspectMonitor = new Monitor(inspectOptions);

Notice the quotes around 'global.http_requests'. That's to make sure the variable is evaluated on the server, and not on the client when inspectOptions is declared.

angchoo commented 7 years ago

Hi Loren,

I have the following code:

var inspectMonitor = new Monitor({ hostName:'192.168.20.122', probeClass: 'Inspect', initParams: { key: 'global.http_requests', pollInterval: 10000 } });

inspectMonitor.on('change', function () {
    var xxx = inspectMonitor.get('value');
    console.log(inspectMonitor.toJSON());
});

inspectMonitor.connect(function (error) {
    console.log('Inspect probe connected.');

    if (error) {
        console.error('Error connecting with the inspect probe: ', error);
        process.exit(1);
    }
});

..and output:

Inspect probe connected. { hostName: '192.168.20.122', probeClass: 'Inspect', initParams: { key: 'global.http_requests', pollInterval: 10000 }, id: '', name: '', probeName: '', appName: '', appInstance: '', probeId: '4092dcdb-d9dd-47b8-5d00-09bb69f027cd', writableAttributes: [ 'value' ], key: 'global.http_requests', pollInterval: 10000, cronPattern: '* * * * * *', value: undefined, isModel: false }

It seems that "value" is undefined as shown, can you please advise?