cd ~/gh-pm-lab mkdir -p pm-lab
1로그 받기
실제 팀에서는 event-log.sh OWNER/REPO --snapshots pm-lab/pm-data/snapshots로 같은 형식의 파일을 만든다(실습 20). Orbit 로그는 그 결과를 흉내 낸 합성 데이터이므로 키트에서 복사한다.
cp github-pm-starter-kit/samples/orbit-event-log.csv pm-lab/ head -9 pm-lab/orbit-event-log.csv wc -l < pm-lab/orbit-event-log.csv
첫 줄은 열 이름이고, 그 뒤 1,988줄이 사건이다. OB-001은 업무 생성부터 업무 완료까지 7개 사건으로 기본 경로를 그대로 지났다.
| 열 | 역할 | 값의 예 |
|---|---|---|
case_id | 사례 (case). 업무 이슈 하나 | OB-001 |
activity | 활동 (activity). 12종 | PR 생성 |
timestamp | 시각. 지역 시각과 시차 | 2026-03-11T16:54:00+09:00 |
resource | 수행자. GitHub 아이디 | dev-d |
ref | 관련 PR 번호. PR에서 온 사건만 있다 | #1001 |
area | 업무의 영역. 업무 이슈의 첫 area:* 라벨 | engineering |
2세 가지 정의
같은 GitHub 기록으로도 사례, 활동, 시각을 다르게 정하면 다른 로그가 나온다. 분석 결과를 읽는 사람에게는 아래 세 가지를 함께 알려야 한다.
| 정의 | Orbit 로그의 선택 | 다른 선택과 그때 달라지는 것 |
|---|---|---|
| 사례 (case notion) | kind:task 업무 이슈 하나 | PR 하나를 사례로 삼으면 리뷰 흐름은 더 정확해지지만, 업무가 언제 시작했고 막혔는지는 사라진다. 업무 하나에 PR이 둘이면(다시 열린 업무) 업무 사례 안에 PR 활동이 두 번 나온다 |
| 활동 (activity) | 12종. 리뷰 댓글 하나하나, 커밋 하나하나는 넣지 않는다 | 커밋마다 사건을 만들면 사건이 수십 배로 늘고 변형이 사례 수만큼 많아진다. 첫 커밋만 남기는 것은 “개발을 시작한 시점”만 필요하기 때문이다 |
| 시각 (timestamp) | GitHub가 남긴 시각. 작업 시작만 18시 스냅숏에서 온다 | 스냅숏을 하루 두 번 찍으면 작업 시작의 오차가 반으로 준다. Project의 Status 변경 이력은 공개 API로 조회할 수 없으므로(실습 18) 스냅숏 외의 방법은 없다 |
3품질 점검
bash github-pm-starter-kit/log-check.sh pm-lab/orbit-event-log.csv
점검 결과에서 고칠 것이 세 가지 나왔다.
| 발견 | 원인 | 그대로 두면 |
|---|---|---|
| 끝나지 않은 사례 3건 (OB-251, OB-252, OB-256) | 9월 4일 18시에 기록을 뽑았을 때 아직 진행 중이었다 | 처리 시간을 잴 수 없다. 마지막 사건이 변경 요청이나 작업 시작인 사례가 변형과 지도에 섞인다 |
| 작업 시작 260건 모두 18:00:00 | 스냅숏 시각이다 | 작업 시작은 날짜까지만 믿을 수 있다. 시간 단위의 대기를 작업 시작에서 재면 오차가 최대 9업무시간이다 |
| 작업 시작보다 첫 커밋이나 막힘이 먼저인 사례 33건 | 같은 날 18시 전에 막힘 라벨을 붙이거나 커밋했다. 스냅숏은 그보다 늦은 18시에 In Progress를 처음 봤다 | “막힘 → 작업 시작” 같은 실제로는 없던 순서가 지도에 생긴다 |
세 번째 문제가 지도를 얼마나 바꾸는지 원본 로그와 정리한 로그의 process-map.sh 결과로 비교하면 다음과 같다. 정리 방법은 다음 단계에서 다룬다.
| 항목 | 원본 로그 | 정리한 로그 |
|---|---|---|
| 사례 · 사건 | 260 · 1,988 | 257 · 1,975 |
| 변형 수 | 29 | 20 |
| “막힘 → 작업 시작” 연결 | 29회 | 0회 |
| “업무 생성 → 막힘” 연결 | 29회 | 0회 |
| “막힘 → 막힘 해소” 연결 | 9회, 중앙값 1일 | 36회, 중앙값 1.9일 |
원본 로그에서는 막힘 36건 중 27건 사이에 작업 시작이 끼어 “막힘 → 막힘 해소” 연결이 9회로 줄고, 대기 시간 중앙값도 1일로 짧게 나온다. 품질 문제 하나가 병목의 크기를 절반으로 보이게 한다.
4정리한 로그 만들기
bash github-pm-starter-kit/log-check.sh pm-lab/orbit-event-log.csv --clean > pm-lab/orbit-event-log-clean.csv
--clean은 두 가지만 고친다.
- 작업 시작이 같은 사례의 첫 커밋이나 막힘보다 늦으면, 작업 시작을 그 사건의 1분 전으로 옮긴다. 실제 시작 시각은 전날 스냅숏(18시)과 그 사건 사이 어딘가이며, 1분 전은 순서만 바로잡는 값이다.
- 마지막 사건이 업무 완료나 업무 닫힘이 아닌 사례를 뺀다.
OB-010은 3월 12일 12:18에 막힘이 기록되었고 작업 시작은 같은 날 18:00이었다. 정리한 로그에서는 작업 시작이 12:17로 옮겨져 “작업 시작 → 막힘” 순서가 된다. 정리한 로그는 사례 257건, 사건 1,975건이며, 작업 시작 31건이 옮겨졌고 226건은 18시 그대로다. 키트의 samples/orbit-event-log-clean.csv가 이 결과와 같은 파일이다.
정리는 분석 결과를 바꾼다. 분석 보고서의 “데이터” 절에 정리 규칙과 건수(작업 시작 31건 보정, 끝나지 않은 사례 3건 제외)를 적어 두면, 숫자가 다른 사람의 분석과 다를 때 원인을 바로 찾을 수 있다.
5관측 기간의 끝
끝나지 않은 사례를 빼면 다른 문제가 생긴다. 기록을 뽑기 직전에 시작한 업무 중에서는 빨리 끝난 업무만 로그에 남는다. Orbit에서 작업 시작이 8월 24일 이후인 끝난 사례 12건의 처리 시간 중앙값은 22.4업무시간이고, 6월 1일~8월 21일에 시작한 119건은 28.2업무시간이다. 기간 끝의 사례가 짧아 보이는 것은 일이 빨라져서가 아니라 오래 걸리는 업무가 아직 끝나지 않았기 때문이다.
기간별 숫자를 비교할 때는 이 효과를 확인한다. bottleneck.sh와 whatif.sh의 --to로 마지막 2주를 빼고 다시 계산해 숫자가 크게 바뀌지 않는지 본다. Orbit에서는 6월 이후 기간의 중앙값이 27.7h에서 28.2h로 바뀐다.
6로그의 수준을 판단하는 기준
2011년 Process Mining Manifesto는 이벤트 로그의 성숙도를 별 1개에서 5개까지 다섯 단계로 나눈다. 같은 로그 안에서도 활동마다 수준이 다르다.
| 수준 (별 개수) | 기준 (요약) | Orbit 로그에서 |
|---|---|---|
| 5 (가장 높음) | 자동으로, 체계적으로, 안전하게 기록되고, 사건과 속성의 뜻이 정의되어 있다 | 해당 없음 |
| 4 | 자동으로, 체계적으로, 믿을 수 있게 기록되고, 사례와 활동 개념이 시스템에 있다 | 해당 없음. GitHub에는 “업무 사례”라는 개념이 없고 닫는 키워드로 엮는다 |
| 3 | 자동으로 기록되고, 기록된 사건은 실제와 맞는다. 다만 무엇을 기록할지 체계는 없다 | PR 생성, 리뷰, 병합, 이슈 닫힘·다시 열림, 라벨 변경 |
| 2 | 시스템의 부산물로 자동 기록되지만, 시스템을 거치지 않고 일할 수 있어 빠지는 사건이 있다 | 작업 시작(스냅숏, Status를 늦게 바꾸면 늦게 잡힌다), PR과 업무의 연결(닫는 키워드를 빠뜨리면 빠진다) |
| 1 (가장 낮음) | 사람이 손으로 기록한다. 실제와 다르거나 빠질 수 있다 | 결정 기록 댓글. 회의나 메신저에서 정하고 댓글을 남기지 않은 결정은 로그에 없다 |
품질 문제의 종류로는 보스(R. P. J. C. Bose), 만스(R. S. Mans), 판 데르 알스트가 2013년에 정리한 네 가지 분류가 쓰인다. 빠진 값(missing), 틀린 값(incorrect), 부정확한 값(imprecise), 관련 없는 값(irrelevant)이다. Orbit에서는 결정 기록이 빠질 수 있고(빠진 값), 작업 시작의 순서가 틀렸고(틀린 값), 작업 시작 시각이 하루 단위다(부정확한 값). 분석 질문과 무관한 업무 유형(예: kind:meeting 운영 이슈)은 event-log.sh의 --label로 처음부터 거른다(관련 없는 값).
7다른 도구로 넘길 때
CSV는 대부분의 프로세스 마이닝 도구가 읽는다. 가져오기 화면에서 case_id를 사례, activity를 활동, timestamp를 시각, resource를 수행자로 지정한다. 표준 교환 형식인 XES(IEEE 1849)가 필요하면 PM4Py의 pm4py.write_xes로 바꾼다. 업무, PR, 리뷰를 각각의 객체로 두는 객체 중심 이벤트 로그(OCEL 2.0)는 업무 하나에 PR 여러 개가 걸리는 관계를 그대로 담지만, 이 과정의 스크립트는 사례 하나 기준의 CSV만 다룬다.
resource 열은 개인 식별 정보다. 팀 밖(외부 컨설턴트, 다른 부서, 외부 AI 도구)에 줄 때는 열을 빼거나 바꾼다. 예: cut -d, -f1-3,5,6 pm-lab/orbit-event-log-clean.csv > pm-lab/orbit-no-resource.csv. 회사의 데이터 반출 규정을 먼저 확인한다.
막히면
| 증상 | 확인과 해결 |
|---|---|
오류: 첫 줄이 case_id,activity,timestamp로 시작해야 한다 | 엑셀에서 저장한 CSV는 첫 줄 앞에 BOM 문자가 붙을 수 있다. head -c 3 원본.csv | od -c의 첫 줄이 357 273 277이면 BOM이다. tail -c +4 원본.csv > 고친.csv로 앞의 3바이트를 지운다 |
| 점검 결과의 시차 표기가 두 개 이상이다 | 추출할 때 --tz를 바꿔 실행한 파일이 섞였다. 한 로그 안의 시차는 하나여야 업무 시간이 맞다 |
--clean 결과가 비어 있다 | 마지막 사건이 업무 완료인 사례가 없다. 업무를 닫는 이유(--reason completed)로 닫았는지 확인한다 |
pm-lab/orbit-event-log.csv를 받고 열 여섯 개의 뜻을 설명할 수 있다.- 사례, 활동, 시각을 다르게 정하면 무엇이 달라지는지 하나씩 말할 수 있다.
log-check.sh의 발견 세 가지와 원인을 확인했다.pm-lab/orbit-event-log-clean.csv를 만들고 OB-010의 순서가 바뀐 것을 확인했다.- 관측 기간 끝의 사례가 짧아 보이는 이유를 설명할 수 있다.
마치며...
이벤트 로그는 GitHub 기록 그 자체가 아니라, 사례·활동·시각을 정해 기록을 다시 엮은 결과다. 정의와 정리 규칙이 바뀌면 지도와 대기 시간이 바뀌므로, 2단계의 모든 숫자는 이 실습에서 만든 orbit-event-log-clean.csv를 기준으로 한다. 다음 실습에서는 정리한 로그로 업무 257건이 실제로 흐른 길을 그린다.