{"id":49265191,"url":"https://github.com/kangjuhyup/rvlog","last_synced_at":"2026-05-24T12:04:41.544Z","repository":{"id":353498073,"uuid":"1219653767","full_name":"kangjuhyup/rvlog","owner":"kangjuhyup","description":"Framework-agnostic TypeScript logging library with decorators, field masking, and error notifications.","archived":false,"fork":false,"pushed_at":"2026-05-16T07:02:13.000Z","size":518,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-16T07:06:12.434Z","etag":null,"topics":["developer-experience","developer-tools","logging","observability","structured-logging","tooling","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kangjuhyup.png","metadata":{"files":{"readme":"README-KR.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-24T04:59:38.000Z","updated_at":"2026-05-16T07:01:26.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kangjuhyup/rvlog","commit_stats":null,"previous_names":["kangjuhyup/rvlog"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kangjuhyup/rvlog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kangjuhyup%2Frvlog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kangjuhyup%2Frvlog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kangjuhyup%2Frvlog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kangjuhyup%2Frvlog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kangjuhyup","download_url":"https://codeload.github.com/kangjuhyup/rvlog/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kangjuhyup%2Frvlog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33096606,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T04:41:52.686Z","status":"ssl_error","status_checked_at":"2026-05-16T04:41:52.009Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["developer-experience","developer-tools","logging","observability","structured-logging","tooling","typescript"],"created_at":"2026-04-25T09:39:20.185Z","updated_at":"2026-05-24T12:04:41.510Z","avatar_url":"https://github.com/kangjuhyup.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rvlog\n\n데코레이터, 민감정보 마스킹, 에러 알림을 제공하는 프레임워크 독립형 TypeScript 로깅 라이브러리입니다.\n\n## 주요 기능\n\n- `@Logging` 데코레이터로 진입, 완료, 에러, duration 자동 로깅\n- 클래스 없이도 쓸 수 있는 `withLogging()`\n- 이름, 이메일, 전화번호, 비밀번호 등을 가릴 수 있는 `@MaskLog`\n- 헬스체크나 고빈도 메서드를 제외하는 `@NoLog`\n- route fan-out, lazy notification resource, cooldown, threshold를 지원하는 `NotificationManager`\n- Node.js 환경에서 파일 저장과 rotate를 지원하는 `FileTransport`\n\n## 설치\n\n코어 패키지 기준 최소 요구 사항:\n\n- `Node.js 18+`\n- `TypeScript 5.7+`\n\n```bash\nnpm install @kangjuhyup/rvlog reflect-metadata\npnpm add @kangjuhyup/rvlog reflect-metadata\nyarn add @kangjuhyup/rvlog reflect-metadata\n```\n\n선택 알림 채널 패키지:\n\n```bash\nnpm install @kangjuhyup/rvlog-slack @kangjuhyup/rvlog-discord @kangjuhyup/rvlog-webhook @kangjuhyup/rvlog-sentry @kangjuhyup/rvlog-email\npnpm add @kangjuhyup/rvlog-slack @kangjuhyup/rvlog-discord @kangjuhyup/rvlog-webhook @kangjuhyup/rvlog-sentry @kangjuhyup/rvlog-email\nyarn add @kangjuhyup/rvlog-slack @kangjuhyup/rvlog-discord @kangjuhyup/rvlog-webhook @kangjuhyup/rvlog-sentry @kangjuhyup/rvlog-email\n```\n\n관련 패키지:\n\n```bash\nnpm install @kangjuhyup/rvlog-react @kangjuhyup/rvlog-nest\npnpm add @kangjuhyup/rvlog-react @kangjuhyup/rvlog-nest\nyarn add @kangjuhyup/rvlog-react @kangjuhyup/rvlog-nest\n```\n\n참고:\n\n- `@Logging`, `@MaskLog`, `rvlog-nest`처럼 메타데이터 기반 기능을 사용할 때는 `reflect-metadata`가 필요합니다.\n- 프레임워크 어댑터는 코어 `rvlog` 최소 요구 사항 외에 별도 런타임 조건이 있을 수 있습니다.\n\n## 기본 사용법\n\n데코레이터를 사용할 때는 앱 시작 지점에서 `reflect-metadata`를 한 번 먼저 import 하세요.\n\n```ts\nimport \"reflect-metadata\";\nimport { Logger, Logging, LogLevel, MaskLog, NoLog } from \"@kangjuhyup/rvlog\";\n\nLogger.configure({\n  minLevel: LogLevel.INFO,\n  pretty: true,\n  serialize: {\n    maxStringLength: 200,\n    maxArrayLength: 20,\n    maxObjectKeys: 30,\n    maxDepth: 4,\n  },\n});\n\nclass CreateUserDto {\n  @MaskLog({ type: \"name\" })\n  name!: string;\n\n  @MaskLog({ type: \"email\" })\n  email!: string;\n}\n\n@Logging\nclass UserService {\n  declare logger: Logger;\n\n  async create(dto: CreateUserDto) {\n    this.logger.info(\"manual log before create\");\n    return { id: 1, ...dto };\n  }\n\n  @NoLog\n  healthCheck() {\n    return \"ok\";\n  }\n}\n```\n\n자동 진입/완료 로그는 기본적으로 `LogLevel.INFO`로 남습니다. 서비스의 생명주기 로그를 다른 레벨로 남기고 싶다면 `level`을 넘기면 됩니다. 실패 로그는 기존처럼 항상 `ERROR`로 남습니다.\n\n```ts\n@Logging({ level: LogLevel.WARN })\nclass BillingService {\n  charge() {\n    return \"ok\";\n  }\n}\n```\n\n## Pretty 출력\n\n기본 보기 좋은 콘솔 포맷은 `pretty: true`로 켤 수 있습니다. 일부 요소만 바꾸고 싶다면 전체 `formatter`를 직접 만들지 않고 `pretty`에 객체 옵션을 넘길 수 있습니다.\n\n```ts\nimport { defineLoggerOptions, Logger, LogLevel } from \"@kangjuhyup/rvlog\";\n\nconst loggerOptions = defineLoggerOptions({\n  pretty: {\n    separator: \"-\u003e\",\n    showTimestamp: false,\n    levelLabels: {\n      [LogLevel.INFO]: \"info\",\n      [LogLevel.ERROR]: \"error\",\n    },\n    levelColors: {\n      [LogLevel.INFO]: \"cyan\",\n      [LogLevel.WARN]: \"yellow\",\n      [LogLevel.ERROR]: \"brightRed\",\n    },\n  },\n});\n\nLogger.configure(loggerOptions);\n```\n\n출력 문자열 전체를 직접 제어해야 한다면 `formatter`를 사용하세요.\n\n## 함수형 사용법\n\n클래스 데코레이터 대신 함수 단위로 동일한 자동 로깅을 적용하고 싶다면 `withLogging()`을 사용하면 됩니다.\n\n```ts\nimport { LogLevel, MaskLog, withLogging } from \"@kangjuhyup/rvlog\";\n\nclass SignupInput {\n  @MaskLog({ type: \"email\" })\n  email!: string;\n\n  @MaskLog({ type: \"full\" })\n  password!: string;\n}\n\nasync function signupImpl(input: SignupInput) {\n  return { id: crypto.randomUUID() };\n}\n\nexport const signup = withLogging(signupImpl, {\n  context: \"signup\",\n  level: LogLevel.DEBUG,\n});\n```\n\n## Node.js 파일 로그\n\n파일 저장 기능은 Node 런타임에서만 `@kangjuhyup/rvlog/node`를 import 하세요.\n\n```ts\nimport \"reflect-metadata\";\nimport { Logger, LogLevel } from \"@kangjuhyup/rvlog\";\nimport { FileTransport } from \"@kangjuhyup/rvlog/node\";\n\nLogger.configure({\n  minLevel: LogLevel.INFO,\n  pretty: true,\n  transports: [\n    new FileTransport({\n      enabled: true,\n      dirPath: \"logs\",\n      fileName: \"rvlog.log\",\n      rotate: {\n        type: \"size\",\n        maxSizeBytes: 1024 * 1024,\n        maxFiles: 3,\n      },\n    }),\n  ],\n});\n```\n\n## Payload 길이 제한\n\n너무 큰 payload를 그대로 로그에 남기면 노이즈와 비용이 커질 수 있습니다. `rvlog`는 문자열, 배열, 객체, 깊은 중첩 값을 로그 전에 잘라낼 수 있습니다.\n\n```ts\nLogger.configure({\n  pretty: true,\n  serialize: {\n    maxStringLength: 200,\n    maxArrayLength: 20,\n    maxObjectKeys: 30,\n    maxDepth: 4,\n    truncateSuffix: \"...\u003ctruncated\u003e\",\n  },\n});\n```\n\n이 직렬화 정책은 다음 경로에 공통으로 적용됩니다.\n\n- `Logger.info(...)`\n- `@Logging`\n- `withLogging()`\n\n## 알림 연동\n\n`NotificationManager`는 알림 라우팅 정책만 담당합니다. 실제 발송 채널은 선택 패키지로 분리되어, 앱이 켠 리소스만 설치하고 lazy import 할 수 있습니다.\n\n```ts\nimport { Logger, LogLevel, NotificationManager } from \"@kangjuhyup/rvlog\";\n\nconst notification = new NotificationManager()\n  .addLazyResource(\"slack\", async () =\u003e {\n    const { SlackChannel } = await import(\"@kangjuhyup/rvlog-slack\");\n    return new SlackChannel(process.env.SLACK_WEBHOOK_URL ?? \"\");\n  })\n  .addLazyResource(\"email\", async () =\u003e {\n    const { EmailChannel, createNodemailerAdapter } = await import(\"@kangjuhyup/rvlog-email\");\n    return new EmailChannel({\n      to: \"ops@example.com\",\n      transport: createNodemailerAdapter(mailer),\n    });\n  })\n  .addRoute({\n    resources: [\"slack\", \"email\"],\n    levels: [LogLevel.ERROR],\n    when: {\n      threshold: { count: 10, windowMs: 60_000 },\n      cooldownMs: 60_000,\n    },\n  });\n\nLogger.configure({ notification });\n```\n\n채널 패키지:\n\n- `@kangjuhyup/rvlog-slack`\n- `@kangjuhyup/rvlog-discord`\n- `@kangjuhyup/rvlog-webhook`\n- `@kangjuhyup/rvlog-sentry`\n- `@kangjuhyup/rvlog-email`\n\n기존 `addRule({ channel, levels, cooldownMs })` API는 호환성을 위해 계속 사용할 수 있습니다.\n\n관련 패키지 문서에 실제 연동 예시가 정리돼 있습니다.\n\n- [packages/rvlog-react/README-KR.md](./packages/rvlog-react/README-KR.md)\n- [packages/rvlog-nest/README-KR.md](./packages/rvlog-nest/README-KR.md)\n\n## 예제\n\n- [example/README.md](./example/README.md)\n- `example/basic`: 순수 TypeScript + 데코레이터\n- `example/express`: Express\n- `example/nestjs`: NestJS\n- `example/react`: React + hooks\n- `example/vanilla`: 브라우저 TypeScript + `withLogging()`\n\n문제 해결 문서:\n\n- [FAQ-KR.md](./FAQ-KR.md)\n\n## 벤치마크 리포트\n\n성능 측정 결과는 아래 문서에 있습니다.\n\n- [benchmark/REPORT-KR.md](./benchmark/REPORT-KR.md)\n# 격리된 LoggerSystem 구성\n\n간단한 앱에서는 기존처럼 `Logger.configure(...)` 기반 전역 설정을 그대로 써도 됩니다.\n\n하지만 앱 단위, 테스트 단위, 테넌트 단위로 로거 상태를 분리하고 싶다면\n`createLoggerSystem(...)`을 사용하는 편이 더 안전합니다.\n\n```ts\nimport {\n  createLoggerSystem,\n  LogLevel,\n  Logger,\n  withLogging,\n} from 'rvlog';\n\nconst system = createLoggerSystem({\n  minLevel: LogLevel.INFO,\n});\n\nconst logger = system.createLogger('UserService');\nlogger.info('격리된 런타임에서 출력되는 로그');\n\nconst wrapped = withLogging(\n  async (userId: string) =\u003e userId,\n  {\n    context: 'user-flow',\n    system,\n  },\n);\n```\n\n이럴 때는 전역 `Logger`가 적합합니다.\n- 프로세스 전체에서 설정이 하나면 충분할 때\n- 가장 단순한 사용 방식이 필요할 때\n\n이럴 때는 `LoggerSystem`이 더 적합합니다.\n- 테스트가 전역 Logger 상태를 오염시키면 안 될 때\n- 여러 앱 또는 여러 테넌트가 같은 런타임을 공유할 때\n- framework adapter마다 transport/notification 구성을 분리하고 싶을 때\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkangjuhyup%2Frvlog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkangjuhyup%2Frvlog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkangjuhyup%2Frvlog/lists"}