[*] 优化logger

This commit is contained in:
acgist
2023-02-04 18:00:27 +08:00
parent e477378d43
commit 96c949513c
46 changed files with 150 additions and 1082 deletions

View File

@@ -10,7 +10,6 @@
},
"dependencies": {
"ws": "^8.12.0",
"debug": "^4.3.1",
"mediasoup": "file:./mediasoup"
},
"devDependencies": {

View File

@@ -13,12 +13,15 @@ module.exports = {
listenIp: "0.0.0.0",
listenPort: process.env.HTTPS_LISTEN_PORT || 4443,
// WebSocket连接密码
username: 'taoyao',
password: 'taoyao',
username: "taoyao",
password: "taoyao",
tls: {
cert: process.env.HTTPS_CERT_PUBLIC_KEY || `${__dirname}/certs/publicKey.pem`,
key: process.env.HTTPS_CERT_PRIVATE_KEY || `${__dirname}/certs/privateKey.pem`,
}
cert:
process.env.HTTPS_CERT_PUBLIC_KEY || `${__dirname}/certs/publicKey.pem`,
key:
process.env.HTTPS_CERT_PRIVATE_KEY ||
`${__dirname}/certs/privateKey.pem`,
},
},
// Mediasoup
mediasoup: {
@@ -133,5 +136,20 @@ module.exports = {
},
maxSctpMessageSize: 262144,
},
}
},
wellcome: `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>桃夭媒体服务</title>
<style type="text/css">
p{text-align:center;}
a{text-decoration:none;}
</style>
</head>
<body>
<p><a href="https://gitee.com/acgist/taoyao">taoyao-media-server</a></p>
<p><a href="https://www.acgist.com">acgist</a></p>
</body>
</html>`,
};

View File

@@ -1,44 +1,46 @@
/**
* 日志
*/
const debug = require("debug");
const config = require("./Config");
class Logger {
//
name = config.name;
constructor(prefix) {
const appName = config.name;
if (prefix) {
this._debug = debug(`${appName}:DEBUG:${prefix}`);
this._info = debug(`${appName}:INFO:${prefix}`);
this._warn = debug(`${appName}:WARN:${prefix}`);
this._error = debug(`${appName}:ERROR:${prefix}`);
} else {
this._debug = debug(`${appName}:DEBUG`);
this._info = debug(`${appName}:INFO`);
this._warn = debug(`${appName}:WARN`);
this._error = debug(`${appName}:ERROR`);
this.name = this.name + ':' + prefix;
}
this._debug.log = console.debug.bind(console);
this._info.log = console.info.bind(console);
this._warn.log = console.warn.bind(console);
this._error.log = console.error.bind(console);
}
get debug() {
return this._debug.log;
debug(...args) {
this.log(console.debug, 'DEBUG', args);
}
get info() {
return this._info.log;
info(...args) {
this.log(console.info, 'INFO', args);
}
get warn() {
return this._warn.log;
warn(...args) {
this.log(console.warn, 'WARN', args);
}
get error() {
return this._error.log;
error(...args) {
this.log(console.error, 'ERROR', args);
}
log(out, level, args) {
if(!args) {
return;
}
if(args.length > 1 && args[0].length > 0) {
out(`${this.name}:${level}:${args[0]}`, ...args.slice(1));
} else if(args.length === 1 && args[0].length > 0) {
out(`${this.name}:${level}:${args[0]}`);
} else {
out("");
}
}
}

View File

@@ -5,7 +5,7 @@
const fs = require("fs");
const ws = require("ws");
const https = require("https");
const mediasoup = require("mediasoup");
// const mediasoup = require("mediasoup");
const config = require("./Config");
const Logger = require("./Logger");
const Signal = require("./Signal");
@@ -83,7 +83,7 @@ async function buildSignalServer() {
logger.info("配置HTTPS服务...");
httpsServer = https.createServer(tls, (request, response) => {
response.writeHead(200);
response.end("taoyao media server");
response.end(config.wellcome);
});
logger.info("配置WebSocket服务...");
webSocketServer = new ws.Server({ server: httpsServer });
@@ -125,7 +125,7 @@ async function buildSignalServer() {
async function main() {
logger.info("开始启动:%s", config.name);
// 启动Mediasoup服务
await buildMediasoupWorkers();
// await buildMediasoupWorkers();
// 启动服务
await buildSignalServer();
logger.info("启动完成:%s", config.name);

View File

@@ -20,7 +20,10 @@ class Signal {
* @param {*} message 消息
* @param {*} session websocket
*/
on(message, session) {}
on(message, session) {
}
}
module.exports = Signal;

View File

@@ -1,137 +0,0 @@
/**
* 配置
*/
const os = require("os");
module.exports = {
// 系统名称
name: "taoyao-media-server",
// 交互式命令行
command: true,
// 信令服务
https: {
listenIp: "0.0.0.0",
listenPort: process.env.HTTPS_LISTEN_PORT || 4443,
// WebSocket连接密码
username: 'taoyao',
password: 'taoyao',
tls: {
cert: process.env.HTTPS_CERT_PUBLIC_KEY || `${__dirname}/certs/publicKey.pem`,
key: process.env.HTTPS_CERT_PRIVATE_KEY || `${__dirname}/certs/privateKey.pem`,
}
},
// Mediasoup
mediasoup: {
// 按照CPU数量配置进程数量
numWorkers: Object.keys(os.cpus()).length,
// Workerhttps://mediasoup.org/documentation/v3/mediasoup/api/#WorkerSettings
workerSettings: {
logLevel: "warn",
logTags: [
"bwe",
"ice",
"rtp",
"rtx",
"svc",
"dtls",
"info",
"sctp",
"srtp",
"rtcp",
"score",
"message",
"simulcast",
],
rtcMinPort: process.env.MEDIASOUP_MIN_PORT || 40000,
rtcMaxPort: process.env.MEDIASOUP_MAX_PORT || 49999,
},
// Routerhttps://mediasoup.org/documentation/v3/mediasoup/api/#RouterOptions
routerOptions: {
mediaCodecs: [
{
kind: "audio",
mimeType: "audio/opus",
clockRate: 48000,
channels: 2,
},
{
kind: "video",
mimeType: "video/VP8",
clockRate: 90000,
parameters: {
"x-google-start-bitrate": 1000,
},
},
{
kind: "video",
mimeType: "video/VP9",
clockRate: 90000,
parameters: {
"profile-id": 2,
"x-google-start-bitrate": 1000,
},
},
{
kind: "video",
mimeType: "video/h264",
clockRate: 90000,
parameters: {
"packetization-mode": 1,
"profile-level-id": "4d0032",
"level-asymmetry-allowed": 1,
"x-google-start-bitrate": 1000,
},
},
{
kind: "video",
mimeType: "video/h264",
clockRate: 90000,
parameters: {
"packetization-mode": 1,
"profile-level-id": "42e01f",
"level-asymmetry-allowed": 1,
"x-google-start-bitrate": 1000,
},
},
],
},
// WebRtcServerhttps://mediasoup.org/documentation/v3/mediasoup/api/#WebRtcServerOptions
webRtcServerOptions: {
listenInfos: [
{
protocol: "udp",
ip: process.env.MEDIASOUP_LISTEN_IP || "0.0.0.0",
announcedIp: process.env.MEDIASOUP_ANNOUNCED_IP,
port: 44444,
},
{
protocol: "tcp",
ip: process.env.MEDIASOUP_LISTEN_IP || "0.0.0.0",
announcedIp: process.env.MEDIASOUP_ANNOUNCED_IP,
port: 44444,
},
],
},
// WebRtcTransporthttps://mediasoup.org/documentation/v3/mediasoup/api/#WebRtcTransportOptions
webRtcTransportOptions: {
listenIps: [
{
ip: process.env.MEDIASOUP_LISTEN_IP || "0.0.0.0",
announcedIp: process.env.MEDIASOUP_ANNOUNCED_IP,
},
],
initialAvailableOutgoingBitrate: 1000000,
minimumAvailableOutgoingBitrate: 600000,
maxSctpMessageSize: 262144,
maxIncomingBitrate: 1500000,
},
// PlainTransporthttps://mediasoup.org/documentation/v3/mediasoup/api/#PlainTransportOptions
plainTransportOptions: {
listenIp: {
ip: process.env.MEDIASOUP_LISTEN_IP || "0.0.0.0",
announcedIp: process.env.MEDIASOUP_ANNOUNCED_IP,
},
maxSctpMessageSize: 262144,
},
}
};

View File

@@ -1,138 +0,0 @@
#!/usr/bin/env node
/**
* 服务
*/
const fs = require("fs");
const ws = require("ws");
const https = require("https");
const mediasoup = require("mediasoup");
const config = require("./Config");
const Logger = require("./Logger");
const Signal = require("./Signal");
const command = require("./Command");
// 日志
const logger = new Logger();
// 信令
const signal = new Signal();
// HTTPS server
let httpsServer;
// WebSocket server
let webSocketServer;
// Mediasoup Worker
const mediasoupWorkers = [];
process.title = config.name;
process.env.DEBUG = process.env.DEBUG || "*mediasoup* *INFO* *WARN* *ERROR*";
/**
* 启动Mediasoup Worker
*/
async function buildMediasoupWorkers() {
const { numWorkers } = config.mediasoup;
logger.info("启动Mediasoup服务%d Worker...", numWorkers);
for (let i = 0; i < numWorkers; i++) {
// 新建Worker
const worker = await mediasoup.createWorker({
logLevel: config.mediasoup.workerSettings.logLevel,
logTags: config.mediasoup.workerSettings.logTags,
rtcMinPort: Number(config.mediasoup.workerSettings.rtcMinPort),
rtcMaxPort: Number(config.mediasoup.workerSettings.rtcMaxPort),
});
// 监听停止服务事件
worker.on("died", () => {
logger.error(
"Mediasoup Worker停止服务两秒之后自动退出... [PID%d]",
worker.pid
);
setTimeout(() => process.exit(1), 2000);
});
// 加入队列
mediasoupWorkers.push(worker);
// 配置WebRTC服务
if (process.env.MEDIASOUP_USE_WEBRTC_SERVER !== "false") {
// 每个Worker端口不能相同
const portIncrement = mediasoupWorkers.length - 1;
const webRtcServerOptions = JSON.parse(JSON.stringify(config.mediasoup.webRtcServerOptions));
for (const listenInfo of webRtcServerOptions.listenInfos) {
listenInfo.port += portIncrement;
}
const webRtcServer = await worker.createWebRtcServer(webRtcServerOptions);
worker.appData.webRtcServer = webRtcServer;
}
// 定时记录使用日志
setInterval(async () => {
const usage = await worker.getResourceUsage();
logger.info(
"Mediasoup Worker使用情况 [pid%d]: %o",
worker.pid,
usage
);
}, 120 * 1000);
}
}
/**
* 启动信令服务
*/
async function buildSignalServer() {
const tls = {
cert: fs.readFileSync(config.https.tls.cert),
key: fs.readFileSync(config.https.tls.key),
};
logger.info("配置HTTPS服务...");
httpsServer = https.createServer(tls, (request, response) => {
response.writeHead(200);
response.end("taoyao media server");
});
logger.info("配置WebSocket服务...");
webSocketServer = new ws.Server({ server: httpsServer });
webSocketServer.on("connection", (session) => {
session.on("open", (message) => {
logger.info("打开信令通道: %s", message);
});
session.on("close", (code) => {
logger.info("关闭信令通道: %o", code);
});
session.on("error", (e) => {
logger.error("信令通道异常: %o", e);
});
session.on("message", (message) => {
logger.debug("收到信令消息: %s", message);
try {
signal.on(JSON.parse(message), session);
} catch (error) {
logger.error(
`处理信令消息异常:
%s
%o`,
message,
error
);
}
});
});
// 打开监听
httpsServer.listen(
Number(config.https.listenPort),
config.https.listenIp,
() => {
logger.info("信令服务启动完成");
}
);
}
async function main() {
logger.info("开始启动:%s", config.name);
// 启动Mediasoup服务
await buildMediasoupWorkers();
// 启动服务
await buildSignalServer();
logger.info("启动完成:%s", config.name);
// 交互式命令行
if (config.command) {
await command();
}
}
main();

View File

@@ -1,26 +0,0 @@
/**
* 信令
* 1. 终端媒体流向
* 2. 处理音频视频:降噪、水印等等
*/
class Signal {
// Mediasoup Worker列表
mediasoupWorkers = [];
// Mediasoup Worker下个索引
nextMediasoupWorkerIndex = 0;
constructor(mediasoupWorkers) {
this.mediasoupWorkers = mediasoupWorkers;
}
/**
* 处理事件
*
* @param {*} message 消息
* @param {*} session websocket
*/
on(message, session) {}
}
module.exports = Signal;