From d1b72930b6f68bd0b37541810893d0e1dfca10d1 Mon Sep 17 00:00:00 2001 From: Ittipat Lusuk Date: Mon, 27 Apr 2026 09:55:10 +0700 Subject: [PATCH] taobin_log --- Dockerfile | 15 ++++ app/main.py | 172 +++++++++++++++++++++++++++++++++++++++++++++ data/logs.db | Bin 0 -> 16384 bytes docker-compose.yml | 11 +++ 4 files changed, 198 insertions(+) create mode 100644 Dockerfile create mode 100644 app/main.py create mode 100644 data/logs.db create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c1c7fc7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.9-slim + +WORKDIR /app + +ENV TZ=Asia/Bangkok + +RUN pip install fastapi uvicorn + +COPY ./app ./app + +RUN mkdir -p /app/data + +EXPOSE 8123 + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8123"] \ No newline at end of file diff --git a/app/main.py b/app/main.py new file mode 100644 index 0000000..f623fd5 --- /dev/null +++ b/app/main.py @@ -0,0 +1,172 @@ +from fastapi import FastAPI, Query +from pydantic import BaseModel, Field +from typing import Optional, List, Dict, Any +from datetime import datetime, timedelta +import sqlite3 +import asyncio + +app = FastAPI(title="Log-Server") +DB_PATH = "/app/data/logs.db" +SERVICE_NAME = "log-service" + +def get_db(): + conn = sqlite3.connect(DB_PATH, check_same_thread=False) + conn.row_factory = sqlite3.Row + return conn + +def init_db(): + with get_db() as conn: + cursor = conn.cursor() + cursor.execute(''' + CREATE TABLE IF NOT EXISTS service_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + service_name TEXT NOT NULL, + log_level TEXT NOT NULL, + message TEXT NOT NULL, + timestamp DATETIME NOT NULL + ) + ''') + cursor.execute(''' + CREATE TABLE IF NOT EXISTS audit_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + requester_name TEXT NOT NULL, + target_service TEXT NOT NULL, + query_start_time TEXT, + query_end_time TEXT, + request_at DATETIME DEFAULT (datetime('now', '+7 hours')) + ) + ''') + conn.commit() + +async def retention_policy_task(): + while True: + try: + limit_date = (datetime.utcnow() - timedelta(days=7)).strftime('%Y-%m-%d %H:%M:%S') + with get_db() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM service_logs WHERE timestamp < ?", (limit_date,)) + conn.commit() + print(f"Cleanup: Deleted logs older than {limit_date}") + except Exception as e: + print(f"Cleanup Error: {e}") + await asyncio.sleep(86400) + +@app.on_event("startup") +async def startup_event(): + init_db() + asyncio.create_task(retention_policy_task()) + +# class LogEntry(BaseModel): +# service_name: str = Field(..., example="AUTH-SERVICE") +# log_level: str = Field(..., example="INFO") +# message: str = Field(..., example="User logged in successfully") +# timestamp: str = Field(..., example="2024-05-20 14:30:05") + +class UserInfo(BaseModel): + displayName: str + email: str + uid: str + +class LogValues(BaseModel): + log_level: str + message: str + timestamp: str + +class LogPayloadPost(BaseModel): + user_info: UserInfo + srv_name: str + values: LogValues + +class LogPayloadGet(BaseModel): + user_info: UserInfo + srv_name: str + start_time: Optional[str] = None + end_time: Optional[str] = None + +class LogRequestPost(BaseModel): + type: str + payload: LogPayloadPost + +class LogRequestGet(BaseModel): + type: str + payload: LogPayloadGet + +@app.post("/add/logs", tags=["Logs Management"]) +async def post_log(req: LogRequestPost): + payload = req.payload + values = payload.values + + with get_db() as conn: + cursor = conn.cursor() + cursor.execute( + "INSERT INTO service_logs (service_name, log_level, message, timestamp) VALUES (?, ?, ?, ?)", + (payload.srv_name, values.log_level, values.message, values.timestamp) + ) + conn.commit() + + return { + "status": "success", + "message": "Log recorded successfully", + "entry_details": { + "service": payload.srv_name, + "level": values.log_level, + "logged_at": values.timestamp, + "user": payload.user_info.displayName + } + } + +@app.post("/get/logs", tags=["Logs Management"]) +async def get_logs(req: LogRequestGet): + payload = req.payload + + with get_db() as conn: + cursor = conn.cursor() + + # audit log + cursor.execute( + "INSERT INTO audit_logs (requester_name, target_service, query_start_time, query_end_time) VALUES (?, ?, ?, ?)", + ( + payload.user_info.displayName, + payload.srv_name, + payload.start_time, + payload.end_time + ) + ) + + query = "SELECT * FROM service_logs WHERE service_name = ?" + params = [payload.srv_name] + + if payload.start_time: + query += " AND datetime(timestamp) >= datetime(?)" + params.append(payload.start_time) + + if payload.end_time: + query += " AND datetime(timestamp) <= datetime(?)" + params.append(payload.end_time) + + query += " ORDER BY timestamp DESC" + + cursor.execute(query, params) + logs = [dict(row) for row in cursor.fetchall()] + + return { + "metadata": { + "requester": payload.user_info.displayName, + "target_service": payload.srv_name, + "total_found": len(logs) + }, + "results": logs + } + +@app.get("/audit-trail", tags=["Requester log"]) +async def view_audit(): + with get_db() as conn: + cursor = conn.cursor() + cursor.execute("SELECT id, requester_name, target_service, request_at FROM audit_logs ORDER BY request_at DESC") + audits = [dict(row) for row in cursor.fetchall()] + + return { + "system_status": "operational", + "requester_count": len(audits), + "history": audits + } \ No newline at end of file diff --git a/data/logs.db b/data/logs.db new file mode 100644 index 0000000000000000000000000000000000000000..52a9bb155e9d185e78fcf9e519157b11c4b8b59d GIT binary patch literal 16384 zcmeI&J#W)M7zgmPQ<@5qxD2RBU9PH15+$)>Cuyl!Fw}*pX%bvVqLXEsBaM`o*1ndP z1*w9S&%uXaWA4Dl#?Hc5;M^un)1b6SAUga{v3!mnKR*8+FZOxsS-Hg-ecAIn9;bOS zOC*Urq?8a66U&rX22B>7^V`y3$Aoo^sBibfM3LAn68{>1Cst?>fB*y_009U<00Izz z00jQKz|meLI=8SOeMocfMVomCjTU#?y=E}%O+B_P)3K;yJ}O&u_&-hFq!(JNK}!|K zdScnMW|uZidz)@p+tjQ()lx;I*|aK7X6z`R?H{m!GvDoc9Y!7NxkD>evDC}u@o4V( zO~&1T`G>8YOQS_*|BV}ngSg9E{p{mOPs3QZF)64&PFFlMt_cvQv}w^bYu&7u9hz)- zoP{SyCc3>>i40AoSLkl zOomz+ab)T!BSq(ymZbOdr#Vk)PRiJ4I_b-!+0I4%wNegFca=hlyUcB~L)N~m;vE(Q zUh~pYhx($>oxNdo26xeD0m5f^-AFjx8IkF%PKU0|zp|{V% z!%jH=KNJ5*lyAx><+buuxf}lx|1ADMg8&2|009U<00Izz00bZa0SNpvfy_*l%r6p> zZ*kt*^Z2