Split logs by date

Move the default location of the log files into a configurable logs
folder and split the written logs up by UTC date to more easily allow
deleting of old logs to be performed.  The log rotation is implemented
by winston-daily-rotate-file.

The old log format will automatically be migrated to the new format and
location if the target folder for the new logs don't yet exists.
This commit is contained in:
Hornwitser committed 2021-12-19 01:42:34 +01:00
1 parent 200ccf8e06
commit fd1f3329bd
5 files changed
+125 -9

No files matched your search

+61
View File
@@ -1,4 +1,7 @@
"use strict";
const events = require("events");
const fs = require("fs-extra");
const path = require("path");
const winston = require("winston");
const Transport = require("winston-transport");
const { LEVEL, MESSAGE } = require("triple-beam");
@@ -6,6 +9,7 @@ const chalk = require("chalk");
const libLink = require("./link");
const libErrors = require("./errors");
const libStream = require("./stream");
/**
@@ -121,10 +125,67 @@ class LinkTransport extends Transport {
}
}
async function migrateLogs(log, directory, pattern) {
const dateRegExp = /^\d{4}-\d{2}-\d{2}/;
let lineStream = new libStream.LineSplitter({ readableObjectMode: true });
let fileStream = fs.createReadStream(log);
fileStream.pipe(lineStream);
let currentDate = null;
let output = null;
async function switchOutput(newOutputPath) {
if (output) {
output.end();
await events.once(output, "close");
}
output = fs.createWriteStream(newOutputPath, { flags: "ax" });
try {
await events.once(output, "open");
// eslint-disable-next-line no-console
console.log(`writing ${newOutputPath}`);
} catch (err) {
if (err.code === "EEXIST") {
// eslint-disable-next-line no-console
console.warn(`Discarding logs for ${newDate} due to target logfile already existing`);
output = null;
} else {
throw err;
}
}
}
for await (let line of lineStream) {
let info = {};
try {
info = JSON.parse(line);
} catch (err) {
// Ignore
}
if (typeof info.timestamp === "string" && dateRegExp.test(info.timestamp)) {
let newDate = info.timestamp.slice(0, 10);
// Only update date forward in time.
if (newDate !== currentDate && (!currentDate || newDate > currentDate)) {
await switchOutput(path.join(directory, pattern.replace("%DATE%", newDate)));
currentDate = newDate;
}
}
if (output) {
if (!output.write(Buffer.concat([line, Buffer.from("\n")]))) {
await events.once(output, "drain");
}
}
}
}
module.exports = {
TerminalFormat,
LinkTransport,
migrateLogs,
// for testing only
_formatServerOutput: formatServerOutput,
+36 -4
View File
@@ -22,6 +22,7 @@ const setBlocking = require("set-blocking");
const yargs = require("yargs");
const util = require("util");
const winston = require("winston");
require("winston-daily-rotate-file");
const jwt = require("jsonwebtoken");
// homebrew modules
@@ -189,6 +190,12 @@ async function initialize() {
choices: ["none"].concat(Object.keys(levels)),
type: "string",
})
.option("log-directory", {
nargs: 1,
describe: "Directory to place logs in",
default: "logs",
type: "string",
})
.option("config", {
nargs: 1,
describe: "master config file to use",
@@ -227,20 +234,45 @@ async function initialize() {
.argv
;
{
// Migration from alpha-10 single file logs, note that we can't use
// the logger here as it's not initalized yet.
/* eslint-disable no-console */
let clusterLogDirectory = path.join(parameters.args.logDirectory, "cluster");
if (!await fs.pathExists(clusterLogDirectory) && await fs.pathExists("cluster.log")) {
console.log("Migrating cluster log...");
await fs.ensureDir(clusterLogDirectory);
await libLoggingUtils.migrateLogs("cluster.log", clusterLogDirectory, "cluster-%DATE%.log");
console.log("Migration complete, you should delete cluster.log now");
}
let masterLogDirectory = path.join(parameters.args.logDirectory, "master");
if (!await fs.pathExists(masterLogDirectory) && await fs.pathExists("master.log")) {
console.log("Migrating master log...");
await fs.ensureDir(masterLogDirectory);
await libLoggingUtils.migrateLogs("master.log", masterLogDirectory, "master-%DATE%.log");
console.log("Migration complete, you should delete master.log now");
}
/* eslint-enable no-console */
}
// Combined log stream of the whole cluster.
parameters.clusterLogger = winston.createLogger({
format: winston.format.json(),
level: "verbose",
levels,
});
parameters.clusterLogger.add(new winston.transports.File({
filename: "cluster.log",
parameters.clusterLogger.add(new winston.transports.DailyRotateFile({
filename: "cluster-%DATE%.log",
utc: true,
dirname: path.join(parameters.args.logDirectory, "cluster"),
}));
// Log stream for the master server.
logger.add(new winston.transports.File({
logger.add(new winston.transports.DailyRotateFile({
format: winston.format.json(),
filename: "master.log",
filename: "master-%DATE%.log",
dirname: path.join(parameters.args.logDirectory, "master"),
}));
logger.add(new winston.transports.Stream({
stream: parameters.clusterLogger,
+1
View File
@@ -28,6 +28,7 @@
"jszip": "^3.2.2",
"set-blocking": "^2.0.0",
"winston": "^3.3.3",
"winston-daily-rotate-file": "^4.5.5",
"ws": "^7.2.3",
"yargs": "^14.2.0"
},
+1
View File
@@ -24,6 +24,7 @@
"pidusage": "^2.0.18",
"set-blocking": "^2.0.0",
"winston": "^3.3.3",
"winston-daily-rotate-file": "^4.5.5",
"yargs": "^14.2.0"
},
"publishConfig": {
+26 -5
View File
@@ -23,6 +23,7 @@ const phin = require("phin");
const util = require("util");
const version = require("./package").version;
const winston = require("winston");
require("winston-daily-rotate-file");
// internal libraries
const libFileOps = require("@clusterio/lib/file_ops");
@@ -1734,6 +1735,12 @@ async function startSlave() {
choices: ["none"].concat(Object.keys(levels)),
type: "string",
})
.option("log-directory", {
nargs: 1,
describe: "Directory to place logs in",
default: "logs",
type: "string",
})
.option("config", {
nargs: 1,
describe: "slave config file to use",
@@ -1754,11 +1761,25 @@ async function startSlave() {
.argv
;
logger.add(new winston.transports.File({
format: winston.format.combine(
winston.format.json(),
),
filename: "slave.log",
{
// Migration from alpha-10 single file logs, note that we can't use
// the logger here as it's not initalized yet.
/* eslint-disable no-console */
let slaveLogDirectory = path.join(args.logDirectory, "slave");
if (!await fs.pathExists(slaveLogDirectory) && await fs.pathExists("slave.log")) {
console.log("Migrating slave log...");
await fs.ensureDir(slaveLogDirectory);
await libLoggingUtils.migrateLogs("slave.log", slaveLogDirectory, "slave-%DATE%.log");
console.log("Migration complete, you should delete slave.log now");
}
/* eslint-enable no-console */
}
logger.add(new winston.transports.DailyRotateFile({
format: winston.format.json(),
filename: "slave-%DATE%.log",
utc: true,
dirname: path.join(args.logDirectory, "slave"),
}));
if (args.logLevel !== "none") {
logger.add(new ConsoleTransport({