콘텐츠로 이동

SourceMap 설정


Sourcemap(소스 코드 매핑)은 프로덕션 환경의 압축된 코드를 원본 소스 코드로 다시 매핑하는 데 사용됩니다. RUM은 해당 심볼 테이블 파일을 zip으로 압축하여 업로드하는 방식으로 이러한 소스 코드 파일 정보 매핑을 지원하며, 이를 통해 보고된 error 메저먼트 데이터를 자동으로 변환할 수 있습니다.

Zip 패키징 설명

js 파일을 webpack으로 난독화 및 압축한 후 생성된 .map 파일을 zip으로 압축할 때, 반드시 압축 해제 후 파일 경로가 error_stack의 URL 경로와 일치해야 합니다. 다음과 같은 error_stack이 있다고 가정합니다.

ReferenceError
  at a.hideDetail @ http://localhost:8080/static/js/app.7fb548e3d065d1f48f74.js:1:1037
  at a.showDetail @ http://localhost:8080/static/js/app.7fb548e3d065d1f48f74.js:1:986
  at <anonymous> @ http://localhost:8080/static/js/app.7fb548e3d065d1f48f74.js:1:1174

변환이 필요한 경로는 /static/js/app.7fb548e3d065d1f48f74.js이며, 이에 해당하는 sourcemap 경로는 /static/js/app.7fb548e3d065d1f48f74.js.map입니다. 따라서 해당 압축 파일의 압축 해제 후 디렉터리 구조는 다음과 같습니다.

sourcemap.zip
└──static/
    └── js
    └── app.7fb548e3d065d1f48f74.js.map

변환 후의 error_stack_source:

ReferenceError
  at a.hideDetail @ webpack:///src/components/header/header.vue:94:0
  at a.showDetail @ webpack:///src/components/header/header.vue:91:0
  at <anonymous> @ webpack:///src/components/header/header.vue:101:0

Web 패키징 방식과 기본적으로 동일합니다.

Android에는 현재 두 가지 유형의 sourcemap 파일이 있습니다. 하나는 Java 바이트코드가 R8/Proguard로 압축 및 난독화된 후 생성되는 mapping 파일이고, 다른 하나는 C/C++ 네이티브 코드 컴파일 시 심볼 테이블과 디버그 정보가 제거되지 않은(unstripped) .so 파일입니다. Android 앱에 두 종류의 sourcemap 파일이 모두 포함된 경우, 패키징 시 두 파일을 모두 zip 패키지에 포함해야 합니다. zip 패키지 압축 해제 후 디렉터리 구조는 다음과 같습니다.

sourcemap.zip
├── mapping.txt
├── armeabi-v7a/
│   ├── libgameengine.so
│   ├── libothercode.so
│   └── libvideocodec.so
├── arm64-v8a/
│   ├── libgameengine.so
│   ├── libothercode.so
│   └── libvideocodec.so
├── x86/
│   ├── libgameengine.so
│   ├── libothercode.so
│   └── libvideocodec.so
└── x86_64/
    ├── libgameengine.so
    ├── libothercode.so
    └── libvideocodec.so

기본적으로 mapping 파일은 <프로젝트 폴더>/<Module>/build/outputs/mapping/<build-type>/에 위치하며, .so 파일은 CMake로 프로젝트를 컴파일하는 경우 <프로젝트 폴더>/<Module>/build/intermediates/cmake/debug/obj/에, NDK로 컴파일하는 경우 <프로젝트 폴더>/<Module>/build/intermediates/ndk/debug/obj/(debug 빌드) 또는 <프로젝트 폴더>/<Module>/build/intermediates/ndk/release/obj/(release 빌드)에 위치합니다.

변환 효과는 다음과 같습니다.

변환 전 error_stack:

java.lang.ArithmeticException: divide by zero
    at prof.wang.activity.TeamInvitationActivity.o0(Unknown Source:1)
    at prof.wang.activity.TeamInvitationActivity.k0(Unknown Source:0)
    at j9.f7.run(Unknown Source:0)
    at java.lang.Thread.run(Thread.java:1012)

변환 후 error_stack_source:

java.lang.ArithmeticException: divide by zero
at prof.wang.activity.TeamInvitationActivity.onClick$lambda-0(TeamInvitationActivity.java:1)
at java.lang.Thread.run(Thread.java:1012)

변환 전 error_stack:

backtrace:
#00 pc 00000000000057fc  /data/app/~~Taci3mQyw7W7iWT7Jxo-ag==/com.ft-Q8m2flQFG1MbGImPiuAZmQ==/lib/arm64/libft_native_exp_lib.so (xc_test_call_4+12)
#01 pc 00000000000058a4  /data/app/~~Taci3mQyw7W7iWT7Jxo-ag==/com.ft-Q8m2flQFG1MbGImPiuAZmQ==/lib/arm64/libft_native_exp_lib.so (xc_test_call_3+8)
#02 pc 00000000000058b4  /data/app/~~Taci3mQyw7W7iWT7Jxo-ag==/com.ft-Q8m2flQFG1MbGImPiuAZmQ==/lib/arm64/libft_native_exp_lib.so (xc_test_call_2+12)
#03 pc 00000000000058c4  /data/app/~~Taci3mQyw7W7iWT7Jxo-ag==/com.ft-Q8m2flQFG1MbGImPiuAZmQ==/lib/arm64/libft_native_exp_lib.so (xc_test_call_1+12)
#04 pc 0000000000005938  /data/app/~~Taci3mQyw7W7iWT7Jxo-ag==/com.ft-Q8m2flQFG1MbGImPiuAZmQ==/lib/arm64/libft_native_exp_lib.so (xc_test_crash+112)
...

변환 후 error_stack_source:

backtrace:

Abort message: 'abort message for ftNative internal testing'
#00 0x00000000000057fc /data/app/~~Taci3mQyw7W7iWT7Jxo-ag==/com.ft-Q8m2flQFG1MbGImPiuAZmQ==/lib/arm64/libft_native_exp_lib.so (xc_test_call_4+12)
xc_test_call_4
/Users/Brandon/Documents/workplace/working/StudioPlace/xCrash/xcrash_lib/src/main/cpp/xcrash/xc_test.c:65:9
#01 0x00000000000058a4 /data/app/~~Taci3mQyw7W7iWT7Jxo-ag==/com.ft-Q8m2flQFG1MbGImPiuAZmQ==/lib/arm64/libft_native_exp_lib.so (xc_test_call_3+8)
xc_test_call_3
/Users/Brandon/Documents/workplace/working/StudioPlace/xCrash/xcrash_lib/src/main/cpp/xcrash/xc_test.c:73:13
#02 0x00000000000058b4 /data/app/~~Taci3mQyw7W7iWT7Jxo-ag==/com.ft-Q8m2flQFG1MbGImPiuAZmQ==/lib/arm64/libft_native_exp_lib.so (xc_test_call_2+12)
xc_test_call_2
/Users/Brandon/Documents/workplace/working/StudioPlace/xCrash/xcrash_lib/src/main/cpp/xcrash/xc_test.c:79:13
#03 0x00000000000058c4 /data/app/~~Taci3mQyw7W7iWT7Jxo-ag==/com.ft-Q8m2flQFG1MbGImPiuAZmQ==/lib/arm64/libft_native_exp_lib.so (xc_test_call_1+12)
xc_test_call_1
/Users/Brandon/Documents/workplace/working/StudioPlace/xCrash/xcrash_lib/src/main/cpp/xcrash/xc_test.c:85:13
#04 0x0000000000005938 /data/app/~~Taci3mQyw7W7iWT7Jxo-ag==/com.ft-Q8m2flQFG1MbGImPiuAZmQ==/lib/arm64/libft_native_exp_lib.so (xc_test_crash+112)
xc_test_crash
/Users/Brandon/Documents/workplace/working/StudioPlace/xCrash/xcrash_lib/src/main/cpp/xcrash/xc_test.c:126:9
...

iOS 플랫폼의 sourcemap 파일은 .dSYM 확장자를 가진 디버그 정보가 포함된 심볼 테이블 파일입니다. 일반적으로 프로젝트 컴파일이 완료되면 .app 파일과 같은 디렉터리에 위치합니다. 예시는 다음과 같습니다.

$ ls -l Build/Products/Debug-iphonesimulator/
total 0
drwxr-xr-x   6 zy  staff  192  8  9 15:27 Fishing.app
drwxr-xr-x   3 zy  staff   96  8  9 14:02 Fishing.app.dSYM
drwxr-xr-x  15 zy  staff  480  8  9 15:27 Fishing.doccarchive
drwxr-xr-x   6 zy  staff  192  8  9 13:55 Fishing.swiftmodule

참고로 XCode Release 빌드에서는 기본적으로 .dSYM 파일이 생성되지만, Debug 빌드에서는 기본적으로 생성되지 않으므로 XCode에서 다음과 같이 설정해야 합니다.

Build Settings -> Code Generation -> Generate Debug Symbols -> Yes
Build Settings -> Build Option -> Debug Information Format -> DWARF with dSYM File

zip으로 패키징할 때 해당 .dSYM 파일을 zip 패키지에 포함하면 됩니다. 프로젝트에 여러 .dSYM 파일이 포함된 경우 모두 함께 zip 패키지에 포함해야 합니다. zip 패키지 압축 해제 후 디렉터리 구조는 대략 다음과 같습니다(.dSYM 파일은 본질적으로 디렉터리이며, macOS의 실행 프로그램 .app 파일과 유사합니다).

sourcemap.zip
├── AFNetworking.framework.dSYM
│   └── Contents
│       ├── Info.plist
│       └── Resources
│           └── DWARF
│               └── AFNetworking
└── App.app.dSYM
    └── Contents
        ├── Info.plist
        └── Resources
            └── DWARF
                └── App

React Native의 sourcemap에는 네이티브 iOS, Android 및 js 부분이 포함되며 총 세 가지 source map이 있습니다.

네이티브 iOS 및 Android의 sourcemap 확보 방법은 해당 플랫폼의 패키징 설명을 참조하세요.

js 부분의 sourcemap 확보 방법은 다음과 같습니다.

Android 소스 맵은 기본적으로 활성화됩니다. 소스 맵 파일은 android/app/build/generated/sourcemaps/react/release/index.android.bundle.map에 위치합니다.

iOS에서 소스 맵 생성을 활성화하려면 몇 가지 추가 설정이 필요합니다. Xcode를 열고 build phase의 "Bundle React Native code and images"를 편집합니다. 다른 내보내기 항목 위에 원하는 출력 경로가 포함된 SOURCEMAP_FILE 항목을 추가합니다.

set -e
#  output source maps
export SOURCEMAP_FILE="./main.jsbundle.map";

With Hermes,React Native <0.71

set -e
#  output source maps
export SOURCEMAP_FILE="./main.jsbundle.map";
#  React Native 0.70,you need to set USE_HERMES to true if Hermes is used, otherwise the source maps won't be generated.
export USE_HERMES=true 

# keep the rest of the script unchanged

# When React Native (0.69,0.71) and using Hermes
# add these lines to compose the packager and compiler source maps into one file
REACT_NATIVE_DIR=../node_modules/react-native

if [ -f "$REACT_NATIVE_DIR/scripts/find-node-for-xcode.sh" ]; then
    source "$REACT_NATIVE_DIR/scripts/find-node-for-xcode.sh"
else
    # Before RN 0.70, the script was named find-node.sh
    source "$REACT_NATIVE_DIR/scripts/find-node.sh"
fi
source "$REACT_NATIVE_DIR/scripts/node-binary.sh"
"$NODE_BINARY" "$REACT_NATIVE_DIR/scripts/compose-source-maps.js" "$CONFIGURATION_BUILD_DIR/main.jsbundle.map" "$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/main.jsbundle.map" -o "../$SOURCEMAP_FILE"

js sourcemap 파일을 확보한 후, 해당 빌드 플랫폼과 대응하는 네이티브 sourcemap과 함께 아래 형식으로 zip 패키징합니다.

// Android
sourcemap.zip
├── js/
    ├── index.android.bundle.map
└── android/
    ├── mapping.txt
    ├── armeabi-v7a/
    │   ├── libgameengine.so
    │   ├── libothercode.so
    │   └── libvideocodec.so
    └── arm64-v8a/
        ├── libgameengine.so
        ├── libothercode.so
        └── libvideocodec.so    
// iOS
sourcemap.zip
├── js/
    ├── main.jsbundle.map 
└── ios/
    ├── AFNetworking.framework.dSYM
    │   └── Contents
    │       ├── Info.plist
    │       └── Resources
    │           └── DWARF
    │               └── AFNetworking
    └── App.app.dSYM
        └── Contents
            ├── Info.plist
            └── Resources
                └── DWARF
                    └── App

source-map-visualization 같은 소스 맵 시각화 도구를 사용하여 파일 사용 가능 여부를 확인할 수 있습니다.

업로드 방식

현재 다음 세 가지 SourceMap 업로드 방식을 지원합니다.

  • 프론트 페이지 업로드: SourceMap 파일을 수동으로 업로드 및 삭제할 때 적합합니다.
  • 스크립트 업로드: 공용 네트워크 DataWay 환경에서 자동 업로드에 적합합니다.
  • 빌드 단계 플러그인 업로드: Web 프로젝트가 패키징 단계에서 SourceMap을 자동 업로드할 때 적합합니다.

프론트 페이지 업로드 및 삭제

패키징 설정이 완료되면 프론트 페이지 [RUM] > [애플리케이션 목록] > [업로드할 애플리케이션 오른쪽 위 더 보기 아이콘 클릭] > [SourceMap]으로 이동하여 파일 업로드 및 삭제 작업을 수행할 수 있습니다. 현재 계정에 "편집" 이상의 권한이 있는지 확인하세요.

업로드 및 삭제는 애플리케이션이 속한 워크스페이스 내에서 수행해야 하며, 현재 워크스페이스만 선택하세요. 워크스페이스 간 읽기 전용 상태에서는 이러한 구성 진입점이 제공되지 않습니다. 자세한 내용은 워크스페이스 간 조회 설명을 참조하세요.

🔍 검색란 아래에서 업로드된 파일 이름과 애플리케이션 유형을 확인할 수 있습니다. 파일 이름을 입력하여 검색할 수 있으며, 아이콘을 클릭하면 현재 파일을 삭제할 수 있습니다.

업로드 유의사항:

  1. 파일 크기는 500M를 초과할 수 없습니다.
  2. 파일 형식은 반드시 .zip이어야 합니다.
  3. 해당 압축 파일의 압축 해제 후 파일 경로가 error_stack의 URL 경로와 일치하는지 확인하세요.
  4. 여러 파일을 동시에 업로드할 수 없습니다.
  5. 동일한 이름의 파일을 업로드하면 덮어쓰기 안내가 표시되므로 주의하세요.

스크립트 업로드

현재 애플리케이션이 공용 네트워크 DataWay 연결 방식을 사용하는 경우, 스크립트를 통해 OpenAPI로 패키징된 sourcemap.zip 파일을 업로드할 수도 있습니다.

자세한 내용은 스크립트로 SourceMap 업로드를 참조하세요.

빌드 단계 플러그인 업로드

Web 프로젝트의 경우 프론트 페이지 업로드와 스크립트 업로드 외에도 프로젝트 빌드 단계에서 플러그인을 통해 SourceMap 파일을 자동으로 업로드할 수 있습니다.

현재 다음 방식을 지원합니다.

SourceMap 업로드가 완료되면 오류 스택 해석에 사용할 수 있습니다.

문서 평가

이 페이지가 도움이 되었나요?