npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@point3/observability

v0.3.1

Published

OpenTelemetry SDK wrapper for Point3 services

Readme

@point3/observability

Point3 서비스용 OpenTelemetry SDK 래퍼. import 한 줄로 traces, metrics, logs 수집이 시작된다.

설치

npm install @point3/observability

@opentelemetry/api는 peer dependency로 자동 설치된다 (npm v7+).

사용법

기본 (제로 설정)

main.ts 최상단에 side-effect import 추가. 반드시 dotenv/config 다음, 모든 애플리케이션 import 전에 위치해야 한다. OTel의 monkey-patching이 모듈 로드 전에 적용되어야 하기 때문.

import "dotenv/config";
import "@point3/observability";

import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";

서비스명은 package.jsonname 필드에서 자동으로 읽는다. 별도 설정 불필요.

커스텀 설정

instrumentation 추가, exporter 교체 등이 필요한 경우 register() 함수를 사용한다. ESM import hoisting 때문에 반드시 별도 파일로 분리해야 한다.

// src/observability.ts
import { register } from "@point3/observability/register";

register({
  instrumentations: (defaults) => [...defaults, new PrismaInstrumentation()],
});
// src/main.ts
import "dotenv/config";
import "./observability";

import { NestFactory } from "@nestjs/core";

로깅

register() 호출 시 console.log, console.error 등 표준 콘솔 메서드가 자동으로 패치된다. 패치된 console은 두 가지 일을 동시에 수행한다:

  1. stdout/stderr 출력 — 터미널에서 로그를 바로 확인할 수 있다
  2. OTel LogRecord 전송 — OTLP를 통해 Alloy → Loki로 수집된다

active span이 있으면 trace_idspan_id가 자동으로 LogRecord에 주입되어, Loki에서 Tempo 트레이스로 바로 연결할 수 있다.

console 메서드 → 로그 레벨 매핑

| console 메서드 | 로그 레벨 | 출력 대상 | |---------------|----------|----------| | console.log() | info | stdout | | console.info() | info | stdout | | console.warn() | warn | stdout | | console.error() | error | stderr | | console.debug() | debug | stdout (기본 LOG_LEVEL=info에서 필터됨) |

구조화 로깅

첫 번째 인자가 객체면 message 필드를 로그 메시지로, 나머지 필드를 OTel LogRecord attributes로 자동 추출한다.

// 단순 문자열
console.log("서버 시작됨");

// 구조화 로깅 — orderId, amount가 OTel attributes로 추출됨
console.log({ message: "주문 생성", orderId: "123", amount: 50000 });

// Error 객체 — exception.stacktrace, exception.type이 자동 추가됨
console.error(new Error("결제 실패"));

레벨 필터링

LOG_LEVEL 환경변수로 출력할 최소 레벨을 지정한다. 기본값은 info.

# error, fatal만 출력
LOG_LEVEL=error node main.js

# debug 이상 전부 출력
LOG_LEVEL=debug node main.js

레벨 우선순위: fatal < error < warn < info < debug < verbose

콘솔 패치 비활성화

OTel SDK는 사용하되 console 몽키패치를 원하지 않는 경우:

import { register } from "@point3/observability/register";

register({ patchConsole: false });

커스텀 로거 통합

console 패치 대신 직접 로깅을 제어해야 하는 경우 (예: 컴플라이언스 요구사항으로 PII 로그를 별도 파이프라인으로 분리), 필요 시 emitLog를 직접 사용할 수 있다.

import { register } from "@point3/observability/register";
import { emitLog } from "@point3/observability/log";
import type { LogLevel } from "@point3/observability/log";

register({ patchConsole: false }); // console 자동 패치 비활성화

// 관측 로그 → OTLP → Loki
emitLog("info", ["이체 요청 수신", { requestId: "abc" }]);

// PII 로그 → 별도 처리 (emitLog를 호출하지 않으므로 Loki에 안 감)
auditLogger.write({ accountNumber: "...", amount: 50000 });

Alloy 설정

@point3/observability가 전송하는 OTLP 로그를 Loki로 라우팅하기 위해 Alloy 설정(config.alloy)을 수정한다.

기존 config에서 3줄만 추가하면 된다:

  1. receiver output에 logs 추가
  2. batch processor output에 logs 추가
  3. otelcol.exporter.loki 컴포넌트 추가

전체 표준 config

// ─── OTLP 수신 ───
otelcol.receiver.otlp "app_service" {
    grpc {
        endpoint = "0.0.0.0:4317"
    }
    http {
        endpoint = "0.0.0.0:4318"
    }

    output {
        metrics = [otelcol.processor.batch.default.input]
        traces  = [otelcol.processor.batch.default.input]
        logs    = [otelcol.processor.batch.default.input] 
    }
}

// ─── 배치 처리 ───
otelcol.processor.batch "default" {
    output {
        metrics = [otelcol.exporter.prometheus.app_service.input]
        traces  = [otelcol.exporter.otlp.tempo.input]
        logs    = [otelcol.exporter.loki.default.input] 
    }
}

// ─── Metrics → Prometheus ───
otelcol.exporter.prometheus "app_service" {
    forward_to = [prometheus.remote_write.default.receiver]
}

// ─── Traces → Tempo ───
otelcol.exporter.otlp "tempo" {
    client {
        endpoint = "<TEMPO_HOST>:4317"
        tls {
            insecure = true
        }
    }
}

otelcol.exporter.loki "default" {
    forward_to = [loki.write.default.receiver]
}

prometheus.remote_write "default" {
    endpoint {
        url = "http://<PROMETHEUS_HOST>:9090/api/v1/write"
    }
}

loki.write "default" {
    endpoint {
        url = "http://<LOKI_HOST>:3100/loki/api/v1/push"
    }
}

변경 요약

| # | 위치 | 변경 | |---|------|------| | 1 | otelcol.receiver.otlp output | logs = [otelcol.processor.batch.default.input] 추가 | | 2 | otelcol.processor.batch output | logs = [otelcol.exporter.loki.default.input] 추가 | | 3 | 새 컴포넌트 | otelcol.exporter.loki "default" → 기존 loki.write.default 재사용 |

otelcol.exporter.loki는 OTel 리소스 속성 service.name을 Loki 레이블 service_name으로 자동 변환한다. 별도 transform 프로세서가 필요 없다.

내보내기 목록

| export | 설명 | |--------|------| | emitLog(level, args) | OTel LogRecord 전송 + stdout/stderr 출력 | | shouldLog(level) | LOG_LEVEL 기준 해당 레벨 출력 여부 | | getConfiguredLogLevel() | 현재 설정된 로그 레벨 반환 | | getOriginalConsole() | 패치 이전의 원본 console 메서드 | | patchConsole() / unpatchConsole() | console 패치 수동 제어 | | LogLevel, LogEntry | 타입 |

환경변수

| 변수 | 설명 | 기본값 | |------|------|--------| | OTEL_SERVICE_NAME | 서비스 이름 (최우선) | package.json name | | OTEL_SERVICE_VERSION | 서비스 버전 | package.json version | | OTEL_EXPORTER_OTLP_ENDPOINT | OTLP 수신 엔드포인트 | http://alloy:4318 | | LOG_LEVEL | 로그 출력 레벨 (error, warn, info, debug, verbose) | info | | NODE_ENV | 실행 환경 | — |

설정 우선순위: 환경변수 > register() 옵션 > package.json > 기본값

기본 동작

설정 없이 import만 하면 아래가 자동으로 구성된다:

  • Exporters: OTLP HTTP (traces, metrics, logs) → http://alloy:4318
  • Instrumentations: getNodeAutoInstrumentations() + RuntimeNodeInstrumentation
  • Metric 전송 간격: 2000ms
  • 런타임 계측 정밀도: 2000ms
  • Graceful Shutdown: SIGINT, SIGTERM 시 SDK 종료 후 process.exit()

진입점

| import 경로 | 동작 | |------------|------| | @point3/observability | side-effect — import 시 즉시 SDK 시작 | | @point3/observability/register | register() 함수만 export, side-effect 없음 | | @point3/observability/log | emitLog, patchConsole 등 로그 유틸리티 export |

@point3/observability를 import하면 내부적으로 register()를 옵션 없이 호출한다. 커스텀이 필요하면 @point3/observability/register에서 직접 호출.

빌드

npm run build      # tsup으로 ESM + CommonJS 듀얼 빌드

출력: dist/.js(ESM), .cjs(CJS), .d.ts(타입), .map(소스맵)