├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── binary-ready.sh ├── binding.gyp ├── compiled ├── linux │ ├── ia32 │ │ └── 0.10 │ │ │ └── sysinfo.node │ └── x64 │ │ └── 0.10 │ │ └── sysinfo.node └── sunos │ ├── ia32 │ └── 0.10 │ │ └── sysinfo.node │ └── x64 │ └── 0.10 │ └── sysinfo.node ├── examples └── test.js ├── lib ├── providers │ ├── index.js │ ├── linux.js │ ├── other.js │ ├── ps.js │ └── sunos.js └── usage.js ├── package.json ├── src ├── binding.cpp ├── binding.h ├── solaris.cpp └── solaris.h ├── sysinfo.js └── test ├── mocha.opts └── usage.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | - "0.12" 5 | - "iojs-v1.1.0" 6 | - "iojs-v1.2.0" 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2011-2014 Arunoda Susiripala 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > **Depricate Notice:** 2 | > 3 | > This project works. But there's a much better project with a similar API.
4 | > It even does not need a binary addon (So, it's easy to use).
5 | > See pidusage: https://github.com/soyuka/pidusage 6 | 7 | # node-usage [![Build Status](https://travis-ci.org/arunoda/node-usage.png?branch=master)](https://travis-ci.org/arunoda/node-usage) 8 | 9 | ### process usage lookup with nodejs 10 | 11 | * Simple interface to lookup cpu and memory usage of any accessible process on the system. 12 | * Works on OSX, Linux, SmartOS and Solaris 13 | * Tested on Heroku, Nodejitsu and Modulus 14 | 15 | ## Example 16 | 17 | ### Code 18 | ~~~js 19 | var usage = require('usage'); 20 | 21 | var pid = process.pid // you can use any valid PID instead 22 | usage.lookup(pid, function(err, result) { 23 | 24 | }); 25 | ~~~ 26 | 27 | ### Result Object 28 | ~~~js 29 | { 30 | memory: 100065280, // in no of bytes 31 | memoryInfo: { 32 | rss: 15966208, // resident size memory in bytes 33 | vsize: 3127906304 // virtual memory size in bytes 34 | }, 35 | cpu: 10.6 // in percentage 36 | } 37 | ~~~ 38 | 39 | ## Average CPU usage vs Current CPU usage 40 | >This is only applicable for Linux 41 | 42 | By default CPU Percentage provided is an average from the starting time of the process. It does not correctly reflect the current CPU usage. (this is also a problem with linux `ps` utility) 43 | 44 | But If you call `usage.lookup()` continuously for a given pid, you can turn on **keepHistory** flag and you'll get the CPU usage since last time you track the usage. This reflects the current CPU usage. 45 | 46 | see following example to enable keepHistory flag 47 | 48 | ~~~js 49 | var pid = process.pid; 50 | var options = { keepHistory: true } 51 | usage.lookup(pid, options, function(err, result) { 52 | 53 | }); 54 | ~~~ 55 | 56 | you can clear history cache too 57 | ~~~js 58 | usage.clearHistory(pid); //clear history for the given pid 59 | usage.clearHistory(); //clean history for all pids 60 | ~~~ 61 | -------------------------------------------------------------------------------- /binary-ready.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git rm binding.gyp 4 | git commit -m "bindings removed" 5 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': [ 3 | { 4 | 'target_name': 'sysinfo', 5 | 'conditions': [ 6 | ['OS=="solaris"', { 7 | 'sources': [ 8 | 'src/solaris.cpp' 9 | ] 10 | }] 11 | ], 12 | "include_dirs": [ 13 | "", 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/arunoda/node-usage.git" 16 | }, 17 | "main": "./lib/usage.js", 18 | "scripts": { 19 | "test": "./node_modules/.bin/mocha" 20 | }, 21 | "engines": { 22 | "node": ">= 0.10.x" 23 | }, 24 | "dependencies": { 25 | "bindings": "1.x.x", 26 | "nan": "^2.0.9" 27 | }, 28 | "devDependencies": { 29 | "mocha": "1.x.x" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/binding.cpp: -------------------------------------------------------------------------------- 1 | #include "binding.h" 2 | #include "nan.h" 3 | using namespace v8; 4 | 5 | void RegisterModule(Local exports) { 6 | 7 | #ifdef is_linux 8 | exports->Set(Nan::New("HERTZ").ToLocalChecked(), Nan::New(sysconf(_SC_CLK_TCK))); 9 | exports->Set(Nan::New("PAGE_SIZE").ToLocalChecked(), Nan::New(sysconf(_SC_PAGESIZE))); 10 | #endif 11 | 12 | #ifdef is_solaris 13 | exports->Set(Nan::New("getUsage").ToLocalChecked(), 14 | FunctionTemplate::New(GetUsage)->GetFunction()); 15 | #endif 16 | exports->Set(Nan::New("OS").ToLocalChecked(), Nan::New(OS).ToLocalChecked()); 17 | } 18 | 19 | NODE_MODULE(sysinfo, RegisterModule); 20 | -------------------------------------------------------------------------------- /src/binding.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef is_linux 4 | #include 5 | #endif 6 | 7 | #ifdef is_solaris 8 | #include "solaris.h" 9 | #endif 10 | -------------------------------------------------------------------------------- /src/solaris.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "solaris.h" 3 | 4 | /* 5 | Getting CPU Usage from the /proc 6 | */ 7 | static int read_buffer(char *buffer, int buffer_size, char* file_path) { 8 | FILE *fp = fopen(file_path, "r"); 9 | if(fp != NULL) { 10 | size_t read_len = fread(buffer, sizeof(char), buffer_size, fp); 11 | if(read_len == 0) { 12 | return 0; 13 | } 14 | 15 | fclose(fp); 16 | return 1; 17 | } else { 18 | return 0; 19 | } 20 | } 21 | 22 | static char* get_proc_file(char* type, char* pid) { 23 | size_t type_len = strlen(type); 24 | size_t pid_len = strlen(pid); 25 | size_t proc_len = strlen("/proc/"); 26 | size_t spaces = 2; 27 | size_t slashes = 1; 28 | 29 | size_t total = proc_len + pid_len + type_len + spaces + slashes + 1; 30 | char* final = (char*)malloc(total); 31 | 32 | sprintf(final, "/proc/%s/%s", pid, type); 33 | return final; 34 | } 35 | 36 | static float get_pct(ushort_t pct) { 37 | uint_t value = pct; /* need 32 bits to compute with */ 38 | value = ((value * 1000) + 0x7000) >> 15; /* [0 .. 1000] */ 39 | 40 | float f_value = (float)value; 41 | return f_value/10; 42 | } 43 | 44 | int get_usage(int pid, ps_usage_t* ps_usage) { 45 | char str_pid[10]; 46 | sprintf(str_pid, "%d", pid); 47 | 48 | char* psinfo_proc_file = get_proc_file("psinfo", str_pid); 49 | psinfo_t psinfo; 50 | int success_psinfo = read_buffer((char*)&psinfo, sizeof(psinfo), psinfo_proc_file); 51 | free(psinfo_proc_file); 52 | 53 | if(success_psinfo) { 54 | ps_usage->cpu = get_pct(psinfo.pr_pctcpu); 55 | ps_usage->memory = psinfo.pr_rssize * 1024; 56 | return 1; 57 | } else { 58 | return 0; 59 | } 60 | } 61 | 62 | /* 63 | V8 Integration 64 | */ 65 | 66 | void AsyncGetUsage(uv_work_t* req) { 67 | UsageData* usageData = static_cast(req->data); 68 | ps_usage_t ps_usage; 69 | int pid_exists = get_usage(usageData->pid, &ps_usage); 70 | 71 | if(pid_exists) { 72 | usageData->ps_usage = ps_usage; 73 | } else { 74 | usageData->failed = true; 75 | } 76 | } 77 | 78 | void AsyncAfterGetUsage(uv_work_t* req) { 79 | UsageData* usageData = static_cast(req->data); 80 | 81 | if(usageData->failed) { 82 | const unsigned argc = 1; 83 | Local argv[argc] = { 84 | Exception::Error(String::New("INVALID_PID")) 85 | }; 86 | usageData->callback->Call(Context::GetCurrent()->Global(), argc, argv); 87 | } else { 88 | Local usage = Object::New(); 89 | usage->Set(String::NewSymbol("cpu"), Number::New(usageData->ps_usage.cpu)); 90 | usage->Set(String::NewSymbol("memory"), Number::New(usageData->ps_usage.memory)); 91 | 92 | const unsigned argc = 2; 93 | Local argv[argc] = { Local::New(Null()), usage }; 94 | usageData->callback->Call(Context::GetCurrent()->Global(), argc, argv); 95 | } 96 | 97 | delete usageData; 98 | delete req; 99 | } 100 | 101 | Handle GetUsage(const Arguments& args) { 102 | HandleScope scope; 103 | 104 | int pid = (int)(Local::Cast(args[0])->Value()); 105 | Local callback = Local::Cast(args[1]); 106 | 107 | UsageData* usageData = new UsageData(); 108 | usageData->pid = pid; 109 | usageData->callback = Persistent::New(callback); 110 | usageData->failed = false; 111 | 112 | uv_work_t* req = new uv_work_t(); 113 | req->data = usageData; 114 | 115 | uv_queue_work(uv_default_loop(), req, AsyncGetUsage, (uv_after_work_cb)AsyncAfterGetUsage); 116 | 117 | return scope.Close(Undefined()); 118 | } 119 | -------------------------------------------------------------------------------- /src/solaris.h: -------------------------------------------------------------------------------- 1 | #ifndef SOLARIS_H 2 | #define SOLARIS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | typedef struct ps_usage { 11 | float cpu; 12 | long memory; 13 | } ps_usage_t; 14 | 15 | using namespace v8; 16 | struct UsageData { 17 | int pid; 18 | Persistent callback; 19 | ps_usage_t ps_usage; 20 | bool failed; 21 | }; 22 | 23 | extern int get_usage(int pid, ps_usage_t* ps_usage); 24 | extern Handle GetUsage(const Arguments& args); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /sysinfo.js: -------------------------------------------------------------------------------- 1 | var format = require('util').format; 2 | 3 | module.exports = function() { 4 | try { 5 | return require('bindings')('sysinfo'); 6 | } catch(ex) { 7 | // let's try to find a pre-compiled binary 8 | 9 | var availableVersionPaths = [ 10 | // currently 0.10.x is enough (currently look for Meteor) 11 | [/v0\.10\..*/, '0.10'] 12 | ]; 13 | 14 | var platform = (process.platform == "solaris")? "sunos": process.platform; 15 | var arch = process.arch; 16 | var version = process.version; 17 | var versionPath; 18 | 19 | for(var lc=0; lc= 0); 16 | assert.ok(result.memory > 0); 17 | assert.ok(result.memoryInfo.rss >= 0); 18 | assert.ok(result.memoryInfo.vsize >= 0); 19 | done(); 20 | }); 21 | }); 22 | 23 | if(process.platform == 'linux') { 24 | test('valid pid - with keepHistory', function(done) { 25 | var options = { keepHistory: true }; 26 | usage.lookup(process.pid, options, function(err, result) { 27 | assert.ifError(err); 28 | assert.ok(result.cpu >= 0); 29 | assert.ok(result.cpuInfo.pcpu >= 0); 30 | assert.ok(result.cpuInfo.pcpuUser >= 0); 31 | assert.ok(result.cpuInfo.pcpuSystem >= 0); 32 | 33 | assert.ok(result.memory > 0); 34 | assert.ok(result.memoryInfo.rss > 0); 35 | assert.ok(result.memoryInfo.vsize > 0); 36 | 37 | for(var lc=0; lc<999999; lc++) { 38 | Math.random(); 39 | } 40 | 41 | setTimeout(function() { 42 | usage.lookup(process.pid, options, checkCpuTime); 43 | }, 200); 44 | }); 45 | 46 | function checkCpuTime (err, result) { 47 | assert.ifError(err); 48 | assert.ok(result.cpu >= 0); 49 | assert.ok(result.cpuInfo.pcpu >= 0); 50 | assert.ok(result.cpuInfo.cpuTime >= 0); 51 | assert.ok(result.cpuInfo.pcpuUser >= 0); 52 | assert.ok(result.cpuInfo.pcpuSystem >= 0); 53 | 54 | assert.ok(result.memory > 0); 55 | assert.ok(result.memoryInfo.rss > 0); 56 | assert.ok(result.memoryInfo.vsize > 0); 57 | usage.clearHistory(); 58 | 59 | usage.lookup(process.pid, options, checkCpuTime); 60 | done(); 61 | } 62 | }); 63 | } 64 | }); 65 | --------------------------------------------------------------------------------