1 Star 0 Fork 62

younger007 / webfunny_monitor

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
config_bin_init.js 25.45 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
var fs = require('fs');
// 初始化bin目录
var pathArray = ["./bin/domain.js", "./bin/httpReqRes.js", "./bin/messageQueue.js", "./bin/mysqlConfig.js", "./bin/purchaseCode.js", "./bin/saveDays.js", "./bin/slave.js", "./bin/stayTimeScope.js", "./bin/stopWebMonitorIdList.js", "./bin/sysMonitor.js", "./bin/useCusEmailSys.js", "./bin/webfunny.js", "./bin/webMonitorIdList.js"]
var fileArray = [
`module.exports = {
// 1. 日志服务(接口)域名 书写形式:localhost:8011;
// 2. 如果设置空字符串,则会使用浏览器域名
localServerDomain: 'localhost:8011',
// 数据可视化服务域名 书写形式:localhost:8010;
localAssetsDomain: 'localhost:8010',
// 日志服务端口号
localServerPort: '8011',
// 可视化系统端口号
localAssetsPort: '8010',
/**
* 注意:不懂可以不用设置,【千万不要乱设置】
*
* 1. 什么情况设置:如果同一个主域名下有多个项目,并且同一个UserId的用户,会访问这多个项目
* 2. 设置结果:使用userId查询,可以将一个用户在多个项目上的行为串联起来。
*
* 例如:www.baidu.com 主域名就是:baidu.com
*/
mainDomain: '' // 默认空字符串就行了
}`,
`module.exports = {
requestTextLength: 1000, // 接口请求参数内容长度限制
responseTextLength: 1000, // 接口返回结果内容长度限制
}
`,
`module.exports = {
messageQueue: false // 是否开启消息队列,默认不开启
}`,
`module.exports = {
write: {
ip: '',
port: '3306',
dataBaseName: 'webfunny_db',
userName: '',
password: ''
},
// 高性能版支持此属性
read: [
// { host: "", username: "", password: "" }
]
}`,
`module.exports = {
purchaseCode: '',
secretCode: ''
}`,
`module.exports = {
saveDays: '8',
}`,
`var app = require('../app');
var { accountInfo } = require("../config/AccountConfig")
global.serverType = "slave"
var port = normalizePort(process.env.PORT || accountInfo.localServerPort);
app.listen(port);
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
`,
`/**
* 用户停留时间,去掉最大值,去掉最小值范围
*
* 去掉最小值: 有些用户进来了就离开,可以不考虑在内
* 去掉最大值: 有些用户进来了,处于不活跃状态,停留时间会很长,也可以去除
*/
module.exports = {
min: 100, // 最小值
max: 100000 // 最大值
}`,
`// 停止日志上报列表
module.exports = []`,
`module.exports = {
openMonitor: true // 企业版可关闭此选项
}`,
`module.exports = {
useCusEmailSys: false, // 是否使用自己的邮件系统, true: 使用配置的邮箱密码;false: 由webfunny系统给你发送邮件
emailUser: "", // 163邮箱用户名
emailPassword: "" // 163邮箱,网易老账号用密码, 新账号用安全码
}`,
`#!/usr/bin/env node
var app = require('../app');
var debug = require('debug')('demo:server');
var { accountInfo } = require("../config/AccountConfig")
global.serverType = "master"
var port = normalizePort(process.env.PORT || accountInfo.localServerPort);
app.listen(port);
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
// 启动静态文件服务器
const KoaStatic = require('koa');
const appStatic = new KoaStatic();
const server = require('koa-static-cache');
/* gzip压缩配置 start */
const compress = require('koa-compress');
const options = {
threshold: 1024 //数据超过1kb时压缩
};
/* gzip压缩配置 end */
// 1.主页静态网页 把静态页统一放到public中管理
const publicServer = server('./views');
// 2.重定向判断
const redirect = ctx => {
ctx.response.redirect('/webfunny/home.html')
};
// 3.分配路由
appStatic.use(compress(options))
appStatic.use(async (ctx, next) => {
if (ctx.url === '/' || ctx.url === '/webfunny/') {
redirect(ctx)
} else {
await next()
}
});
appStatic.use(publicServer);
appStatic.listen(accountInfo.localAssetsPort);`,
`module.exports = []`
]
fs.mkdir( "./bin", function(err){
if ( err ) {
console.log("= 文件夹 /bin 已经存在")
} else {
console.log("= 创建文件夹 /bin")
}
pathArray.forEach((path, index) => {
fs.readFile(path, "", (err) => {
if (err) {
console.log("× " + path + " 配置文件不存在,即将创建...")
fs.writeFile(path, fileArray[index], (err) => {
if (err) throw err;
console.log("" + path + " 配置文件创建完成!");
});
} else {
console.log("" + path + " 配置文件已存在!")
}
});
})
});
/**
* 初始化alarm目录
*/
var alarmPathArray = ["./alarm/alarmName.js", "./alarm/dingding.js", "./alarm/feishu.js", "./alarm/weixin.js", "./alarm/index.js",]
var alarmFileArray = [
`module.exports = {
PV: "浏览页面次数",
UV: "浏览页面人数",
JsError: "JS代码错误次数",
ConsoleError: "自定义错误次数",
http: "接口请求次数",
httpError: "接口错误次数",
resourceError: "静态资源错误次数",
}`,
`/**
* 这里是钉钉机器人(关键字)的相关配置
* 关键字列表:
* 1. 警报
*/
module.exports = {
url: "", // 钉钉机器人的 webHook URL
config: {
"msgtype": "text",
"text": {
"content": ""
},
"at": {
"atMobiles": [ // 想要@的成员列表
"000"
],
"isAtAll": false // 是否@所有人
}
}
}`,
`/**
* 这里是飞书的机器人(关键字)的相关配置
* 关键字列表:
* 1. 警报
*/
module.exports = {
url: "", // 飞书机器人的URL
config: {
"msg_type": "text",
"content": {
"text": ""
},
}
}`,
`/**
* 这里是企业微信机器人的相关配置
*/
module.exports = {
url: "", // 企业微信机器人的 webHook URL
config: {
"msgtype": "text",
"text": {
"content": "我只是一个机器人测试,请忽略我",
"mentioned_list":["xxx",],
"mentioned_mobile_list":["182xxxx4111"] // 将要艾特的人
}
}
}`,
`const sendEmail = require('../util_cus/sendEmail');
const dingDing = require('../alarm/dingding')
const weiXin = require('../alarm/weixin')
const feiSHu = require('../alarm/feishu')
const Utils = require('../util/utils')
const AccountConfig = require('../config/AccountConfig')
const { accountInfo } = AccountConfig
const AlarmNames = require('./alarmName')
const alarmCallback = (project, rule, users) => {
const { projectName, projectType, chooseHook } = project
const {type, happenCount, compareType, limitValue} = rule
const compareStr = compareType === "up" ? ">=" : "<"
const projectHook = chooseHook ? JSON.parse(chooseHook) : {value: "", name: "", webHook: ""}
/**生成警报配置 */
// 添加用户手机号
users.forEach((user) => {
dingDing.config.at.atMobiles.push(user.phone)
weiXin.config.text.mentioned_mobile_list.push(user.phone)
})
// 生成警报内容
const contentStr = type + "警报!" +
"您的" + projectType + "项目【" + projectName + "】发出警报:" +
type + "数量 " + compareStr + " " + limitValue + " 已经发生" + happenCount + "次了,请及时处理。"
dingDing.config.text.content = contentStr
weiXin.config.text.content = contentStr
feiSHu.config.content.text = contentStr
switch(projectHook.value) {
case "dingding":
// 1. 通知钉钉机器人
Utils.postJson(projectHook.webHook, dingDing.config) // 钉钉机器人
break
case "weixin":
// 2. 通知微信机器人
Utils.postJson(projectHook.webHook, weiXin.config) // 微信机器人
break
case "feishu":
// 3. 通知飞书机器人
Utils.postJson(projectHook.webHook, feiSHu.config) // 飞书机器人
break
default:
break
}
// 4. 发送邮件通知
if (users && users.length && accountInfo.emailUser && accountInfo.emailPassword) {
users.forEach((user) => {
const email = user.emailName
sendEmail(email, AlarmNames[type] + "警报!", contentStr, accountInfo.emailUser, accountInfo.emailPassword)
})
}
}
module.exports = {
alarmCallback
}`,
]
fs.mkdir( "./alarm", function(err){
if ( err ) {
console.log("= 文件夹 /alarm 已经存在")
} else {
console.log("= 创建文件夹 /alarm")
}
alarmPathArray.forEach((path, index) => {
fs.readFile(path, "", (err) => {
if (err) {
console.log("× " + path + " 配置文件不存在,即将创建...")
fs.writeFile(path, alarmFileArray[index], (err) => {
if (err) throw err;
console.log("" + path + " 配置文件创建完成!");
});
} else {
console.log("" + path + " 配置文件已存在!")
}
});
})
});
/**
* 初始化util_cus目录
*/
var cusUtilPathArray = ['./util_cus/index.js', './util_cus/sendEmail.js']
var cusUtilFileArray = [
`const sendEmail = require("./sendEmail")
module.exports = {
sendEmail
}`,
`const nodemailer = require('nodemailer')
const AccountConfig = require('../config/AccountConfig')
const { accountInfo } = AccountConfig
/**
* 自己配置邮箱:在 bin/useCusEmailSys.js文件中 参数改为true,并配置自己的163邮箱和密码
* @param targetEmail 目标邮箱地址
* @param emailTitle 邮件标题
* @param emailContent 邮件正文
* @param user 系统邮箱地址(不传参,则默认使用配置的邮箱地址)
* @param pass 系统邮箱密码(不传参,则默认使用配置的邮箱密码)
*/
const sendEmail = (targetEmail, emailTitle, emailContent, user = accountInfo.emailUser, pass = accountInfo.emailPassword) => {
const company = "webfunny"
let transporter = nodemailer.createTransport({
host: "smtp.163.com",
port: 465,
secure: true, // true for 465, false for other ports
auth: { user,pass }
});
// send mail with defined transport object
transporter.sendMail({
from: "'" + company + "' <" + user + ">", // sender address
to: targetEmail, // list of receivers
subject: emailTitle, // Subject line
text: emailContent, // plain text body
html: emailContent // html body
});
}
module.exports = sendEmail`
]
fs.mkdir( "./util_cus", function(err){
if ( err ) {
console.log("= 文件夹 /util_cus 已经存在")
} else {
console.log("= 创建文件夹 /util_cus")
}
cusUtilPathArray.forEach((path, index) => {
fs.readFile(path, "", (err) => {
if (err) {
console.log("× " + path + " 配置文件不存在,即将创建...")
fs.writeFile(path, cusUtilFileArray[index], (err) => {
if (err) throw err;
console.log("" + path + " 配置文件创建完成!");
});
} else {
console.log("" + path + " 配置文件已存在!")
}
});
})
});
/**
* 初始化interceptor目录
*/
// 初始化interceptor/config目录
var configArray = ["./interceptor/config/dingRobot.js", "./interceptor/config/consoleError.js", "./interceptor/config/httpError.js", "./interceptor/config/jsError.js", "./interceptor/config/resourceError.js"]
var configConArray = [
`/**
* 这里是钉钉机器人(关键字)的相关配置
* 关键字列表:
* 1. 发生了一个
* 2. JS错误数量达到
* 3. JS错误率达到
* 4. 自定义异常数量达到
* 5. 自定义异常率达到
* 6. 接口报错数量达到
* 7. 接口报错率达到
* 8. 静态资源错误量达到
* 9. 静态资源错误率达到
*/
module.exports = {
url: "", // 钉钉机器人的URL
config: {
"msgtype": "text",
"text": {
"content": ""
},
"at": {
"atMobiles": [ // 想要@的成员列表
"18501754111"
],
"isAtAll": false // 是否@所有人
}
}
}
`,
`/**
* consoleError异常报警配置
*/
module.exports = {
errorCount: 100,
errorPercent: 10 // 这里是百分比
}`,
`/**
* consoleError异常报警配置
*/
module.exports = {
errorCount: 100,
errorPercent: 10 // 这里是百分比
}`,
`/**
* JS异常报警配置
*/
module.exports = {
errorCount: 100,
errorPercent: 10 // 这里是百分比
}`,
`/**
* resourceError异常报警配置
*/
module.exports = {
errorCount: 100,
errorPercent: 10 // 这里是百分比
}`
]
// 初始化interceptor警报文件
var interceptorArray = ["./interceptor/index.js", "./interceptor/customerWarning.js", "./interceptor/httpRequest.js", "./interceptor/javascriptError.js", "./interceptor/resourceError.js"]
var interceptorConArray = [
`const handleResultWhenJavascriptError = require('../interceptor/javascriptError')
const handleResultWhenHttpRequest = require('../interceptor/httpRequest')
const handleResultWhenResourceError = require('../interceptor/resourceError')
module.exports = {
handleResultWhenJavascriptError, handleResultWhenHttpRequest, handleResultWhenResourceError
}`,
`/**
* 这里是使用者自定义的回调方法,每隔10分钟会调用一次。
* 由你们自行决定如何发起警报,通过接口通知你们自己的服务即可。
* @param res 参数返回所有的警告信息。
* 无论你想发送到邮箱,短信,钉钉等,你们自己发送接口通知吧。
*/
const jsError = require('./config/jsError')
const consoleError = require('./config/consoleError')
const httpError = require('./config/httpError')
const resourceError = require('./config/resourceError')
const dingRobot = require("./config/dingRobot")
const domain = require("../bin/domain")
const Utils = require('../util/utils')
const customerWarningCallback = (warningInfoList) => {
if (warningInfoList !== "undefined" && warningInfoList.length > 0) {
warningInfoList.forEach((item) => {
const { webMonitorId, hour, uv, jsErrorCount, consoleErrorCount, resourceErrorCount, httpErrorCount, jsErrorUvCount, consoleErrorUvCount, resourceErrorUvCount, httpErrorUvCount } = item
todayUvCount = parseInt(uv, 10)
let jsErrorPercent = todayUvCount > 0 ? jsErrorUvCount / todayUvCount : 0
let consoleErrorPercent = todayUvCount > 0 ? consoleErrorUvCount / todayUvCount : 0
let resourceErrorPercent = todayUvCount > 0 ? resourceErrorUvCount / todayUvCount : 0
let httpErrorPercent = todayUvCount > 0 ? httpErrorUvCount / todayUvCount : 0
jsErrorPercent = Utils.toFixed(jsErrorPercent * 100, 2)
consoleErrorPercent = Utils.toFixed(consoleErrorPercent * 100, 2)
resourceErrorPercent = Utils.toFixed(resourceErrorPercent * 100, 2)
httpErrorPercent = Utils.toFixed(httpErrorPercent * 100, 2)
let warnMsg = ""
if (jsErrorCount >= jsError.errorCount || jsErrorPercent >= jsError.errorPercent) {
const {url, config} = dingRobot
config.text.content = "您的前端项目(" + webMonitorId + ")\\r\\n时间:" + hour + "\\r\\nJS错误率达到:" + jsErrorPercent + "%\\r\\nJS错误量达到:" + jsErrorCount + "\\r\\n 查看详情:http://" + domain.localAssetsDomain + "/webfunny/javascriptError.html"
warnMsg = config.text.content
global.monitorInfo.warningMessageList.push({msg: warnMsg, time: new Date().Format("yyyy-MM-dd hh:mm:ss")})
Utils.postJson(url,config) // 钉钉机器人
// 如果需要其他通知方式,请在此完成报警逻辑
}
if (consoleErrorCount >= consoleError.errorCount || consoleErrorPercent >= consoleError.errorPercent) {
const {url, config} = dingRobot
config.text.content = "您的前端项目(" + webMonitorId + ")\\r\\n时间:" + hour + "\\r\\n自定义异常率达到:" +consoleErrorPercent + "%\\r\\n自定义异常量达到:" +consoleErrorCount + "\\r\\n 查看详情:http://" + domain.localAssetsDomain + "/webfunny/javascriptError.html"
warnMsg = config.text.content
global.monitorInfo.warningMessageList.push({msg: warnMsg, time: new Date().Format("yyyy-MM-dd hh:mm:ss")})
Utils.postJson(url,config) // 钉钉机器人
// 如果需要其他通知方式,请在此完成报警逻辑
}
if (httpErrorCount >= httpError.errorCount || httpErrorPercent >= httpError.errorPercent) {
const {url, config} = dingRobot
config.text.content = "您的前端项目(" + webMonitorId + ")\\r\\n时间:" + hour + "\\r\\n接口报错率达到:" + httpErrorPercent + "%\\r\\n接口报错量达到:" + httpErrorCount + "\\r\\n 查看详情:http://" + domain.localAssetsDomain + "/webfunny/httpError.html"
warnMsg = config.text.content
global.monitorInfo.warningMessageList.push({msg: warnMsg, time: new Date().Format("yyyy-MM-dd hh:mm:ss")})
Utils.postJson(url,config) // 钉钉机器人
// 如果需要其他通知方式,请在此完成报警逻辑
}
if (resourceErrorCount >= resourceError.errorCount || resourceErrorPercent >= resourceError.errorPercent) {
const {url, config} = dingRobot
config.text.content = "您的前端项目(" + webMonitorId + ")\\r\\n时间:" + hour + "\\r\\n静态资源错误率达到:" + resourceErrorPercent + "%\\r\\n静态资源错误量达到:" + resourceErrorCount + "\\r\\n查看详情:http://" + domain.localAssetsDomain + "/webfunny/resourceError.html"
warnMsg = config.text.content
global.monitorInfo.warningMessageList.push({msg: warnMsg, time: new Date().Format("yyyy-MM-dd hh:mm:ss")})
Utils.postJson(url,config) // 钉钉机器人
// 如果需要其他通知方式,请在此完成报警逻辑
}
})
}
}
module.exports = {
customerWarningCallback
}`,
`const Utils = require('../util/utils');
const dingRobot = require("./config/dingRobot")
const domain = require('../bin/domain')
/**
* 这里是接口的拦截器的拦截器。
* 每次上报接口日志,都会调用这个方法(可以处理报错,超时等等)
*/
const handleResultWhenHttpRequest = (res) => {
// console.log(res) // 打印查看其他字段
const {webMonitorId, statusResult, status, loadTime, simpleUrl, httpUrl } = res
const simpleHttpUrl = Utils.b64DecodeUnicode(httpUrl)
if (statusResult === "请求返回") {
switch(status) {
case 200:
break;
case 404:
case 500:
case 502:
const {url, config} = dingRobot
config.text.content = "您的前端项目(" + webMonitorId + ")发生了一个接口错误:\\r\\n状态:" + status + "\\r\\n接口:" + simpleHttpUrl + "\\r\\n页面:" + simpleUrl + "\\r\\n查看详情:http://" + domain.localAssetsDomain + "/webfunny/httpError.html"
Utils.postJson(url,config) // 通知机器人
// 如果需要其他通知方式,请在此完成报警逻辑
break;
default:
break;
}
// 接口耗时大于10s
if (loadTime > 10000) {
// 填写你的逻辑
}
}
}
module.exports = handleResultWhenHttpRequest`,
`const Utils = require('../util/utils');
const dingRobot = require("./config/dingRobot")
const domain = require('../bin/domain')
/**
* 这里是js错误的拦截器。
* 每次发生js报错,都会调用这个方法
*/
const handleResultWhenJavascriptError = (res) => {
/**
* webMonitorId: 每个项目对应的id,如果需要特殊处理某个项目,就可以用它
* infoType: 错误类型,on_error、console_error
* errorMessage: 错误消息
*/
// console.log(res) // 打印查看其他字段
const {webMonitorId, infoType, errorMessage, simpleUrl} = res
const tempErrorMessage = Utils.b64DecodeUnicode(errorMessage)
const msgArr = tempErrorMessage.split(": ")
const type = msgArr[0] || msgArr[1] || msgArr[2] || ""
const errorObj = {
type,
logData: res
}
global.monitorInfo.errorLogListForLast200.push(errorObj)
if (infoType === "on_error") {
// 根据错误类型处理
switch(type) {
case "TypeError":
case "ReferenceError":
case "UncaughtInPromiseError":
const {url, config} = dingRobot
config.text.content = "您的前端项目(" + webMonitorId + ")发生了一个错误:\\r\\n类型:" + type + "\\r\\n信息:" + tempErrorMessage + "\\r\\n页面:" + simpleUrl + "\\r\\n查看详情:http://" + domain.localAssetsDomain + "/webfunny/javascriptErrorDetail.html?infoType=" + infoType + "&timeType=0&errorMsg=" + errorMessage
Utils.postJson(url,config) // 通知机器人
// 如果需要其他通知方式,请在此完成报警逻辑
break;
case "Script error.":
break;
default:
break;
}
} else if (infoType === "console_error") {
// 这里是自定义报错:捕获的都是 console.error 打印的错误
}
}
module.exports = handleResultWhenJavascriptError`,
`/**
* 这里是静态资源错误的拦截器。
* 每次发生静态资源报错,都会调用这个方法
*/
const handleResultWhenResourceError = (res) => {
// console.log(res) // 打印查看其他字段
const {webMonitorId, sourceUrl, simpleUrl, happenDate} = res
// 下方书写自己的逻辑
const errorObj = {
type: "resourceError",
logData: res
}
}
module.exports = handleResultWhenResourceError`
]
fs.mkdir( "./interceptor", function(err){
if ( err ) {
console.log("= 文件夹 /interceptor 已经存在")
} else {
console.log("= 创建文件夹 /interceptor")
}
interceptorArray.forEach((path, index) => {
fs.readFile(path, "", (err) => {
if (err) {
console.log("× " + path + " 配置文件不存在,即将创建...")
fs.writeFile(path, interceptorConArray[index], (err) => {
if (err) throw err;
console.log("" + path + " 配置文件创建完成!");
});
} else {
console.log("" + path + " 配置文件已存在!")
}
});
})
fs.mkdir( "./interceptor/config", function(err){
if ( err ) {
console.log("= 文件夹 /interceptor/config 已经存在")
} else {
console.log("= 创建文件夹 /interceptor/config")
}
configArray.forEach((path, index) => {
fs.readFile(path, "", (err) => {
if (err) {
console.log("× " + path + " 配置文件不存在,即将创建...")
fs.writeFile(path, configConArray[index], (err) => {
if (err) throw err;
console.log("" + path + " 配置文件创建完成!");
});
} else {
console.log("" + path + " 配置文件已存在!")
}
});
})
});
});
JavaScript
1
https://gitee.com/younger007/webfunny_monitor.git
git@gitee.com:younger007/webfunny_monitor.git
younger007
webfunny_monitor
webfunny_monitor
master

搜索帮助