10000 process: add --redirect-warnings command line argument · nodejs/node@16802c0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 16802c0

Browse files
jasnellMylesBorins
authored andcommitted
process: add --redirect-warnings command line argument
The --redirect-warnings command line argument allows process warnings to be written to a specified file rather than printed to stderr. Also adds an equivalent NODE_REDIRECT_WARNINGS environment variable. If the specified file cannot be opened or written to for any reason, the argument is ignored and the warning is printed to stderr. If the file already exists, it will be appended to. Backport-PR-URL: #12677 PR-URL: #10116 Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Michal Zasso <targos@protonmail.com> Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
1 parent 2d3e735 commit 16802c0

File tree

8 files changed

+182
-2
lines changed
  • doc
    • api
  • lib/internal/process
  • src
  • test/parallel
  • 8 files changed

    +182
    -2
    lines changed

    doc/api/cli.md

    Lines changed: 21 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -122,6 +122,16 @@ added: v6.0.0
    122122

    123123
    Print stack traces for process warnings (including deprecations).
    124124

    125+
    ### `--redirect-warnings=file`
    126+
    <!-- YAML
    127+
    added: REPLACEME
    128+
    -->
    129+
    130+
    Write process warnings to the given file instead of printing to stderr. The
    131+
    file will be created if it does not exist, and will be appended to if it does.
    132+
    If an error occurs while attempting to write the warning to the file, the
    133+
    warning will be written to stderr instead.
    134+
    125135
    ### `--trace-sync-io`
    126136
    <!-- YAML
    127137
    added: v2.1.0
    @@ -383,6 +393,17 @@ Note: Be aware that unless the child environment is explicitly set, this
    383393
    evironment variable will be inherited by any child processes, and if they use
    384394
    OpenSSL, it may cause them to trust the same CAs as node.
    385395

    396+
    ### `NODE_REDIRECT_WARNINGS=file`
    397+
    <!-- YAML
    398+
    added: REPLACEME
    399+
    -->
    400+
    401+
    When set, process warnings will be emitted to the given file instead of
    402+
    printing to stderr. The file will be created if it does not exist, and will be
    403+
    appended to if it does. If an error occurs while attempting to write the
    404+
    warning to the file, the warning will be written to stderr instead. This is
    405+
    equivalent to using the `--redirect-warnings=file` command-line flag.
    406+
    386407
    [emit_warning]: process.html#process_process_emitwarning_warning_name_ctor
    387408
    [Buffer]: buffer.html#buffer_buffer
    388409
    [debugger]: debugger.html

    doc/node.1

    Lines changed: 10 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -112,6 +112,10 @@ Silence all process warnings (including deprecations).
    112112
    .BR \-\-trace\-warnings
    113113
    Print stack traces for process warnings (including deprecations).
    114114

    115+
    .TP
    116+
    .BR \-\-redirect\-warnings=\fIfile\fR
    117+
    Write process warnings to the given file instead of printing to stderr.
    118+
    115119
    .TP
    116120
    .BR \-\-trace\-sync\-io
    117121
    Print a stack trace whenever synchronous I/O is detected after the first turn
    @@ -255,6 +259,12 @@ containing trusted certificates.
    255259
    If \fB\-\-use\-openssl\-ca\fR is enabled, this overrides and sets OpenSSL's
    256260
    file containing trusted certificates.
    257261

    262+
    .TP
    263+
    .BR NODE_REDIRECT_WARNINGS=\fIfile\fR
    264+
    Write process warnings to the given file instead of printing to stderr.
    265+
    (equivalent to using the \-\-redirect\-warnings=\fIfile\fR command-line
    266+
    argument).
    267+
    258268
    .SH BUGS
    259269
    Bugs are tracked in GitHub Issues:
    260270
    .ur https://github.com/nodejs/node/issues

    lib/internal/process/warning.js

    Lines changed: 73 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -4,10 +4,81 @@ const traceWarnings = process.traceProcessWarnings;
    44
    const noDeprecation = process.noDeprecation;
    55
    const traceDeprecation = process.traceDeprecation;
    66
    const throwDeprecation = process.throwDeprecation;
    7+
    const config = process.binding('config');
    78
    const prefix = `(${process.release.name}:${process.pid}) `;
    89

    910
    exports.setup = setupProcessWarnings;
    1011

    12+
    var fs;
    13+
    var cachedFd;
    14+
    var acquiringFd = false;
    15+
    function nop() {}
    16+
    17+
    function lazyFs() {
    18+
    if (!fs)
    19+
    fs = require('fs');
    20+
    return fs;
    21+
    }
    22+
    23+
    function writeOut(message) {
    24+
    if (console && typeof console.error === 'function')
    25+
    return console.error(message);
    26+
    process._rawDebug(message);
    27+
    }
    28+
    29+
    function onClose(fd) {
    30+
    return function() {
    31+
    lazyFs().close(fd, nop);
    32+
    };
    33+
    }
    34+
    35+
    function onOpen(cb) {
    36+
    return function(err, fd) {
    37+
    acquiringFd = false;
    38+
    if (fd !== undefined) {
    39+
    cachedFd = fd;
    40+
    process.on('exit', onClose(fd));
    41+
    }
    42+
    cb(err, fd);
    43+
    process.emit('_node_warning_fd_acquired', err, fd);
    44+
    };
    45+
    }
    46+
    47+
    function onAcquired(message) {
    48+
    // make a best effort attempt at writing the message
    49+
    // to the fd. Errors are ignored at this point.
    50+
    return function(err, fd) {
    51+
    if (err)
    52+
    return writeOut(message);
    53+
    lazyFs().appendFile(fd, `${message}\n`, nop);
    54+
    };
    55+
    }
    56+
    57+
    function acquireFd(cb) {
    58+
    if (cachedFd === undefined && !acquiringFd) {
    59+
    acquiringFd = true;
    60+
    lazyFs().open(config.warningFile, 'a', onOpen(cb));
    61+
    } else if (cachedFd !== undefined && !acquiringFd) {
    62+
    cb(null, cachedFd);
    63+
    } else {
    64+
    process.once('_node_warning_fd_acquired', cb);
    65+
    }
    66+
    }
    67+
    68+
    function output(message) {
    69+
    if (typeof config.warningFile === 'string') {
    70+
    acquireFd(onAcquired(message));
    71+
    return;
    72+
    }
    73+
    writeOut(message);
    74+
    }
    75+
    76+
    function doEmitWarning(warning) {
    77+
    return function() {
    78+
    process.emit('warning', warning);
    79+
    };
    80+
    }
    81+
    1182
    function setupProcessWarnings() {
    1283
    if (!process.noProcessWarnings && process.env.NODE_NO_WARNINGS !== '1') {
    1384
    process.on('warning', (warning) => {
    @@ -21,7 +92,7 @@ function setupProcessWarnings() {
    2192
    var toString = warning.toString;
    2293
    if (typeof toString !== 'function')
    2394
    toString = Error.prototype.toString;
    24-
    console.error(`${prefix}${toString.apply(warning)}`);
    95+
    output(`${prefix}${toString.apply(warning)}`);
    2596
    }
    2697
    });
    2798
    }
    @@ -44,6 +115,6 @@ function setupProcessWarnings() {
    44115
    if (throwDeprecation && warning.name === 'DeprecationWarning')
    45116
    throw warning;
    46117
    else
    47-
    process.nextTick(() => process.emit('warning', warning));
    118+
    process.nextTick(doEmitWarning(warning));
    48119
    };
    49120
    }

    src/node.cc

    Lines changed: 13 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -199,12 +199,16 @@ bool trace_warnings = false;
    199199
    // that is used by lib/module.js
    200200
    bool config_preserve_symlinks = false;
    201201

    202+
    202203
    // Set in node.cc by ParseArgs when --expose-internals or --expose_internals is
    203204
    // used.
    204205
    // Used in node_config.cc to set a constant on process.binding('config')
    205206
    // that is used by lib/internal/bootstrap_node.js
    206207
    bool config_expose_internals = false;
    207208

    209+
    // Set in node.cc by ParseArgs when --redirect-warnings= is used.
    210+
    const char* config_warning_file;
    211+
    208212
    // process-relative uptime base, initialized at start-up
    209213
    static double prog_start_time;
    210214
    static bool debugger_running;
    @@ -3701,6 +3705,8 @@ static void PrintHelp() {
    37013705
    "function is used\n"
    37023706
    " --no-warnings silence all process warnings\n"
    37033707
    " --trace-warnings show stack traces on process warnings\n"
    3708+
    " --redirect-warnings=path\n"
    3709+
    " write warnings to path instead of stderr\n"
    37043710
    " --trace-sync-io show stack trace when use of sync IO\n"
    37053711
    " is detected after the first tick\n"
    37063712
    " --track-heap-objects track heap object allocations for heap "
    @@ -3765,6 +3771,7 @@ static void PrintHelp() {
    37653771
    " prefixed to the mod 474D ule search path\n"
    37663772
    "NODE_REPL_HISTORY path to the persistent REPL history file\n"
    37673773
    "OPENSSL_CONF load OpenSSL configuration from file\n"
    3774+
    "NODE_REDIRECT_WARNINGS write warnings to path instead of stderr\n"
    37683775
    "\n"
    37693776
    "Documentation can be found at https://nodejs.org/\n");
    37703777
    }
    @@ -3866,6 +3873,8 @@ static void ParseArgs(int* argc,
    38663873
    no_process_warnings = true;
    38673874
    } else if (strcmp(arg, "--trace-warnings") == 0) {
    38683875
    trace_warnings = true;
    3876+
    } else if (strncmp(arg, "--redirect-warnings=", 20) == 0) {
    3877+
    config_warning_file = arg + 20;
    38693878
    } else if (strcmp(arg, "--trace-deprecation") == 0) {
    38703879
    trace_deprecation = true;
    38713880
    } else if (strcmp(arg, "--trace-sync-io") == 0) {
    @@ -4401,6 +4410,10 @@ void Init(int* argc,
    44014410
    if (openssl_config.empty())
    44024411
    SafeGetenv("OPENSSL_CONF", &openssl_config);
    44034412

    4413+
    if (auto redirect_warnings = secure_getenv("NODE_REDIRECT_WARNINGS")) {
    4414+
    config_warning_file = redirect_warnings;
    4415+
    }
    4416+
    44044417
    // Parse a few arguments which are specific to Node.
    44054418
    int v8_argc;
    44064419
    const char** v8_argv;

    src/node_config.cc

    Lines changed: 10 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -12,6 +12,7 @@ using v8::Context;
    1212
    using v8::Local;
    1313
    using v8::Object;
    1414
    using v8::ReadOnly;
    15+
    using v8::String;
    1516
    using v8::Value;
    1617

    1718
    // The config binding is used to provide an internal view of compile or runtime
    @@ -47,6 +48,15 @@ void InitConfig(Local<Object> target,
    4748

    4849
    if (config_expose_internals)
    4950
    READONLY_BOOLEAN_PROPERTY("exposeInternals");
    51+
    52+
    if (config_warning_file != nullptr) {
    53+
    Local<String> name = OneByteString(env->isolate(), "warningFile");
    54+
    Local<String> value = String::NewFromUtf8(env->isolate(),
    55+
    config_warning_file,
    56+
    v8::NewStringType::kNormal)
    57+
    .ToLocalChecked();
    58+
    target->DefineOwnProperty(env->context(), name, value).FromJust();
    59+
    }
    5060
    } // InitConfig
    5161

    5262
    } // namespace node

    src/node_internals.h

    Lines changed: 5 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -49,6 +49,11 @@ extern bool config_preserve_symlinks;
    4949
    // that is used by lib/internal/bootstrap_node.js
    5050
    extern bool config_expose_internals;
    5151

    52+
    // Set in node.cc by ParseArgs when --redirect-warnings= is used.
    53+
    // Used to redirect warning output to a file rather than sending
    54+
    // it to stderr.
    55+
    extern const char* config_warning_file;
    56+
    5257
    // Forward declaration
    5358
    class Environment;
    5459

    Lines changed: 25 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,25 @@
    1+
    'use strict';
    2+
    3+
    // Tests the NODE_REDIRECT_WARNINGS environment variable by spawning
    4+
    // a new child node process that emits a warning into a temporary
    5+
    // warnings file. Once the process completes, the warning file is
    6+
    // opened and the contents are validated
    7+
    8+
    const common = require('../common');
    9+
    const fs = require('fs');
    10+
    const fork = require('child_process').fork;
    11+
    const path = require('path');
    12+
    const assert = require('assert');
    13+
    14+
    common.refreshTmpDir();
    15+
    16+
    const warnmod = require.resolve(common.fixturesDir + '/warnings.js');
    17+
    const warnpath = path.join(common.tmpDir, 'warnings.txt');
    18+
    19+
    fork(warnmod, {env: {NODE_REDIRECT_WARNINGS: warnpath}})
    20+
    .on('exit', common.mustCall(() => {
    21+
    fs.readFile(warnpath, 'utf8', common.mustCall((err, data) => {
    22+
    assert.ifError(err);
    23+
    assert(/\(node:\d+\) Warning: a bad practice warning/.test(data));
    24+
    }));
    25+
    }));
    Lines changed: 25 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,25 @@
    1+
    'use strict';
    2+
    3+
    // Tests the --redirect-warnings command line flag by spawning
    4+
    // a new child node process that emits a warning into a temporary
    5+
    // warnings file. Once the process completes, the warning file is
    6+
    // opened and the contents are validated
    7+
    8+
    const common = require('../common');
    9+
    const fs = require('fs');
    10+
    const fork = require('child_process').fork;
    11+
    const path = require('path');
    12+
    const assert = require('assert');
    13+
    14+
    common.refreshTmpDir();
    15+
    16+
    const warnmod = require.resolve(common.fixturesDir + '/warnings.js');
    17+
    const warnpath = path.join(common.tmpDir, 'warnings.txt');
    18+
    19+
    fork(warnmod, {execArgv: [`--redirect-warnings=${warnpath}`]})
    20+
    .on('exit', common.mustCall(() => {
    21+
    fs.readFile(warnpath, 'utf8', common.mustCall((err, data) => {
    22+
    assert.ifError(err);
    23+
    assert(/\(node:\d+\) Warning: a bad practice warning/.test(data));
    24+
    }));
    25+
    }));

    0 commit comments

    Comments
     (0)
    0