MaskWork#maskPanos stderr을 모두 error로 기록 — 로그 레벨 매핑 오류
RCA: MaskWork::maskPanos | PyTorch UserWarning: No PYTORCH_KERNEL_CACHE_PATH or HOME
Error Log#
MaskWork::maskPanos | script /tmp/lib/face-body-detector/sam3/model/encoder.py:358: UserWarning: No PYTORCH_KERNEL_CACHE_PATH or HOME environment variable set! This disables kernel caching. (Triggered internally at /pytorch/aten/src/ATen/native/cuda/jit_utils.cpp:1426.)
spatial_shapes.prod(1).cumsum(0)[:-1],
Impact#
- Service:
cupixworks-pix-genie-preprocessor-instance - Team: sinsw
- 발생 횟수: 17
- 최초 발생: 2026-04-20T01:40:00.654Z
- 최근 발생: 2026-04-20T02:11:33.502Z
Root Cause Summary#
MaskWork::maskPanos 메서드가 face-body-detector Python 스크립트를 child process로 실행할 때, spawn()의 env 옵션에 INPUT_DIRPATH, OUTPUT_DIRPATH, OPTION_FILE_PATH 세 가지 변수만 전달하고 부모 프로세스의 환경변수(process.env)를 상속하지 않는다. Node.js의 spawn()은 env가 명시적으로 지정되면 부모 환경변수를 완전히 대체하므로, HOME과 PYTORCH_KERNEL_CACHE_PATH가 모두 누락된다. PyTorch의 CUDA JIT 컴파일러(jit_utils.cpp:1426)가 kernel cache 디렉토리를 결정할 때 이 두 변수를 참조하는데, 둘 다 없으면 UserWarning을 stderr로 출력한다. TypeScript 코드의 process.stderr.on('data', ...) 핸들러(mask-work.ts:40-42)가 모든 stderr 출력을 logger.error() 레벨로 기록하여 Datadog에 에러로 수집된다. 처리 자체는 정상 완료되지만, CUDA kernel caching이 비활성화되어 반복 실행 시 성능이 저하된다.
Technical Analysis#
Code Path#
- Entry point:
cupix-pano-postprocessor/src/pano-postprocessor-service.ts:126—maskPanos()호출 - Child process spawn:
cupix-pano-postprocessor/src/work/mask-work.ts:29-33— 환경변수 교체 - Stderr handler:
cupix-pano-postprocessor/src/work/mask-work.ts:40-42—logger.error로 기록 - BlurScriptPath:
cupix-pano-postprocessor/src/config/constants.ts:5—/tmp/lib/face-body-detector/run.sh
1. PanoPostprocessorService에서 mask 처리를 시작:
// cupix-pano-postprocessor/src/pano-postprocessor-service.ts:123-127
if (maskTypeOption) {
this.maskWork.createOptionFile(optionPath, maskTypeOption);
start = Date.now();
await this.maskWork.maskPanos(downloadDir, maskDir!, optionPath);
this.panoPostprocessorManager.logElapsedTime(start, 'blur_panos');
2. MaskWork::maskPanos에서 face-body-detector Python 스크립트를 실행:
// cupix-pano-postprocessor/src/work/mask-work.ts:29-33
const process: ChildProcessWithoutNullStreams = spawn('stdbuf', ['-oL', 'bash', BlurScriptPath], {
cwd: path.dirname(BlurScriptPath),
stdio: 'pipe',
env: { INPUT_DIRPATH: inputDir, OUTPUT_DIRPATH: outputDir, OPTION_FILE_PATH: optionPath }
});
env 프로퍼티에 3개의 변수만 설정하고 ...process.env를 포함하지 않아, HOME, PATH, PYTORCH_KERNEL_CACHE_PATH 등 모든 부모 프로세스 환경변수가 자식 프로세스에 전달되지 않는다.
3. stderr 핸들러가 모든 stderr 출력을 error로 기록:
// cupix-pano-postprocessor/src/work/mask-work.ts:40-42
process.stderr.on('data', (data) => {
logger.error('MaskWork::maskPanos | script %s', data.toString());
});
Python의 warnings.warn()은 기본적으로 stderr로 출력하므로, PyTorch의 UserWarning이 에러 레벨로 기록된다.
4. 비교: PixGenieProcess는 올바르게 환경변수를 전달:
// cupix-pix-genie-preprocessor-agent/src/process/pixgenie.process.ts:65-70
this._process = spawn('python3', [PixGenieProcess.PIXGENIE_SCRIPT_PATH], {
env: { ...process.env, ...this.buildEnvironment(params) },
stdio: ['ignore', 'pipe', 'pipe'],
cwd: params.workspaceDir,
signal: this._abortController.signal
});
PixGenieProcess는 ...process.env spread를 사용하여 부모의 환경변수를 보존한 후 커스텀 변수를 추가하는 올바른 패턴을 사용하고 있다. 또한 stderr를 logger.warn 레벨로 기록한다 (pixgenie.process.ts:99-103).
5. BlurScriptPath는 face-body-detector 라이브러리를 가리킴:
// cupix-pano-postprocessor/src/config/constants.ts:5
export const BlurScriptPath = '/tmp/lib/face-body-detector/run.sh';
이 스크립트가 SAM3 모델(/tmp/lib/face-body-detector/sam3/model/encoder.py:358)을 로드하면서 PyTorch CUDA JIT 컴파일이 트리거되고, HOME이 없어 커널 캐싱이 비활성화된다.
Log Evidence#
Datadog 쿼리:
service:cupixworks-pix-genie-preprocessor-instance status:error "face-body-detector"
Time range: 2026-04-20T00:40:00Z to 2026-04-20T02:30:00Z
대표 에러 로그 (capture 45640, job 106527):
{
"timestamp": "2026-04-20T02:08:56.855Z",
"status": "error",
"service": "cupixworks-pix-genie-preprocessor-instance",
"message": "MaskWork::maskPanos | script /tmp/lib/face-body-detector/sam3/model/encoder.py:358: UserWarning: No PYTORCH_KERNEL_CACHE_PATH or HOME environment variable set! This disables kernel caching.",
"capture.id": 45640,
"job.id": 106527,
"team.domain": "sinsw",
"tenant": "nswgov",
"region": "ap-southeast-2",
"host.name": "7b2ed70d85ca",
"user.email": "robert.grahame2@det.nsw.edu.au"
}
영향받은 캡처 타임라인:
| Timestamp | Capture ID | Job ID | Host | Region |
|---|---|---|---|---|
| 2026-04-20T01:34:47.308Z | 45638 | 106526 | e34324c4cf20, d4eab215fcf3, c2d01ab4cf38 | ap-southeast-2 |
| 2026-04-20T01:40:00.654Z | 45641 | 106534 | 39453121dfcb, 7b2ed70d85ca | ap-southeast-2 |
| 2026-04-20T01:42:59.991Z | 45639 | 106525 | 39453121dfcb, 7b2ed70d85ca | ap-southeast-2 |
| 2026-04-20T02:08:56.855Z | 45640 | 106527 | 7b2ed70d85ca | ap-southeast-2 |
모든 에러가 동일한 tenant(nswgov), team(sinsw)에서 발생. 여러 호스트 컨테이너에서 동시 발생하여 인프라 문제가 아닌 코드 구성 문제임을 확인.
동일 시간대 context 로그에서 처리 정상 완료 확인:
service:cupixworks-pix-genie-preprocessor-instance -status:error
Time range: 2026-04-20T00:40:00Z to 2026-04-20T02:30:00Z
{
"timestamp": "2026-04-20T01:02:27.539Z",
"status": "info",
"message": "PreprocessorService::run | Starting Pix Genie preprocessing"
}
{
"timestamp": "2026-04-20T01:02:27.540Z",
"status": "info",
"message": "PixGenieProcess::execute | begin - captureId: 44894"
}
warn 레벨 로그에서 PixGenieProcess의 stderr 출력도 확인 (download progress bar):
{
"timestamp": "2026-04-20T02:23:07.000Z",
"status": "warn",
"message": "PixGenieProcess | STDERR: 100%|██████████| 1.13G/1.13G [00:00<00:00, 3.38GB/s]"
}
PixGenieProcess는 동일한 stderr 출력을 warn 레벨로 기록하는 반면, MaskWork는 error 레벨로 기록한다는 차이가 확인됨.
Fix Recommendation#
즉시 조치 (Critical)#
- 파일:
cupixworks/applications/agents/packages/cupix-pano-postprocessor/src/work/mask-work.ts:32 spawn()의env옵션에...process.env를 추가하여 부모 프로세스의 환경변수를 상속하도록 수정.PixGenieProcess(pixgenie.process.ts:66)의{ ...process.env, ...customEnv }패턴을 참고.
단기 개선 (1주 이내)#
- 파일:
cupixworks/applications/agents/packages/cupix-pano-postprocessor/src/work/mask-work.ts:40-42 - stderr 핸들러의 로그 레벨을
logger.error에서logger.warn으로 변경. Python 프로세스의 stderr에는 warning, deprecation notice, progress bar 등 에러가 아닌 메시지가 포함될 수 있다. 실제 에러는 exit code로 판별하며, 현재 코드도process.on('close', ...)핸들러(mask-work.ts:49-57)에서 exit code를 확인하고 있다.
장기 개선 (재발 방지)#
- 모든 agent 패키지에서
spawn()호출 시env옵션에 항상...process.env를 spread하는 패턴을 표준화.PixGenieProcess의 패턴({ ...process.env, ...customEnv })을 표준으로 채택. - Dockerfile에
ENV PYTORCH_KERNEL_CACHE_PATH=/tmp/.cache/torch/kernels를 추가하여 컨테이너 레벨에서 PyTorch 커널 캐시 경로를 명시적으로 설정하는 방안 검토.
Monitoring#
- 수정 후 에러 감소 확인:
service:cupixworks-pix-genie-preprocessor-instance status:error "MaskWork::maskPanos" "PYTORCH_KERNEL_CACHE_PATH"
- mask 처리 성능 변화 모니터링 (kernel caching 활성화로 인한 개선):
service:cupixworks-pix-genie-preprocessor-instance "blur_panos" "elapsed"
Risk Assessment#
- Risk level: low
- 예상 복잡도: trivial
- 이유: 처리는 정상 완료되며 기능적 영향 없음. GPU 커널 재컴파일로 인한 성능 저하만 존재. 수정은
spawn()호출의env옵션에...process.envspread 추가 및 stderr 로그 레벨 변경.