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

时间:2015-02-09 17:21:46

标签: 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&#的异常错误39;声明它无法打开要写入的日志文件。

从我读过的所有内容中,所有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'
}

1 个答案:

答案 0 :(得分:3)

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,不需要安装)