From 3de3845cdef92231881bf1791b0e94aad89bf7ed Mon Sep 17 00:00:00 2001 From: MurakawaTakuya Date: Mon, 20 Jan 2025 16:34:20 +0900 Subject: [PATCH] =?UTF-8?q?fixup!=20logger=E3=81=AB=E3=83=AA=E3=82=AF?= =?UTF-8?q?=E3=82=A8=E3=82=B9=E3=83=88=E3=81=AE=E8=A9=B3=E7=B4=B0=E3=82=92?= =?UTF-8?q?=E8=A8=98=E9=8C=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- functions/src/index.ts | 89 ++++++++++++++----------- functions/src/routers/goalRouter.ts | 73 +++++++++++++++----- functions/src/routers/postRouter.ts | 61 +++++++++++++---- functions/src/routers/reactionRouter.ts | 16 +++-- functions/src/routers/resultRouter.ts | 9 +-- functions/src/routers/userRouter.ts | 72 +++++++++++++++----- 6 files changed, 227 insertions(+), 93 deletions(-) diff --git a/functions/src/index.ts b/functions/src/index.ts index abbe510..5b786b0 100644 --- a/functions/src/index.ts +++ b/functions/src/index.ts @@ -21,7 +21,7 @@ import resultRouter from "./routers/resultRouter"; import userRouer from "./routers/userRouter"; const app = express(); -app.set("trust proxy", true); // trueにしないと全ユーザーでlimitが共通になる +app.set("trust proxy", false); app.use(helmet()); app.use(cors()); app.use(express.json()); @@ -41,16 +41,14 @@ const verifyAppCheckToken = async ( } try { - const decodedToken = await admin - .appCheck() - .verifyToken(appCheckToken as string); - console.log("Verified App Check Token:", decodedToken); + await admin.appCheck().verifyToken(appCheckToken as string); return next(); } catch (error) { logger.error({ message: `Invalid App Check token with ${appCheckToken}:`, error, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); return res.status(401).send("Invalid App Check token."); } @@ -73,10 +71,10 @@ app.use( rateLimit({ windowMs: 10 * 60 * 1000, max: 200, - // keyGenerator: (req) => { - // const key = req.headers["x-forwarded-for"] || req.ip || "unknown"; - // return Array.isArray(key) ? key[0] : key; - // }, + keyGenerator: (req) => { + const key = req.headers["x-forwarded-for"] || req.ip || "unknown"; + return Array.isArray(key) ? key[0] : key; + }, handler: (req, res) => { return res .status(429) @@ -89,10 +87,10 @@ app.use( rateLimit({ windowMs: 60 * 60 * 1000, max: 500, - // keyGenerator: (req) => { - // const key = req.headers["x-forwarded-for"] || req.ip || "unknown"; - // return Array.isArray(key) ? key[0] : key; - // }, + keyGenerator: (req) => { + const key = req.headers["x-forwarded-for"] || req.ip || "unknown"; + return Array.isArray(key) ? key[0] : key; + }, handler: (req, res) => { return res .status(429) @@ -121,30 +119,28 @@ export { } from "./tasks"; // テスト用API -app.use( - "/helloWorld", - rateLimit({ - // 10分に最大10回に制限 - windowMs: 10 * 60 * 1000, - max: 10, - // keyGenerator: (req) => { - // const key = req.headers["x-forwarded-for"] || req.ip || "unknown"; - // return Array.isArray(key) ? key[0] : key; - // }, - handler: (req, res) => { - return res - .status(429) - .json({ message: "Too many requests, please try again later." }); - }, - }) -); +const helloWorldRateLimiter = rateLimit({ + windowMs: 10 * 60 * 1000, // 10分 + max: 10, // 最大10回 + keyGenerator: (req) => { + const key = req.headers["x-forwarded-for"] || req.ip || "unknown"; + return Array.isArray(key) ? key[0] : key; + }, + handler: (req, res) => { + return res + .status(429) + .json({ message: "Too many requests, please try again later." }); + }, +}); -export const helloWorld = onRequest({ region: region }, (req, res) => { - logger.info({ - message: "Hello log!", - ...getRequestData(req), +export const helloWorld = onRequest({ region: region }, async (req, res) => { + helloWorldRateLimiter(req, res, async () => { + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); + res.send("Hello World!"); }); - res.send("Hello World!"); }); const db = admin.firestore(); @@ -177,12 +173,11 @@ export const beforecreated = beforeUserCreated( } ); +// リクエストのheader, parameters, bodyを取得 export const getRequestData = (req: Request) => { + // requestLog return { - ip: req.ip, headers: req.headers, - requestMethod: req.method, - status: req.statusCode, parameters: { query: req.query, params: req.params, @@ -190,3 +185,19 @@ export const getRequestData = (req: Request) => { body: req.body, }; }; + +// リクエストのhttp情報を取得 +export const getHttpRequestData = (req: Request) => { + // httpRequest + const statusCode = req.statusCode || "202"; + return { + requestMethod: req.method, + requestUrl: `${req.method} ${statusCode}: ${req.protocol}://${req.get( + "host" + )}${req.originalUrl}`, + status: statusCode, + userAgent: req.get("User-Agent"), + remoteIp: req.ip, + protocol: req.httpVersion ? `HTTP/${req.httpVersion}` : req.protocol, + }; +}; diff --git a/functions/src/routers/goalRouter.ts b/functions/src/routers/goalRouter.ts index 8538123..586620d 100644 --- a/functions/src/routers/goalRouter.ts +++ b/functions/src/routers/goalRouter.ts @@ -1,7 +1,7 @@ import express, { Request, Response } from "express"; import admin from "firebase-admin"; import { logger } from "firebase-functions"; -import { getRequestData } from ".."; +import { getHttpRequestData, getRequestData } from ".."; import { Goal, GoalWithId } from "../types"; const router = express.Router(); @@ -11,8 +11,8 @@ const db = admin.firestore(); router.get("/", async (req: Request, res: Response) => { try { logger.info({ - message: "Get: goal/", - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); const goalSnapshot = await db.collection("goal").get(); @@ -34,7 +34,11 @@ router.get("/", async (req: Request, res: Response) => { return res.json(goalData); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error fetching goals" }); } }); @@ -44,8 +48,8 @@ router.get("/:userId", async (req: Request, res: Response) => { try { const userId = req.params.userId; logger.info({ - message: `Get: goal/${userId}`, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); const goalSnapshot = await db @@ -73,7 +77,11 @@ router.get("/:userId", async (req: Request, res: Response) => { return res.json(goalData); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error fetching goals" }); } }); @@ -86,9 +94,16 @@ router.post("/", async (req: Request, res: Response) => { try { ({ userId, deadline, text } = req.body as Goal); - logger.info({ message: `Post: goal/${userId}`, ...getRequestData(req) }); + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(400).json({ message: "Invalid request body" }); } @@ -114,13 +129,18 @@ router.post("/", async (req: Request, res: Response) => { logger.info({ message: "Goal created successfully", goalId, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); return res .status(201) .json({ message: "Goal created successfully", goalId }); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error creating goal" }); } }); @@ -128,7 +148,10 @@ router.post("/", async (req: Request, res: Response) => { // PUT: 目標を更新 router.put("/:goalId", async (req: Request, res: Response) => { const goalId = req.params.goalId; - logger.info({ message: `PUT: goal/${goalId}`, ...getRequestData(req) }); + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); const { userId, deadline, text }: Partial = req.body; if (!goalId) { @@ -161,11 +184,16 @@ router.put("/:goalId", async (req: Request, res: Response) => { logger.info({ message: "Goal updated successfully", goalId, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); return res.json({ message: "Goal updated successfully", goalId }); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error updating goal" }); } }); @@ -174,7 +202,10 @@ router.put("/:goalId", async (req: Request, res: Response) => { router.delete("/:goalId", async (req: Request, res: Response) => { try { const goalId = req.params.goalId; - logger.info({ message: `DELETE: goal/${goalId}`, ...getRequestData(req) }); + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); if (!goalId) { return res.status(400).json({ message: "goalId is required" }); @@ -198,7 +229,8 @@ router.delete("/:goalId", async (req: Request, res: Response) => { } catch (error) { logger.error({ error: `Error deleting image: ${error}`, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); return res.status(500).json({ message: "Error deleting image" }); } @@ -208,11 +240,16 @@ router.delete("/:goalId", async (req: Request, res: Response) => { logger.info({ message: "Goal deleted successfully", goalId, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); return res.json({ message: "Goal deleted successfully", goalId }); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error deleting goal" }); } }); diff --git a/functions/src/routers/postRouter.ts b/functions/src/routers/postRouter.ts index 94e92cc..d920bbc 100644 --- a/functions/src/routers/postRouter.ts +++ b/functions/src/routers/postRouter.ts @@ -1,7 +1,7 @@ import express, { Request, Response } from "express"; import admin from "firebase-admin"; import { logger } from "firebase-functions"; -import { getRequestData } from ".."; +import { getHttpRequestData, getRequestData } from ".."; import { updateStreak } from "../status"; import { PostWithGoalId } from "../types"; @@ -11,7 +11,10 @@ const db = admin.firestore(); // GET: 全ての投稿を取得 router.get("/", async (req: Request, res: Response) => { try { - logger.info({ message: "GET: post/", ...getRequestData(req) }); + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); const goalSnapshot = await db.collection("goal").get(); if (goalSnapshot.empty) { @@ -39,7 +42,11 @@ router.get("/", async (req: Request, res: Response) => { return res.json(postData); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error fetching posts" }); } }); @@ -48,7 +55,10 @@ router.get("/", async (req: Request, res: Response) => { router.get("/:userId", async (req: Request, res: Response) => { try { const userId = req.params.userId; - logger.info({ message: `GET: post/${userId}`, ...getRequestData(req) }); + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); const goalSnapshot = await db .collection("goal") @@ -76,7 +86,11 @@ router.get("/:userId", async (req: Request, res: Response) => { return res.json(postData); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error fetching user's posts" }); } }); @@ -90,9 +104,16 @@ router.post("/", async (req: Request, res: Response) => { try { ({ goalId, text = "", storedId, submittedAt } = req.body); - logger.info({ message: `POST: post/${goalId}`, ...getRequestData(req) }); + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(400).json({ message: "Invalid request body" }); } @@ -127,13 +148,18 @@ router.post("/", async (req: Request, res: Response) => { logger.info({ message: "Post updated successfully", goalId, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); return res .status(201) .json({ message: "Post updated successfully", goalId }); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error creating post" }); } }); @@ -142,7 +168,10 @@ router.post("/", async (req: Request, res: Response) => { router.delete("/:goalId", async (req: Request, res: Response) => { try { const goalId = req.params.goalId; - logger.info({ message: `DELETE: post/${goalId}`, ...getRequestData(req) }); + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); if (!goalId) { return res.status(400).json({ message: "goalId is required" }); @@ -166,7 +195,8 @@ router.delete("/:goalId", async (req: Request, res: Response) => { } catch (error) { logger.error({ error: `Error deleting image: ${error}`, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); return res.status(500).json({ message: "Error deleting image" }); } @@ -179,11 +209,16 @@ router.delete("/:goalId", async (req: Request, res: Response) => { logger.info({ message: "Post deleted successfully", goalId, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); return res.json({ message: "Post deleted successfully", goalId }); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error deleting post" }); } }); diff --git a/functions/src/routers/reactionRouter.ts b/functions/src/routers/reactionRouter.ts index fac85bd..989696c 100644 --- a/functions/src/routers/reactionRouter.ts +++ b/functions/src/routers/reactionRouter.ts @@ -1,7 +1,7 @@ import express, { Request, Response } from "express"; import admin from "firebase-admin"; import { logger } from "firebase-functions"; -import { getRequestData } from ".."; +import { getHttpRequestData, getRequestData } from ".."; import { Reaction, ReactionTypeMap } from "../types"; const router = express.Router(); @@ -10,7 +10,10 @@ const db = admin.firestore(); // PUT: リアクションを更新 router.put("/:goalId", async (req: Request, res: Response) => { const goalId = req.params.goalId; - logger.info({ message: `PUT: reaction/${goalId}`, ...getRequestData(req) }); + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); const { userId, reactionType }: Partial = req.body; if (!userId || !goalId) { @@ -56,11 +59,16 @@ router.put("/:goalId", async (req: Request, res: Response) => { message: "Reaction updated successfully", goalId, userId, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); return res.json({ message: "Reaction updated successfully", goalId }); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error updating Reaction" }); } }); diff --git a/functions/src/routers/resultRouter.ts b/functions/src/routers/resultRouter.ts index 1299c4f..e8e2a9d 100644 --- a/functions/src/routers/resultRouter.ts +++ b/functions/src/routers/resultRouter.ts @@ -1,7 +1,7 @@ import express, { Request, Response } from "express"; import admin from "firebase-admin"; import { logger } from "firebase-functions"; -import { getRequestData } from ".."; +import { getHttpRequestData, getRequestData } from ".."; import { countCompletedGoals, countFailedGoals, getStreak } from "../status"; import { GoalWithIdAndUserData, User } from "../types"; import { getUserFromId } from "./userRouter"; @@ -152,8 +152,8 @@ const processGoals = async ( router.get("/:userId?", async (req: Request, res: Response) => { const userId = req.params.userId; logger.info({ - message: `GET: result/${userId ?? ""}`, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); let limit = parseInt(req.query.limit as string) || 10; @@ -177,7 +177,8 @@ router.get("/:userId?", async (req: Request, res: Response) => { } catch (error) { logger.error({ error, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); return res.status(500).json({ message: "Error fetching results" }); } diff --git a/functions/src/routers/userRouter.ts b/functions/src/routers/userRouter.ts index 7e0567a..b06180a 100644 --- a/functions/src/routers/userRouter.ts +++ b/functions/src/routers/userRouter.ts @@ -1,7 +1,7 @@ import express, { Request, Response } from "express"; import admin from "firebase-admin"; import { logger } from "firebase-functions"; -import { getRequestData } from ".."; +import { getHttpRequestData, getRequestData } from ".."; import { countCompletedGoals, countFailedGoals, getStreak } from "../status"; import { User } from "../types"; @@ -11,7 +11,10 @@ const db = admin.firestore(); // GET: 全てのユーザーデータを取得 router.get("/", async (req: Request, res: Response) => { try { - logger.info({ message: "GET: user/", ...getRequestData(req) }); + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); const userSnapshot = await db.collection("user").get(); if (userSnapshot.empty) { @@ -38,7 +41,11 @@ router.get("/", async (req: Request, res: Response) => { return res.json(userData); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error fetching user data" }); } }); @@ -47,7 +54,10 @@ router.get("/", async (req: Request, res: Response) => { router.get("/id/:userId", async (req: Request, res: Response) => { try { const userId = req.params.userId; - logger.info({ message: `GET: user/${userId}`, ...getRequestData(req) }); + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); const userDoc = await getUserFromId(userId); @@ -70,7 +80,11 @@ router.get("/id/:userId", async (req: Request, res: Response) => { return res.json(userData); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error fetching user data" }); } }); @@ -83,9 +97,16 @@ router.post("/", async (req: Request, res: Response) => { try { ({ name, userId, fcmToken = "" } = req.body); - logger.info({ message: `POST: user/${userId}`, ...getRequestData(req) }); + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(400).json({ message: "Invalid request body" }); } @@ -104,13 +125,18 @@ router.post("/", async (req: Request, res: Response) => { message: "User created successfully", userId, name, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); return res .status(201) .json({ message: "User created successfully", userId }); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error creating user" }); } }); @@ -118,7 +144,10 @@ router.post("/", async (req: Request, res: Response) => { // PUT: ユーザー情報を更新 router.put("/:userId", async (req: Request, res: Response) => { const userId = req.params.userId; - logger.info({ message: `PUT: user/${userId}`, ...getRequestData(req) }); + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); const { name, fcmToken }: Partial = req.body; if (!userId) { @@ -144,11 +173,16 @@ router.put("/:userId", async (req: Request, res: Response) => { logger.info({ message: "User updated successfully", userId, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); return res.json({ message: "User updated successfully", userId }); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error updating user" }); } }); @@ -157,7 +191,10 @@ router.put("/:userId", async (req: Request, res: Response) => { router.delete("/:userId", async (req: Request, res: Response) => { try { const userId = req.params.userId; - logger.info({ message: `DELETE: user/${userId}`, ...getRequestData(req) }); + logger.info({ + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); if (!userId) { return res.status(400).json({ message: "userId is required" }); @@ -174,11 +211,16 @@ router.delete("/:userId", async (req: Request, res: Response) => { logger.info({ message: "User deleted successfully", userId, - ...getRequestData(req), + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), }); return res.json({ message: "User deleted successfully", userId }); } catch (error) { - logger.error({ error, ...getRequestData(req) }); + logger.error({ + error, + httpRequest: getHttpRequestData(req), + requestLog: getRequestData(req), + }); return res.status(500).json({ message: "Error deleting user" }); } });