Audit logs API
Document Management SDK의 Audit Logs는 파일·사용자·관리 활동을 Document Governance SDK 연동 구조를 통해 수집·저장하고 조회할 수 있도록 구현한 사례입니다. Storage와 Editor의 활동이 하나의 증적 기록으로 연결되는 구조는 Governance Integration에서 확인할 수 있습니다.
tenant의 감사 기록을 읽는 두 개의 읽기 전용 endpoint입니다. 페이지 단위 조회와, 기간 전체를 내려받는 CSV 내보내기입니다.
Base URL과 인가
/api/external/v1/admins/audit-logs
이 endpoint들은 ADMIN 역할을 가진 계정으로 발급된 API Key가 필요합니다. 인가는 역할만으로 결정되며 키의
scope는 검사하지 않습니다. 두 endpoint 모두 읽기 전용이므로 api:read만 가진 키도 api:write를 가진 키와
동일하게 동작합니다.
조회 대상 tenant는 호출한 키를 기준으로 서버가 고정합니다. 다른 tenant를 지정하는 요청 파라미터는 없습니다.
tenant는 요청 host로 판별하므로 키를 발급받은 도메인으로 호출해야 하며, 다른 도메인으로 호출하면
API_KEY_004로 실패합니다.
governance.audit.enabled=false로 동작하는 환경은 이 endpoint들을 아예 등록하지 않으며 모든 호출이 404가
됩니다. 여기서의 404는 경로가 틀렸다는 뜻이 아니라 기능이 꺼져 있다는 뜻입니다.
데이터 출처
감사 이벤트는 Drive 데이터베이스에 저장되지 않습니다. 거버넌스 서버에 있고, Drive가 거버넌스 조회 API를 프록시합니다. 거버넌스 인증은 서버 사이드에서 처리되므로 호출자에게는 Drive API Key 외에 필요한 것이 없습니다.
이 구조 때문에 알아 둘 점이 하나 있습니다. 거버넌스 어휘를 벗어난 필터 값은 400이 아니라 500으로 돌아옵니다.
거버넌스는 그 값을 400으로 거절하지만 Drive가 이를 RESPONSE_001로 감쌉니다. 모든 필터는 아래에 나열된 값
안에서 보냅니다.
필터 값
eventCategory
| 값 | 포함 범위 |
|---|---|
LOGIN | 로그인, 로그아웃, 계정 잠금 상태 |
FILE_FOLDER | 파일과 폴더 행위 |
SHARE | 공유 |
USER_MANAGEMENT | 사용자와 관리자 계정 관리 |
SETTING | 환경 설정 변경 |
eventCategory는 하나만 보낼 것두 개 이상을 보내면 오류가 아니라 200에 0건이 돌아오며, 이는 "그런 사건이 없음"과 구분되지 않습니다.
2026-09-14 실측: eventCategory=LOGIN&eventCategory=SHARE는 totalCount 0을 반환했습니다. 여러 카테고리를 한
번에 보려면 각 카테고리를 eventTypes로 펼쳐서 보냅니다.
channel
| 값 | 포함 범위 |
|---|---|
WEB | 웹 화면 |
API | 외부 API |
MCP | MCP |
SYSTEM | 사용자 요청 없이 시스템에서 발생 |
outcomeStatus
| 값 | 포함 범위 |
|---|---|
SUCCESS | 동작 성공 |
FAIL | 동작 실패 |
eventType
41개 값이며, 각각 하나의 카테고리에 속합니다.
| 카테고리 | 종류 |
|---|---|
LOGIN | LOGIN, LOGOUT, ACCOUNT_LOCKED_STATUS_CHANGE |
FILE_FOLDER | FILE_CREATE, FILE_UPLOAD, FILE_DOWNLOAD, FILE_PREVIEW, FILE_OPEN, FILE_EDIT, FILE_DELETE, FILE_PERMANENT_DELETE, FILE_RESTORE, FILE_RENAME, FILE_MOVE, FILE_COPY, FOLDER_CREATE, FOLDER_DOWNLOAD, FOLDER_DELETE, FOLDER_PERMANENT_DELETE, FOLDER_RESTORE, FOLDER_RENAME |
SHARE | SHARE_CREATE, SHARE_PERMISSION_CHANGE, SHARE_REMOVE |
USER_MANAGEMENT | USER_CREATE, USER_DELETE, USER_PERMANENT_DELETE, USER_RESTORE, USER_INFO_UPDATE, USER_TWOFACTOR_RESET, USER_PASSWORD_CHANGE, USER_STATUS_CHANGE, ADMIN_CREATE, ADMIN_DELETE, ADMIN_PERMANENT_DELETE, ADMIN_RESTORE, ADMIN_INFO_UPDATE, ADMIN_PASSWORD_CHANGE, ADMIN_STATUS_CHANGE |
SETTING | SETTING_UPDATE, SETTING_ALLOWED_IP_CHANGE |
로그인 성공과 실패는 둘 다 LOGIN으로 기록되며, 구분은 outcomeStatus입니다. 로그아웃만 LOGOUT으로 따로
남습니다. 따라서 LOGIN으로 필터하면 성공과 실패가 함께 나옵니다.
날짜
요청 날짜는 yyyy-MM-dd입니다. 기간은 from 당일 00:00부터 to 다음 날 00:00 직전까지이므로 종료일이
결과에 포함됩니다. 응답의 값은 Asia/Seoul 기준 yyyy-MM-dd HH:mm:ss.SSS입니다.
감사 이벤트 목록 조회
GET /api/external/v1/admins/audit-logs
호출한 키의 tenant를 페이지 번호 방식으로 조회합니다. 정렬은 occurredAt 내림차순으로 고정이며 정렬
파라미터는 없습니다.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
pi | integer | Yes | 페이지 번호, 1부터 |
ps | integer | Yes | 페이지 크기, 1에서 200. 더 큰 값은 거버넌스 상한인 200으로 잘립니다 |
actorEmail | string | No | 행위자 이메일, 정확일치. 부분 검색은 지원하지 않습니다 |
from | string | No | 시작일, 당일 포함 |
to | string | No | 종료일, 당일 포함 |
eventCategory | string | No | 카테고리 값 하나 |
eventTypes | string[] | No | 이벤트 종류, 값마다 한 번씩 반복 |
channel | string | No | WEB, API, MCP, SYSTEM 중 하나 |
outcomeStatus | string | No | SUCCESS 또는 FAIL |
eventTypes는 쉼표로 잇지 않고 반복해서 보냅니다: eventTypes=FILE_RENAME&eventTypes=FILE_MOVE. 개수 제한은
없으며, 실질 상한은 요청 URL 길이로 기본 웹 서버에서 8 KB입니다.
curl -X GET "https://drive.example.com/api/external/v1/admins/audit-logs?pi=1&ps=20&from=2026-09-01&to=2026-09-14&eventCategory=FILE_FOLDER&eventTypes=FILE_RENAME&eventTypes=FILE_MOVE" \
-H "Authorization: Bearer replace-with-your-api-key" \
-H "Content-Type: application/json"
{
"result": true,
"code": 200,
"data": [
{
"eventId": "019b2f58-7f3a-7c21-8e90-4c1f2f2e7840",
"occurredAt": "2026-09-14 14:11:03.510",
"eventType": "FILE_RENAME",
"eventCategory": "FILE_FOLDER",
"actorType": "HUMAN",
"actorName": "First user",
"actorEmail": "user1@example.com",
"objectType": "FILE",
"objectName": "Proposal.pptx",
"objectEmail": null,
"objectPath": "MY/Sales/2026",
"outcomeStatus": "SUCCESS",
"outcomeCode": null,
"channel": "WEB",
"clientIp": "198.51.100.20",
"tenantSeq": "3",
"tenantName": "Example tenant",
"change": {
"before": "Proposal_draft.pptx",
"after": "Proposal.pptx"
},
"targets": null
}
],
"totalCount": 1234,
"pageIndex": 1,
"pageSize": 20
}
목록 응답에는 message가 없습니다. 페이징 값은 totalCount, pageIndex, pageSize로 내려옵니다.
| 필드 | 타입 | 설명 |
|---|---|---|
eventId | string | 거버넌스가 발급한 이벤트 식별자 |
occurredAt | string | 발생 시각 |
eventType | string | 이벤트 종류. eventTypes가 매칭하는 값 |
eventCategory | string | 해당 종류가 속한 상위 분류 |
actorType | string | 행위자 유형. HUMAN |
actorName | string | 행위자 표시 이름 |
actorEmail | string | 행위자 이메일. Drive 계정 id와 같은 값 |
objectType | string | 대상 유형: FILE, FOLDER, USER, SETTING |
objectName | string | 대상 이름 - 파일이나 폴더 이름, 계정 이름 등 |
objectEmail | string | 대상 계정 이메일. 대상이 계정인 경우에만 있고 아니면 null |
objectPath | string | 부모 폴더 기준 대상 경로. 맨 앞 세그먼트는 위치 코드로 MY는 내 드라이브, SHARE는 공유 문서함 |
outcomeStatus | string | SUCCESS 또는 FAIL |
outcomeCode | string | 실패 사유 코드. 실패 건에만 있고 아니면 null |
channel | string | 요청이 들어온 경로 |
clientIp | string | 요청 클라이언트 IP |
tenantSeq | string | tenant 식별자. 거버넌스 scope id |
tenantName | string | tenant 이름. 거버넌스 scope 이름 |
change | object | 변경 전후를 담은 {before, after, summary}. 변경성 이벤트에만 |
targets | object[] | 공유 대상자 등 대상 목록. 해당하는 이벤트에만 |
{
"result": false,
"code": 400,
"errorCode": "REQUEST_001",
"message": "[{msg=must not be null, field=pi}]"
}
감사 이벤트 CSV 내보내기
GET /api/external/v1/admins/audit-logs/export
조건에 맞는 기간 전체를 CSV로 내려받습니다. 목록 조회와 같은 필터를 받되 페이징 파라미터는 받지 않으며, 본문은 JSON 봉투 없는 CSV 원문입니다.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
from | string | No | 시작일, 당일 포함. 비우면 to의 92일 전 |
to | string | No | 종료일, 당일 포함. 비우면 현재 시각 |
actorEmail | string | No | 행위자 이메일, 정확일치 |
eventCategory | string | No | 카테고리 값 하나 |
eventTypes | string[] | No | 이벤트 종류, 값마다 한 번씩 반복 |
channel | string | No | WEB, API, MCP, SYSTEM 중 하나 |
outcomeStatus | string | No | SUCCESS 또는 FAIL |
기간 상한은 92일입니다. 두 날짜를 모두 비우면 최근 92일이 적용되고, 그보다 긴 구간은 400으로 거절됩니다. 달력 기준 한 분기가 89일에서 92일이므로 92일이면 어떤 3개월 구간도 담깁니다. 더 긴 기간이 필요하면 구간을 나눠 여러 번 호출합니다.
pi와 ps는 이 endpoint에서 쓰지 않으며 보내도 무시됩니다. 응답은 한 페이지가 아니라 기간 전체입니다.
curl -X GET "https://drive.example.com/api/external/v1/admins/audit-logs/export?from=2026-06-01&to=2026-09-01&eventCategory=SHARE" \
-H "Authorization: Bearer replace-with-your-api-key" \
-o audit-events.csv
| 응답 헤더 | 값 |
|---|---|
Content-Type | text/csv |
Content-Disposition | attachment; filename*=UTF-8''audit-events_20260601-20260901.csv |
Content-Length | 없음 - 본문을 조각으로 나눠 보내므로 전체 크기를 미리 알 수 없습니다 |
파일 이름은 audit-events_{from}-{to}.csv 형식입니다.
schemaVersion,eventId,eventType,sourceEventType,occurredAt,origin.system,…,observedIp,ingestKeyId
1.0,019b2f58-7f3a-7c21-8e90-4c1f2f2e7840,FILE_RENAME,FILE_RENAME,2026-07-16T05:11:03.510Z,TFD,…,198.51.100.20,key-acme-01
파일 규격은 거버넌스 원본 그대로입니다. BOM이 붙은 UTF-8, CRLF 줄 끝, RFC 4180 따옴표, 순서가 계약의 일부인 44개 열, 그리고 수식으로 읽힐 수 있는 값 앞의 작은따옴표입니다. 목록 응답보다 열이 많습니다.
{
"result": false,
"code": 400,
"message": "감사 로그 내보내기 기간은 최대 92일입니다."
}
내보내기 실패는 공통 봉투의 예외입니다. errorCode가 없습니다.
응답은 조각으로 나뉘어 전송됩니다. 첫 조각을 보낸 시점에 이미 200이 나갔으므로, 그 뒤의 실패는 응답이 도중에 끊기는 것으로만 나타납니다. 규격을 지키는 HTTP 클라이언트는 마지막 조각이 오지 않는 것을 오류로 처리하며 잘린 파일을 받아들이지 않지만, 받은 내용이 완결되었는지 확인할 책임은 여전히 클라이언트에 있습니다.
긴 기간은 스트리밍으로 파일에 저장합니다. 한 행이 약 1,450바이트이므로 10만 행이면 약 138 MB입니다. 응답
전체를 메모리에 올리는 방식 - 브라우저 Blob, 문자열 변환 등 - 은 기간이 길면 실패할 수 있습니다. curl -o나
스트림 복사로 파일에 바로 흘려 쓰는 방식을 권합니다.
동시 실행은 서버 인스턴스당 10건까지이며 tenant를 구분하지 않고 셉니다. 11건째부터 429가 반환되고 목록 조회는 영향을 받지 않습니다. 429는 재시도해도 안전합니다.
{
"result": false,
"code": 429,
"message": "다른 내보내기가 진행 중입니다. 잠시 뒤 다시 시도해 주세요."
}
에러
| 코드 | 상태 | 의미 |
|---|---|---|
API_KEY_004 | 401 | 인증 실패 - 헤더 누락, 알 수 없는 값, 비활성이거나 만료된 키, 비활성 계정, 다른 tenant의 도메인 |
AUTH_009 | 403 | 호출한 키가 ADMIN 역할이 아님 |
REQUEST_001 | 400 | 검증 실패. message에 걸린 필드가 담깁니다. pi나 ps 누락, 또는 1 미만 등 |
RESPONSE_001 | 500 | 거버넌스 조회 실패. 거버넌스 어휘를 벗어난 필터 값도 포함 |
API가 반환하는 전체 코드 목록은 Errors를 참고합니다.