Logcat을 이용한 로그 작성 및 보기

Android 스튜디오의 Logcat 창에는 시스템 메시지(예: 가비지 컬렉션 발생)와 Log 클래스를 사용하여 앱에 추가한 메시지가 표시됩니다. 메시지는 실시간으로 표시되며, 이전 메시지를 볼 수 있도록 기록이 유지됩니다.

관심 있는 정보만 표시하기 위해 필터를 만들고, 메시지에 표시되는 정보의 양을 수정하고, 우선순위 레벨을 설정하고, 앱 코드를 통해 생성된 메시지만 표시하고, 로그를 검색할 수 있습니다. 기본적으로 Logcat은 가장 최근 실행한 앱과 관련된 로그 출력만 보여줍니다.

앱에서 예외가 발생하면 Logcat은 메시지를 표시한 다음 코드 줄 링크를 포함한 연결된 스택 트레이스를 표시합니다.

실행 창에는 현재 실행 중인 앱의 로그 메시지가 표시됩니다. Logcat 출력 디스플레이는 구성할 수 있지만 실행 창은 구성할 수 없습니다.

앱 로그 보기

앱의 로그 메시지를 표시하려면 다음을 따르세요.

  1. 기기에서 앱을 빌드하고 실행합니다.
  2. View > Tool Windows > Logcat을 클릭합니다(또는 도구 창 모음에서 Logcat 을 클릭).

Logcat 창에는 그림 1과 같이 창 상단의 메뉴에서 선택한 앱의 로그 메시지가 표시됩니다.

그림 1. Logcat 창

기본적으로 Logcat은 기기에서 실행 중인 앱의 로그 메시지만 표시합니다. 이 기본값을 변경하려면 Logcat 메시지 필터링 방법을 참고하세요.

Logcat 툴바는 다음과 같은 버튼을 제공합니다.

  1. Clear logcat : 클릭하여 표시된 로그를 삭제합니다.
  2. Scroll to the end : 클릭하여 로그의 맨 아래로 이동하고 최신 로그 메시지를 확인합니다. 그런 다음 로그에서 한 줄을 클릭하면 뷰는 그 지점에서 스크롤하는 것을 일시중지합니다.
  3. Up the stack trace Down the stack trace : 클릭하여 로그의 스택 트레이스에서 위아래로 이동하면서 출력된 예외에 표시되는 이전 또는 다음 파일 이름을 선택합니다. 이 동작은 로그에서 파일 이름을 클릭하는 것과 같습니다.
  4. Use soft wraps : 클릭하여 줄바꿈을 사용하고 가로 방향 스크롤을 금지합니다. 그러나 줄바꿈이 불가능한 문자열은 가로 방향 스크롤이 계속 필요할 수도 있습니다.
  5. Print : 클릭하여 Logcat 메시지를 출력합니다. 표시되는 대화상자에서 출력 환경설정을 선택한 후 메시지를 PDF로 저장하도록 선택할 수도 있습니다.
  6. Restart : 클릭하여 로그를 삭제하고 Logcat을 다시 시작합니다. Clear Logcat 버튼과 달리 이 기능은 이전의 로그 메시지를 복구하여 표시합니다. 따라서 이 기능은 Logcat이 응답하지 않는 상황에서 로그 메시지를 잃고 싶지 않은 경우 가장 유용합니다.
  7. Logcat header : 클릭하여 Configure Logcat Header 대화상자를 열고 각 Logcat 메시지의 출력 형식(예: 날짜와 시간의 표시 여부)을 사용자설정합니다.
  8. Screen capture : 클릭하여 스크린샷을 캡처합니다.
  9. Screen record : 클릭하여 기기의 동영상을 녹화합니다(최대 3분).

로그 메시지 작성

Log 클래스를 사용하면 Logcat에 표시되는 로그 메시지를 만들 수 있습니다. 모든 Android 로그 메시지에는 태그 및 태그와 연관된 우선순위가 있습니다. 시스템 로그 메시지의 태그는 메시지가 시작되는 시스템 구성요소를 나타내는 짧은 문자열입니다.

다음 로그 메서드를 사용합니다. 가장 높은 우선순위부터 가장 낮은 우선순위 순으로 나열되어 있습니다.

사용자 정의 태그는 현재 클래스의 이름과 같이 사용자가 유용하다고 생각하는 정보를 나타내는 어떤 문자열이든 가능합니다. Log 메서드 호출에서 태그를 정의합니다. 예를 들면 다음과 같습니다.

Kotlin

Log.d(tag, message)

자바

Log.d(tag, message);

전체 옵션 목록은 Log 클래스 설명을 참고하세요.

개발 단계를 제외하고 상세 로그를 앱으로 컴파일하면 안 됩니다. 디버그 로그는 컴파일되지만 런타임 시 삭제됩니다. 오류, 경고, 정보 로그는 항상 유지됩니다.

각 로그 메서드에서 첫 번째 매개변수는 고유한 태그여야 하며 두 번째 매개변수는 메시지입니다. 시스템 로그 메시지의 태그는 메시지가 시작되는 시스템 구성요소를 나타내는 짧은 문자열입니다. 태그는 현재 클래스의 이름과 같이 유용하다고 생각하는 어떤 문자열이든 가능합니다.

클래스의 TAG 상수를 첫 번째 매개변수에서 사용한다고 선언하는 것이 좋습니다. 예를 들어, 다음과 같이 정보 로그 메시지를 만들 수 있습니다.

Kotlin

private const val TAG = "MyActivity"
...
Log.i(TAG, "MyClass.getView() — get item number $position")

자바

private static final String TAG = "MyActivity";
...
Log.i(TAG, "MyClass.getView() — get item number " + position);

참고: 태그 이름이 23자(영문 기준)를 초과하는 경우 Logcat 출력에서 잘립니다.

Logcat 메시지 형식

로그 메시지 형식은 다음과 같습니다.

date time PID-TID/package
priority/tag: message

PID는 '처리 식별자'를 나타내고 TID는 '스레드 식별자'를 나타냅니다. PID와 TID는 스레드가 하나뿐인 경우 동일할 수 있습니다.

예를 들어, 다음 로그 메시지의 우선순위는 V이고 태그는 AuthZen입니다.

12-10 13:02:50.071 1901-4229/com.google.android.gms V/AuthZen: Handling delegate intent.

로그 수준 설정

로그 수준을 설정하여 Logcat에서 모든 메시지를 표시할지 또는 가장 엄격한 조건을 나타내는 메시지만 표시할지 제어할 수 있습니다.

Logcat은 로그 수준 설정과 관계없이 모든 메시지를 계속 수집합니다. 이 설정은 Logcat이 무엇을 표시할지만 결정합니다.

로그 수준 메뉴에서 다음 값 중 하나를 선택합니다.

  • Verbose: 모든 로그 메시지를 표시합니다(기본 설정).
  • Debug: 개발 단계에서만 유용한 디버그 로그 메시지뿐 아니라 이 목록에서 그보다 레벨이 낮은 메시지도 표시합니다.
  • Info: 일반적인 사용을 위해 예상할 수 있는 로그 메시지뿐 아니라 이 목록에서 그보다 레벨이 낮은 메시지도 표시합니다.
  • Warn: 아직 오류는 아니지만 발생할 수 있는 문제뿐 아니라 이 목록에서 그보다 레벨이 낮은 메시지도 표시합니다.
  • Error: 오류를 일으킨 문제뿐 아니라 이 목록에서 그보다 레벨이 낮은 메시지도 표시합니다.
  • Assert: 개발자가 발생해서는 안 된다고 생각하는 문제를 표시합니다.

Logcat 메시지 검색

현재 Logcat에 표시된 메시지를 검색하려면 다음을 따르세요.

  1. (선택사항) 정규 표현식 검색 패턴을 사용하려면 Regex를 선택합니다.
  2. 검색 입력란 에 문자 시퀀스를 입력합니다.

    검색 결과에 따라 Logcat 출력 화면이 변경됩니다.

  3. Enter 키를 눌러 이 세션 동안 메뉴에 검색 문자열을 저장합니다.
  4. 검색을 반복하려면 검색 메뉴에서 저장된 검색을 선택합니다. 필요에 따라 Regex를 선택하거나 선택 해제합니다.

Logcat 메시지 필터링

로그 출력을 관리 가능한 수준으로 줄이는 한 가지 방법은 필터를 사용해 로그 출력을 제한하는 것입니다.

참고: 필터는 Logcat에 현재 표시되고 있는 메시지뿐만 아니라 전체 Logcat 기록에 적용됩니다. 검사하려는 필터 출력을 볼 수 있도록 다른 표시 옵션이 알맞게 설정되어 있는지 확인하세요.

필터를 정의하고 적용하는 방법은 다음과 같습니다.

  1. 필터 메뉴에서 필터 옵션을 선택합니다.
    • Show only selected application: 앱 코드에서 생성된 메시지만 표시합니다(기본 설정). Logcat이 활성 상태인 앱의 PID를 사용하여 로그 메시지를 필터링합니다.
    • No Filters: 필터를 적용하지 않습니다. 개발자가 선택한 프로세스와 관계없이 Logcat이 기기에서 수신되는 모든 로그 메시지를 표시합니다.
    • Edit Filter Configuration: 사용자설정 필터를 만들거나 수정합니다. 예를 들어, 두 앱의 로그 메시지를 동시에 볼 수 있는 필터를 만들 수 있습니다.

    필터를 정의한 후 메뉴에서 이러한 필터를 선택할 수도 있습니다. 필터를 메뉴에서 삭제하려면 필터를 삭제하세요.

  2. Edit Filter Configuration을 선택한 경우 필터를 만들거나 수정합니다.
    1. Create New Logcat Filter 대화상자에서 필터 매개변수를 지정합니다.
      • Filter Name: 정의하려는 필터의 이름을 입력하거나, 왼쪽 창에서 기존 필터를 선택하여 수정합니다. 이름에는 소문자, 밑줄, 숫자만 사용할 수 있습니다.
      • Log Tag: 태그를 지정합니다(선택사항).
      • Log Message: 로그 메시지 텍스트를 지정합니다(선택사항).
      • Package Name: 패키지 이름을 지정합니다(선택사항).
      • PID: 프로세스 ID를 지정합니다(선택사항).
      • Log Level: 로그 레벨을 선택합니다(선택사항).
      • Regex: 특정 매개변수에 정규 표현식 문법을 사용하려면 이 옵션을 선택합니다.
    2. 왼쪽 창에 필터 정의를 추가하려면 +를 클릭합니다.

      필터를 삭제하려면 왼쪽 창에서 삭제할 필터를 선택한 후 -를 클릭하세요.

    3. 위 작업을 완료하면 OK를 클릭합니다.

원하는 로그 메시지가 표시되지 않으면 No filters를 선택하고 특정 로그 메시지를 검색하세요.

가비지 컬렉션 메시지 읽기

가비지 컬렉션(GC) 이벤트가 발생하면 정보가 Logcat에 출력될 때가 있습니다.

앱 메모리에 관한 자세한 정보는 메모리 프로파일러를 사용하세요.

Dalvik 로그 메시지

Dalvik(ART 아님)에서는 모든 GC가 Logcat에 다음 정보를 출력합니다.

D/dalvikvm(PID): GC_Reason Amount_freed,
Heap_stats, External_memory_stats, Pause_time

예:

D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms

로그 메시지가 누적되는 동안 힙 통계에서 증가하는 부분이 있는지 찾아보세요. 이 값이 계속 증가한다면 메모리 누수가 있을 수 있습니다.

Dalvik 로그 메시지에는 다음과 같은 용어가 포함됩니다.

GC Reason(GC 이유)
GC를 트리거한 이유와 컬렉션의 종류에 관한 설명입니다. 다음과 같은 이유가 나타날 수 있습니다.
GC_CONCURRENT
힙이 가득 차기 시작하면 메모리를 해제하는 동시 GC입니다.
GC_FOR_MALLOC
힙이 이미 가득 찼을 때 앱이 메모리 할당을 시도했기 때문에 GC가 발생한 것이므로 시스템이 앱을 중지하고 메모리를 회수해야 했습니다.
GC_HPROF_DUMP_HEAP
힙을 분석하기 위해 HPROF 파일 생성을 요청할 때 발생하는 GC입니다.
GC_EXPLICIT
명시적 GC입니다(예: gc() 호출 시). 하지만 이 메서드는 호출하지 마세요. 대신 필요한 경우 GC를 실행하세요.
GC_EXTERNAL_ALLOC
외부에서 할당된 메모리를 위한 GC입니다(예: 네이티브 메모리 또는 NIO 바이트 버퍼에 저장되는 픽셀 데이터). 이는 API 수준 10 이하에서만 발생합니다. 최신 버전은 Dalvik 힙에서 모든 것을 할당합니다.
Amount freed(회수한 메모리 크기)
이 GC를 통해 회수한 메모리의 크기입니다.
Heap stats(힙 통계)
힙에서 회수한 비율로, (라이브 객체 수)/(총 힙 크기)로 계산됩니다.
External memory stats(외부 메모리 통계)
API 수준 10 이하에서 외부 할당된 메모리로, (할당된 메모리의 크기)/(컬렉션이 발생하게 되는 한계)입니다.
Pause time(일시중지 횟수)
힙이 클수록 일시중지 횟수가 많아집니다. 동시 일시중지 횟수는 두 번의 일시중지를 표시하는데, 하나는 컬렉션의 시작 시점이고 다른 하나는 종료 시점 근처입니다.

ART 로그 메시지

Dalvik과 달리, ART는 GC를 명시적으로 요청하지 않으면 GC에 관한 메시지를 로그에 기록하지 않습니다. GC 정보는 GC가 명시적인 경우나 GC 일시중지가 5ms를 초과하거나 GC 지속 시간이 100ms를 초과할 때만 출력됩니다. 앱이 일시중지를 인식할 수 있는 상태에 있지 않다면(예: 앱이 사용자가 GC 일시중지를 인식할 수 없는 백그라운드에 있을 때) 명시적인 GC를 제외하고 GC 정보는 출력되지 않습니다.

ART는 가비지 컬렉션 로그 메시지에 다음 정보를 포함합니다.

I/art: GC_Reason GC_Name Objects_freed(Size_freed) AllocSpace Objects,
    Large_objects_freed(Large_object_size_freed) Heap_stats LOS objects, Pause_time(s)

예:

I/art : Explicit concurrent mark sweep GC freed 104710(7MB) AllocSpace objects,
    21(416KB) LOS objects, 33% free, 25MB/38MB, paused 1.230ms total 67.216ms

ART 로그 메시지에는 다음 용어가 포함됩니다.

GC Reason(GC 이유)
GC를 트리거한 이유와 컬렉션의 종류에 관한 설명입니다. 다음과 같은 이유가 나타날 수 있습니다.
Concurrent
앱 스레드를 정지하지 않는 동시 GC입니다. 이 GC는 백그라운드 스레드에서 실행되며 메모리 할당을 막지 않습니다.
Alloc
힙이 이미 가득 찼을 때 앱이 메모리 할당을 시도했기 때문에 GC가 시작되었습니다. 이 경우에는 가비지 컬렉션이 할당 스레드에서 발생합니다.
Explicit
앱이 가비지 컬렉션을 명시적으로 요청했습니다(예: System.gc() 또는 Runtime.gc() 호출). 그러나 Dalvik과 마찬가지로, ART에서는 가급적 GC를 신뢰하고 명시적 GC를 요청하지 않는 것이 좋습니다. 명시적 GC는 할당 스레드를 차단하고 불필요하게 CPU 사이클을 낭비하므로 사용하지 않는 것을 권장합니다. 명시적 GC로 인해 다른 스레드가 선점될 경우에는 버벅거림(앱의 끊김 현상, 떨림 또는 중단)이 발생할 수도 있습니다.
NativeAlloc
비트맵 또는 RenderScript 할당 객체와 같은 네이티브 할당에 따른 네이티브 메모리 압력으로 인해 발생한 GC입니다.
CollectorTransition
힙 전환으로 인해 발생한 GC입니다. 이는 앱이 일시중지를 인식할 수 있는 상태 간에 변경되는 경우와 같이 런타임 시 GC 전략을 변경하면 발생합니다. 가비지 컬렉터 전환은 사용 가능 목록으로 지정된 공간에서 범프 포인터 공간으로(또는 그 반대로) 모든 객체를 복사하도록 구성됩니다.

이는 앱이 일시중지를 인식할 수 있는 상태(예: 앱이 사용자가 GC 일시중지를 인식할 수 있는 포그라운드에 있을 때)에서 일시중지를 인식할 수 없는 상태로 프로세스 상태를 변경할 때(또는 그 반대로) Android 8.0 미만 버전을 실행하는 RAM이 부족한 기기에서만 발생합니다.

HomogeneousSpaceCompact
같은 종류의 공간 압축은 사용 가능 목록 공간 간의 압축으로, 보통 앱이 일시중지를 인식할 수 없는 프로세스 상태로 이동할 때 발생합니다. 이 작업을 하는 주된 이유는 RAM 사용량을 줄이고 힙 조각 모음을 하기 위해서 입니다.
DisableMovingGc
실제 GC 이유는 아니지만, 동시 힙 압축이 이루어지는 동안 GetPrimitiveArrayCritical을 사용했기 때문에 가비지 컬렉션이 차단되었다는 점에 주의해야 합니다. 일반적으로, GetPrimitiveArrayCritical은 가비지 컬렉터 이동을 제한하므로 사용하지 않을 것을 적극적으로 권장합니다.
HeapTrim
GC 이유는 아니지만, 힙 트림을 마칠 때까지 가비지 컬렉션이 차단된다는 점에 주의해야 합니다.
GC Name(GC 이름)
ART에서는 다음을 실행하는 다양한 GC가 있습니다.
Concurrent mark sweep (CMS)
이미지 공간을 제외한 모든 공간을 수집하는 전체 힙 컬렉터입니다.
Concurrent partial mark sweep
이미지 및 zygote 공간을 제외한 모든 공간을 수집하는 거의 완전한 힙 컬렉터입니다.
Concurrent sticky mark sweep
마지막 GC 이후로 할당된 객체만 회수할 수 있는 세대 간 컬렉터입니다. 이 가비지 컬렉션이 더 빠르고 일시중지 횟수도 적으므로 전체 또는 부분 마크 스윕보다 더 자주 실행됩니다.
Marksweep + semispace
힙 조각 모음을 위한 같은 종류의 공간 압축뿐 아니라 힙 전환에도 사용되는 비동시 방식의 복사 GC입니다.
Objects freed(회수한 객체 수)
크지 않은 객체 공간에서 이 GC를 통해 회수한 객체의 수입니다.
Size freed(회수한 공간의 크기)
크지 않은 객체 공간에서 이 GC를 통해 회수한 바이트 수입니다.
Large objects freed(회수한 큰 객체 수)
이 가비지 컬렉션으로 회수한 큰 객체 공간에 있는 객체 수입니다.
Large object size freed(회수한 큰 객체의 크기)
이 가비지 컬렉션으로 회수한 큰 객체 공간에 있는 바이트 수입니다.
Heap stats(힙 통계)
회수한 비율로, (라이브 객체 수)/(총 힙 크기)로 계산됩니다.
Pause times(일시중지 횟수)
일반적으로 일시중지 횟수는 GC 실행 중에 수정한 객체 참조의 개수에 비례합니다. 현재 ART CMS GC는 GC 종료 시점 근처에서 한 번만 일시중지됩니다. 이동 GC에는 GC 지속 시간 중 대부분의 시간 동안 지속하는 긴 일시중지가 있습니다.

Logcat에 다량의 GC 메시지가 표시되면 힙 통계에서 증가하는 부분이 있는지 확인합니다. 이 값이 계속 증가하고 있고 작아질 것으로 보이지 않는다면 메모리 누수가 있을 수 있습니다.

또는 'Alloc' 이유를 지정하는 GC가 있는 경우 이미 힙 용량에 거의 도달해 있는 것이므로 곧 메모리 부족 예외가 발생할 수 있습니다.