18P by hongminhee 2달전 | ★ favorite | 댓글 7개

라이브러리 vs 애플리케이션: 근본적으로 다른 로깅 요구사항

  • 애플리케이션 로깅: 개발자가 직접 제어하는 환경에서 명시적 설정과 관리
  • 라이브러리 로깅: 타인의 프로젝트에 포함되어 사용자 환경과 선택권 존중 필요
  • 기존 방식의 한계: 애플리케이션 중심 로거(winston, Pino)를 라이브러리에 적용 시 강제성 문제
  • 라이브러리 제작자의 딜레마: 디버깅 정보 제공 vs 사용자에게 부담 주지 않기

현재 라이브러리 로깅의 문제점

  • 파편화된 로깅 생태계: Express는 DEBUG=express:*, Mongoose는 mongoose.set('debug', true) 등 각기 다른 방식 사용
  • 의존성 딜레마: winston, Pino 같은 애플리케이션 중심 라이브러리 사용 시 사용자에게 원치 않는 의존성과 설정 강요
  • 침묵 vs 강요: 로깅을 아예 포기하거나 사용자에게 로깅 방식을 강제하는 양극단 선택지
  • 의존성 주입의 복잡성: 더 정교한 접근법이지만 API 복잡도 증가와 사용자 부담 가중

LogTape의 "라이브러리 우선" 철학

  • 조건부 활성화: 로깅이 설정되지 않으면 완전한 무작동, 설정되면 통합 관리
  • 사용자 선택권 보장: 라이브러리가 로깅 방식을 강제하지 않고 사용자가 원할 때만 활성화
  • 제로 의존성: 5.3KB 크기로 공급망 보안 위험 제거 및 버전 충돌 방지
  • ESM/CJS 완전 지원: 호환성 체인 문제 해결 및 tree shaking을 통한 번들 최적화

실용적 장점들

  • 성능 최적화: 비활성화 시 거의 제로 오버헤드, 활성화 시 우수한 콘솔 출력 성능
  • 네임스페이스 분리: ["my-lib", "feature"] 형태의 계층적 카테고리로 충돌 방지
  • TypeScript 우선 설계: 추가 타입 패키지 없이 완전한 타입 안전성 제공
  • 기존 시스템과의 브리징: winston, Pino 어댑터를 통한 점진적 도입 지원

현실적 고려사항

  • 어댑터의 의미: 아직 생태계 표준이 아닌 현실 인정과 실용적 타협책
  • Python 생태계 영감: 표준 logging 라이브러리로 통합된 Python의 성공 사례 참조
  • 미래 지향적 접근: 라이브러리 생태계의 점진적 개선을 위한 하나의 선택지로 제시

어떻게 해야 설정을 안했을 때 무작동인지 이해가 잘 안되네요.
getLogger를 할 때 이미 로거를 생성하고 debug를 찍으면 작동하는데 말이죠.

제가 코드를 봤을 때는 그저 작동하지않는 것 처럼 보이게하는 거고
string연산을 늦춰주는것도 아니기에
그저 로그레벨 설정하면 찍어주지않는 타 라이브러리랑 무작동이 어떻게 다른지 이해가 잘안되네요

어라, configure()/configureSync()를 호출하지 않았는데도 로그가 찍히나요? 어디에 찍히나요? 콘솔 화면에 찍히나요?

아, 여기서 이야기하는 작동하다는 console이나 file에 로그가 저장되는것을 의미하는 것이 아니라, 함수가 실행되어 실질적으로 오버헤드가 있냐를 이야기 드렸던겁니다.

오해가 있을법하네요

물론 로거의 주 오버헤드가 system call인걸로 미루어보았을 때 오버헤드가 없다고는 볼 수 있지만
그게 타 로거와의 차별점이냐?라고 하기에는 타 로거 또한 동일하게 동작하기에 그렇다는거죠

아하, 그런 말씀이셨군요. 일단 null output 기준으로 벤치마크를 돌려 봤을 때는 오버헤드가 거의 없다고 볼 수 있겠더라고요. 하지만, 성능적인 오버헤드보다 좀 더 중요하다고 생각했던 건 디폴트 동작이 no-op이냐 아니냐에 있다고 봤습니다. 라이브러리 저자 입장에서는 라이브러리 내에서 로그를 찍더라도 라이브러리를 사용하는 애플리케이션이 실행될 때 멋대로 콘솔이나 파일에 로그가 출력되면 곤란하니까요.

아하, SHOW GN이였네요.
요즘 생태계는 로거를 외부에서 주입받는 형태를 많이 선택하다보니 공감이 안됐던것도 있는 것 같습니다.
설정되지않으면 당연히 작동하지않으니까요.
그래도 지금까지 해당 생태계에 없던 로거 인터페이스기도 하고, 자유도가 높다보니 더 좋은 것 같습니다.

주신 벤치마크 기준의 경우 system call을 제외하고 null output을 출력하다보니
이 부분에 대해서는 내부 로거 형태에 따라서 확실히 다를 수 있다고 생각이되네요.

이 부분에서는 Pino와 세배까지 차이를 가져가는군요. 크


FYI: 추가로 제가 말씀드렸던 외부에서 주입받는 로거의 형태는 Openai Node sdk만 보셔도 로거를 외부에서 주입받아서 출력을 하는 형태라서 쉽게 확인해보실 수 있을 것 같습니다.