RESTAPI_SERVER/database/log-queries.js

243 lines
7.1 KiB
JavaScript
Raw Permalink Normal View History

const dbConnection = require('./connection');
// API 로그 테이블 생성
async function createApiLogTable() {
const createTableQuery = `
CREATE TABLE API_LOGS (
ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
API_KEY_ID VARCHAR2(255),
API_KEY_NAME VARCHAR2(255),
USER_ID NUMBER,
USERNAME VARCHAR2(100),
METHOD VARCHAR2(10) NOT NULL,
ENDPOINT VARCHAR2(500) NOT NULL,
REQUEST_BODY CLOB,
RESPONSE_STATUS NUMBER,
RESPONSE_TIME NUMBER,
IP_ADDRESS VARCHAR2(45),
USER_AGENT VARCHAR2(1000),
CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`;
let connection;
try {
connection = await dbConnection.getConnection();
await connection.execute(createTableQuery);
console.log('API_LOGS 테이블이 생성되었습니다.');
} catch (error) {
if (error.errorNum !== 955) { // ORA-00955: name is already used by an existing object
console.error('API_LOGS 테이블 생성 실패:', error);
throw error;
} else {
console.log('API_LOGS 테이블이 이미 존재합니다.');
}
} finally {
if (connection) {
try {
await connection.close();
} catch (err) {
console.error('연결 종료 실패:', err);
}
}
}
}
// API 로그 저장
async function saveApiLog(logData) {
const query = `
INSERT INTO API_LOGS (
API_KEY_ID, API_KEY_NAME, USER_ID, USERNAME, METHOD, ENDPOINT,
REQUEST_BODY, RESPONSE_STATUS, RESPONSE_TIME, IP_ADDRESS, USER_AGENT
) VALUES (
:apiKeyId, :apiKeyName, :userId, :username, :method, :endpoint,
:requestBody, :responseStatus, :responseTime, :ipAddress, :userAgent
)
`;
const binds = {
apiKeyId: logData.apiKeyId || null,
apiKeyName: logData.apiKeyName || null,
userId: logData.userId || null,
username: logData.username || null,
method: logData.method,
endpoint: logData.endpoint,
requestBody: logData.requestBody ? JSON.stringify(logData.requestBody) : null,
responseStatus: logData.responseStatus,
responseTime: logData.responseTime,
ipAddress: logData.ipAddress,
userAgent: logData.userAgent
};
let connection;
try {
connection = await dbConnection.getConnection();
const result = await connection.execute(query, binds, { autoCommit: true });
return result;
} catch (error) {
console.error('API 로그 저장 실패:', error);
throw error;
} finally {
if (connection) {
try {
await connection.close();
} catch (err) {
console.error('연결 종료 실패:', err);
}
}
}
}
// API 로그 조회 (페이징)
async function getApiLogs(page = 1, limit = 50, filters = {}) {
let whereClause = '';
const binds = {};
if (filters.startDate) {
whereClause += ' AND CREATED_AT >= :startDate';
binds.startDate = new Date(filters.startDate);
}
if (filters.endDate) {
whereClause += ' AND CREATED_AT <= :endDate';
binds.endDate = new Date(filters.endDate);
}
if (filters.method) {
whereClause += ' AND METHOD = :method';
binds.method = filters.method;
}
if (filters.endpoint) {
whereClause += ' AND ENDPOINT LIKE :endpoint';
binds.endpoint = `%${filters.endpoint}%`;
}
if (filters.username) {
whereClause += ' AND USERNAME LIKE :username';
binds.username = `%${filters.username}%`;
}
const offset = (page - 1) * limit;
binds.limit = limit;
binds.offset = offset;
const query = `
SELECT * FROM (
SELECT a.*, ROW_NUMBER() OVER (ORDER BY CREATED_AT DESC) as rn
FROM API_LOGS a
WHERE 1=1 ${whereClause}
) WHERE rn > :offset AND rn <= :offset + :limit
`;
const countQuery = `
SELECT COUNT(*) as total
FROM API_LOGS
WHERE 1=1 ${whereClause}
`;
let connection;
try {
connection = await dbConnection.getConnection();
const [logsResult, countResult] = await Promise.all([
connection.execute(query, binds),
connection.execute(countQuery, binds)
]);
return {
logs: logsResult.rows.map(row => ({
id: row[0],
apiKeyId: row[1],
apiKeyName: row[2],
userId: row[3],
username: row[4],
method: row[5],
endpoint: row[6],
requestBody: row[7],
responseStatus: row[8],
responseTime: row[9],
ipAddress: row[10],
userAgent: row[11],
createdAt: row[12]
})),
total: countResult.rows[0][0],
page,
limit,
totalPages: Math.ceil(countResult.rows[0][0] / limit)
};
} catch (error) {
console.error('API 로그 조회 실패:', error);
throw error;
} finally {
if (connection) {
try {
await connection.close();
} catch (err) {
console.error('연결 종료 실패:', err);
}
}
}
}
// API 로그 통계
async function getApiLogStats() {
const queries = {
totalRequests: 'SELECT COUNT(*) as count FROM API_LOGS',
todayRequests: `SELECT COUNT(*) as count FROM API_LOGS WHERE CREATED_AT >= TRUNC(SYSDATE)`,
topEndpoints: `
SELECT ENDPOINT, COUNT(*) as count
FROM API_LOGS
GROUP BY ENDPOINT
ORDER BY count DESC
FETCH FIRST 10 ROWS ONLY
`,
topUsers: `
SELECT USERNAME, COUNT(*) as count
FROM API_LOGS
WHERE USERNAME IS NOT NULL
GROUP BY USERNAME
ORDER BY count DESC
FETCH FIRST 10 ROWS ONLY
`
};
let connection;
try {
connection = await dbConnection.getConnection();
const results = {};
for (const [key, query] of Object.entries(queries)) {
const result = await connection.execute(query);
if (key === 'totalRequests' || key === 'todayRequests') {
results[key] = result.rows[0][0];
} else {
results[key] = result.rows.map(row => ({
name: row[0],
count: row[1]
}));
}
}
return results;
} catch (error) {
console.error('API 로그 통계 조회 실패:', error);
throw error;
} finally {
if (connection) {
try {
await connection.close();
} catch (err) {
console.error('연결 종료 실패:', err);
}
}
}
}
module.exports = {
createApiLogTable,
saveApiLog,
getApiLogs,
getApiLogStats
};