| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 1025868 commit 9a0dad2
14 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -625,6 +625,32 @@ Path to the file used to store the persistent REPL history. The default path is | |||
| 625 | 625 | `~/.node_repl_history`, which is overridden by this variable. Setting the value | |
| 626 | 626 | to an empty string (`''` or `' '`) disables persistent REPL history. | |
| 627 | 627 | ||
| 628 | + ### `NODE_V8_COVERAGE=dir` | ||
| 629 | + | ||
| 630 | + When set, Node.js will begin outputting [V8 JavaScript code coverage][] to the | ||
| 631 | + directory provided as an argument. Coverage is output as an array of | ||
| 632 | + [ScriptCoverage][] objects: | ||
| 633 | + | ||
| 634 | + ```json | ||
| 635 | + { | ||
| 636 | + "result": [ | ||
| 637 | + { | ||
| 638 | + "scriptId": "67", | ||
| 639 | + "url": "internal/tty.js", | ||
| 640 | + "functions": [] | ||
| 641 | + } | ||
| 642 | + ] | ||
| 643 | + } | ||
| 644 | + ``` | ||
| 645 | + | ||
| 646 | + `NODE_V8_COVERAGE` will automatically propagate to subprocesses, making it | ||
| 647 | + easier to instrument applications that call the `child_process.spawn()` family | ||
| 648 | + of functions. `NODE_V8_COVERAGE` can be set to an empty string, to prevent | ||
| 649 | + propagation. | ||
| 650 | + | ||
| 651 | + At this time coverage is only collected in the main thread and will not be | ||
| 652 | + output for code executed by worker threads. | ||
| 653 | + | ||
| 628 | 654 | ### `OPENSSL_CONF=file` | |
| 629 | 655 | <!-- YAML | |
| 630 | 656 | added: v6.11.0 | |
@@ -691,6 +717,8 @@ greater than `4` (its current default value). For more information, see the | |||
| 691 | 717 | [`process.setUncaughtExceptionCaptureCallback()`]: process.html#process_process_setuncaughtexceptioncapturecallback_fn | |
| 692 | 718 | [Chrome DevTools Protocol]: https://chromedevtools.github.io/devtools-protocol/ | |
| 693 | 719 | [REPL]: repl.html | |
| 720 | + [ScriptCoverage]: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-ScriptCoverage | ||
| 721 | + [V8 JavaScript code coverage]: https://v8project.blogspot.com/2017/12/javascript-code-coverage.html | ||
| 694 | 722 | [debugger]: debugger.html | |
| 695 | 723 | [emit_warning]: process.html#process_process_emitwarning_warning_type_code_ctor | |
| 696 | 724 | [experimental ECMAScript Module]: esm.html#esm_loader_hooks | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -496,6 +496,14 @@ function normalizeSpawnArguments(file, args, options) { | |||
| 496 | 496 | var env = options.env || process.env; | |
| 497 | 497 | var envPairs = []; | |
| 498 | 498 | ||
| 499 | + // process.env.NODE_V8_COVERAGE always propagates, making it possible to | ||
| 500 | + // collect coverage for programs that spawn with white-listed environment. | ||
| 501 | + if (process.env.NODE_V8_COVERAGE && | ||
| 502 | + !Object.prototype.hasOwnProperty.call(options.env || {}, | ||
| 503 | + 'NODE_V8_COVERAGE')) { | ||
| 504 | + env.NODE_V8_COVERAGE = process.env.NODE_V8_COVERAGE; | ||
| 505 | + } | ||
| 506 | + | ||
| 499 | 507 | // Prototype values are intentionally included. | |
| 500 | 508 | for (var key in env) { | |
| 501 | 509 | const value = env[key]; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -98,6 +98,12 @@ | |||
| 98 | 98 | if (global.__coverage__) | |
| 99 | 99 | NativeModule.require('internal/process/write-coverage').setup(); | |
| 100 | 100 | ||
| 101 | + if (process.env.NODE_V8_COVERAGE) { | ||
| 102 | + const { resolve } = NativeModule.require('path'); | ||
| 103 | + process.env.NODE_V8_COVERAGE = resolve(process.env.NODE_V8_COVERAGE); | ||
| 104 | + NativeModule.require('internal/process/coverage').setup(); | ||
| 105 | + } | ||
| 106 | + | ||
| 101 | 107 | ||
| 102 | 108 | { | |
| 103 | 109 | const traceEvents = process.binding('trace_events'); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,6 +29,8 @@ const envVars = new Map([ | |||
| 29 | 29 | 'of stderr' }], | |
| 30 | 30 | ['NODE_REPL_HISTORY', { helpText: 'path to the persistent REPL ' + | |
| 31 | 31 | 'history file' }], | |
| 32 | + ['NODE_V8_COVERAGE', { helpText: 'directory to output v8 coverage JSON ' + | ||
| 33 | + 'to' }], | ||
| 32 | 34 | ['OPENSSL_CONF', { helpText: 'load OpenSSL configuration from file' }] | |
| 33 | 35 | ].concat(hasIntl ? [ | |
| 34 | 36 | ['NODE_ICU_DATA', { helpText: 'data path for ICU (Intl object) data' + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,71 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + const path = require('path'); | ||
| 3 | + const { mkdirSync, writeFileSync } = require('fs'); | ||
| 4 | + // TODO(addaleax): add support for coverage to worker threads. | ||
| 5 | + const hasInspector = process.config.variables.v8_enable_inspector === 1 && | ||
| 6 | + require('internal/worker').isMainThread; | ||
| 7 | + let inspector = null; | ||
| 8 | + if (hasInspector) inspector = require('inspector'); | ||
| 9 | + | ||
| 10 | + let session; | ||
| 11 | + | ||
| 12 | + function writeCoverage() { | ||
| 13 | + if (!session) { | ||
| 14 | + return; | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + const filename = `coverage-${process.pid}-${Date.now()}.json`; | ||
| 18 | + try { | ||
| 19 | + // TODO(bcoe): switch to mkdirp once #22302 is addressed. | ||
| 20 | + mkdirSync(process.env.NODE_V8_COVERAGE); | ||
| 21 | + } catch (err) { | ||
| 22 | + if (err.code !== 'EEXIST') { | ||
| 23 | + console.error(err); | ||
| 24 | + return; | ||
| 25 | + } | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + const target = path.join(process.env.NODE_V8_COVERAGE, filename); | ||
| 29 | + | ||
| 30 | + try { | ||
| 31 | + session.post('Profiler.takePreciseCoverage', (err, coverageInfo) => { | ||
| 32 | + if (err) return console.error(err); | ||
| 33 | + try { | ||
| 34 | + writeFileSync(target, JSON.stringify(coverageInfo)); | ||
| 35 | + } catch (err) { | ||
| 36 | + console.error(err); | ||
| 37 | + } | ||
| 38 | + }); | ||
| 39 | + } catch (err) { | ||
| 40 | + console.error(err); | ||
| 41 | + } finally { | ||
| 42 | + session.disconnect(); | ||
| 43 | + session = null; | ||
| 44 | + } | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + exports.writeCoverage = writeCoverage; | ||
| 48 | + | ||
| 49 | + function setup() { | ||
| 50 | + if (!hasInspector) { | ||
| 51 | + console.warn('coverage currently only supported in main thread'); | ||
| 52 | + return; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + session = new inspector.Session(); | ||
| 56 | + session.connect(); | ||
| 57 | + session.post('Profiler.enable'); | ||
| 58 | + session.post('Profiler.startPreciseCoverage', { callCount: true, | ||
| 59 | + detailed: true }); | ||
| 60 | + | ||
| 61 | + const reallyReallyExit = process.reallyExit; | ||
| 62 | + | ||
| 63 | + process.reallyExit = function(code) { | ||
| 64 | + writeCoverage(); | ||
| 65 | + reallyReallyExit(code); | ||
| 66 | + }; | ||
| 67 | + | ||
| 68 | + process.on('exit', writeCoverage); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + exports.setup = setup; | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -172,6 +172,10 @@ function setupKillAndExit() { | |||
| 172 | 172 | ||
| 173 | 173 | process.kill = function(pid, sig) { | |
| 174 | 174 | var err; | |
| 175 | + if (process.env.NODE_V8_COVERAGE) { | ||
| 176 | + const { writeCoverage } = require('internal/process/coverage'); | ||
| 177 | + writeCoverage(); | ||
| 178 | + } | ||
| 175 | 179 | ||
| 176 | 180 | // eslint-disable-next-line eqeqeq | |
| 177 | 181 | if (pid != (pid | 0)) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -143,6 +143,7 @@ | |||
| 143 | 143 | 'lib/internal/process/worker_thread_only.js', | |
| 144 | 144 | 'lib/internal/querystring.js', | |
| 145 | 145 | 'lib/internal/process/write-coverage.js', | |
| 146 | + 'lib/internal/process/coverage.js', | ||
| 146 | 147 | 'lib/internal/readline.js', | |
| 147 | 148 | 'lib/internal/repl.js', | |
| 148 | 149 | 'lib/internal/repl/await.js', | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,6 @@ | |||
| 1 | + const a = 99; | ||
| 2 | + if (true) { | ||
| 3 | + const b = 101; | ||
| 4 | + } else { | ||
| 5 | + const c = 102; | ||
| 6 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,7 @@ | |||
| 1 | + const a = 99; | ||
| 2 | + if (true) { | ||
| 3 | + const b = 101; | ||
| 4 | + } else { | ||
| 5 | + const c = 102; | ||
| 6 | + } | ||
| 7 | + process.exit(1); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,7 @@ | |||
| 1 | + const a = 99; | ||
| 2 | + if (true) { | ||
| 3 | + const b = 101; | ||
| 4 | + } else { | ||
| 5 | + const c = 102; | ||
| 6 | + } | ||
| 7 | + process.kill(process.pid, "SIGINT"); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments