Seize the day

POST : Backend study

Elysia by BunJS study

https://github.com/elysiajs/elysia

 

GitHub - elysiajs/elysia: Ergonomic Framework for Humans

Ergonomic Framework for Humans. Contribute to elysiajs/elysia development by creating an account on GitHub.

github.com

 

프로젝트 생성

bun create elysia elysia_test
cd elysia_test
bun dev
$ bun run --watch src/index.ts
🦊 Elysia is running at localhost:3000

 

TLS(https) 지원

const app = new Elysia()
  .get("/", () => "Hello Elysia")
  .listen({
      port: 3000,
      tls: {
        key: Bun.file("/Users/dajkim76/test/server.key"),
        cert: Bun.file("/Users/dajkim76/test/server.crt"),
      },
      hostname: "0.0.0.0"
    });

 

compression(gzip)지원

bun add elysia-compress
import { compression } from 'elysia-compress'

const app = new Elysia()
  .use(compression({ threshold: 100, encodings: ['deflate', 'gzip']}))
  .get("/hello", () => "Hello Elysia Hello Elysia Hello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello ElysiaHello Elysia")

 

logger 여러 종류가 있지만 
https://github.com/PunGrumpy/logixlysia 간단하고 충분한 스펙이다. 

bun add logixlysia
import logixlysia from 'logixlysia'

const logger = logixlysia({
  config: {
    ip: true,
    logFilePath: './example.log',
    customLogFormat:
      '🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}',
    // logFilter: {
    //   level: ['ERROR', 'WARNING'],
    //   status: [500, 404],
    //   method: 'GET'
    // }
  }
})

const app = new Elysia()
  .use(logger)

결과는..

# 콘솔로그
      ┌────────────────────────────────────────────────┐
      │                                                │
      │                 Elysia v1.0.27                 │
      │                                                │
      │  🦊 Elysia is running at https://0.0.0.0:3000  │
      │                                                │
      └────────────────────────────────────────────────┘

🦊 Elysia is running at 0.0.0.0:3000
🦊 7/7/2024, 12:13:38 AM INFO    30ms   GET     /hello 200
🦊 7/7/2024, 12:13:46 AM INFO    1ms    GET     /hello 200
🦊 7/7/2024, 12:13:47 AM INFO    1ms    GET     /hello 200
🦊 7/7/2024, 12:13:47 AM INFO    844µs  GET     /hello 200
🦊 7/7/2024, 12:13:48 AM INFO    1ms    GET

# 파일 로그
dajkim76@Kims-Mac-mini ~/test/elysia_test % cat example.log
🦊 7/7/2024, 12:13:38 AM INFO        39ms         GET     /hello 200
🦊 7/7/2024, 12:13:46 AM INFO         3ms         GET     /hello 200
🦊 7/7/2024, 12:13:47 AM INFO         3ms         GET     /hello 200
🦊 7/7/2024, 12:13:47 AM INFO         2ms         GET     /hello 200
🦊 7/7/2024, 12:13:48 AM INFO         2ms         GET     /hello 200

 

logger 두번째 winston를 지원하는 elysia-logging 이게 나아보인다.

bun add @otherguy/elysia-logging
bun add winston
import { ElysiaLogging } from "@otherguy/elysia-logging";
import { type Logger, LogFormat } from "@otherguy/elysia-logging";
import { createLogger, transports, format } from "winston";

// Define Winston logger
const logger : Logger = createLogger({
  // Use the LOG_LEVEL environment variable, or default to "info"
  level: Bun.env.LOG_LEVEL ?? "info",

  // Use JSON format
  format: format.json(),

  // Log to the console
  transports: [new transports.Console()],
});

const elysiaLogging = ElysiaLogging(logger, {
  level: "info",

  // Access logs in JSON format
  format: LogFormat.JSON,
})

const app = new Elysia()
  .use(elysiaLogging)

결과는

🦊 Elysia is running at 0.0.0.0:3000
{"level":"info","message":"GET /hello completed with status 200 in 20.76ms","request":{"ip":"127.0.0.1","method":"GET","url":{"params":{},"path":"/hello"}},"response":{"status_code":200,"time":20761917}}
{"level":"info","message":"GET /hello completed with status 200 in 2.129ms","request":{"ip":"127.0.0.1","method":"GET","url":{"params":{},"path":"/hello"}},"response":{"status_code":200,"time":2129250}}
{"level":"info","message":"GET /hello completed with status 200 in 618.7µs","request":{"ip":"127.0.0.1","method":"GET","url":{"params":{},"path":"/hello"}},"response":{"status_code":200,"time":618709}}

 

파일로 쓰는 걸로 바꿔보자..

bun add winston-daily-rotate-file

코드 수정

import { ElysiaLogging } from "@otherguy/elysia-logging";
import { type Logger, LogFormat } from "@otherguy/elysia-logging";
import  * as winston from "winston";
const winstonDaily = require('winston-daily-rotate-file')

const logDir = './logs'; // log 파일을 관리할 폴더
const IS_DEVELOPMENT = true;

const dailyOptions = (level: string) => {
  return {
    level,
    datePattern: 'YYYY-MM-DD',
    dirname: logDir + `/${level}`,
    filename: `%DATE%.${level}.log`,
    maxFiles: 7, //7일치 로그파일 저장
    zippedArchive: true, // 로그가 쌓이면 압축하여 관리
    format: winston.format.combine(
      winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), 
    ),
  };
};

const consoleOptions = {
  level: 'debug', //console은 debug 이상은 다 출력한다
  format: winston.format.combine(
    //winston.format.colorize({ all: true }),
    winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
  ),
};

const createTransports = () => {
  const transprots : winston.transport[]= [];
  if (IS_DEVELOPMENT) {
    // Console에 출력은 개발모드일때만 한다.
    transprots.push(new winston.transports.Console(consoleOptions));
  }

  transprots.push(new winstonDaily(dailyOptions('debug'))); // 404 not found
  transprots.push(new winstonDaily(dailyOptions('info'))); // normal api request
  transprots.push(new winstonDaily(dailyOptions('warn'))); // error api response
  transprots.push(new winstonDaily(dailyOptions('error'))); // internal error
  return transprots;
};




// Define Winston logger
const logger : Logger = winston.createLogger({
  // Use the LOG_LEVEL environment variable, or default to "info"
  level: Bun.env.LOG_LEVEL ?? "info",

  // Use JSON format
  format: winston.format.json(),

  // Log to the console
  transports: createTransports(),
});

const elysiaLogging = ElysiaLogging(logger, {
  level: "info",

  // Access logs in JSON format
  format: LogFormat.JSON,
})

const app = new Elysia()
  .use(elysiaLogging)

결과는

콘솔은

🦊 Elysia is running at 0.0.0.0:3000
{"level":"info","message":"GET /hello completed with status 200 in 17.24ms","request":{"ip":"127.0.0.1","method":"GET","url":{"params":{},"path":"/hello"}},"response":{"status_code":200,"time":17236792}}
{"level":"info","message":"GET /hello completed with status 200 in 515.6µs","request":{"ip":"127.0.0.1","method":"GET","url":{"params":{},"path":"/hello"}},"response":{"status_code":200,"time":515583}}
{"level":"info","message":"GET /hello completed with status 200 in 408.4µs","request":{"ip":"127.0.0.1","method":"GET","url":{"params":{},"path":"/hello"}},"response":{"status_code":200,"time":408417}}

파일은
dajkim76@Kims-Mac-mini ~/test/elysia_test/logs/info % cat 2024-07-07.info.log
{"level":"info","message":"GET /hello completed with status 200 in 17.24ms","request":{"ip":"127.0.0.1","method":"GET","url":{"params":{},"path":"/hello"}},"response":{"status_code":200,"time":17236792}}
{"level":"info","message":"GET /hello completed with status 200 in 515.6µs","request":{"ip":"127.0.0.1","method":"GET","url":{"params":{},"path":"/hello"}},"response":{"status_code":200,"time":515583}}
{"level":"info","message":"GET /hello completed with status 200 in 408.4µs","request":{"ip":"127.0.0.1","method":"GET","url":{"params":{},"path":"/hello"}},"response":{"status_code":200,"time":408417}}

NestJS에서 쓰든 코드를 가져왔는데 일단 동작은 한다. 파일로 쓰기도 잘 되고,  logger.error("")로 했을 때 error 디렉토리에도 error만 분리되서 잘 저장된다. 하지만 timestamp가 저장되지 않고 user-Agent로 찍혔으면 좋겠는데.  생각해보니 NestJS에서도 middleware로 HTTP log를 쓰도록 했었네.  구현부를 더 들여다보면 가능할 지도 모르지만 로그는 여기까지만 테스트 ..

Basic Auth

https://github.com/itsyoboieltr/elysia-basic-auth  
https://github.com/eelkevdbos/elysia-basic-auth 

잘 안 됨

 

RateLimit

bun add elysia-rate-limit 

기본값이 6초 내에 10번 이상 요청이 들어오면 429 에러 응답.

import { rateLimit } from 'elysia-rate-limit'


const app = new Elysia()
  .use(rateLimit())

 

cron job

https://elysiajs.com/plugins/cron.html 

 

JWT 인증

https://elysiajs.com/plugins/jwt.html

 

Firebase IdToken 인증

 

유용한 링크

https://mirzaleka.medium.com/bun-crud-api-with-elysia-js-mongodb-10e73d484723

 

 

top

posted at

2024. 7. 7. 00:32


CONTENTS

Seize the day
BLOG main image
김대정의 앱 개발 노트와 사는 이야기
RSS 2.0Tattertools
공지
아카이브
최근 글 최근 댓글
카테고리 태그 구름사이트 링크