SDK API 레퍼런스 v0.5.0
@dicolytics/discord.js 패키지의 공개 API 전체를 정리합니다.
createDicolytics
SDK 인스턴스를 생성하고 discord.js 클라이언트에 리스너를 등록합니다. new Dicolytics(client, options).attach()와 동일합니다.
function createDicolytics(
client: Client,
options: DicolyticsOptions
): Dicolyticsdef create_dicolytics(
bot: discord.Bot,
**options: DicolyticsOptions
) -> Dicolytics매개변수
| 매개변수 | 타입 | 설명 |
|---|---|---|
client | Client | discord.js v14 클라이언트 인스턴스 |
options | DicolyticsOptions | 설정 옵션 참고 |
반환값
Dicolytics 인스턴스를 반환합니다.
예외
| 조건 | 동작 |
|---|---|
apiKey가 비어 있거나 누락 | TypeError 동기 예외 |
client에 이미 SDK 인스턴스가 연결됨 | Error 동기 예외 |
| 그 외 옵션 오류 | 기본값으로 대체 (예외 없음) |
사용 예시
import { Client, GatewayIntentBits } from 'discord.js';
import { createDicolytics } from '@dicolytics/discord.js';
const client = new Client({
intents: [GatewayIntentBits.Guilds],
});
const analytics = createDicolytics(client, {
apiKey: process.env.DICOLYTICS_KEY!,
});
client.login(process.env.DISCORD_TOKEN);import os
import discord
from dicolytics import create_dicolytics
bot = discord.Bot()
analytics = create_dicolytics(bot, api_key=os.environ["DICOLYTICS_KEY"])
bot.run(os.environ["DISCORD_TOKEN"])const analytics = createDicolytics(client, {
apiKey: process.env.DICOLYTICS_KEY!,
endpoint: 'https://analytics.example.com',
debug: true,
});analytics = create_dicolytics(bot,
api_key=os.environ["DICOLYTICS_KEY"],
endpoint="https://analytics.example.com",
debug=True,
)const analytics = createDicolytics(client, {
apiKey: process.env.DICOLYTICS_KEY!,
clusterId: Number(process.env.CLUSTER_ID),
});analytics = create_dicolytics(bot,
api_key=os.environ["DICOLYTICS_KEY"],
cluster_id=int(os.environ["CLUSTER_ID"]),
)DicolyticsOptions
createDicolytics의 두 번째 인자로 전달하는 설정 객체입니다.
interface DicolyticsOptions {
apiKey: string;
endpoint?: string;
disabledEvents?: readonly string[];
debug?: boolean;
snapshotIntervalMs?: number;
flushIntervalMs?: number;
requestTimeoutMs?: number;
clusterId?: number;
autoCapturePromiseRejections?: boolean;
}# create_dicolytics()의 키워드 인자로 전달
api_key: str # 필수
endpoint: str = "https://api.dicolytics.com"
disabled_events: list[str] = []
debug: bool = False
snapshot_interval_ms: int = 60000
flush_interval_ms: int = 5000
request_timeout_ms: int = 10000
cluster_id: int | None = None
auto_capture_exceptions: bool = False| 옵션 | 타입 | 기본값 | 최솟값 | 설명 |
|---|---|---|---|---|
apiKey | string | (필수) | -- | 프로젝트 API 키 (dk_live_... 형식) |
endpoint | string | https://api.dicolytics.com | -- | API 기본 URL |
disabledEvents | string[] | [] | -- | 비활성화할 이벤트 타입 |
debug | boolean | false | -- | 진단 로그 출력 |
snapshotIntervalMs | number | 60000 | 10000 | 스냅샷 주기 (ms) |
flushIntervalMs | number | 5000 | 250 | 플러시 주기 (ms) |
requestTimeoutMs | number | 10000 | 1000 | HTTP 타임아웃 (ms) |
clusterId | number | -- | 0 (최대 32767) | 클러스터 식별자 |
autoCapturePromiseRejections | boolean | false | -- | 미처리 rejection 자동 보고 |
각 옵션의 상세 설명은 설정 옵션을 참고하세요.
track()
커스텀 이벤트를 기록합니다.
analytics.track(name: string, props?: Record<string, unknown>): voidanalytics.track(name: str, props: dict[str, Any] | None = None) -> None매개변수
| 매개변수 | 타입 | 설명 |
|---|---|---|
name | string | 이벤트 이름 (최대 256바이트 UTF-8, 앞뒤 공백 자동 제거) |
props | Record<string, unknown> / dict | 속성 (최대 50키, 키당 100자, 전체 8 KiB) |
사용 예시
// 이름만
analytics.track('daily_reward_claimed');
// 이름 + 속성
analytics.track('purchase', {
sku: 'premium_role',
amount: 1500,
currency: 'KRW',
guildId: interaction.guildId,
});
// 다양한 속성 타입
analytics.track('level_up', {
userId: member.id,
newLevel: 42,
isVIP: true,
achievedAt: new Date(), // ISO-8601 문자열로 변환됨
});# 이름만
analytics.track("daily_reward_claimed")
# 이름 + 속성
analytics.track("purchase", {
"sku": "premium_role",
"amount": 1500,
"currency": "KRW",
"guild_id": str(interaction.guild_id),
})
# 다양한 속성 타입
analytics.track("level_up", {
"user_id": str(member.id),
"new_level": 42,
"is_vip": True,
"achieved_at": datetime.now().isoformat(),
})절대 throw하지 않음
track()은 어떤 상황에서도 예외를 던지지 않습니다. SDK 내부 오류는 무시되며, 봇 동작에 영향을 주지 않습니다.
자세한 사용법과 예시는 커스텀 이벤트를 참고하세요.
captureError()
오류를 명시적으로 보고합니다. error 타입 이벤트로 전송됩니다.
analytics.captureError(
error: unknown,
context?: Record<string, unknown>
): voidanalytics.capture_error(
exc: BaseException,
context: dict[str, Any] | None = None,
) -> None매개변수
| 매개변수 | 타입 | 설명 |
|---|---|---|
error / exc | unknown / BaseException | 오류 객체. Error 인스턴스가 아니어도 처리됩니다. |
context | Record<string, unknown> / dict | 추가 컨텍스트 (선택) |
context에 사용 가능한 특수 키
| 키 | 타입 | 설명 |
|---|---|---|
guildId | string | 서버 ID (envelope의 guild_id에 설정됨) |
channelId | string | 채널 ID (envelope의 channel_id에 설정됨) |
userId | string | 사용자 ID (envelope의 user_id에 설정됨) |
위 키 외의 나머지 context 항목들은 이벤트 data 내부에 포함됩니다.
오류 필드 제한
| 필드 | 최대 크기 |
|---|---|
name | 200자 |
message | 2 KiB |
stack | 8 KiB |
사용 예시
try {
await riskyOperation();
} catch (err) {
analytics.captureError(err, {
userId: interaction.user.id,
guildId: interaction.guildId,
operation: 'risky_operation',
additionalInfo: 'some context',
});
}try:
await risky_operation()
except Exception as exc:
analytics.capture_error(exc, {
"user_id": interaction.user.id,
"guild_id": interaction.guild_id,
"operation": "risky_operation",
"additional_info": "some context",
})절대 throw하지 않음
captureError()는 어떤 상황에서도 예외를 던지지 않습니다. 오류 보고가 실패해도 봇 동작에 영향을 주지 않습니다.
Error가 아닌 값 처리
| 입력 타입 | 처리 방식 |
|---|---|
Error 인스턴스 | name, message, stack 추출 |
string | message로 사용, name은 "Error" |
| 그 외 | String(value)를 message로 사용 |
flush()
대기 중인 모든 이벤트를 즉시 서버로 전송합니다.
analytics.flush(): Promise<void>await analytics.flush() -> None동작
- 이벤트 큐의 모든 대기 이벤트를 배치로 묶어 전송합니다.
- 전송이 완료될 때까지 기다립니다.
- 실패해도 절대 reject하지 않습니다.
사용 시점
일반적으로 호출할 필요 없습니다. SDK가 자동으로 플러시합니다.
- 50개 이벤트 대기 시 즉시 플러시
- 5초마다 타이머 기반 플러시 (
flushIntervalMs옵션으로 변경 가능)
수동 플러시가 유용한 경우:
// 중요한 이벤트 즉시 전송
analytics.track('critical_purchase', { amount: 99900 });
await analytics.flush();
// 테스트 환경에서 전송 강제
analytics.track('test_event');
await analytics.flush();# 중요한 이벤트 즉시 전송
analytics.track("critical_purchase", {"amount": 99900})
await analytics.flush()
# 테스트 환경에서 전송 강제
analytics.track("test_event")
await analytics.flush()shutdown()
리스너와 타이머를 모두 해제하고 마지막 플러시를 수행합니다.
analytics.shutdown(): Promise<void>await analytics.shutdown() -> None동작
| 단계 | 설명 |
|---|---|
| 1 | 모든 discord.js 이벤트 리스너 제거 |
| 2 | 내부 타이머(setInterval) 해제 |
| 3 | 대기 이벤트 최종 플러시 (최대 3초 대기) |
여러 번 호출해도 안전합니다. 절대 reject하지 않습니다.
자동 종료 처리
SDK는 다음 시그널에 자동으로 종료 플러시를 수행합니다.
| 시그널 | 동작 |
|---|---|
SIGINT | 최대 3초간 플러시 후 시그널 재전달 |
SIGTERM | 최대 3초간 플러시 후 시그널 재전달 |
beforeExit | 최대 3초간 플러시 |
참고
직접 shutdown()을 호출하는 것도 가능하지만, 프로세스 종료 시 SDK가 자동으로 마지막 이벤트를 전송합니다.
타이머 unref
SDK의 모든 내부 타이머는 unref()로 설정됩니다. 즉, SDK 타이머만으로는 Node.js 프로세스가 유지되지 않습니다. 다른 활성 작업이 없으면 프로세스가 정상 종료됩니다.
전달 의미론
SDK의 이벤트 전달 동작을 요약합니다. 자세한 내용은 전송과 재시도를 참고하세요.
| 항목 | 동작 |
|---|---|
| 이벤트 ID | UUIDv7 (RFC 9562). 재시도 시 동일 ID 재사용 → 서버 측 중복 제거 |
| 엔벨로프 | POST {endpoint}/v1/events -- 배치당 최대 500개 / 1 MiB |
| 플러시 | 50개 대기 또는 5초마다. 동시 요청 1개 (순서 보장) |
| 재시도 | 5xx/네트워크 오류 시 지수 백오프 (최대 5회). 400은 드롭. 401은 전송 비활성화 |
| 429 | Retry-After 준수 (기본 300초). heartbeat/guild_snapshot은 계속 전송 |
| 버퍼 | 최대 5,000개 (초과 시 오래된 이벤트부터 삭제) |
| 종료 | SIGINT/SIGTERM 시 최대 3초간 플러시 후 시그널 재전달 |
| 타이머 | 모든 타이머 unref() -- SDK가 프로세스를 유지하지 않음 |
내보내기 (exports)
@dicolytics/discord.js 패키지에서 내보내는 전체 목록입니다.
// 클래스 & 팩토리
export { Dicolytics, createDicolytics };
// 타입
export type {
DicolyticsOptions,
AnalyticsEvent,
EventEnvelope,
IngestAcceptedResponse,
SdkInfo,
DisableableEvent,
EventType,
};
// 상수
export { EVENT_TYPES, SDK_NAME, SDK_VERSION };EVENT_TYPES
모든 이벤트 타입 문자열을 담은 상수 객체입니다. disabledEvents 옵션에 사용할 수 있습니다.
import { createDicolytics, EVENT_TYPES } from '@dicolytics/discord.js';
const analytics = createDicolytics(client, {
apiKey: '...',
disabledEvents: [
EVENT_TYPES.eventTypingStart, // 'event_typing_start'
EVENT_TYPES.eventPresenceUpdate, // 'event_presence_update'
],
});from dicolytics import create_dicolytics
analytics = create_dicolytics(bot,
api_key="...",
disabled_events=[
"event_typing_start",
"event_presence_update",
],
)전체 EVENT_TYPES 목록은 이벤트 레퍼런스를 참고하세요.