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

我有一个Node.js服务脚本,必须在启动CentOS 7服务器时执行。 我使用了一个init.d模板来创build一个启动守护进程。 如果我以root身份login到服务器,并使用以下命令在terminal中手动执行脚本,则init.d脚本完美工作:

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

Node脚本执行并执行它所做的事情,包括写入应用程序目录内的日志文件夹中的某些日志文件。

我的问题是,当服务器重新启动时,init.d脚本执行得很好,它也启动节点脚本,只有节点脚本然后错误与一个未捕获的types'ENOENT'例外说明它不能打开日志文件是要写入。

从我读过的所有东西中,所有的init.d脚本在启动时都以root身份执行,所以我希望它能够正常工作,就像在terminal中使用sudo手动启动init.d脚本一样。

对于我的生活,我无法弄清楚交易是什么。 在系统启动时,我认为它是一个许可的东西或环境的东西,不同于在terminal中运行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'] 

logging温斯顿

 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; 

configuration保存日志文件path

 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可执行文件的path启动节点脚本。

您需要通过__dirname指定脚本的目录以使path为绝对path。

 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'); 在它之前。 ( 这是一个本地模块 ,不需要安装)