我有一个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'
}
答案 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,不需要安装)