├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bin ├── spm-nodejs-diagnostics.js ├── spmconfig.js └── spmmonitor.js ├── changelog.hbs ├── example ├── childProcess.js ├── cluster.js ├── longComputation.js └── simple-server.js ├── lib ├── eventLoopAgent.js ├── eventLoopStats.js ├── gcAgent.js ├── httpServerAgent.js ├── index.js └── workerAgent.js ├── package-lock.json ├── package.json └── test ├── test-node-versions.sh └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | 30 | # files created by spm during tests 31 | spmlogs 32 | spmdb 33 | .spmagentrc 34 | 35 | # debug 36 | .vscode 37 | 38 | # npm config 39 | .npmrc 40 | .npmignore -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - linux 3 | sudo: false 4 | language: node_js 5 | addons: 6 | apt: 7 | sources: 8 | - ubuntu-toolchain-r-test 9 | packages: 10 | - g++-4.8 11 | node_js: 12 | - "8" 13 | - "10" 14 | - "12" 15 | - "14" 16 | install: 17 | - export CXX=g++-4.8 18 | - $CXX --version 19 | - npm i node-pre-gyp@latest 20 | - npm i 21 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### Changelog 2 | 3 | All notable changes to this project will be documented in this file. Dates are displayed in UTC. 4 | 5 | Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). 6 | 7 | #### [4.2.7](https://github.com/sematext/spm-agent-nodejs/compare/4.2.6...4.2.7) 8 | 9 | > 7 August 2023 10 | 11 | - fix: upgrade libraries [`#69`](https://github.com/sematext/spm-agent-nodejs/pull/69) 12 | - Bump semver from 5.7.1 to 5.7.2 [`#67`](https://github.com/sematext/spm-agent-nodejs/pull/67) 13 | - Bump word-wrap from 1.2.3 to 1.2.4 [`#68`](https://github.com/sematext/spm-agent-nodejs/pull/68) 14 | 15 | #### [4.2.6](https://github.com/sematext/spm-agent-nodejs/compare/4.2.5...4.2.6) 16 | 17 | > 15 June 2023 18 | 19 | - chore: upgrade spm-agent library [`#66`](https://github.com/sematext/spm-agent-nodejs/pull/66) 20 | - Release 4.2.6 [`ca7868b`](https://github.com/sematext/spm-agent-nodejs/commit/ca7868b8d476ca84f70affe43a1e77100425f551) 21 | 22 | #### [4.2.5](https://github.com/sematext/spm-agent-nodejs/compare/4.2.4...4.2.5) 23 | 24 | > 15 June 2023 25 | 26 | - chore: upgrade spm_agent library [`#65`](https://github.com/sematext/spm-agent-nodejs/pull/65) 27 | - Release 4.2.5 [`2d472a5`](https://github.com/sematext/spm-agent-nodejs/commit/2d472a5528def82aa083851eef61a5c9bb241b62) 28 | 29 | #### [4.2.4](https://github.com/sematext/spm-agent-nodejs/compare/4.2.3...4.2.4) 30 | 31 | > 15 June 2023 32 | 33 | - Fix library vulnerabilities [`#64`](https://github.com/sematext/spm-agent-nodejs/pull/64) 34 | - Bump yaml from 1.10.2 to [`#61`](https://github.com/sematext/spm-agent-nodejs/pull/61) 35 | - Bump vm2 from 3.9.17 to 3.9.19 [`#63`](https://github.com/sematext/spm-agent-nodejs/pull/63) 36 | - Bump vm2 from 3.9.16 to 3.9.17 [`#60`](https://github.com/sematext/spm-agent-nodejs/pull/60) 37 | - Bump vm2 from 3.9.11 to 3.9.16 [`#59`](https://github.com/sematext/spm-agent-nodejs/pull/59) 38 | - Bump http-cache-semantics from 4.1.0 to 4.1.1 [`#58`](https://github.com/sematext/spm-agent-nodejs/pull/58) 39 | - chore: upgrade the libraries with vulnerabilities [`332bd95`](https://github.com/sematext/spm-agent-nodejs/commit/332bd95b95023f605c0a91c6708afe77786a0422) 40 | - chore: remove the test of already deleted process [`9fdfbd1`](https://github.com/sematext/spm-agent-nodejs/commit/9fdfbd13c536ed4d7a091619eb8aec9894c4b12c) 41 | - Release 4.2.4 [`91e7cd3`](https://github.com/sematext/spm-agent-nodejs/commit/91e7cd3a1dcd036fe73f095b088b4344e7f0883c) 42 | 43 | #### [4.2.3](https://github.com/sematext/spm-agent-nodejs/compare/4.2.2...4.2.3) 44 | 45 | > 16 December 2022 46 | 47 | - SC-14625: Update mocha to version 10.2.0 and switch gc-stats to Sematext fork [`#55`](https://github.com/sematext/spm-agent-nodejs/pull/55) 48 | - Bump qs from 6.5.2 to 6.5.3 [`#53`](https://github.com/sematext/spm-agent-nodejs/pull/53) 49 | - Update mocha to version 10.2.0 and switch gc-stats to Sematext fork [`3df9823`](https://github.com/sematext/spm-agent-nodejs/commit/3df982359dd1dd674127711fc7b4d3d43b47e76c) 50 | - Release 4.2.3 [`d8d2dbe`](https://github.com/sematext/spm-agent-nodejs/commit/d8d2dbed912e3775f43d3e3aa90b6742b8e65d7d) 51 | 52 | #### [4.2.2](https://github.com/sematext/spm-agent-nodejs/compare/4.2.1...4.2.2) 53 | 54 | > 13 October 2022 55 | 56 | - Point gc-stats to fork with custom binary URI [`#51`](https://github.com/sematext/spm-agent-nodejs/pull/51) 57 | - Bump vm2 from 3.9.10 to 3.9.11 [`#50`](https://github.com/sematext/spm-agent-nodejs/pull/50) 58 | - Release 4.2.2 [`ab462d6`](https://github.com/sematext/spm-agent-nodejs/commit/ab462d6cff1247dfe35fe623b3cd21b438f70865) 59 | 60 | #### [4.2.1](https://github.com/sematext/spm-agent-nodejs/compare/4.2.0...4.2.1) 61 | 62 | > 20 September 2022 63 | 64 | - Update dependencies [`#49`](https://github.com/sematext/spm-agent-nodejs/pull/49) 65 | - Bump jose from 1.28.1 to 1.28.2 [`#48`](https://github.com/sematext/spm-agent-nodejs/pull/48) 66 | - SC-12404: Address high score vulnerability [`#47`](https://github.com/sematext/spm-agent-nodejs/pull/47) 67 | - Address high score vulnerability [`f423b8e`](https://github.com/sematext/spm-agent-nodejs/commit/f423b8e32d536775df875c0ecb6b6904c5fab5ae) 68 | - Release 4.2.1 [`b55e454`](https://github.com/sematext/spm-agent-nodejs/commit/b55e4547d211425b711a03622e8c40d596cb3df2) 69 | 70 | #### [4.2.0](https://github.com/sematext/spm-agent-nodejs/compare/4.1.4...4.2.0) 71 | 72 | > 8 July 2022 73 | 74 | - SC-13033 Update dependencies [`#46`](https://github.com/sematext/spm-agent-nodejs/pull/46) 75 | - Bump minimist from 1.2.5 to 1.2.6 [`#43`](https://github.com/sematext/spm-agent-nodejs/pull/43) 76 | - Bump node-fetch from 2.6.1 to 2.6.7 [`#44`](https://github.com/sematext/spm-agent-nodejs/pull/44) 77 | - Bump moment from 2.29.1 to 2.29.2 [`#42`](https://github.com/sematext/spm-agent-nodejs/pull/42) 78 | - Update dependencies [`1f14495`](https://github.com/sematext/spm-agent-nodejs/commit/1f14495eaab2f737fdc84d6ff7b266e1665cf074) 79 | - Release 4.2.0 [`5276ebf`](https://github.com/sematext/spm-agent-nodejs/commit/5276ebf0a750e770b808329b1c1369f3750f8d3a) 80 | - Added a pointer to tag configuration [`04429df`](https://github.com/sematext/spm-agent-nodejs/commit/04429df542bb631bbb48533a5327531da6ff9bf4) 81 | 82 | #### [4.1.4](https://github.com/sematext/spm-agent-nodejs/compare/4.1.3...4.1.4) 83 | 84 | > 1 July 2021 85 | 86 | - Bump ws from 6.2.1 to 6.2.2 [`#40`](https://github.com/sematext/spm-agent-nodejs/pull/40) 87 | - Bump glob-parent from 5.1.1 to 5.1.2 [`#41`](https://github.com/sematext/spm-agent-nodejs/pull/41) 88 | - Bump hosted-git-info from 2.8.8 to 2.8.9 [`#39`](https://github.com/sematext/spm-agent-nodejs/pull/39) 89 | - Bump handlebars from 4.7.6 to 4.7.7 [`#38`](https://github.com/sematext/spm-agent-nodejs/pull/38) 90 | - Bump jose from 1.28.0 to 1.28.1 [`#37`](https://github.com/sematext/spm-agent-nodejs/pull/37) 91 | - update deps [`2a336ec`](https://github.com/sematext/spm-agent-nodejs/commit/2a336ecc487d1c50a02e3e1eabc70be2d4802099) 92 | - updated deps [`36dd221`](https://github.com/sematext/spm-agent-nodejs/commit/36dd22133c2d7d93139b907f2cdedf34310f71b2) 93 | - Release 4.1.4 [`55aad02`](https://github.com/sematext/spm-agent-nodejs/commit/55aad0215d19eb05c0b40410a9768cc8ac81265e) 94 | 95 | #### [4.1.3](https://github.com/sematext/spm-agent-nodejs/compare/4.1.2...4.1.3) 96 | 97 | > 7 April 2021 98 | 99 | - updated deps [`a192811`](https://github.com/sematext/spm-agent-nodejs/commit/a1928114728f80c578ba6c6573f3c312b5b29d41) 100 | - Release 4.1.3 [`59a1bea`](https://github.com/sematext/spm-agent-nodejs/commit/59a1beac988b4c98ef07dd4d760db8e48c64b34d) 101 | 102 | #### [4.1.2](https://github.com/sematext/spm-agent-nodejs/compare/4.1.1...4.1.2) 103 | 104 | > 15 February 2021 105 | 106 | - update spm-agent [`dff975f`](https://github.com/sematext/spm-agent-nodejs/commit/dff975f3bbabb580801fcc7203ebcaa187613cf1) 107 | - Release 4.1.2 [`e5bcad0`](https://github.com/sematext/spm-agent-nodejs/commit/e5bcad0b2a0bed1e5a7ad9107d6279af55512893) 108 | 109 | #### [4.1.1](https://github.com/sematext/spm-agent-nodejs/compare/4.1.0...4.1.1) 110 | 111 | > 13 January 2021 112 | 113 | - remove process agent [`eb6fe30`](https://github.com/sematext/spm-agent-nodejs/commit/eb6fe30b9f24af3286216006405ea16f97ccc637) 114 | - Release 4.1.1 [`e91929b`](https://github.com/sematext/spm-agent-nodejs/commit/e91929b63a934e66f61038765a47e6ca350e68ed) 115 | 116 | #### [4.1.0](https://github.com/sematext/spm-agent-nodejs/compare/4.0.4...4.1.0) 117 | 118 | > 22 December 2020 119 | 120 | - Bump ini from 1.3.5 to 1.3.7 [`#33`](https://github.com/sematext/spm-agent-nodejs/pull/33) 121 | - audit [`645c593`](https://github.com/sematext/spm-agent-nodejs/commit/645c593f69749f47689c5994589168da11aae038) 122 | - update som-agent [`fcc70fc`](https://github.com/sematext/spm-agent-nodejs/commit/fcc70fcf2feaff91c70a0c4a41109e73cca701aa) 123 | - Release 4.1.0 [`5cda30f`](https://github.com/sematext/spm-agent-nodejs/commit/5cda30fd3aa623982af5926c747a561923a19314) 124 | 125 | #### [4.0.4](https://github.com/sematext/spm-agent-nodejs/compare/4.0.3...4.0.4) 126 | 127 | > 21 October 2020 128 | 129 | - Release 4.0.4 [`7bf75f6`](https://github.com/sematext/spm-agent-nodejs/commit/7bf75f6d31ca8ad0df805cf04d20f101fb437994) 130 | - fix require [`cddc55a`](https://github.com/sematext/spm-agent-nodejs/commit/cddc55a895dcf09cd1119a5645f27b755ab3387d) 131 | 132 | #### [4.0.3](https://github.com/sematext/spm-agent-nodejs/compare/4.0.2...4.0.3) 133 | 134 | > 21 October 2020 135 | 136 | - Bump node-fetch from 2.6.0 to 2.6.1 [`#32`](https://github.com/sematext/spm-agent-nodejs/pull/32) 137 | - change gc-stats dep [`d216f02`](https://github.com/sematext/spm-agent-nodejs/commit/d216f024ff64201b144f55c6642ba808b3ed0b59) 138 | - updated npm deps [`2fd9870`](https://github.com/sematext/spm-agent-nodejs/commit/2fd9870dff0716e379a7ece3b425e75cd6e98fb6) 139 | - Release 4.0.3 [`12b5438`](https://github.com/sematext/spm-agent-nodejs/commit/12b543802119e443cc708069bdff545e426deed2) 140 | 141 | #### [4.0.2](https://github.com/sematext/spm-agent-nodejs/compare/4.0.1...4.0.2) 142 | 143 | > 11 May 2020 144 | 145 | - updated deps [`6fe61fd`](https://github.com/sematext/spm-agent-nodejs/commit/6fe61fdd23d14407972ca52a235e71716a4bcc5c) 146 | - updated diag package [`9eecbf1`](https://github.com/sematext/spm-agent-nodejs/commit/9eecbf10e94a743b20886da7ca75590e516c5b5e) 147 | - Release 4.0.2 [`8467a3f`](https://github.com/sematext/spm-agent-nodejs/commit/8467a3f8e626417b679eb66549de822adbd552a5) 148 | 149 | #### [4.0.1](https://github.com/sematext/spm-agent-nodejs/compare/4.0.0...4.0.1) 150 | 151 | > 17 April 2020 152 | 153 | - added changelog [`7a9b7a3`](https://github.com/sematext/spm-agent-nodejs/commit/7a9b7a3550dbb6c8dc38cf262d8fca2568d85935) 154 | - Release 4.0.1 [`ccec648`](https://github.com/sematext/spm-agent-nodejs/commit/ccec64865112816c2be883c93e960407be4070b5) 155 | - fixed release config [`d593b46`](https://github.com/sematext/spm-agent-nodejs/commit/d593b468162157c58b6ac3c7eab7dd14c21c943d) 156 | 157 | ### [4.0.0](https://github.com/sematext/spm-agent-nodejs/compare/3.0.3...4.0.0) 158 | 159 | > 17 April 2020 160 | 161 | - Remove OS monitor with node-df [`#31`](https://github.com/sematext/spm-agent-nodejs/pull/31) 162 | - Added release it config [`#30`](https://github.com/sematext/spm-agent-nodejs/pull/30) 163 | - added auto changelog to release it scripts [`bffe2d8`](https://github.com/sematext/spm-agent-nodejs/commit/bffe2d8b502782c54d25de0f4b61e54b61637344) 164 | - removed npx [`30f0566`](https://github.com/sematext/spm-agent-nodejs/commit/30f0566354e6d7f318cb9834dba3c17d81d8e46c) 165 | - removed OS monitor [`739806f`](https://github.com/sematext/spm-agent-nodejs/commit/739806f0497b9547ae47e3860d23f9aa28644c3d) 166 | 167 | #### [3.0.3](https://github.com/sematext/spm-agent-nodejs/compare/3.0.1...3.0.3) 168 | 169 | > 21 February 2020 170 | 171 | - Fix and edit for spmconfig command to take env vars [`#28`](https://github.com/sematext/spm-agent-nodejs/pull/28) 172 | - clean up generated file [`8c965bf`](https://github.com/sematext/spm-agent-nodejs/commit/8c965bf111afa49ca6d9bdf7eaa77f0771565203) 173 | - fixed and refactored spmconfig command to take env vars [`4d08b2c`](https://github.com/sematext/spm-agent-nodejs/commit/4d08b2c7fca32f5dc92a79fe52e736b4ab6cfb51) 174 | - update readme pm2 section [`15c8da9`](https://github.com/sematext/spm-agent-nodejs/commit/15c8da9d459481325727d14eade322e45a80a90e) 175 | 176 | #### [3.0.1](https://github.com/sematext/spm-agent-nodejs/compare/3.0.0...3.0.1) 177 | 178 | > 22 January 2020 179 | 180 | - Added fixes to process metrics [`#22`](https://github.com/sematext/spm-agent-nodejs/pull/22) 181 | - Add missing tags pid, ppid [`#27`](https://github.com/sematext/spm-agent-nodejs/pull/27) 182 | - add process.thread.count metric [`#26`](https://github.com/sematext/spm-agent-nodejs/pull/26) 183 | - Add infra token to setup script [`#24`](https://github.com/sematext/spm-agent-nodejs/pull/24) 184 | - add infra token to process metrics [`#25`](https://github.com/sematext/spm-agent-nodejs/pull/25) 185 | - hotfix: updated OS agent, edited pm2 config to not need env var [`78f936d`](https://github.com/sematext/spm-agent-nodejs/commit/78f936daadf366e7b08359579cae0ee117de5729) 186 | - update npm packages [`eb8b6eb`](https://github.com/sematext/spm-agent-nodejs/commit/eb8b6ebed5d025c23d0f2180966f62179131f5dc) 187 | - fix failing tests for processAgent [`5c2d99a`](https://github.com/sematext/spm-agent-nodejs/commit/5c2d99a9c60ac59eefd65743fae870101282ec07) 188 | 189 | ### [3.0.0](https://github.com/sematext/spm-agent-nodejs/compare/2.0.4...3.0.0) 190 | 191 | > 5 December 2019 192 | 193 | - Bump lodash from 4.17.11 to 4.17.15 [`#19`](https://github.com/sematext/spm-agent-nodejs/pull/19) 194 | - Bump eslint from 3.18.0 to 6.4.0 [`#20`](https://github.com/sematext/spm-agent-nodejs/pull/20) 195 | - SC-4677: Added support for tracking process types [`#17`](https://github.com/sematext/spm-agent-nodejs/pull/17) 196 | - change all nodejs-metrics to influx-metric format [`#18`](https://github.com/sematext/spm-agent-nodejs/pull/18) 197 | - SC-4677: added generic tests for various cases [`7c84fd7`](https://github.com/sematext/spm-agent-nodejs/commit/7c84fd7e06ee981b1d66cbcf48fc7da83e9c5a26) 198 | - SC-4677: code cleanup + testing [`22494f7`](https://github.com/sematext/spm-agent-nodejs/commit/22494f7179294b4c2fc757b57befcaec8be5681a) 199 | - SC-4677: separated worker metrics into dedicated agent and added process agent [`31a85e8`](https://github.com/sematext/spm-agent-nodejs/commit/31a85e87959fb78ec6cfba371a62099a648a4003) 200 | 201 | #### [2.0.4](https://github.com/sematext/spm-agent-nodejs/compare/2.0.3...2.0.4) 202 | 203 | > 5 November 2019 204 | 205 | - update dependencies, standard code format, remove deprecated modules [`daf61a9`](https://github.com/sematext/spm-agent-nodejs/commit/daf61a9a0e25652d62f64e6cb01ea8ebb01a51d6) 206 | - Tweaked a few old links [`d47ac12`](https://github.com/sematext/spm-agent-nodejs/commit/d47ac1255035291a98156d1340d2483712365b05) 207 | - Release 2.0.4 [`3b00ecd`](https://github.com/sematext/spm-agent-nodejs/commit/3b00ecd7193a3fb57177f01e26cb349b29f07942) 208 | 209 | #### [2.0.3](https://github.com/sematext/spm-agent-nodejs/compare/2.0.2...2.0.3) 210 | 211 | > 26 April 2019 212 | 213 | - Release 2.0.3 [`ee2d318`](https://github.com/sematext/spm-agent-nodejs/commit/ee2d318540b378a19ac2a1597fc04cc9b77faf3c) 214 | - fix link to documentation [`7a48c5f`](https://github.com/sematext/spm-agent-nodejs/commit/7a48c5f97a9934e937ea270839c463b066be3382) 215 | 216 | #### [2.0.2](https://github.com/sematext/spm-agent-nodejs/compare/2.0.1...2.0.2) 217 | 218 | > 26 April 2019 219 | 220 | - update dependencies [`fa72947`](https://github.com/sematext/spm-agent-nodejs/commit/fa729470b4ba102987efd3f5fb655045e59d28e6) 221 | - Release 2.0.2 [`b078237`](https://github.com/sematext/spm-agent-nodejs/commit/b078237aea9fe30ee10d81fb63064158f4c8a588) 222 | - update screenshot [`54643d1`](https://github.com/sematext/spm-agent-nodejs/commit/54643d129c1ce54be809ca0145de5a9c6d534013) 223 | 224 | #### [2.0.1](https://github.com/sematext/spm-agent-nodejs/compare/2.0.0...2.0.1) 225 | 226 | > 28 December 2018 227 | 228 | - remove mentions of node 0.10/0.12/4 [`1664702`](https://github.com/sematext/spm-agent-nodejs/commit/1664702eeaf33bc46c23d4f3987e8790249da9a6) 229 | - remove support for Node.js v4 [`1369f91`](https://github.com/sematext/spm-agent-nodejs/commit/1369f916e8232ecd4919045546b033e7ab7e8430) 230 | - Release 2.0.1 [`45c5b0d`](https://github.com/sematext/spm-agent-nodejs/commit/45c5b0d5bef403c2bba143a6739421224e277848) 231 | 232 | ### [2.0.0](https://github.com/sematext/spm-agent-nodejs/compare/1.30.9...2.0.0) 233 | 234 | > 28 December 2018 235 | 236 | - add package-lock.json [`908002a`](https://github.com/sematext/spm-agent-nodejs/commit/908002ad8951f20c698b72e9960999fdc2cb9b53) 237 | - update node packages [`b81dc7a`](https://github.com/sematext/spm-agent-nodejs/commit/b81dc7a5f3944e9f7aadb602ca0ca715a2b98fdd) 238 | - update yarn.lock [`a467f7e`](https://github.com/sematext/spm-agent-nodejs/commit/a467f7e77aaf5fdbbf7dbd0e7db02ea0f2a2e60e) 239 | 240 | #### [1.30.9](https://github.com/sematext/spm-agent-nodejs/compare/1.30.8...1.30.9) 241 | 242 | > 6 July 2017 243 | 244 | - update yarn.lock [`14564a1`](https://github.com/sematext/spm-agent-nodejs/commit/14564a1a3d6b135ff00798f7e7243553eb4a3bea) 245 | - Update README.md [`59c33d6`](https://github.com/sematext/spm-agent-nodejs/commit/59c33d61a4b20afe75ab7154ee9ca5e2d4ee4f39) 246 | - add EU instructions [`7978152`](https://github.com/sematext/spm-agent-nodejs/commit/7978152de4fe22c70caa1e2a07aa5d0706c1b0b4) 247 | 248 | #### [1.30.8](https://github.com/sematext/spm-agent-nodejs/compare/1.30.7...1.30.8) 249 | 250 | > 7 April 2017 251 | 252 | - Release 1.30.8 [`5fa7dd5`](https://github.com/sematext/spm-agent-nodejs/commit/5fa7dd5d50ceaa6e00f530024cfe477108fd62e4) 253 | - update screenshot [`d3baeb6`](https://github.com/sematext/spm-agent-nodejs/commit/d3baeb6fe0a06d90a3aea925c23def0dc3bfced1) 254 | 255 | #### [1.30.7](https://github.com/sematext/spm-agent-nodejs/compare/1.30.6...1.30.7) 256 | 257 | > 8 March 2017 258 | 259 | - feat: domain handling [`#11`](https://github.com/sematext/spm-agent-nodejs/pull/11) 260 | - style: standard [`ec58d43`](https://github.com/sematext/spm-agent-nodejs/commit/ec58d433511402630a49466aa46ccd2549af8289) 261 | - fix: typos, constants [`1bf739d`](https://github.com/sematext/spm-agent-nodejs/commit/1bf739d35d0e6c4ac8d51aba616c7d022df6364b) 262 | - fix: make sure we clean setInterval [`4faffe5`](https://github.com/sematext/spm-agent-nodejs/commit/4faffe52d639ddfb1cd7692530c8bf7c44ff21ca) 263 | 264 | #### [1.30.6](https://github.com/sematext/spm-agent-nodejs/compare/1.30.4...1.30.6) 265 | 266 | > 27 February 2017 267 | 268 | - Release 1.30.6 [`868023e`](https://github.com/sematext/spm-agent-nodejs/commit/868023e07157eef75c9d6eb7592fd531bdfe949c) 269 | - support npm 'startup' [`d0becef`](https://github.com/sematext/spm-agent-nodejs/commit/d0becef0bd5a8eb34da58744d12e6f074e3fb90e) 270 | - update travis for node 7 [`6acd1fa`](https://github.com/sematext/spm-agent-nodejs/commit/6acd1fa77d017278d77a20497c6d34f4952ea64a) 271 | 272 | #### [1.30.4](https://github.com/sematext/spm-agent-nodejs/compare/1.30.3...1.30.4) 273 | 274 | > 25 January 2017 275 | 276 | - generate default config in YAML format, updated dependencies [`db18cde`](https://github.com/sematext/spm-agent-nodejs/commit/db18cde8f318a7e5efa3d5d76c2098dea697dfc3) 277 | - Release 1.30.4 [`029c6c1`](https://github.com/sematext/spm-agent-nodejs/commit/029c6c122bfce32f702ba801424681facd9d17de) 278 | 279 | #### [1.30.3](https://github.com/sematext/spm-agent-nodejs/compare/1.30.2...1.30.3) 280 | 281 | > 16 January 2017 282 | 283 | - update dependencies [`e8b4a1e`](https://github.com/sematext/spm-agent-nodejs/commit/e8b4a1e909cb2b1c4bf6812898cfbf28075c3982) 284 | - Release 1.30.3 [`a6ee800`](https://github.com/sematext/spm-agent-nodejs/commit/a6ee800f1ea66702a92b991a2f615ed017fbcb5f) 285 | 286 | #### [1.30.2](https://github.com/sematext/spm-agent-nodejs/compare/1.30.1...1.30.2) 287 | 288 | > 22 September 2016 289 | 290 | - add check for pm2 env / master mode, fix typo [`478105e`](https://github.com/sematext/spm-agent-nodejs/commit/478105e5dbf03b7b85a356df4aa6ce2b788a2a22) 291 | - Release 1.30.2 [`0dd50a5`](https://github.com/sematext/spm-agent-nodejs/commit/0dd50a5f4969691f8fad4c25af44f0d0179dea6b) 292 | - add check for pm2 env / master mode [`69fcd99`](https://github.com/sematext/spm-agent-nodejs/commit/69fcd998f884a84b7b940a41f71f33a9c078b33d) 293 | 294 | #### 1.30.1 295 | 296 | > 15 July 2016 297 | 298 | - updated test and readme [`8adcfb4`](https://github.com/sematext/spm-agent-nodejs/commit/8adcfb4cd9af290a2a162fd5f03d066abd3ac8aa) 299 | - code format, multi-version test script [`040b981`](https://github.com/sematext/spm-agent-nodejs/commit/040b98138b3cfabf5fbdd32e81ab3c1912a4ce2f) 300 | - jshintrc and code formatting [`caa22c4`](https://github.com/sematext/spm-agent-nodejs/commit/caa22c4d03f92815a7e30665f48140f66877f0e4) 301 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2015 Sematext Group, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | spm-agent-nodejs 2 | ================ 3 | 4 | 5 | ![npm-stats](https://nodei.co/npm/spm-agent-nodejs.png?downloads=true&downloadRank=true) 6 | 7 | This is the [Node.js monitoring](https://sematext.com/integrations/nodejs-monitoring) agent for [Sematext Cloud](https://sematext.com/cloud). 8 | 9 | The following information is collected and transmitted to Sematext: 10 | 11 | - OS Metrics (CPU / Mem) 12 | - Process Memory 13 | - EventLoop stats 14 | - Garbage Collector stats 15 | - Web server stats (requests, error rate, response times etc.) 16 | Working for all web servers frameworks that use Node.js http/https module including 17 | - "connect" based frameworks 18 | - Express.js, 19 | - Sails.js 20 | - Hapi.js 21 | - Restify 22 | - and others ... 23 | 24 | The module is able to run in cluster mode (master/worker). 25 | 26 | # Status 27 | 28 | Supported Node-Versions: Node >= 6.x. 29 | 30 | Please check our [blog](https://sematext.com/tag/node-js/) for more information or contact us at [npmjs@sematext.com](mailto:npmjs@sematext.com). 31 | 32 | # Installation 33 | 34 | - [How to Add Performance Monitoring to Node.js Applications](https://sematext.com/blog/adding-monitoring-to-node-js-and-io-js-apps/) 35 | 36 | ``` 37 | 38 | npm install spm-agent-nodejs 39 | 40 | ``` 41 | 42 | Get a free account and create a Node.js API token at [sematext.com/spm](https://apps.sematext.com/ui/registration) 43 | 44 | # Configuration 45 | 46 | We use https://www.npmjs.com/package/rc for configuration. This means config parameters can be passed via several config 47 | locations command-line args or ENV variables. We recommend to use a file in current directory in INI or JSON format called ".spmagentrc". 48 | This file can be generated by calling a helper script: 49 | 50 | export MONITORING_TOKEN=YOUR-NODEJS-MONITORING-TOKEN 51 | export INFRA_TOKEN=YOUR-INFRA-MONITORING-TOKEN 52 | node ./node_modules/spm-agent-nodejs/bin/spmconfig.js 53 | 54 | The command above generates following default configuration file (YAML format): 55 | 56 | # Directory for buffered metrics 57 | dbDir: ./spmdb 58 | 59 | # Application Token for SPM 60 | tokens: 61 | monitoring: YOUR-NODEJS-MONITORING-TOKEN 62 | infra: YOUR-INFRA-MONITORING-TOKEN 63 | 64 | logger 65 | # log file directory default is ./spmlogs 66 | dir: ./spmlogs 67 | # silent = true means no creation of log files 68 | silent: false 69 | # log level for output - debug, info, error, defaults to error to be quiet 70 | level: error 71 | 72 | 73 | The only required setting is the Sematext App Token, this could be set via config file ".spmagentrc" or environment variable: 74 | 75 | export spmagent_tokens__monitoring=YOUR-NODEJS-MONITORING-TOKEN 76 | 77 | Please note the use of double "_" for nested properties 78 | 79 | 80 | ## Configuration via Environment Variables 81 | 82 | export MONITORING_TOKEN=YOUR-NODEJS-MONITORING-TOKEN 83 | export INFRA_TOKEN=YOUR-INFRA-MONITORING-TOKEN 84 | # default is SaaS at sematext.com, URL needs to be changed for on-prem to the local SPM receiver 85 | export SPM_RECEIVER_URL=https://local-spm-server:8084/_bulk 86 | export EVENTS_RECEIVER_URL=https://local-event-receiver/ 87 | export SPM_DB_DIR=/tmp 88 | export SPM_LOG_DIRECTORY=./logs 89 | export SPM_LOG_LEVEL=error 90 | export SPM_LOG_TO_CONSOLE=true 91 | export HTTPS_PROXY=http://my-local-proxy-server 92 | 93 | ## Changing API endpoints for Sematext Cloud EU 94 | 95 | ``` 96 | export SPM_RECEIVER_URL=https://spm-receiver.eu.sematext.com/receiver/v1 97 | export EVENTS_RECEIVER_URL=https://event-receiver.eu.sematext.com 98 | ``` 99 | 100 | # Tags 101 | 102 | To configure tags to send along with metrics please see [spm-agent README](https://github.com/sematext/spm-agent/blob/master/README.md). 103 | 104 | # Usage 105 | 106 | ## Method 1: Preloading spm-agent-nodejs - no source code modifications requred 107 | 108 | The command line option "-r" preloads node modules before the actual application is started. In this case the original source code needs no modification: 109 | 110 | ```sh 111 | node -r './spm-agent-nodejs' yourApp.js 112 | ``` 113 | 114 | ## Method 2: Add spm-agent-nodejs to your source code 115 | Add this line at the begin of your source code / main script / app.js 116 | 117 | ``` 118 | # add spm-agent-nodejs to your project 119 | npm i spm-agent-nodejs --save 120 | ``` 121 | 122 | ```js 123 | require('spm-agent-nodejs') 124 | ``` 125 | 126 | ## With PM2 127 | Use the absolute path to your `.env` file to enable PM2 monitoring. 128 | 129 | ```js 130 | // load env vars if you're using dotenv 131 | require('dotenv').config({ path: '/absolute/path/to/your/project/.env' }) 132 | // start agent 133 | require('spm-agent-nodejs') 134 | ``` 135 | 136 | ```bash 137 | pm2 start app.js -i max 138 | ``` 139 | 140 | # Results 141 | 142 | - _[Top Node.js Metrics to Watch](https://blog.sematext.com/top-nodejs-metrics-to-watch/) 143 | ![SPM for Node.js screenshot](https://sematext.com/wp-content/uploads/2019/04/sematext-nodejs-metrics.png)_ 144 | 145 | # Troubleshooting 146 | 147 | Please visit our [documentation](https://sematext.com/docs/integration/node.js/) for more information. 148 | 149 | # Other monitoring packages 150 | 151 | Please check out [spm-metrics-js](https://www.npmjs.com/package/spm-metrics-js) to monitor any custom metric in your application. 152 | 153 | [Sematext Docker Agent](https://hub.docker.com/r/sematext/agent/) (see also: https://sematext.com/docker and https://sematext.com/kubernetes) 154 | 155 | # LICENSE 156 | 157 | Apache 2 - see [LICENSE](https://github.com/sematext/spm-agent-nodejs/blob/master/LICENSE) file. 158 | -------------------------------------------------------------------------------- /bin/spm-nodejs-diagnostics.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* 3 | * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved 4 | * 5 | * @licence SPM for Node.js is free-to-use, proprietary software. 6 | * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext) 7 | * This source code may not be copied, reverse engineered, or altered for any purpose. 8 | * This source code is to be used exclusively by users and customers of Sematext. 9 | * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies. 10 | */ 11 | var fs = require('fs') 12 | var AdmZip = require('adm-zip') 13 | var zip = new AdmZip() 14 | var config = require('spm-agent').Config 15 | var util = require('util') 16 | var os = require('os') 17 | var path = require('path') 18 | 19 | var systemInfo = { 20 | operatingSystem: os.type() + ', ' + os.platform() + ', ' + os.release() + ', ' + os.arch(), 21 | processVersions: process.versions, 22 | processEnvironment: process.env 23 | } 24 | 25 | // load ENV like Logsene receivers from file containing 26 | // env vars e.g. SPM_RECEIVER_URL, EVENTS_RECEIVER_URL, LOGSENE_RECEIVER_URL 27 | // the file overwrites the actual environment 28 | // and is used by Sematext Enterprise or multi-region setups to 29 | // setup receiver URLs 30 | function loadEnvFromFile (fileName) { 31 | try { 32 | var receivers = fs.readFileSync(fileName).toString() 33 | if (receivers) { 34 | var lines = receivers.split('\n') 35 | } 36 | systemInfo.receiverConfigFileUsed = fileName 37 | systemInfo.receivers = receivers 38 | console.log('Reading receivers.config: ' + fileName) 39 | lines.forEach(function (line) { 40 | var kv = line.split('=') 41 | if (kv.length === 2 && kv[1].length > 0) { 42 | process.env[kv[0].trim()] = kv[1].trim() 43 | console.log(kv[0].trim() + ' = ' + kv[1].trim()) 44 | } 45 | }) 46 | } catch (error) {} 47 | } 48 | var envFileName = '/etc/sematext/receivers.config' 49 | /** 50 | if (/win/.test(os.platform()) { 51 | envFileName = process.env.ProgramData + '\\Sematext\\receivers.config' 52 | } 53 | **/ 54 | loadEnvFromFile(envFileName) 55 | 56 | var cfgDumpFileName = path.join(os.tmpdir(), 'spm-nodejs-diagnostics.json') 57 | fs.writeFileSync(cfgDumpFileName, util.inspect(config).toString() + '\nSystem-Info:\n' + util.inspect(systemInfo)) 58 | zip.addLocalFile(cfgDumpFileName) 59 | zip.addLocalFolder(config.logger.dir) 60 | 61 | var archFileName = path.join(os.tmpdir(), 'spm-nodejs-diagnostics.zip') 62 | zip.writeZip(archFileName) 63 | console.log('Sematext Agent Node.js diagnostics info is in: ' + archFileName) 64 | console.log('Please e-mail the file to support@sematext.com') 65 | fs.unlink(cfgDumpFileName, function () {}) 66 | -------------------------------------------------------------------------------- /bin/spmconfig.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* 3 | * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved 4 | * 5 | * @licence SPM for NodeJS is free-to-use, proprietary software. 6 | * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext) 7 | * This source code may not be copied, reverse engineered, or altered for any purpose. 8 | * This source code is to be used exclusively by users and customers of Sematext. 9 | * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies. 10 | */ 11 | const fs = require('fs') 12 | const os = require('os') 13 | const path = require('path') 14 | 15 | let monitoringToken = '' 16 | let monitoringTokenString = '' 17 | let infraToken = '' 18 | 19 | if (process.env.SPM_TOKEN) { 20 | monitoringToken = process.env.SPM_TOKEN 21 | monitoringTokenString = ` spm: ${monitoringToken}` 22 | } 23 | if (process.env.MONITORING_TOKEN) { 24 | monitoringToken = process.env.MONITORING_TOKEN 25 | monitoringTokenString = ` monitoring: ${monitoringToken}` 26 | } 27 | if (process.env.INFRA_TOKEN) { infraToken = process.env.INFRA_TOKEN } 28 | 29 | if (monitoringToken === '') { 30 | console.log('[Required] Add a MONITORING_TOKEN to your environment: \'$ export MONITORING_TOKEN=\'') 31 | process.exit(0) 32 | } 33 | if (infraToken === '') { 34 | console.log('[Optional] Add an INFRA_TOKEN to your environment: \'$ export INFRA_TOKEN=\'\n') 35 | } 36 | 37 | let useLinuxAgent = 'false' 38 | if (os.platform() === 'linux') { 39 | useLinuxAgent = 'true' 40 | } 41 | const cfgLines = [ 42 | "# Please don't change this configuration", 43 | '# Directory for buffered metrics', 44 | 'useLinuxAgent: ' + useLinuxAgent, 45 | `dbDir: ${path.join(process.cwd(), 'spmdb')}`, 46 | ' ', 47 | '# SPM_MONITOR_TAGS=project:frontend,environment:test,role:testserver', 48 | '# Application Token for SPM', 49 | 'tokens:', 50 | `${monitoringTokenString}`, 51 | `${infraToken !== '' ? ` infra: ${infraToken}\n` : ''}`, 52 | 'logger:', 53 | ' # log file directory default is __dirname / spmlogs', 54 | ` dir: ${path.join(process.cwd(), 'spmlogs')}`, 55 | ' # silent = true means no creation of log files', 56 | ' silent: false ', 57 | ' # log level for output - debug, info, error, defaults to error to be quiet', 58 | ' level: error ' 59 | ] 60 | const cfgFileContent = cfgLines.join('\r\n') 61 | fs.writeFileSync('.spmagentrc', cfgFileContent) 62 | console.log('Create default config to file: ./.spmagentrc \n' + cfgFileContent) 63 | -------------------------------------------------------------------------------- /bin/spmmonitor.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* 3 | * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved 4 | * 5 | * @licence SPM for NodeJS is free-to-use, proprietary software. 6 | * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext) 7 | * This source code may not be copied, reverse engineered, or altered for any purpose. 8 | * This source code is to be used exclusively by users and customers of Sematext. 9 | * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies. 10 | */ 11 | // "use strict" 12 | var fs = require('fs') 13 | 14 | try { 15 | var script = fs.readFileSync(process.argv[2]).toString() 16 | if (process.argv.length < 2) { 17 | console.log('Please specify a node.js script to run with activated SPM agent') 18 | console.log('e.g. spmmonitor ./server/app.js') 19 | } 20 | var scriptName = process.argv[2] 21 | 22 | require('spm-agent-nodejs') 23 | // Remove Arguments for Runner Script, to give started process a clean ENV 24 | process.argv.splice(1, 1) 25 | process.argv.splice(2, 1) 26 | 27 | script = fs.readFileSync(scriptName).toString() 28 | var lines = script.split('\n') 29 | if (lines[0] && /^#!/.test(lines[0])) { 30 | console.log('removed shebang line:' + lines[0]) 31 | lines[0] = '\n' 32 | } 33 | eval(lines.join('\n')) // eslint-disable-line 34 | } catch (err) { 35 | console.error(err) 36 | process.exit(1) 37 | } 38 | -------------------------------------------------------------------------------- /changelog.hbs: -------------------------------------------------------------------------------- 1 | {{#each releases}} 2 | {{#if @first}} 3 | {{#each merges}} 4 | - {{{message}}}{{#if href}} [`#{{id}}`]({{href}}){{/if}} 5 | {{/each}} 6 | {{#each fixes}} 7 | - {{{commit.subject}}}{{#each fixes}}{{#if href}} [`#{{id}}`]({{href}}){{/if}}{{/each}} 8 | {{/each}} 9 | {{#each commits}} 10 | - {{#if breaking}}**Breaking change:** {{/if}}{{{subject}}}{{#if href}} [`{{shorthash}}`]({{href}}){{/if}} 11 | {{/each}} 12 | {{/if}} 13 | {{/each}} 14 | -------------------------------------------------------------------------------- /example/childProcess.js: -------------------------------------------------------------------------------- 1 | const spmAgent = require('../lib/index.js') // or 'spm-agent-nodejs' 2 | 3 | spmAgent.on('stats', function (stats) { 4 | // console.log(stats) 5 | }) 6 | spmAgent.on('metric', function (metric) { 7 | // if (metric.name === 'http') { 8 | // if (metric.name === 'numWorkers') { 9 | // if (metric.sct === 'APP') { 10 | if (metric.name === 'process' || metric.name === 'numWorkers') { 11 | console.log(metric) 12 | } 13 | }) 14 | 15 | spmAgent.on('metric', function (metric) { 16 | // if ( 17 | // metric.measurement === 'nodejs.process' 18 | // ) { 19 | console.log(metric) 20 | console.log('\n\n') 21 | // } 22 | }) 23 | 24 | // if (process.send === undefined) { 25 | // console.log('started directly') 26 | // } else { 27 | // console.log('started from fork()') 28 | // } 29 | 30 | const { resolve } = require('path') 31 | const { fork } = require('child_process') 32 | const http = require('http') 33 | http 34 | .createServer(function (req, res) { 35 | const longComputation = fork(resolve(__dirname, 'longComputation.js')) 36 | longComputation.send('start') 37 | longComputation.on('message', sum => { 38 | res.end(String(sum)) 39 | longComputation.kill(1) 40 | }) 41 | }) 42 | .listen(4000) 43 | -------------------------------------------------------------------------------- /example/cluster.js: -------------------------------------------------------------------------------- 1 | const spmAgent = require('../lib/index.js') // or 'spm-agent-nodejs' 2 | 3 | const cluster = require('cluster') 4 | const numCPUs = require('os').cpus().length 5 | const http = require('http') 6 | const port = 3000 7 | 8 | if (process.send === undefined) { 9 | console.log('started directly') 10 | } else { 11 | console.log('started from fork()') 12 | } 13 | 14 | const masterProcess = () => { 15 | console.log(`Master running on port ${port} with pid ${process.pid}`) 16 | 17 | /** 18 | * Agent Tests 19 | */ 20 | spmAgent.on('stats', function (stats) { 21 | // console.log(stats) 22 | }) 23 | spmAgent.on('metric', function (metric) { 24 | if ( 25 | // metric.name === 'process' || 26 | metric.name === 'numWorkers' 27 | ) { 28 | console.log(metric) 29 | } 30 | }) 31 | 32 | for (let i = 0; i < numCPUs; i++) { 33 | cluster.fork() 34 | cluster.on('exit', worker => cluster.fork()) 35 | } 36 | } 37 | const childProcess = () => { 38 | /** 39 | * Agent Tests 40 | */ 41 | spmAgent.on('stats', function (stats) { 42 | // console.log(stats) 43 | }) 44 | spmAgent.on('metric', function (metric) { 45 | // if ( 46 | // metric.name === 'process' || 47 | // metric.name === 'numWorkers' 48 | // ) { 49 | console.log(metric) 50 | // } 51 | }) 52 | 53 | console.log( 54 | `Worker${cluster.worker.id} running on port ${port} with pid ${cluster.worker.process.pid}` 55 | ) 56 | http 57 | .createServer(function (req, res) { 58 | res.end('Hello World') 59 | }) 60 | .listen(port) 61 | } 62 | 63 | if (cluster.isMaster) { 64 | masterProcess() 65 | } else { 66 | childProcess() 67 | } 68 | -------------------------------------------------------------------------------- /example/longComputation.js: -------------------------------------------------------------------------------- 1 | const spmAgent = require('../lib/index.js') // or 'spm-agent-nodejs' 2 | spmAgent.on('stats', function (stats) { 3 | // console.log(stats) 4 | }) 5 | spmAgent.on('metric', function (metric) { 6 | // if (metric.sct === 'APP') { 7 | if ( 8 | metric.name === 'process' || 9 | metric.name === 'numWorkers' 10 | ) { 11 | console.log(metric) 12 | } 13 | }) 14 | 15 | // if (process.send === undefined) { 16 | // console.log('started directly') 17 | // } else { 18 | // console.log('started from fork()') 19 | // } 20 | 21 | const longComputation = () => { 22 | let sum = 0 23 | for (let i = 0; i < 1e10; i++) { 24 | sum += i 25 | } 26 | return sum 27 | } 28 | 29 | process.on('message', (msg) => { 30 | const sum = longComputation() 31 | process.send(sum) 32 | }) 33 | 34 | process.on('message', msg => { 35 | if (msg === 'stop') { 36 | process.exit() 37 | } 38 | }) 39 | -------------------------------------------------------------------------------- /example/simple-server.js: -------------------------------------------------------------------------------- 1 | var spmAgent = require('../lib/index.js') // or 'spm-agent-nodejs' 2 | spmAgent.on('stats', function (stats) { 3 | // console.log(stats) 4 | }) 5 | // spmAgent.on('metric', function (metric) { 6 | // if (metric.name === 'http') { 7 | // console.log(metric) 8 | // } 9 | // }) 10 | spmAgent.on('metric', function (metric) { 11 | // if ( 12 | // metric.name === 'os' 13 | // ) { 14 | // console.log(metric) 15 | // console.log('\n---------------------------------------------------\n') 16 | // } 17 | 18 | console.log(metric) 19 | console.log('\n---------------------------------------------------\n') 20 | }) 21 | 22 | var http = require('http') 23 | http.createServer(function (req, res) { 24 | res.end('Hello World') 25 | }).listen(3000) 26 | -------------------------------------------------------------------------------- /lib/eventLoopAgent.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved 3 | * 4 | * @licence SPM for NodeJS is free-to-use, proprietary software. 5 | * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext) 6 | * This source code may not be copied, reverse engineered, or altered for any purpose. 7 | * This source code is to be used exclusively by users and customers of Sematext. 8 | * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies. 9 | */ 10 | 11 | 'use strict' 12 | const { Agent } = require('spm-agent') 13 | const monitor = require('./eventLoopStats.js') 14 | 15 | module.exports = function () { 16 | const elAgent = new Agent( 17 | { 18 | start: function (agent) { 19 | this.elListener = function (stats) { 20 | const timestamp = new Date() 21 | const metric = { 22 | timestamp: timestamp, 23 | measurement: 'nodejs.eventloop', 24 | tags: {}, 25 | fields: { 26 | count: stats.count, 27 | time: stats.time, 28 | 'latency.min': stats.min, 29 | 'latency.max': stats.max, 30 | 'latency.max.avg': stats.avg 31 | } 32 | } 33 | agent.addMetrics(metric) 34 | } 35 | monitor.on('data', this.elListener) 36 | monitor.start() 37 | }, 38 | stop: function () { 39 | monitor.removeListener('data', this.elListener) 40 | } 41 | } 42 | ) 43 | return elAgent 44 | } 45 | -------------------------------------------------------------------------------- /lib/eventLoopStats.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved 3 | * 4 | * @licence SPM for NodeJS is free-to-use, proprietary software. 5 | * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext) 6 | * This source code may not be copied, reverse engineered, or altered for any purpose. 7 | * This source code is to be used exclusively by users and customers of Sematext. 8 | * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies. 9 | */ 10 | 11 | var util = require('util') 12 | var events = require('events') 13 | 14 | function EventLoopStats () { 15 | events.EventEmitter.call(this) 16 | } 17 | util.inherits(EventLoopStats, events.EventEmitter) 18 | 19 | EventLoopStats.prototype.start = function () { 20 | var measures = [[0, 0]] 21 | var time = process.hrtime() 22 | var interval = 500 23 | this.measureInterval = setInterval(function () { 24 | measures.push(process.hrtime(time)) 25 | if (measures.length === 2) { 26 | time = process.hrtime() 27 | measures[0] = [measures[0][0] - measures[1][0], measures[0][1] - measures[1][1]] 28 | measures[1] = [0, 0] 29 | } 30 | }, interval) 31 | 32 | this.reporterInterval = setInterval(function () { 33 | var timesInMicroSecs = measures.reduce(function (prev, value, i) { 34 | if (i > 0) { 35 | var diffInMicroSeconds = (measures[i][0] - measures[i - 1][0]) * 1e9 + (measures[i][1] - measures[i - 1][1]) 36 | var key = Math.floor(diffInMicroSeconds - interval * 1e6) / 1e3 37 | // this means our timer was executed too early? -> negative delay, lets ignore dr. who phenomena in nodejs 38 | if (key < 0) { 39 | return prev 40 | } 41 | prev[key] = prev[key] || 0 42 | prev[key]++ 43 | } 44 | return prev 45 | }, {}) 46 | var stats = { count: 0, time: 0, avg: 0, min: 1e12, max: 0 } 47 | for (var key in timesInMicroSecs) { 48 | stats.time += parseInt(key, 10) * timesInMicroSecs[key] 49 | stats.count += timesInMicroSecs[key] 50 | stats.max = Math.max(parseInt(key, 10), stats.max) 51 | stats.min = Math.min(parseInt(key, 10), stats.min) 52 | } 53 | stats.avg = Math.floor(stats.time / stats.count) 54 | // console.log (stats) 55 | this.emit('data', stats) 56 | measures[0] = measures.pop() 57 | measures.length = 1 58 | }.bind(this), 10 * 1000) 59 | 60 | if (this.measureInterval.unref && this.reporterInterval.unref) { 61 | this.measureInterval.unref() 62 | this.reporterInterval.unref() 63 | } 64 | } 65 | 66 | EventLoopStats.prototype.stop = function () { 67 | if (this.measureInterval && this.reporterInterval) { 68 | clearInterval(this.measureInterval) 69 | clearInterval(this.reporterInterval) 70 | } 71 | } 72 | 73 | module.exports = new EventLoopStats() 74 | -------------------------------------------------------------------------------- /lib/gcAgent.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved 3 | * 4 | * @licence SPM for NodeJS is free-to-use, proprietary software. 5 | * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext) 6 | * This source code may not be copied, reverse engineered, or altered for any purpose. 7 | * This source code is to be used exclusively by users and customers of Sematext. 8 | * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies. 9 | */ 10 | 'use strict' 11 | 12 | const { Agent, Config } = require('spm-agent') 13 | const gcStats = (require('@sematext/gc-stats'))() 14 | 15 | function getProcessHeapInfo () { 16 | const pm = process.memoryUsage() 17 | const metrics = {} 18 | metrics.processHeapUsed = pm.heapUsed 19 | metrics.processHeapTotal = pm.heapTotal 20 | metrics.processMemoryRss = pm.rss 21 | return metrics 22 | } 23 | 24 | function getGcStats () { 25 | return { 26 | start: function (agent) { 27 | const Measured = require('measured-core') 28 | const fullGc = new Measured.Counter() 29 | const incGc = new Measured.Counter() 30 | const heapCompactions = new Measured.Counter() 31 | const gcTimes = new Measured.Histogram() 32 | const heapDiff = new Measured.Histogram() 33 | let lastHeapInfo = getProcessHeapInfo() 34 | gcStats.on('stats', function (info) { 35 | if (info.gctype === 1) { 36 | incGc.inc() 37 | } 38 | if (info.gctype === 2) { 39 | fullGc.inc() 40 | } 41 | if (info.gctype === 3) { 42 | incGc.inc() 43 | fullGc.inc() 44 | } 45 | if (info.pause) { 46 | gcTimes.update(info.pauseMS) 47 | } 48 | lastHeapInfo = getProcessHeapInfo() 49 | heapDiff.update(info.diff.usedHeapSize * -1) 50 | }) 51 | 52 | const timerId = setInterval(function () { 53 | const now = new Date() 54 | const heapInfo = lastHeapInfo 55 | const heapCompactionsJSON = heapCompactions.toJSON() 56 | const metricValues = { 57 | 'gc.inc': incGc.toJSON() || 0, 58 | 'gc.full': fullGc.toJSON() || 0, 59 | 'gc.time': gcTimes.toJSON().sum || 0, 60 | 'gc.heap.compactions': heapCompactionsJSON || 0, 61 | 'gc.heap.diff': heapDiff.toJSON().sum || 0, 62 | 'heap.used': heapInfo.processHeapUsed || 0, 63 | 'heap.size': heapInfo.processHeapTotal || 0, 64 | 'memory.rss': heapInfo.processMemoryRss || 0 65 | } 66 | agent.addMetrics({ timestamp: now, measurement: 'nodejs', tags: {}, fields: metricValues }) 67 | fullGc.reset(0) 68 | incGc.reset(0) 69 | heapCompactions.reset(0) 70 | gcTimes.reset() 71 | heapDiff.reset() 72 | }, Config.collectionInterval) 73 | if (timerId.unref) { 74 | timerId.unref() 75 | } 76 | }, 77 | stop: function () {} 78 | } 79 | } 80 | module.exports = function () { 81 | return new Agent(getGcStats()) 82 | } 83 | -------------------------------------------------------------------------------- /lib/httpServerAgent.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved 3 | * 4 | * @licence SPM for NodeJS is free-to-use, proprietary software. 5 | * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext) 6 | * This source code may not be copied, reverse engineered, or altered for any purpose. 7 | * This source code is to be used exclusively by users and customers of Sematext. 8 | * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies. 9 | */ 10 | 11 | 'use strict' 12 | 13 | /** 14 | * HttpServerAgent - wraping createServer to add instrumentation 15 | * 16 | */ 17 | 18 | const http = require('http') 19 | const https = require('https') 20 | 21 | // constants 22 | const FINISH_EVENT_NAME = 'finish' 23 | const ABRUPT_CLOSE_EVENT_NAME = 'close' 24 | 25 | module.exports = function httpServerAgent () { 26 | const { Agent, Config, Logger } = require('spm-agent') 27 | const Measured = require('measured-core') 28 | const histogram = new Measured.Histogram() 29 | const timer = new Measured.Timer() 30 | 31 | // setup context for monitoring 32 | const ctx = { 33 | reqSize: 0, 34 | resSize: 0, 35 | timer: timer, 36 | logger: Logger, 37 | histogram: histogram, 38 | stats: Measured.createCollection() 39 | } 40 | 41 | // bind monitorHttp safely 42 | const monitor = safeProcess(ctx, monitorHttp) 43 | 44 | // setup monitoring agent 45 | const hAgent = new Agent({ 46 | start: function (agent) { 47 | this._agent = agent 48 | patchHttpServer(monitor) 49 | patchHttpsServer(monitor) 50 | const timerId = setInterval(function () { 51 | const stats = ctx.stats 52 | const httpStats = stats.toJSON() 53 | const responseTimes = histogram.toJSON() 54 | const timestamp = new Date() 55 | 56 | const metricValue = { 57 | requests: httpStats.requests ? httpStats.requests.count : 0, // http.requestCount (int) 58 | errors: httpStats.errRate ? httpStats.errRate.count : 0, // http.errorCount (int) 59 | 'errors.3xx': httpStats['3xxRate'] ? httpStats['3xxRate'].count : 0, // http.3xx (int) 60 | 'errors.4xx': httpStats['4xxRate'] ? httpStats['4xxRate'].count : 0, // http.4xx (int) 61 | 'errors.5xx': httpStats['5xxRate'] ? httpStats['5xxRate'].count : 0, // http.5xx (int) 62 | 'requests.size.total': ctx.reqSize, 63 | 'response.size.total': ctx.resSize, 64 | 'responses.latency.min': Number(responseTimes.min), 65 | 'responses.latency.max': Number(responseTimes.max), 66 | 'responses.time': Number(responseTimes.sum) 67 | } 68 | 69 | if (metricValue.requests > 0 || metricValue.errors > 0) { 70 | agent.addMetrics({ timestamp: timestamp, measurement: 'nodejs', tags: {}, fields: metricValue }) 71 | } 72 | 73 | // cleanup aggregate stats 74 | stats.end() 75 | 76 | // create & reset new metrics 77 | ctx.stats = Measured.createCollection() 78 | histogram.reset() 79 | timer.reset() 80 | ctx.reqSize = 0 81 | ctx.resSize = 0 82 | }, Config.collectionInterval) 83 | 84 | // unref so we can gracefully exit 85 | if (timerId.unref) { 86 | timerId.unref() 87 | } 88 | } 89 | }) 90 | 91 | return hAgent 92 | } 93 | 94 | /** 95 | * Make sure we deoptimize small part of fn 96 | */ 97 | function safeProcess (ctx, fn) { 98 | return function processRequest (req, res) { 99 | try { 100 | fn(ctx, req, res) 101 | } catch (ex) { 102 | ctx.logger.error(ex) 103 | } 104 | } 105 | } 106 | 107 | /** 108 | * Req/res handler for monitoring 109 | * @param {Object} ctx 110 | * @param {http.IncomingMessage} req 111 | * @param {http.ServerResponse} res 112 | */ 113 | function monitorHttp (ctx, req, res) { 114 | let stopwatch = ctx.timer.start() 115 | 116 | function endOfConnectionHandler () { 117 | // cached consts 118 | const stats = ctx.stats 119 | const histogram = ctx.histogram 120 | 121 | // capture duration 122 | const duration = stopwatch.end() 123 | stopwatch = null 124 | stats.meter('requests').mark() 125 | 126 | // duration is in ms as float with nanosecond precision, 127 | // but we use microseconds with the backend 128 | histogram.update(Math.round(duration * 1000), Date.now()) 129 | if (res.getHeader) { 130 | ctx.resSize += ((res.getHeader('Content-Length') || 0) * 1) 131 | } 132 | 133 | if (req.headers) { 134 | ctx.reqSize += (req.headers['content-length'] || 0) * 1 135 | } 136 | 137 | // capture special response codes 138 | if (res.statusCode >= 300) { 139 | if (res.statusCode < 400) { 140 | stats.meter('3xxRate').mark() 141 | } else if (res.statusCode < 500) { 142 | stats.meter('errRate').mark() 143 | stats.meter('4xxRate').mark() 144 | } else { 145 | stats.meter('errRate').mark() 146 | stats.meter('5xxRate').mark() 147 | } 148 | } 149 | 150 | res.removeListener(FINISH_EVENT_NAME, endOfConnectionHandler) 151 | res.removeListener(ABRUPT_CLOSE_EVENT_NAME, endOfConnectionHandler) 152 | 153 | // this is invoked to cleanup domains from possible timers bound to it 154 | // cleanDomainNamespace() 155 | } 156 | 157 | res.on(FINISH_EVENT_NAME, endOfConnectionHandler) 158 | res.on(ABRUPT_CLOSE_EVENT_NAME, endOfConnectionHandler) 159 | } 160 | 161 | /** 162 | * Monkey-patching! 163 | */ 164 | const origHttpCreateServer = http.createServer 165 | const origHttpsCreateServer = https.createServer 166 | 167 | function patchHttpServer (monitorReqHandler) { 168 | http.createServer = function () { 169 | const server = origHttpCreateServer.apply(http, arguments) 170 | server.on('request', monitorReqHandler) 171 | return server 172 | } 173 | http.Server = http.createServer 174 | } 175 | 176 | function patchHttpsServer (monitorReqHandler) { 177 | https.createServer = function () { 178 | const server = origHttpsCreateServer.apply(https, arguments) 179 | server.on('request', monitorReqHandler) 180 | return server 181 | } 182 | https.Server = https.createServer 183 | } 184 | 185 | function unpatchHttpServer () { 186 | http.createServer = origHttpCreateServer 187 | http.Server = origHttpCreateServer 188 | } 189 | 190 | function unpatchHttpsServer () { 191 | https.createServer = origHttpsCreateServer 192 | https.Server = origHttpsCreateServer 193 | } 194 | 195 | module.exports.unpatchHttpServer = unpatchHttpServer 196 | module.exports.unpatchHttpsServer = unpatchHttpsServer 197 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved 3 | * 4 | * @licence SPM for NodeJS is free-to-use, proprietary software. 5 | * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext) 6 | * This source code may not be copied, reverse engineered, or altered for any purpose. 7 | * This source code is to be used exclusively by users and customers of Sematext. 8 | * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies. 9 | */ 10 | var SpmAgent = require('spm-agent') 11 | 12 | function NodeJSAgent () { 13 | // prepare move from SPM_TOKEN to MONITORING_TOKEN + backward compatibility 14 | if (process.env.SPM_TOKEN && !SpmAgent.Config.tokens.spm) { 15 | SpmAgent.Config.tokens.spm = process.env.SPM_TOKEN 16 | SpmAgent.Config.tokens.monitoring = process.env.SPM_TOKEN 17 | } 18 | if (process.env.MONITORING_TOKEN && !SpmAgent.Config.tokens.monitoring) { 19 | SpmAgent.Config.tokens.spm = process.env.MONITORING_TOKEN 20 | SpmAgent.Config.tokens.monitoring = process.env.MONITORING_TOKEN 21 | } 22 | if (process.env.INFRA_TOKEN && !SpmAgent.Config.tokens.infra) { 23 | SpmAgent.Config.tokens.infra = process.env.INFRA_TOKEN 24 | } 25 | var njsAgent = new SpmAgent() 26 | var agentsToLoad = [ 27 | './eventLoopAgent.js', 28 | './gcAgent.js', 29 | './httpServerAgent.js', 30 | './workerAgent.js' 31 | ] 32 | agentsToLoad.forEach(function (a) { 33 | try { 34 | var Monitor = require(a) 35 | njsAgent.createAgent(new Monitor()) 36 | } catch (err) { 37 | console.error(err) 38 | SpmAgent.Logger.error('Error loading agent ' + a + ' ' + err) 39 | } 40 | }) 41 | return njsAgent 42 | } 43 | 44 | module.exports = NodeJSAgent() 45 | -------------------------------------------------------------------------------- /lib/workerAgent.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved 3 | * 4 | * @licence SPM for NodeJS is free-to-use, proprietary software. 5 | * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext) 6 | * This source code may not be copied, reverse engineered, or altered for any purpose. 7 | * This source code is to be used exclusively by users and customers of Sematext. 8 | * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies. 9 | */ 10 | 'use strict' 11 | 12 | const cluster = require('cluster') 13 | const { Agent, Config } = require('spm-agent') 14 | 15 | function getWorkers () { 16 | return { 17 | start: function (agent) { 18 | const timerId = setInterval(function () { 19 | const timestamp = new Date() 20 | if (cluster.isMaster || process.env.NODE_APP_INSTANCE === 0 || process.env.SPM_MASTER_MODE === '1' || process.env.STARTUP === 'true') { 21 | agent.addMetrics({ 22 | timestamp: timestamp, 23 | measurement: 'nodejs', 24 | tags: {}, 25 | fields: { workers: Object.keys(cluster.workers || {}).length || 1 } 26 | }) 27 | } 28 | }, Config.collectionInterval) 29 | if (timerId.unref) { 30 | timerId.unref() 31 | } 32 | }, 33 | stop: function () {} 34 | } 35 | } 36 | module.exports = function () { 37 | return new Agent(getWorkers()) 38 | } 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spm-agent-nodejs", 3 | "version": "4.2.7", 4 | "description": "Node.js monitoring agent for SPM by Sematext", 5 | "main": "lib/index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "engines": { 10 | "node": ">=6.0.0" 11 | }, 12 | "scripts": { 13 | "test": "npm run lint && mocha --exit test/test.js", 14 | "lint": "standard", 15 | "doc": "doxx --source . -i node_modules,spmlog,spmdb -t \"SPM Agent\" ./docs", 16 | "auto-changelog": "auto-changelog", 17 | "release": "release-it" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/sematext/spm-agent-nodejs.git" 22 | }, 23 | "keywords": [ 24 | "SPM", 25 | "APM", 26 | "application performance monitoring", 27 | "Sematext", 28 | "performance monitoring", 29 | "monitoring", 30 | "alerting", 31 | "anomaly detection", 32 | "heartbeat", 33 | "metrics", 34 | "custom metrics", 35 | "devops", 36 | "operations", 37 | "dashboards", 38 | "profiling", 39 | "memwatch", 40 | "gc-profiler", 41 | "agent", 42 | "logging" 43 | ], 44 | "author": "Sematext Group, Inc.", 45 | "license": "Copyright (c) Sematext Group, Inc.", 46 | "bugs": { 47 | "url": "https://github.com/sematext/spm-agent-nodejs/issues" 48 | }, 49 | "homepage": "http://www.sematext.com", 50 | "dependencies": { 51 | "adm-zip": "^0.4.14", 52 | "measured-core": "^1.51.1", 53 | "spm-agent": "^2.2.5" 54 | }, 55 | "optionalDependencies": { 56 | "minimist": "^1.2.6", 57 | "@sematext/gc-stats": "^1.5.8" 58 | }, 59 | "devDependencies": { 60 | "auto-changelog": "^1.16.2", 61 | "babel-eslint": "^10.0.3", 62 | "mocha": "^10.2.0", 63 | "release-it": "^16.1.3", 64 | "standard": "^14.3.1", 65 | "request": "^2.88.0" 66 | }, 67 | "release-it": { 68 | "github": { 69 | "release": true, 70 | "tokenRef": "RELEASE_IT_GITHUB_TOKEN", 71 | "releaseNotes": "npx auto-changelog --stdout --commit-limit false -u --template ./changelog.hbs", 72 | "____comment": "\"assets\": [\"dist/agent-*\"]" 73 | }, 74 | "hooks": { 75 | "after:bump": "npx auto-changelog -p" 76 | } 77 | }, 78 | "standard": { 79 | "parser": "babel-eslint" 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /test/test-node-versions.sh: -------------------------------------------------------------------------------- 1 | npm install ny -g 2 | for version in 0.8 0.10 0.12 1.2 1.5 3 | do 4 | ny $version 5 | node --version 6 | rm -rf ./node_modules 7 | npm install --silent 8 | npm test 9 | done 10 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Sematext Group, Inc. 3 | * All Rights Reserved 4 | * 5 | * SPM for NodeJS is free-to-use, proprietary software. 6 | * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext) 7 | * This source code may not be copied, reverse engineered, or altered for any purpose. 8 | * This source code is to be used exclusively by users and customers of Sematext. 9 | * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies. 10 | */ 11 | /* global describe, it */ 12 | process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' 13 | // make sure config has an infra token before spm-agent is laoded first time 14 | if (!process.env.INFRA_TOKEN) { 15 | process.env.INFRA_TOKEN = 'INFRA_TOKEN' 16 | } 17 | var SpmAgent = require('spm-agent') 18 | var config = SpmAgent.Config 19 | var port = (process.env.NJS_TEST_PORT || 8097) 20 | var receiverUrl = 'http://127.0.0.1:' + port 21 | config.rcFlat.spmSenderBulkInsertUrl = receiverUrl 22 | config.collectionInterval = 1 23 | 24 | function httpTest (njsAgent, done) { 25 | try { 26 | var checkMetric = function (metric) { 27 | if (metric.fields.requests) { 28 | done() 29 | } else { 30 | njsAgent.once('metric', checkMetric) 31 | } 32 | } 33 | njsAgent.once('metric', checkMetric) 34 | } catch (ex) { 35 | console.error('Error in HTTP Worker:' + ex.stack) 36 | done(ex) 37 | } 38 | } 39 | 40 | describe('SPM for Node.js tests', function () { 41 | it('Generic HTTP Server Agent sends metrics', function (done) { 42 | try { 43 | this.timeout(25000) 44 | config.collectionInterval = 500 45 | var HttpAgent = require('../lib/httpServerAgent.js') 46 | var njsAgent = new HttpAgent() 47 | njsAgent.start() 48 | var http = require('http') 49 | http.createServer(function (req, res) { 50 | res.writeHead(200, { 'Content-Type': 'text/plain' }) 51 | res.end('{"code":"200"}\n') 52 | }).listen(port, '127.0.0.1') 53 | httpTest(njsAgent, done) 54 | setTimeout(function () { 55 | const request = require('request') 56 | request.get('http://127.0.0.1:' + (port) + '/', function (err) { 57 | if (err) { 58 | console.log('Error' + err.stack) 59 | } 60 | }) 61 | }, 700) 62 | } catch (err) { 63 | console.error(err.stack) 64 | done(err) 65 | } 66 | }) 67 | 68 | it('GC Agent metrics', function (done) { 69 | try { 70 | this.timeout(300000) 71 | var GcAgent = require('../lib/gcAgent.js') 72 | var agent = new GcAgent() 73 | agent.start() 74 | var checkMetric = function () { 75 | agent.stop() 76 | done() 77 | } 78 | agent.once('metric', checkMetric) 79 | var wasteMemory = [] 80 | for (var i = 0; i < 300000; i++) { 81 | var tmp = 'Wasting some memory' 82 | } 83 | 84 | wasteMemory.push(tmp) 85 | } catch (err) { 86 | console.error(err.stack) 87 | done(err) 88 | } 89 | }) 90 | it('EventLoop Agent metrics', function (done) { 91 | try { 92 | this.timeout(15000) 93 | var ElAgent = require('../lib/eventLoopAgent.js') 94 | var agent = new ElAgent() 95 | agent.start() 96 | var checkMetric = function () { 97 | agent.removeListener('metric', checkMetric) 98 | agent.stop() 99 | done() 100 | } 101 | agent.once('metric', checkMetric) 102 | } catch (err) { 103 | done(err) 104 | } 105 | }) 106 | it('Wait for metrics: GC, Event Loop and OS monitor', function (done) { 107 | this.timeout(30000) 108 | config.maxDataPoints = 1 109 | config.logger.console = false 110 | config.logger.level = 'debug' 111 | var NjsAgent = require('../lib/index.js') 112 | var metricTypes = { gc: 0, eventloop: 0 } 113 | 114 | function checkMetrics (metric) { 115 | if (metric.fields.time) { 116 | metricTypes.eventloop = 1 117 | } 118 | if (metric.fields['heap.size']) { 119 | metricTypes.gc = 1 120 | } 121 | metricTypes[metric.name] = 1 122 | var checksum = metricTypes.gc + metricTypes.eventloop 123 | if (checksum > 1) { 124 | NjsAgent.removeListener('metric', checkMetrics) 125 | done() 126 | NjsAgent.stop() 127 | } 128 | } 129 | NjsAgent.on('metric', checkMetrics) 130 | }) 131 | 132 | it('Wait for metrics: Worker Agent', function (done) { 133 | this.timeout(30000) 134 | config.maxDataPoints = 1 135 | config.logger.console = false 136 | config.logger.level = 'debug' 137 | var NjsAgent = require('../lib/index.js') 138 | let metricCounter = 0 139 | 140 | function checkMetrics (metric) { 141 | if (metric.fields && metric.fields.workers) { 142 | metricCounter++ 143 | } 144 | if (metricCounter > 0) { 145 | NjsAgent.removeListener('metric', checkMetrics) 146 | done() 147 | NjsAgent.stop() 148 | } 149 | } 150 | NjsAgent.on('metric', checkMetrics) 151 | }) 152 | }) 153 | --------------------------------------------------------------------------------