본문으로 건너뛰기

디버그 로깅

chat()이 예상대로 동작하지 않을 수 있습니다. 청크가 누락되거나, 미들웨어가 실행되지 않거나, 도구 호출의 인수가 잘못된 경우입니다. 이 가이드를 마치면 디버그 로깅을 활성화하고 호출을 통과하는 모든 청크, 미들웨어 변환 및 도구 호출을 확인할 수 있습니다.

활성화

모든 activity 호출에 debug: true를 추가합니다.

import { chat } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";

const stream = chat({
adapter: openaiText("gpt-5.5"),
messages: [{ role: "user", content: "Hello" }],
debug: true,
});

이제 모든 내부 이벤트가 [tanstack-ai:<category>] 접두사와 함께 콘솔에 출력됩니다.

[tanstack-ai:request] activity=chat provider=openai model=gpt-5.5 messages=1 tools=0 stream=true
[tanstack-ai:agentLoop] run started
[tanstack-ai:provider] provider=openai type=response.output_text.delta
[tanstack-ai:output] type=TEXT_MESSAGE_CONTENT
...

출력 범위 좁히기

true 대신 DebugConfig 객체를 전달합니다. 지정하지 않은 모든 카테고리는 기본적으로 true이므로 특정 플래그를 false로 설정하여 전환합니다.

import { chat } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";

chat({
adapter: openaiText("gpt-5.5"),
messages: [{ role: "user", content: "Hello" }],
debug: { middleware: false }, // everything except middleware
});

특정 카테고리만 보려면 나머지를 명시적으로 false로 설정합니다. 오류는 기본적으로 true이므로 완전히 조용하게 해야 하는 경우가 아니라면 활성 상태로 유지합니다.

import { chat } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";

chat({
adapter: openaiText("gpt-5.5"),
messages: [{ role: "user", content: "Hello" }],
debug: {
provider: true,
output: true,
middleware: false,
tools: false,
agentLoop: false,
config: false,
errors: true, // keep errors on — they're cheap and important
request: false,
},
});

자체 로거로 전달

Logger 구현을 전달하면 모든 디버그 출력이 console 대신 해당 로거를 통해 전달됩니다.

import { chat, type Logger } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";
import pino from "pino";
import { messages } from "./server";

const pinoLogger = pino();
const logger: Logger = {
debug: (msg, meta) => pinoLogger.debug(meta, msg),
info: (msg, meta) => pinoLogger.info(meta, msg),
warn: (msg, meta) => pinoLogger.warn(meta, msg),
error: (msg, meta) => pinoLogger.error(meta, msg),
};

chat({
adapter: openaiText("gpt-5.5"),
messages,
debug: { logger }, // all categories on, piped to pino
});

기본 로거는 ConsoleLogger로 내보내므로 이를 감싸서 사용할 수 있습니다.

import { ConsoleLogger } from "@tanstack/ai";

Logger는 try/catch로 감싸집니다

Logger 구현에서 예외가 발생하면(순환 메타에 대한 JSON.stringify, 동기적으로 거부하는 전송 계층, 바인딩된 this의 오타 등) 해당 예외를 삼켜 로그 호출을 발생시킨 실제 오류(예: chat 스트림 내부의 프로바이더 SDK 실패)를 가리지 않도록 합니다. 로그 줄은 표시되지 않지만 파이프라인 오류는 발생한 예외와 RUN_ERROR 청크를 통해 계속 표면화됩니다.

자체 로거의 실패 시점을 알아야 한다면 구현 내부에서 보호합니다.

import { type Logger } from "@tanstack/ai";
import pino from "pino";

const pinoLogger = pino();
const logger: Logger = {
debug: (msg, meta) => {
try {
pinoLogger.debug(meta, msg);
} catch (err) {
// surface to wherever you track infra errors
process.stderr.write(`logger failed: ${String(err)}\n`);
}
},
info: (msg, meta) => pinoLogger.info(meta, msg),
warn: (msg, meta) => pinoLogger.warn(meta, msg),
error: (msg, meta) => pinoLogger.error(meta, msg),
};

카테고리 참조

카테고리기록 내용적용 대상
request프로바이더로 보내는 호출(모델, 메시지 수, 도구 수)모든 activity
provider프로바이더 SDK에서 받은 모든 원시 청크/프레임스트리밍 activity (chat, realtime, 스트리밍 generateAudio/generateSpeech/generateTranscription)
output호출자에게 전달되는 모든 청크 또는 결과모든 activity
middleware각 미들웨어 훅 전후의 입력과 출력chat()만 해당
tools도구 호출 실행 전후chat()만 해당
agentLoop에이전트 루프 반복과 단계 전환chat()만 해당
config미들웨어 onConfig 훅이 반환한 설정 변환chat()만 해당
errors파이프라인 어디에서든 포착된 모든 오류모든 activity

오류는 항상 기록됩니다

오류는 debug를 생략해도 조건 없이 로거를 통과합니다.

import { chat } from "@tanstack/ai";
import { adapter } from "./server";

chat({ adapter, messages: [{ role: "user", content: "Hello" }] }); // still prints [tanstack-ai:errors] ... on failure

오류를 포함해 완전히 침묵시키려면 debug: false 또는 debug: { errors: false }로 설정합니다. 오류는 발생한 예외 또는 RUN_ERROR 스트림 청크를 통해 호출자에게도 항상 전달됩니다. 로거는 추가적인 표면일 뿐 유일한 오류 전달 경로가 아닙니다.

chat 외의 활동

동일한 debug 옵션이 모든 activity에서 작동합니다.

import {
summarize,
generateImage,
generateSpeech,
generateAudio,
generateTranscription,
type Logger,
} from "@tanstack/ai";
import { adapter } from "./server";
import { logger } from "./logger";

const text = "Long article to summarize...";
const audio = new File([""], "recording.mp3", { type: "audio/mpeg" });

summarize({ adapter, text, debug: true });
generateImage({ adapter, prompt: "a cat", debug: { logger } });
generateSpeech({ adapter, text, debug: { request: true } });
generateAudio({ adapter, prompt: "ambient piano", debug: true });
generateTranscription({ adapter, audio, debug: { provider: true } });

이 중 하나를 스트리밍할 때(generateAudio, generateSpeech, stream: truegenerateTranscription), provider 카테고리는 원시 SDK 청크를 내보내고 output은 호출자에게 전달되는 AG-UI 형태의 청크를 내보냅니다. 미디어 파이프라인이 멈춘 것처럼 보이거나 도착한 바이트가 예상과 다를 때 유용합니다.

chat 전용 카테고리(middleware, tools, agentLoop, config)는 해당 activity의 파이프라인에 이런 개념이 없으므로 실행되지 않습니다.

미들웨어를 만들면서 미들웨어를 통과하는 청크를 확인하려면 로깅 미들웨어를 작성하는 것보다 debug: { middleware: true }를 사용하는 편이 빠릅니다. 자체 미들웨어 작성 방법은 미들웨어를 참고합니다.