feat(api): adopt pino request logging

This commit is contained in:
William Valentin
2025-10-17 09:54:46 -07:00
parent 37411bc890
commit 994da9a4e1
6 changed files with 69 additions and 55 deletions

View File

@@ -1,12 +1,15 @@
import express from 'express'; import express from "express";
import { setRoutes } from './routes/index'; import { setRoutes } from "./routes/index";
import { errorHandler } from './middlewares/errorHandler'; import { errorHandler } from "./middlewares/errorHandler";
import requestLogger from './middlewares/requestLogger'; import pino from "pino";
import pinoHttp from "pino-http";
const logger = pino({ level: process.env.LOG_LEVEL || "info" });
const app = express(); const app = express();
const PORT = process.env.PORT || 3000; const PORT = process.env.PORT || 3000;
app.use(requestLogger); app.set("logger", logger);
app.use(pinoHttp({ logger }));
app.use(express.json()); app.use(express.json());
setRoutes(app); setRoutes(app);
@@ -14,5 +17,5 @@ setRoutes(app);
app.use(errorHandler); app.use(errorHandler);
app.listen(PORT, () => { app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`); logger.info(`Server is running on port ${PORT}`);
}); });

View File

@@ -1,23 +1,34 @@
import { Request, Response } from 'express'; import { Request, Response } from "express";
import StreamService from '../services/streamService'; import StreamService from "../services/streamService";
import { Logger } from "pino";
export default class StreamController { export default class StreamController {
constructor(private streamService: StreamService) { } constructor(
private streamService: StreamService,
private logger: Logger,
) {}
// GET /api/streams/:key // GET /api/streams/:key
async streamAudio(req: Request, res: Response) { async streamAudio(req: Request, res: Response) {
const { fileName: key } = req.params as { fileName: string }; const { fileName: key } = req.params as { fileName: string };
const range = req.headers.range as string | undefined; const range = req.headers.range as string | undefined;
if (!key) return res.status(400).send('Missing file key'); if (!key) return res.status(400).send("Missing file key");
try { try {
const result = await this.streamService.streamFromS3({ key, range }); this.logger.info(
res.writeHead(result.status, result.headers); `Attempting to stream file: ${key}, range: ${range || "none"}`,
result.body.pipe(res); );
} catch (err: any) { const result = await this.streamService.streamFromS3({ key, range });
const message = err?.message || 'Error streaming audio'; this.logger.info(
const status = err?.statusCode || 500; `Streaming successful for ${key}, status: ${result.status}, content-length: ${result.headers["Content-Length"]}`,
res.status(status).send(message); );
} res.writeHead(result.status, result.headers);
result.body.pipe(res);
} catch (err: any) {
this.logger.error({ err, key }, `Error streaming audio file ${key}`);
const message = err?.message || "Error streaming audio";
const status = err?.statusCode || 500;
res.status(status).send(message);
} }
} }
}

View File

@@ -1,8 +0,0 @@
import { Request, Response, NextFunction } from 'express';
const requestLogger = (req: Request, res: Response, next: NextFunction) => {
console.log(`${req.method} ${req.url}`);
next();
};
export default requestLogger;

View File

@@ -1,18 +1,28 @@
import { Application, Router, Request, Response } from 'express'; import { Application, Router, Request, Response } from "express";
import StreamController from '../controllers/streamController'; import StreamController from "../controllers/streamController";
import StreamService from '../services/streamService'; import StreamService from "../services/streamService";
const router = Router(); const router = Router();
const streamService = new StreamService();
const streamController = new StreamController(streamService);
export function setRoutes(app: Application) { export function setRoutes(app: Application) {
// Health endpoints // Health endpoints
app.get('/', (_req: Request, res: Response) => res.status(200).send('OK')); app.get("/", (_req: Request, res: Response) => res.status(200).send("OK"));
app.get('/healthz', (_req: Request, res: Response) => res.status(200).json({ status: 'ok' })); app.get("/healthz", (_req: Request, res: Response) =>
res.status(200).json({ status: "ok" }),
);
app.use('/api/streams', router); const streamService = new StreamService(
router.get('/:fileName', streamController.streamAudio.bind(streamController)); app.get("logger"),
process.env.S3_BUCKET,
process.env.S3_PREFIX,
);
const streamController = new StreamController(
streamService,
app.get("logger"),
);
router.get("/:fileName", streamController.streamAudio.bind(streamController));
app.use("/api/streams", router);
} }
export default router; export default router;

View File

@@ -1,11 +0,0 @@
import { Router } from 'express';
import StreamController from '../controllers/streamController';
import StreamService from '../services/streamService';
const router = Router();
const streamService = new StreamService();
const streamController = new StreamController(streamService);
router.get('/:fileName', streamController.streamAudio.bind(streamController));
export default router;

9
s3-nodejs-api/src/types/pino.d.ts vendored Normal file
View File

@@ -0,0 +1,9 @@
import { Logger } from 'pino';
declare global {
namespace Express {
interface Request {
log: Logger;
}
}
}