Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(): add logger store and view functionality #4

Merged
merged 1 commit into from
May 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
**/values.dev.yaml
LICENSE
README.md
/src/logs/*
6 changes: 4 additions & 2 deletions .env
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
PROJECT_NAME= mock-api-framework
PROJECT_NAME= llm-mock
SERVER_PORT=8000
LLM_URL_ENDPOINT=chatgpt/chat/completions
## MOCK_LLM_RESPONSE_TYPE can be 'lorem' or 'stored'
MOCK_LLM_RESPONSE_TYPE=lorem
MOCK_LLM_RESPONSE_TYPE=stored
MAX_LOREM_PARAS=8
# SET DEBUG TO * START DETAILED DEBUGGING LOGS AND OFF TO STOP
DEBUG=OFF
LLM_NAME=chatgpt
VALIDATE_REQUESTS=ON
# SET LOG_REQUESTS TO ON TO CONSOLE LOG DETAILS OF ALL INCOMING REQUESTS (VALIDATE REQUESTS MUST ALSO BE ON)
LOG_REQUESTS=ON
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
*.log
*.log
/src/logs/*
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ services:
DEBUG: ${DEBUG}
LLM_NAME: ${LLM_NAME}
VALIDATE_REQUESTS: ${VALIDATE_REQUESTS}
LOG_REQUESTS: ${LOG_REQUESTS}
ports:
- 8000:8000
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@types/express": "^4.17.21",
"dotenv": "^16.4.5",
"msw": "^2.3.0",
"pretty-print-json": "^3.0.1",
"tsx": "^4.10.2",
"typescript": "^5.4.5",
"xo": "^0.58.0"
Expand Down
7 changes: 6 additions & 1 deletion src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import { createServer } from '@mswjs/http-middleware';
import * as seeders from './seeders/index.js';
import getApiPaths from './utilities/file-scan.js';
import serverPage from './utilities/server-page.js';
import logPage from './utilities/log-page.js';

const { apiHandlers, apiPaths } = await getApiPaths();

const httpServer = createServer(...apiHandlers, ...serverPage(apiPaths));
const httpServer = createServer(
...apiHandlers,
...serverPage(apiPaths),
...logPage(),
);

httpServer.listen(process.env?.SERVER_PORT ?? 8000);

Expand Down
78 changes: 78 additions & 0 deletions src/utilities/log-page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { http, HttpResponse } from 'msw';
import { prettyPrintJson, FormatOptions } from 'pretty-print-json';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const createHtml = () => {
function readLogs() {
const logFolder = `${__dirname}/../logs`;
const logPath = path.join(logFolder, 'api_request_log.json');
let logs = '';
// Append the log entry to the log file
try {
logs = fs.readFileSync(logPath, 'utf8');
} catch {
logs = '{"message": "No logs found"}';
}

return logs;
}

const htmlString = `
<html>
<header>
<link rel=stylesheet href=https://cdn.jsdelivr.net/npm/pretty-print-json@3.0/dist/css/pretty-print-json.css>
</header>
<body style="margin: 0px; background-color: #00200B; display: flex; flex-direction: column; justify-content: center; align-items: center; min-height:100vh; font-family: sans-serif;">
<h2 style="color:white">Last POST Request Made</h2>
<h3 style="color:white">File can be viewed in /src/logs folder in container or local machine</h3>
<div class="json-container" style="width: 100%; padding:20px; box-sizing: border-box;">
${prettyPrintJson.toHtml(JSON.parse(readLogs()), { indent: 4, lineNumbers: true })}
</div>

<script src=https://cdn.jsdelivr.net/npm/pretty-print-json@3.0/dist/pretty-print-json.min.js></script>
</body>
<style>

.highlight {
background-color:#28831C;
padding:5px 10px 5px 10px;
border-radius: 5px;
font-weight: bold;
color: white;
margin-left: 15px;
border: 3px white solid;
}

.info {
font-weight: bold;
padding: 10px 0px 10px 0px;
}
.logs {
max-width: 400px;
}
</style>
</html>
`;

return htmlString;
};

const logPage = () => {
return [
http.get(`/logs`, () => {
return new HttpResponse(createHtml(), {
status: 200,
headers: {
'Content-Type': 'text/html',
},
});
}),
];
};

export default logPage;
23 changes: 23 additions & 0 deletions src/utilities/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { type DefaultBodyType } from 'msw';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

export default function logger(logItem: DefaultBodyType) {
const logFolder = `${__dirname}/../logs`;
const logPath = path.join(logFolder, 'api_request_log.json');

// Convert the object to a string
const logEntry = `[${JSON.stringify(logItem).trim().replaceAll('\n', '')}]\n`;

// Append the log entry to the log file

fs.writeFile(logPath, logEntry, (err: any) => {
if (err) {
console.error('Error writing to log file:', err);
}
});
}
6 changes: 4 additions & 2 deletions src/utilities/server-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const prefix = process.env?.LLM_URL_ENDPOINT ?? '';
const homePage = (apiPaths: string[]) => {
const htmlString = `
<html>
<body style="background-color: #00200B; display: flex; flex-direction: column; justify-content: center; align-items: center; height:100%; font-family: sans-serif;">
<body style="margin: 0px; background-color: #00200B; display: flex; flex-direction: column; justify-content: center; align-items: center; height:100vh; font-family: sans-serif;">

<div style="text-align: center; width: 80%; background-color: #00200B; padding:50px; border-radius: 10px; display: flex; flex-direction: column; justify-content: center; align-items: center; color:white">
<h1 style="padding-bottom: 50px;"> Mock LLM Server: <span class="highlight">Running</span></h1>
Expand All @@ -18,7 +18,9 @@ const homePage = (apiPaths: string[]) => {
<h3 class="info">Mocked LLM: <span class="highlight">${process.env?.LLM_NAME?.toUpperCase() ?? 'NONE'}</span> </h3>
<h3 class="info">Response Type: <span class="highlight">${process.env.MOCK_LLM_RESPONSE_TYPE?.toUpperCase() ?? 'NONE'}</span> </h3>
<h3 class="info">${process.env.MOCK_LLM_RESPONSE_TYPE === 'lorem' ? ` Maximum sentences: <span class="highlight"> ${process.env?.MAX_LOREM_PARAS} </span>` : ''}</h3>
<h3 class="info">POST Request Validation: <span class="highlight">${process.env?.VALIDATE_REQUESTS?.toUpperCase() ?? 'NONE'}</span> </h3>
<h3 class="info">LLM Request Validation: <span class="highlight">${process.env?.VALIDATE_REQUESTS?.toUpperCase() ?? 'NONE'}</span> </h3>
<h3 class="info">Http Request Log: <span class="highlight">${process.env?.LOG_REQUESTS?.toUpperCase() ?? 'NONE'}</span> </h3>
<h3 class="info">View Logs url: <a class="highlight" href="/logs">localhost:${process.env?.SERVER_PORT}/logs</a> </h3>
<h3 class="info">Debug Mode: <span class="highlight">${process.env.DEBUG === '*' ? 'ON' : 'OFF'}</span> </h3>

<h3 class="info">API endpoint (GET & POST): ${apiPaths.map((path) => '<a class="highlight" href="' + prefix + '">/' + prefix + '</a>').join('')}</h3>
Expand Down
7 changes: 7 additions & 0 deletions src/utilities/validate-request.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type DefaultBodyType, type StrictRequest } from 'msw';
import logger from './logger.js';

const logRequestBody = (data: Record<string, any>) => {
console.log('Request Body:', data);
Expand Down Expand Up @@ -36,6 +37,12 @@ export const validateRequest = async (
return request
.json()
.then((data) => {
// Log Request if Debug is set to on
if (process.env?.LOG_REQUESTS?.toUpperCase() === 'ON') {
console.log('REQUEST:', data);
logger(data);
}

const requiredKeys = Object.keys(requestTemplate.default[0]);

if (typeof data !== 'object' || data === null) {
Expand Down