diff --git a/lamda/.gitignore b/lamda/.gitignore new file mode 100644 index 0000000..3e0a573 --- /dev/null +++ b/lamda/.gitignore @@ -0,0 +1,3 @@ +/dist +node_modules +.idea \ No newline at end of file diff --git a/lamda/README.md b/lamda/README.md new file mode 100644 index 0000000..6924fa2 --- /dev/null +++ b/lamda/README.md @@ -0,0 +1,124 @@ +## 사전 요구 사항 + +- **Node.js** (버전 20 이상) + +## 설치 및 사용법 + +1.**패키지 설치**: + +```bash +npm install +``` + +2.**프로젝트 빌드**: + +TypeScript를 컴파일하고 `.mjs` 파일로 변환합니다. + +```bash +npm run build +``` + +3.**`/dist/index.js` Lambda 함수 사용**: + +4.**Lambda 함수 호출**: + +```bash +curl --location 'https://your-lambda-url/' \ +--header 'Content-Type: application/json' \ +--data '{ + "appKey": "{appKey}", + "repeat": 10 +}' +``` + +## 예시 응답 + +```json +{ + "averageTime": 32.77718769300003, + "maxTime": 1909.24762, + "minTime": 6.588578999999299, + "successCount": 1000, + "failureCount": 0, + "totalExecutionTime": 32800.551787000004, + "memoryUsed": "128 MB", + "requestId": "3c269a70-b0ba-4912-88f0-f61e5dee018c", + "timings": [ + { + "index": 0, + "time": 1909.24762, + "statusCode": 201 + }, + { + "index": 897, + "time": 618.7067969999989, + "statusCode": 201 + }, + { + "index": 563, + "time": 400.04752400000143, + "statusCode": 201 + }, + { + "index": 214, + "time": 380.8735259999994, + "statusCode": 201 + }, + { + "index": 1, + "time": 351.5926810000001, + "statusCode": 201 + }, + { + "index": 4, + "time": 339.9373370000003, + "statusCode": 201 + }, + { + "index": 20, + "time": 339.90371999999934, + "statusCode": 201 + }, + { + "index": 895, + "time": 220.41194600000017, + "statusCode": 201 + }, + { + "index": 564, + "time": 212.24562899999728, + "statusCode": 201 + }, + { + "index": 8, + "time": 200.19748899999968, + "statusCode": 201 + }, + { + "index": 15, + "time": 200.19742299999962, + "statusCode": 201 + }, + { + "index": 10, + "time": 199.67243499999995, + "statusCode": 201 + }, + { + "index": 6, + "time": 199.41130600000042, + "statusCode": 201 + }, + { + "index": 12, + "time": 180.20744199999945, + "statusCode": 201 + }, + { + "index": 9, + "time": 180.0771120000004, + "statusCode": 201 + } + ] +} +``` \ No newline at end of file diff --git a/lamda/package-lock.json b/lamda/package-lock.json new file mode 100644 index 0000000..581bf03 --- /dev/null +++ b/lamda/package-lock.json @@ -0,0 +1,38 @@ +{ + "name": "lamda", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "lamda", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@types/aws-lambda": "^8.10.143", + "typescript": "^5.5.4" + } + }, + "node_modules/@types/aws-lambda": { + "version": "8.10.143", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.143.tgz", + "integrity": "sha512-u5vzlcR14ge/4pMTTMDQr3MF0wEe38B2F9o84uC4F43vN5DGTy63npRrB6jQhyt+C0lGv4ZfiRcRkqJoZuPnmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/lamda/package.json b/lamda/package.json new file mode 100644 index 0000000..7dc1b8c --- /dev/null +++ b/lamda/package.json @@ -0,0 +1,15 @@ +{ + "name": "lamda", + "version": "1.0.0", + "scripts": { + "build": "tsc" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "devDependencies": { + "@types/aws-lambda": "^8.10.143", + "typescript": "^5.5.4" + } +} diff --git a/lamda/src/index.ts b/lamda/src/index.ts new file mode 100644 index 0000000..89a941b --- /dev/null +++ b/lamda/src/index.ts @@ -0,0 +1,100 @@ +import { Handler } from 'aws-lambda'; + +/*global fetch*/ +/*global performance*/ +export const handler: Handler = async (event, context) => { + const startTotalTime = performance.now(); // 전체 시작 시간 기록 + + // 요청 본문을 파싱 + const body = JSON.parse(event.body || '{}'); + const repeat = body.repeat; + + if (typeof repeat !== 'number' || repeat <= 0) { + return { + statusCode: 400, + body: JSON.stringify({ + message: "'repeat' must be a positive number" + }), + }; + } + + const appKey = body.appKey; + if (typeof appKey !== 'string' || appKey.length === 0) { + return { + statusCode: 400, + body: JSON.stringify({ + message: "'appKey' must be a non-empty string" + }), + }; + } + + const url = 'https://api.logbat.info/logs'; + const level = 'info'; + + const timings: { index: number; time: number; statusCode: number }[] = []; + let totalTime = 0; + let successCount = 0; + let failureCount = 0; + let maxTime = -Infinity; + let minTime = Infinity; + + for (let i = 0; i < repeat; i++) { + const startTime = performance.now(); // 개별 요청 시작 시간 + let statusCode = 0; + + try { + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'appKey': appKey + }, + body: JSON.stringify({ + level: level, + timestamp: new Date().toISOString(), + data: context.awsRequestId + ' - ' + i + }), + }); + + statusCode = response.status; + if (response.ok) { + successCount++; + } else { + failureCount++; + } + } catch (error) { + statusCode = 500; // 네트워크 오류 등으로 인한 실패 처리 + failureCount++; + } + + const endTime = performance.now(); // 개별 요청 종료 시간 + const elapsedTime = endTime - startTime; + + timings.push({ index: i, time: elapsedTime, statusCode: statusCode }); + totalTime += elapsedTime; + maxTime = Math.max(maxTime, elapsedTime); + minTime = Math.min(minTime, elapsedTime); + } + + // sort by time + timings.sort((a, b) => b.time - a.time); + + const averageTime = totalTime / repeat; + const endTotalTime = performance.now(); // 전체 종료 시간 기록 + const totalExecutionTime = endTotalTime - startTotalTime; + + return { + statusCode: 201, + body: JSON.stringify({ + averageTime: averageTime, + maxTime: maxTime, + minTime: minTime, + successCount: successCount, + failureCount: failureCount, + totalExecutionTime: totalExecutionTime, + memoryUsed: context.memoryLimitInMB + ' MB', + requestId: context.awsRequestId, + timings: timings, + }), + }; +}; \ No newline at end of file diff --git a/lamda/tsconfig.json b/lamda/tsconfig.json new file mode 100644 index 0000000..cacc9cd --- /dev/null +++ b/lamda/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "es2020", // Node.js 20을 지원하는 ES2020으로 타겟 설정 + "module": "esnext", // ECMAScript 모듈 형식으로 설정 + "strict": true, // 엄격한 타입 검사를 활성화 + "preserveConstEnums": true, // const 열거형을 유지 + "noEmitOnError": true, // 컴파일 오류 시 출력하지 않음 + "sourceMap": false, // 소스 맵 생성을 비활성화 + "moduleResolution": "node", // Node.js 스타일의 모듈 해석을 사용 + "esModuleInterop": true, // ES 모듈 호환성을 활성화 + "skipLibCheck": true, // 라이브러리 타입 검사를 건너뜀 + "forceConsistentCasingInFileNames": true,// 파일 이름 대소문자 일관성을 강제 + "outDir": "./dist", // 출력 디렉토리 설정 + "declaration": false, // 타입 선언 파일 생성 비활성화 + "isolatedModules": true // 개별 모듈 컴파일을 강제 + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "**/*.test.ts"] +} \ No newline at end of file