디버그 로깅
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: true인 generateTranscription), provider 카테고리는 원시 SDK 청크를 내보내고 output은 호출자에게 전달되는 AG-UI 형태의 청크를 내보냅니다. 미디어 파이프라인이 멈춘 것처럼 보이거나 도착한 바이트가 예상과 다를 때 유용합니다.
chat 전용 카테고리(middleware, tools, agentLoop, config)는 해당 activity의 파이프라인에 이런 개념이 없으므로 실행되지 않습니다.
관련 항목
미들웨어를 만들면서 미들웨어를 통과하는 청크를 확인하려면 로깅 미들웨어를 작성하는 것보다 debug: { middleware: true }를 사용하는 편이 빠릅니다. 자체 미들웨어 작성 방법은 미들웨어를 참고합니다.