누구나 확인 할 수 있는 안드로이드 Log

안녕하세요. Android 플랫폼에서 화해 앱을 개발을 하고 있는 한국용입니다. logcat

 

하나의 앱 서비스를 만들기 위해서는 많은 사람의 노력이 필요합니다. 절대로 혼자서는 만들 수 없고, 다양한 분야의 사람들이 여러 가지 방법으로 협업하고 노력할 때 제대로 된 서비스를 만들 수 있다고 생각합니다. 하지만 서로가 다른 분야에서 업무를 하고 있고 일하는 방식도 달라 여러 사람이 협업을 한다는 것이 결코 쉬운 일은 아닙니다.

 

제가 이 콘텐츠를 통해 말하려 하는 것은 효율적으로 협업하기 위해 다른 플랫폼이나 팀에서 겪고 계시던 불편을 개발로써 해결하고자 했던 부분입니다.

 

화해 앱에서 발생하는 사용자 이벤트 로그를 앱 개발자가 아닌 다른 분들은 확인하기 어려운 문제가 있었습니다. 안드로이드 플랫폼에서 데이터팀과 데이터 로그 프로세스 관련 논의 중 어떻게 하면 쉽게 확인할 수 있을지, 앱 개발로 이 문제를 해결할 수 있을지 고민하는 과정이 있었습니다. 그 결과 나온 방법을 소개해드리기 위해 제목을 ‘누구나 확인할 수 있는 안드로이드 Log’라고 지어봤습니다.

 


 

 

개발 배경

 

데이터팀의 힘든 시간들

버드뷰의 밴드 조직에서 개발하고 있는 앱 개발자, 프론트엔드 개발자 분들은 매 과제마다 이벤트 로그 작업을 하고 있기 때문에 어느 정도 어려움을 이해하고 있었습니다. 개발팀이 데이터 로그를 추가하고 나면 데이터팀에서 확인 QA 시간을 거치는데 정확한 로그 확인을 위해 직접 개발 툴(Android Studio, Xcode)을 설치하고 직접 빌드해서 앱에서 발생하는 로그를 확인하고 있었습니다. (지금은 Firebase 콘솔에서 확인하기도 합니다)

 

 

logcat

 

 

💦 데이터팀 애로 사항

  • 직접 개발환경을 설치하여 빌드하고 로그 확인 시 준비과정이 너무 길고 힘듦
  • 예전 버전에 대한 로그 확인이 너무 어려움

 

logcat

 

 

이런 어려운 순간들이 업무를 진행하는데 있어서 지치고 힘들게 하는 원인이 됩니다. 그래서 개발로 해결할 방법을 모색하기 시작했습니다. 여러가지 방법을 고민하는 도중에 개발환경 없이 앱 자체에서 로그를 확인 할 수 있으면 문제가 해결되지 않을까 생각하게 되었습니다.

 

제가 앱 개발을 하면서 내부적으로 확인하고 있는 로그(Logcat)를 디버그모드로 연결하지 않고 앱 화면에 직접 보여주는 부분부터 시작하게 되었습니다.

 

 

 

요건 정의

누가 시킨 것도 아니고 과제도 아니니 요건 같은 건 있을 리 없습니다. 제 마음대로 요건을 정의하고 화면 설계를 시작합니다.

 

logcat

 

 

logcat

 

  • 안드로이드 스튜디오에 Logcat화면을 그대로 앱 화면으로 옮겨오고 싶었습니다.
  • 어떤 화면이든 항상 떠 있어야 앱 인터렉션에 따라 로그를 확인할 수 있습니다. 화면 어느 곳을 누를지 모르니 당연히 움직일 수 있어야겠죠?
  • 실시간으로 앱에서 발생하는 로그를 보여줘야 합니다.
  • 앱에서 발생하는 로그는 아주 많습니다.(시스템, 개발용도) 조금이라도 편리하게 사용하기 위해선 검색이 필요합니다.
  • 특정 플랫폼 및 팀에서 원하는 로그에 대한 패턴이 있을 테니 어느 정도 구별할 수 있는 로그의 경우 필터링을 미리 해두면 보기 편리할 것입니다.

 

 

 

구현

logcat 명령어와 Floating Window를 활용하여 구현합니다.

 

로그를 가져와야 합니다.

  • ADB 명령어를 통해 로그를 가져옵니다. Android Debug Bridge는 말 그대로 기기와 통신하는 Command-Line 툴입니다. 앱 설치 및 디버깅과 같은 다양한 기기와의 작업에 도움을 주는 명령어들이 있으며 그중에서 logcat 명령어를 통해 로그를 가져오게 됩니다.
  • Runtime.getRuntime().exec()를 이용하여 logcat 명령어를 실행하고 출력되는 로그들을 전달하게 됩니다.
val pid = android.os.Process.myPid()
val commandArray = mutableListOf("logcat", "-v", "time", "--pid=$pid")
logcat = Runtime.getRuntime().exec(commandArray.toTypedArray())
val br = BufferedReader(InputStreamReader(logcat?.inputStream), 4 * 1024)
var line: String
val separator = System.getProperty("line.separator")
while (br.readLine().also { line = it } != null) {
    emitter.onNext(line + separator)
}
  • logcat의 로그는 기기에서 오류가 발생할 때의 스택 트레이스와 앱에서 개발자가 직접 작성한 Log 클래스 메시지, 그리고 시스템 메시지의 로그를 보여주는 기능을 합니다.

 

 

앱 최상단에서 볼 수 있는 화면을 그립니다.

  • Floating Window
    • 일반적인 컴포넌트가 아닌 항상 떠 있는 뷰
    • 일반적인 Activity나 Fragment가 아닌 Service로 윈도우에 직접 뷰를 붙여야 합니다. 그래서 화해 앱 내의 화면이 이동하더라도 항상 제일 위에 떠 있게 됩니다.

class OverlayLogPopup : LifecycleService() {
    private val rootViewParams: WindowManager.LayoutParams by lazy {
        val type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
        } else {
            WindowManager.LayoutParams.TYPE_PHONE
        }

        WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            type,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            PixelFormat.TRANSLUCENT
        )
    }
    
    private val windowManager: WindowManager by lazy {
        getSystemService(WINDOW_SERVICE) as WindowManager
    }
    
    override fun onCreate() {
        super.onCreate()
        windowManager.addView(rootView, rootViewParams)
    }
    ...
}

 


 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="kr.co.company.hwahae">

     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

     <application>
         <service
            android:name=".overlaylog.OverlayLogPopup"
            android:permission="android.permission.SYSTEM_ALERT_WINDOW" />
     </application>

 </manifest>

  • 터치를 이용하여 윈도우 위치를 변경할 수 있어야 합니다.

private val touchListener = View.OnTouchListener { _, event ->
    when (event?.action) {
        MotionEvent.ACTION_DOWN -> {
            touchX = event.rawX
            touchY = event.rawY
            viewX = rootViewParams.x
            viewY = rootViewParams.y
        }
        MotionEvent.ACTION_MOVE -> {
            val x = (event.rawX - touchX).toInt()
            val y = (event.rawY - touchY).toInt()

            rootViewParams.x = viewX + x
            rootViewParams.y = viewY + y

            windowManager.updateViewLayout(rootView, rootViewParams)
            return@OnTouchListener true
        }
    }
    return@OnTouchListener false
}

 

 

 

화면 설명

  • 언제든지 떠다니는 윈도우 화면으로 로그 확인
  • 홈버튼을 누르거나 백버튼으로 앱 종료 시에는 다른 앱에 영향을 줄 수 있기 때문에 종료 처리

 

 

작은 버튼으로 시작

  • 앱 사용에 방해되지 않도록 이동 시킬 수 있음

리스트로 로그 확인

  • 로그 화면을 위 아래로 드래그해서 이동
logcat logcat

 

 

필터 (스피너 선택)

  • EventLog(데이터로그), WebView, API

그 외 기능

  • 펼치기, 로그 삭제, 닫기
logcat logcat

 

 

 

 

활용도

처음 시작은 데이터팀의 문제 사항을 해결하기 위해 만들었지만, 디버그 목적의 활용도는 다른 플랫폼 에게도 충분히 있을 것으로 예상합니다.

  • 데이터팀
    • 데이터 로그 QA 과정에서 1차적인 이벤트 로그 실시간 확인할 수 있습니다.
⚠️해당 기능은 이벤트 로그가 실제 firebase에 적재된 것을 확인하는 것이 아니고 앱에서 해당 이벤트 로그를 호출하는 부분입니다. 디버그 목적으로만 사용되기 때문에 이 부분을 이해하고 로그 자체에 대한 데이터 로그 적재 여부는 여러 가지 변수가 많아 보장할 수 없습니다.

 

  • 프론트엔드 플랫폼
    • Chrome Inspect로 콘솔 로그는 확인할 수 있지만 기기 연결하는 것보다 빠르게 실제 디바이스에서 발생하는 WebView 관련 로그 확인 가능합니다.
  • 백엔드 플랫폼
    • 앱에서 받은 API 응답을 가공된 정보가 아닌 순수한 API 데이터로 확인
  • 광고 TF
    • 자체 광고 관련 로그 개발 시 로그 확인

 

 

 

마치며

아직 시범적인 디버그 용도의 기능이기 때문에 불편한 점도, 오류도 있어 추가로 개발해야 할 부분이 남아있는 단계입니다. 하지만 협업 과정에서 겪고 있는 문제를 개발로 해결하려고 노력한 점과 화해 앱을 많은 사람이 같이 개선해 나가기 위한 도구를 만들었다는 점에서 의미가 있다고 생각합니다. 저희 안드로이드 플랫폼에서는 앞으로도 협업을 중요시하며 협업 시 발생하는 문제점을 효율적으로 개선하고 해결하기 위해 노력해나갈 것입니다.

 

 

 


 

logcat

 

 

이 콘텐츠가 마음에 드셨다면 다음 콘텐츠도 확인해보세요!

Unit Test 시작하기

 

 

채용정보 확인하기

 

18
by nc nd