diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/index.ts | 90 | ||||
| -rw-r--r-- | src/util/config.ts | 38 | ||||
| -rw-r--r-- | src/util/logger.ts | 21 |
3 files changed, 94 insertions, 55 deletions
diff --git a/src/index.ts b/src/index.ts index 4955ba6..53592da 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,50 +6,56 @@ import { MongoClient } from "mongodb"; import path from "path"; import fs from "fs"; +import winston from "winston"; +import expressWinston from "express-winston"; + +dotenv.config(); + import formats, { Format } from "./formats"; import Metadata from "./metadata"; +import logger_config from "./util/logger"; +import { config_or_error, handle_shutdown } from "./util/config"; // Start-up configuration -dotenv.config(); +const BIND_ADDRESS = process.env.BIND_ADDRESS || "localhost"; const PORT = Number(process.env.PORT || 3000); const TOKEN = process.env.TOKEN || ""; const UPLOAD_LIMIT = Number(process.env.UPLOAD_LIMIT || 4194304); -const MONGO_URI = - process.env.MONGO_URI || - (() => { - throw Error("MONGO_URI must be defined"); - })(); + +const logger = winston.createLogger(logger_config("ROOT")); + +const MONGO_URI = config_or_error("MONGO_URI"); const MONGO_DB = process.env.MONGO_DB || "ao-coverage"; -const HOST_DIR = - process.env.HOST_DIR || - (() => { - throw Error("HOST_DIR must be defined"); - })(); +const HOST_DIR = config_or_error("HOST_DIR"); fs.accessSync(HOST_DIR, fs.constants.R_OK | fs.constants.W_OK); if (!path.isAbsolute(HOST_DIR)) { - throw Error("HOST_DIR must be an absolute path"); + logger.error("HOST_DIR must be an absolute path"); + process.exit(1); } new MongoClient(MONGO_URI, { useUnifiedTopology: true }).connect( (err, mongo) => { if (err !== null) { - throw err; + logger.error(err); + process.exit(1); } const app: express.Application = express(); const metadata = new Metadata(mongo.db(MONGO_DB)); + app.use( + expressWinston.logger({ + ...logger_config("HTTP"), + // filter out token query param from URL + msg: + '{{req.method}} {{req.url.replace(/token=[-\\w.~]*(&*)/, "token=$1")}} - {{res.statusCode}} {{res.responseTime}}ms' + }) + ); + // Upload HTML file app.post("/v1/:org/:repo/:branch/:commit.html", (req, res) => { const { org, repo, branch, commit } = req.params; - console.info( - "POST request to /v1/%s/%s/%s/%s.html", - org, - repo, - branch, - commit - ); const { token, format } = req.query; //TODO @Metadata token should come from metadata @@ -112,11 +118,10 @@ new MongoClient(MONGO_URI, { useUnifiedTopology: true }).connect( app.get("/v1/:org/:repo/:branch.svg", (req, res) => { const { org, repo, branch } = req.params; - console.info("GET request to /v1/%s/%s/%s.svg", org, repo, branch); metadata.getHeadCommit(org, repo, branch).then( commit => { - console.debug( + logger.debug( "Found commit %s for ORB %s/%s/%s", commit, org, @@ -136,11 +141,10 @@ new MongoClient(MONGO_URI, { useUnifiedTopology: true }).connect( app.get("/v1/:org/:repo/:branch.html", (req, res) => { const { org, repo, branch } = req.params; - console.info("GET request to /v1/%s/%s/%s.html", org, repo, branch); metadata.getHeadCommit(org, repo, branch).then( commit => { - console.debug( + logger.debug( "Found commit %s for ORB %s/%s/%s", commit, org, @@ -161,13 +165,6 @@ new MongoClient(MONGO_URI, { useUnifiedTopology: true }).connect( // provide hard link for commit app.get("/v1/:org/:repo/:branch/:commit.svg", (req, res) => { const { org, repo, branch, commit } = req.params; - console.info( - "GET request to /v1/%s/%s/%s/%s.svg", - org, - repo, - branch, - commit - ); res.sendFile(path.join(HOST_DIR, org, repo, branch, commit, "badge.svg")); }); @@ -175,39 +172,22 @@ new MongoClient(MONGO_URI, { useUnifiedTopology: true }).connect( // provide hard link for commit app.get("/v1/:org/:repo/:branch/:commit.html", (req, res) => { const { org, repo, branch, commit } = req.params; - console.info( - "GET request to /v1/%s/%s/%s/%s.html", - org, - repo, - branch, - commit - ); res.sendFile( path.join(HOST_DIR, org, repo, branch, commit, "index.html") ); }); - const server = app.listen(PORT, () => { - console.log("Express started on port " + PORT); + app.use(expressWinston.errorLogger(logger_config("_ERR"))); + + const server = app.listen(PORT, BIND_ADDRESS, () => { + logger.info("Express has started: http://%s:%d/", BIND_ADDRESS, PORT); }); // application exit handling - const handle_closure = (signal: NodeJS.Signals) => { - console.log("%s signal received. Closing shop.", signal); - - mongo.close().then(() => { - console.log("Mongo client connection closed."); - server.close(() => { - console.log("Express down."); - process.exit(); - }); - }); - }; - const handle_codes: NodeJS.Signals[] = ["SIGTERM", "SIGHUP", "SIGINT"]; - const process_event = (code: NodeJS.Signals) => - process.on(code, handle_closure); - handle_codes.map(process_event); + handle_codes.map((code: NodeJS.Signals) => { + process.on(code, handle_shutdown(mongo, server)); + }); } ); diff --git a/src/util/config.ts b/src/util/config.ts new file mode 100644 index 0000000..c155e64 --- /dev/null +++ b/src/util/config.ts @@ -0,0 +1,38 @@ +import winston from "winston"; +import { MongoClient } from "mongodb"; +import { Server } from "http"; + +import logger_config from "./logger"; + +const logger = winston.createLogger(logger_config("ROOT")); + +export const config_or_error = (var_name: string) => { + if (!process.env[var_name]) { + logger.error("%s must be defined", var_name); + process.exit(1); + return ""; + } else { + return process.env[var_name] || ""; + } +}; + +export const handle_shutdown = (mongo: MongoClient, server: Server) => ( + signal: NodeJS.Signals +) => { + logger.warn("%s signal received. Closing shop.", signal); + + mongo + .close() + .then(() => { + logger.info("MongoDB client connection closed."); + return new Promise((res, rej) => + server.close(err => { + logger.info("Express down."); + (err ? rej : res)(err); + }) + ); + }) + .finally(() => { + process.exit(0); + }); +}; diff --git a/src/util/logger.ts b/src/util/logger.ts new file mode 100644 index 0000000..bafb829 --- /dev/null +++ b/src/util/logger.ts @@ -0,0 +1,21 @@ +import winston from "winston"; +const { combine, splat, timestamp, label, colorize, printf } = winston.format; +const { Console } = winston.transports; + +const LOG_LEVEL = process.env.LOG_LEVEL || "info"; + +/** + * Provides standard logging format and output for the server. + */ +export default (clazz: string, level: string = LOG_LEVEL) => ({ + format: combine( + splat(), + timestamp(), + label({ label: clazz }), + colorize(), + printf(({ level, message, label, timestamp }) => { + return `${timestamp} [${label}] ${level}: ${message}`; + }) + ), + transports: [new Console({ level: level })] +}); |
