호출과 쿼리
요청, cron 실행, 큐 배치, 이메일마다 하나씩 남는 기록과 그 위의 Query Builder, 저장한 쿼리, 로그 패턴, 요청 하나의 상세 보기를 설명합니다.
워커가 호출될 때마다 기록이 남습니다. 요청 ID, 시각, 핸들러, 메서드, 호스트, 경로, 라우트, 상태, 실제 경과 시간, 배포 버전, 결과입니다. 이 기록은 워커가 아니라 Runlot의 프런트가 남기므로 샘플링되지 않으며, 요청 도중 프로세스가 죽어도 남습니다. 사용량 차트가 세는 것과 같은 관측이므로, 요청이 몇 개였는지에 대해 둘이 다를 수 없습니다.
내용이 수집 대상이면 기록에는 해당 호출의 콘솔 줄, 예외, 스팬도 함께 담깁니다.
결과
결과는 핸들러에 무슨 일이 있었는지를 Cloudflare Workers와 같은 용어로 나타냅니다.
| 결과 | 의미 |
|---|---|
ok | 핸들러가 반환했습니다. 500을 반환한 핸들러도 ok입니다. 그런 경우는 $response.status로 거르세요 |
exception | 핸들러가 예외를 던졌습니다 |
exceededMemory | 이 요청을 처리하는 동안 프로젝트 자체의 메모리 한도 때문에 프로세스가 종료되었습니다 |
exceededCpu, exceededWallTime | 런타임 한도가 요청을 끝냈습니다 |
canceled | 응답하기 전에 클라이언트가 떠났습니다 |
internalError | 프로세스가 시그널로 종료되었습니다. 기록에 시그널 이름이 남습니다 |
메모리 때문에 종료된 프로세스는 처리 중이던 요청을 모두 함께 끝내며, 그 요청들은 아무것도 보고할 수 없습니다. Runlot이 나중에 이 요청들을 프로세스의 종료 기록과 맞추므로, 각 요청에 한도와 최고 사용량이 함께 exceededMemory로 표시됩니다.
Query Builder
Observability → Invocations에서 Query Builder를 엽니다. 보기(calculations, invocations, events, traces)를 고른 다음 필터, 검색어, 계산, 그룹 키를 지정합니다. 같은 쿼리를 JSON으로 쓸 수 있고, CLI가 이를 실행합니다.
{
"timeframe": { "last": "24h" },
"view": "calculations",
"filters": [{ "key": "$response.status", "op": "gte", "value": 500 }],
"calculations": [{ "op": "count" }, { "op": "p99", "key": "$wall_ms" }],
"groupBy": ["$route"],
"orderBy": { "calc": 0, "dir": "desc" },
"limit": 20
}runlot logs query --file q.json # a table
runlot logs query --file q.json --json # the raw result- 기본 제공 키는
$로 시작합니다.$request.path,$request.method,$response.status,$route,$wall_ms,$outcome,$event_type,$deployment.version,$level,$message,$source,$request_id,$span.name,$duration_ms,$region,$country등이 있습니다. 직접 만든 키에는 접두사가 없습니다.userId처럼 로그로 출력한 객체의 필드이며, 하위 필드는order.total처럼 씁니다. - 연산자:
eq,neq,gt,gte,lt,lte,includes,not_includes,starts_with,regex(RE2),exists,not_exists. 필터는 AND로 결합합니다. - 계산:
count,count_distinct,min,max,sum,avg,stddev,variance, 그리고p001부터p999까지의 백분위수(두 자리는 퍼센트, 세 자리는 퍼밀). - 제한: 필터 20개, 계산 10개, 그룹 키 5개, 1,000행, 쿼리당 10초. 기간은 플랜의 보관 기간으로 잘리며, 잘린 경우 응답에 그렇게 표시됩니다.
SQL은 없습니다. 쿼리는 Runlot이 프로젝트 필터를 추가한 매개변수화된 SQL로 컴파일되므로, 쿼리가 다른 프로젝트의 데이터를 읽을 수는 없습니다.
저장한 쿼리
Query Builder에서 쿼리를 저장하면 URL이 생깁니다. 저장한 쿼리는 프로젝트의 모든 사람에게 보이며, 조직 범위로 저장한 쿼리는 조직의 모든 프로젝트에서 보입니다. 각자 자주 쓰는 쿼리에 별표를 달 수 있습니다. Free는 프로젝트당 저장한 쿼리 10개, Pro는 무제한입니다.
로그 패턴
Patterns 탭은 숫자, ID 같은 가변 토큰을 가린 템플릿으로 로그 줄을 묶고, 패턴마다 개수, 예시 줄, 처음 본 시각, 기간 동안의 추세를 보여 줍니다. 새로 생겼거나 급증한 패턴은 쿼리 없이도 바로 보입니다.
요청 하나
runlot logs request 4bf92f3577b34da6a3ce929d0e0e4736Request 4bf92f3577b34da6a3ce929d0e0e4736
POST my-app.me.runlot.app/checkout → 502 1,204 ms 2026-10-23T03:12:40.118Z
outcome exceededMemory (recorded as workerExited)
route /checkout · v42 · fetch
exit exceededMemory at 2026-10-23T03:12:41.004Z (code -1, SIGKILL, OOM-killed, peak 271 MiB of 256 MiB)
Logs (3)
…
Spans (4)
fetch /checkout |####################| 1,204 ms
db.query SELECT … | #### | 212 ms
…확정된 결과와 그 원인이 된 프로세스 종료, 스택을 포함한 요청의 로그, 스팬의 텍스트 워터폴, 요청이 Runlot Errors에 일으킨 이슈, 그리고 요청이 속한 cron, 큐, 이메일 기록 행을 보여 줍니다. --json은 기록 전체를 출력합니다.
대시보드에서 같은 요청은 /o/<org>/p/<project>/observability/requests/<id>에 있습니다. 로그인한 상태의 오류 페이지는 이곳으로 바로 연결됩니다.
API로 쓰기
위의 모든 기능은 /v1/orgs/{org}/projects/{project}/observability/ 아래의 공개 API입니다. query, keys와 values(Query Builder가 제안하는 추천 필드), patterns, requests/{requestId}, saved-queries가 있습니다. 읽기는 viewer 이상의 역할이 필요하고, 쿼리 저장은 member가 필요합니다. API 레퍼런스를 참고하세요.