728x90
반응형

Selenium을 파이썬에서만 쓸 수 있을 줄 알았는데 NodeJS에서도 된다는 말을 듣고 javascript로 만들어볼까 한다.

 

1. Chrome 을 다운로드한다.

https://www.google.com/chrome/index.html

 

Chrome 웹브라우저

더욱 스마트해진 Google로 더 간편하고 안전하고 빠르게.

www.google.com

 

2. 아래 사진처럼 크롬 버전을 익혀둔다.

3. 크롬 버전을 확인했으면 앞자리 수에 맞는 크롬 드라이버를 설치한다.

 

ChromeDriver - WebDriver for Chrome - Downloads

Current Releases If you are using Chrome version 104, please download ChromeDriver 104.0.5112.29 If you are using Chrome version 103, please download ChromeDriver 103.0.5060.53 If you are using Chrome version 102, please download ChromeDriver 102.0.5005.61

chromedriver.chromium.org

 

4. 윈도우로 설치해준다. ( 버전은 다를 수 있습니다. )

 

5. 압축을 해제한 후 해당 파일 경로를 알아둔다. ( 나중에 셀레니움에서 사용 )

 

 

5. NodeJS와 VSCode를 설치한다.

https://nodejs.org/ko/download/

 

다운로드 | Node.js

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

nodejs.org

 

개인적으로 생각하는 쓰기 좋은 vscode typescript 확장들

  1. ES7+ React/Redux/React-Native snippets
  2. ESLint
  3. Live Server
  4. Prettier

 

6. npm init 및 필요 구성 모듈을 설치해준다.

$ npm init
$ npm i express typescript ts-node nodemon @types/node @types/express

 

7. typscript를 위한 옵션을 설정하기 위해 다음 명령어를 입력해준다.

$ npx tsc --init

 

/tsconfig.json

{
  "compilerOptions": {
    "target": "es6", // 어떤 버전으로 컴파일할지 작성 
    "module": "commonjs", //어떤 모듈 방식으로 컴파일할지 설정
    "outDir": "./dist",	//컴파일 후 js 파일들이 생성되는 곳
    "rootDir": ".",	//루트 폴더
    "strict": true,	//strict 옵션 활성화
    "moduleResolution": "node",	//모듈 해석 방법 설정: 'node' (Node.js)
    "esModuleInterop": true,
     "jsx": "react"
  }
}

 

8. app.ts 파일을 만든다.

/app.ts

import express, { Request, Response, NextFunction } from 'express';

const app = express();


app.get('/welcome', (req: Request, res: Response, next: NextFunction) => {
    res.send('welcome!');
});

app.listen('1234', () => {
    console.log(`
  ################################################
  🛡️  Server listening on port: 1234🛡️
  ################################################
`);
});

 

9. pakage.json 파일을 수정해준다.

...
"scripts": {
    "start": "node dist/app.js", 
    "build": "tsc -p .", 
    "dev": "nodemon --watch \"src/**/*.ts\" --exec \"ts-node\" app.ts"
  }
 ...
  • build : typscript 파일을 js 파일로 컴파일해준다.
  • start : 컴파일한 js 파일로 서버를 실행한다.

 

10. 빌드하고 시작해본다.

$ npm run build
$ npm run start

 

정상적으로 뜨는 것을 확인할 수 있다.

 

또한 내가 express를 쓸 때 기본적으로 사용하는게 body-parser와cookie-parser, dotenv인데, 자세한 내용은 검색하면 나온다.

 

나중에 json 형식으로 통신할 때나 쿠키를 사용할 때, 중요한 정보를 환경 변수로 사용할 때 대비하자.

 

11. body-parser , cookie-parser, dotenv를 설치한다.

$ npm install --save body-parser @types/body-parser cookie-parser @types/cookie-parser dotenv

 

 

12. app.ts 파일을 수정해준다.

import express, { Request, Response, NextFunction } from 'express';

// parser
import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser';

// dotenv
import dotenv from 'dotenv'
dotenv.config();

const app = express();

app.use(bodyParser.json())
app.use(cookieParser())


app.get('/welcome', (req: Request, res: Response, next: NextFunction) => {
    res.send('welcome!');
});

app.listen('1234', () => {
    console.log(`
  ################################################
  🛡️  Server listening on port: 1234🛡️
  ################################################
`);
});

 

13. 좀 더 짜임새있는 구조를 위해 미리 폴더들을 만들어두자.

14. routers 밑에 파일을 만들고, app.ts 파일을 수정해준다.

/routers/one.ts

import express, { Request, Response, NextFunction } from 'express';
var router = express.Router();

router.get('/', async function (req: Request, res: Response, next: NextFunction) {
    res.send('welcome!');
});

export default router;

 

/app.ts

import express, { Request, Response, NextFunction } from 'express';

// parser
import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser';

// router
import oneRouter from './routers/one'

const app = express();

app.use(bodyParser.json())
app.use(cookieParser())

app.use('/one',oneRouter)

app.listen('1234', () => {
    console.log(`
  ################################################
  🛡️  Server listening on port: 1234🛡️
  ################################################
`);
});

 

15. logging 미들웨어를 만들기 위해 다음 명령어로 설치해준다.

$ npm install winston @types/winston winston winston-daily-rotate-file

 

/config/winston.ts

import winston, { info } from 'winston';
import winstonDaily from 'winston-daily-rotate-file';

const logDir = 'logs';  // logs 디렉토리 하위에 로그 파일 저장
const { combine, timestamp, printf } = winston.format;

// Define log format
const logFormat = printf(info => {
  return `${info.timestamp} ${info.level}: ${info.message}`;
});

/*
 * Log Level
 * error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6
 */

const loggerError = winston.createLogger({
  format: combine(
    timestamp({
      format: 'YYYY-MM-DD HH:mm:ss',
    }),
    logFormat,
  ),
  transports: [
    // error 레벨 로그를 저장할 파일 설정
    new winstonDaily({
      level: 'info',
      datePattern: 'YYYY-MM-DD',
      dirname: logDir + '/error',  // error.log 파일은 /logs/error 하위에 저장 
      filename: `%DATE%.error.log`,
      maxFiles: 30,
      watchLog: true,
      zippedArchive: true,
    }),
  ],
});

const loggerInfo = winston.createLogger({
  format: combine(
    timestamp({
      format: 'YYYY-MM-DD HH:mm:ss',
    }),
    logFormat,
  ),
  transports: [
    // info 레벨 로그를 저장할 파일 설정
    new winstonDaily({
      level: 'info',
      datePattern: 'YYYY-MM-DD',
      dirname: logDir + '/info',
      filename: `%DATE%.info.log`,
      maxFiles: 30,  // 30일치 로그 파일 저장
      watchLog: true,
      zippedArchive: true, 
    }),
  ],
});

const loggerHttp = winston.createLogger({
  format: combine(
    timestamp({
      format: 'YYYY-MM-DD HH:mm:ss',
    }),
    logFormat,
  ),
  transports: [
    // http 레벨 로그를 저장할 파일 설정
    new winstonDaily({
      level: 'info',
      datePattern: 'YYYY-MM-DD',
      dirname: logDir + '/http',
      filename: `%DATE%.http.log`,
      maxFiles: 30,  // 30일치 로그 파일 저장
      watchLog: true,
      zippedArchive: true, 
    }),
  ],
});

const loggerDebug = winston.createLogger({
  format: combine(
    timestamp({
      format: 'YYYY-MM-DD HH:mm:ss',
    }),
    logFormat,
  ),
  transports: [
    // debug 레벨 로그를 저장할 파일 설정
    new winstonDaily({
      level: 'info',
      datePattern: 'YYYY-MM-DD',
      dirname: logDir + '/debug', 
      filename: `%DATE%.debug.log`,
      maxFiles: 30,
      watchLog: true,
      zippedArchive: true,
    }),
  ],
});


// Production 환경이 아닌 경우(dev 등) 
if (process.env.NODE_ENV !== 'production') {
  loggerInfo.add(new winston.transports.Console({
    format: winston.format.combine(
      winston.format.colorize(),  // 색깔 넣어서 출력
      winston.format.simple(),  // `${info.level}: ${info.message} JSON.stringify({ ...rest })` 포맷으로 출력
    )
  }));
}

// Production 환경이 아닌 경우(dev 등) 
if (process.env.NODE_ENV !== 'production') {
  loggerError.add(new winston.transports.Console({
    format: winston.format.combine(
      winston.format.colorize(),  // 색깔 넣어서 출력
      winston.format.simple(),  // `${info.level}: ${info.message} JSON.stringify({ ...rest })` 포맷으로 출력
    )
  }));
}

if (process.env.NODE_ENV !== 'production') {
  loggerHttp.add(new winston.transports.Console({
    format: winston.format.combine(
      winston.format.colorize(),  // 색깔 넣어서 출력
      winston.format.simple(),  // `${info.level}: ${info.message} JSON.stringify({ ...rest })` 포맷으로 출력
    )
  }));
}

if (process.env.NODE_ENV !== 'production') {
  loggerDebug.add(new winston.transports.Console({
    format: winston.format.combine(
      winston.format.colorize(),  // 색깔 넣어서 출력
      winston.format.simple(),  // `${info.level}: ${info.message} JSON.stringify({ ...rest })` 포맷으로 출력
    )
  }));
}

export { 
  loggerInfo,
  loggerError,
  loggerHttp,
  loggerDebug,
 };

 

/middlewares/index.ts

export * from "./http"

 

/middlewares/http.ts

import express, { Request, Response, NextFunction } from 'express';
import {   
    loggerInfo,
    loggerError,
    loggerHttp,
    loggerDebug,
 } from '../config/winston'

interface LOGSTR {
    url : string;
    method : string;
    query? : Object;
    body? : Object;
}

export const httpLoggingMiddleware = async (req: Request, res: Response, next: NextFunction) => {

    let logStr: LOGSTR = {
        url : "",
        method: "",
        query: "",
        body: "",
    }

    try {
        // 접속 경로
        logStr.url = req.originalUrl;

        // 메소드
        logStr.method = req.method;

        switch (req.method) {
            case 'GET':
                logStr.query = req.query;
                break;
            case 'POST':
                logStr.body = req.body;
                break;
            case 'PATCH':
                logStr.body = req.body;
                break;
            case 'DELETE':
                logStr.query = req.query;
                break;
        }

        loggerHttp.info(JSON.stringify(logStr))

        next();
    }
    catch (Err) {
        loggerError.info(Err)
        res.send({ success: false });
    }
}

 

/routers/one.ts

import express, { Request, Response, NextFunction } from 'express';
var router = express.Router();

// middlewares
import { httpLoggingMiddleware } from '../middlewares'

// logger
import {
    loggerHttp,
    loggerDebug,
    loggerError,
    loggerInfo 
    } from '../config/winston';

router.get('/',httpLoggingMiddleware, async function (req: Request, res: Response, next: NextFunction) {
    res.send('welcome!');
});

export default router;

 

 

16. /one 라우터에 접근해보고 로그 데이터가 잘 생성되는지 확인한다.

get 메소드는 브라우저 url 창에 입력해도 된다.

728x90
반응형

+ Recent posts