node.js - CentOS、Node.js、init.d、ENOENT,当应用程序自动启动时,无法在系统重新启动时打开或写入日志文件

标签 node.js init.d centos7

我有一个 Node.js 服务脚本,必须在 CentOS 7 服务器启动时执行。我使用 init.d 模板来创建启动守护进程。如果我以 root 身份登录服务器并使用以下命令在终端中手动执行脚本,则 init.d 脚本可以完美运行:

sudo /etc/init.d/ServerStatusService start(stop,restart,status)

Node 脚本执行并执行其操作,不会出现任何问题,其中包括写入应用程序目录内日志文件夹中的一些日志文件。

我遇到的问题是,当服务器重新启动时,init.d 脚本执行得很好,并且它也启动了 Node 脚本,只有 Node 脚本会出错,并出现“ENOENT”类型的未捕获异常,表明它无法打开要写入的日志文件。

从我读过的所有内容来看,所有 init.d 脚本在启动时都以 root 身份执行,因此我希望它能够正常工作,就像我在终端中使用 sudo 手动启动 init.d 脚本一样。

我无论如何也搞不懂这到底是怎么回事。我假设它是系统启动时的权限或环境,与在终端中运行 sudo 不同。

我还使用以下选项运行 init.d 脚本来复制启动时机器的状态,但它就像启动时一样失败。

env -i LANG="$LANG" PATH="$PATH" TERM="$TERM" /etc/init.d/ServerStatusService start

我的 init.d 脚本

#!/bin/sh

NODE_ENV="staging"
PORT="8088"
APP_DIR="/var/www/ServerStatusClientn"
NODE_APP="serverStatusService.js"
CONFIG_DIR="$APP_DIR"
PID_DIR="$APP_DIR/pid"
PID_FILE="$PID_DIR/app.pid"
LOG_DIR="$APP_DIR/logs"
LOG_FILE="$LOG_DIR/app.log"
NODE_EXEC=$(which node)

USAGE="Usage: $0 {start|stop|restart|status} [--force]"
FORCE_OP=false

pid_file_exists() {
    [ -f "$PID_FILE" ]
}

get_pid() {
    echo "$(cat "$PID_FILE")"
}

is_running() {
    PID=$(get_pid)
    ! [ -z "$(ps aux | awk '{print $2}' | grep "^$PID$")" ]
}

start_it() {
    mkdir -p "$PID_DIR"
    mkdir -p "$LOG_DIR"

    echo "Starting node app ..."
    PORT="$PORT" NODE_ENV="$NODE_ENV" NODE_CONFIG_DIR="$CONFIG_DIR" $NODE_EXEC "$APP_DIR/$NODE_APP"  1>"$LOG_FILE" 2>&1 &
    echo $! > "$PID_FILE"
    echo "Node app started with pid $!"
}

stop_process() {
    PID=$(get_pid)
    echo "Killing process $PID"
    kill $PID
}

remove_pid_file() {
    echo "Removing pid file"
    rm -f "$PID_FILE"
}

start_app() {
    if pid_file_exists
    then
        if is_running
        then
            PID=$(get_pid)
            echo "Node app already running with pid $PID"
            exit 1
        else
            echo "Node app stopped, but pid file exists"
            if [ $FORCE_OP = true ]
            then
                echo "Forcing start anyways"
                remove_pid_file
                start_it
            fi
        fi
    else
        start_it
    fi
}

stop_app() {
    if pid_file_exists
    then
        if is_running
        then
            echo "Stopping node app ..."
            stop_process
            remove_pid_file
            echo "Node app stopped"
        else
            echo "Node app already stopped, but pid file exists"
            if [ $FORCE_OP = true ]
            then
                echo "Forcing stop anyways ..."
                remove_pid_file
                echo "Node app stopped"
            else
                exit 1
            fi
        fi
    else
        echo "Node app already stopped, pid file does not exist"
        exit 1
    fi
}

status_app() {
    if pid_file_exists
    then
        if is_running
        then
            PID=$(get_pid)
            echo "Node app running with pid $PID"
        else
            echo "Node app stopped, but pid file exists"
        fi
    else
        echo "Node app stopped"
    fi
}

case "$2" in
    --force)
        FORCE_OP=true
    ;;

    "")
    ;;

    *)
        echo $USAGE
        exit 1
    ;;
esac

case "$1" in
    start)
        start_app
    ;;

    stop)
        stop_app
    ;;

    restart)
        stop_app
        start_app
    ;;

    status)
        status_app
    ;;

    *)
        echo $USAGE
        exit 1
    ;;
esac

错误日志

error: uncaughtException: ENOENT, open 'logs/mediaServerStatus-debug.log' date=Mon Feb 09 2015 11:03:00 GMT-0700 (MST), pid=6329, uid=0, gid=0, cwd=/, execPath=/usr/bin/node, version=v0.10.33, argv=[/usr/bin/node, /var/www/MediaServerStatusService/service.js], rss=40230912, heapTotal=28055552, heapUsed=14903704, loadavg=[0.064453125, 0.18310546875, 0.181640625], uptime=6808.08772411, trace=[], stack=[Error: ENOENT, open 'logs/mediaServerStatus-debug.log']
error: uncaughtException: ENOENT, open 'logs/mediaServerStatus-debug.log' date=Mon Feb 09 2015 11:03:00 GMT-0700 (MST), pid=6329, uid=0, gid=0, cwd=/, execPath=/usr/bin/node, version=v0.10.33, argv=[/usr/bin/node, /var/www/MediaServerStatusService/service.js], rss=40230912, heapTotal=28055552, heapUsed=15008752, loadavg=[0.064453125, 0.18310546875, 0.181640625], uptime=6808.090709357, trace=[], stack=[Error: ENOENT, open 'logs/mediaServerStatus-debug.log']

使用 Winston 进行日志记录

var winston = require('winston'),
config = require('../config/config');
winston.emitErrs = true;

var debug = new winston.Logger({
    transports: [
        new winston.transports.Console({
            level: 'debug',
            handleExceptions: true,
            json: false,
            colorize: true
        })
    ]
});

if(config.logging.debugToFile){
    debug.add(
        winston.transports.File,
        {
            name: 'debug-file',
            level: 'debug',
            filename: config.logging.debug,
            handleExceptions: true,
            json: true,
            maxsize: 5242880, //5MB
            maxFiles: 5,
            colorize: false
        }
    );
}

var info = new winston.Logger({
    transports: [
        new winston.transports.Console({
            level: 'info',
            handleExceptions: true,
            json: false,
            colorize: true
        })
    ]
});

var warn = new winston.Logger({
    transports: [
        new winston.transports.File({
            name: 'warn-file',
            level: 'warn',
            filename: config.logging.warn,
            handleExceptions: true,
            json: true,
            maxsize: 5242880, //5MB
            maxFiles: 5,
            colorize: false
        }),
        new winston.transports.Console({
            level: 'warn',
            handleExceptions: true,
            json: false,
            colorize: true
        })
    ]
});

var error = new winston.Logger({
    transports: [
        new winston.transports.File({
            name: 'error-file',
            level: 'error',
            filename: config.logging.error,
            handleExceptions: true,
            json: true,
            maxsize: 5242880, //5MB
            maxFiles: 5,
            colorize: false
        }),
        new winston.transports.Console({
            level: 'error',
            handleExceptions: true,
            json: false,
            colorize: true
        })
    ]
});

var loggers = {
    debug: function(msg, callback){
        debug.debug(msg, callback);
    },
    info: function(msg, callback){
        info.info(msg, callback);
    },
    warn: function(msg, callback){
        warn.warn(msg, callback);
    },
    error: function(msg, callback){
        error.error(msg, callback);
    },
    log: function(level,msg, callback){
        var lvl = exports[level];
        lvl(msg, callback);
    }
};

// Logging
module.exports = loggers;

配置保存日志文件路径

logging: {
    debugToFile: true,
    debug: './logs/mediaServerStatus-debug.log',
    info: './logs/mediaServerStatus-info.log',
    warn: './logs/mediaServerStatus-warn.log',
    error: './logs/mediaServerStatus-error.log'
}

最佳答案

Init.d 脚本从 node 可执行文件的路径启动 Node 脚本。

您需要通过 __dirname 指定脚本的目录使路径成为绝对路径。

logging: {
    debugToFile: true,
    debug: path.join(__dirname, 'logs/mediaServerStatus-debug.log'),
    info:  path.join(__dirname, 'logs/mediaServerStatus-info.log'),
    warn:  path.join(__dirname, 'logs/mediaServerStatus-warn.log'),
    error: path.join(__dirname, 'logs/mediaServerStatus-error.log'),
}

请务必在其之前添加var path = require('path');。 ( it's a native module ,不需要安装)

关于node.js - CentOS、Node.js、init.d、ENOENT,当应用程序自动启动时,无法在系统重新启动时打开或写入日志文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28415537/

相关文章:

node.js - VS Code 没有为在 Docker 容器中运行的 Node 应用程序命中断点

nginx - 添加 nginx 作为 ubuntu 服务停止并重新加载不起作用

ruby - 如何在没有 ruby​​ 的情况下列出 init.d 脚本的文件

amazon-web-services - 已断开 没有可用的受支持的身份验证方法(服务器发送公钥) 发送公钥 gssapi key 和麦克风

php - Laravel 主机不允许连接到此 mysql 服务器 (Centos 7)

node.js,socket.io 只能在本地工作,无法从内网系统访问

javascript - core-js/babel-polyfill polyfill 函数显示为 [native code]

macos - Node.js 版本和 Heroku

node.js - 带 Angular RSA库

linux - Raspbian 启动时自动运行命令