Android 앱의 릴리스 버전을 빌드하기 전에 모든 디버그 로깅 호출을 제거하는 방법은 무엇입니까?


397

Google에 따르면 Android 앱을 Google Play에 게시하기 전에 " 소스 코드에서 Log 메소드 호출을 비활성화 "해야합니다 . 발행 체크리스트 의 섹션 3에서 추출하십시오 .

릴리스 할 응용 프로그램을 빌드하기 전에 로깅을 비활성화하고 디버깅 옵션을 비활성화하십시오. 소스 파일에서 Log 메소드에 대한 호출을 제거하여 로깅을 비활성화 할 수 있습니다.

내 오픈 소스 프로젝트는 규모가 크며 릴리스 할 때마다 수동으로 수행하기가 어렵습니다. 또한 다음과 같이 로그 줄을 제거하는 것이 까다로울 수 있습니다.

if(condition)
  Log.d(LOG_TAG, "Something");
data.load();
data.show();

Log 줄을 주석 처리하면 조건이 다음 줄에 적용되며 기회는 load ()가 호출되지 않습니다. 그러한 상황이 존재하지 않아야한다고 결정할 수있을 정도로 드문 일입니까?

그렇다면 더 나은 소스 코드 수준의 방법이 있습니까? 또는 모든 Log 행을 효율적이지만 안전하게 제거하는 영리한 ProGuard 구문입니까?


2
이것이 출판 체크리스트에 있다는 것을 기억하지 못했기 때문에 +1.
rds

51
차단되지 않은 행을 주석 처리하려면 "//"대신 "; //"를 사용하십시오.
02 초

이 작업을 취소 할 수 있어야하는 경우 sed 's_^\(\s*Log\.\)_;//'`date|tr -s \ -`'\1_g'대신 사용하는 것이 좋습니다.
08 초에 yingted

2
Dimitar가 추가 한 링크는 더 이상 작동하지 않습니다. 대신 source.android.com/source/code-style.html#log-sparingly 찾았습니다 .
JosephL

1
@ mboy : 요즘 주로 성능을 기대할 수 있지만 이전 Android 버전에서는 보안상의 이점도 있습니다.
니콜라스 라울

답변:


488

나는 훨씬 쉽게 솔루션은 모든 잊지 찾을 if여기 저기 검사를 그냥 사용 ProGuard에서을 어떤 밖으로 제거하기 위해서 Log.d()또는 Log.v()우리가 우리의 개미 호출 할 때 메서드 호출을 release대상입니다.

이렇게하면 항상 일반 빌드에 대해 디버그 정보가 출력되므로 릴리스 빌드에 대해 코드를 변경할 필요가 없습니다. 또한 ProGuard는 바이트 코드를 여러 번 통과하여 원하지 않는 다른 명령문, 빈 블록을 제거하고 적절한 경우 짧은 방법을 자동으로 인라인 할 수 있습니다.

예를 들어 다음은 Android 용 기본 ProGuard 구성입니다.

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

-keep class * extends android.app.Activity
-assumenosideeffects class android.util.Log {
    public static *** d(...);
    public static *** v(...);
}

파일에 저장 한 다음 Ant에서 ProGuard를 호출하여 방금 컴파일 한 JAR과 사용중인 Android 플랫폼 JAR을 전달합니다.

ProGuard 매뉴얼 의 예제 도 참조하십시오 .


업데이트 (4.5 년 후) : 요즘에는 Android 로깅에 Timber 를 사용했습니다 .

Log로그 태그가 자동으로 설정되고 서식이 지정된 문자열과 예외를 쉽게 기록 할 수 있는 기본 구현 보다 약간 우수 할뿐만 아니라 런타임에 다른 로깅 동작을 지정할 수도 있습니다.

이 예제에서 로깅 명령문은 내 앱의 디버그 빌드에서 logcat에만 작성됩니다.

Application onCreate()방법으로 목재를 설정했습니다 .

if (BuildConfig.DEBUG) {
  Timber.plant(new Timber.DebugTree());
}

그런 다음 내 코드의 다른 곳에서 쉽게 로깅 할 수 있습니다.

Timber.d("Downloading URL: %s", url);
try {
  // ...
} catch (IOException ioe) {
  Timber.e(ioe, "Bad things happened!");
}

개발 중에 모든 로그 문이 logcat으로 전송되고 프로덕션 환경에서는 디버그 문이 기록되지 않지만 오류는 Crashlytics에 자동으로보고되는 고급 예제 는 Timber 샘플 앱 을 참조하십시오 .


59
그리고 왜 기본 proguard 파일에 있지 않습니까?
rds

10
행이 제거되면 프로덕션 스택 추적 행 번호가 코드의 행 번호와 달라집니다.
Guy

5
Log 호출을 제거하면 스택 추적에서 줄 번호가 이동한다는 것을 확인할 수 있습니다. 항상 동기화되지는 않을 것입니다 (몇 가지 빠른 테스트를 수행했지만 로그 호출에서 문자열을 연결하는 경우 원인이 무엇인지 정확하게 파악할 수는 없습니다), 때로는 몇 줄이 벗어날 수도 있습니다. 쉽게 로그 호출을 제거하는 능력에 대한 문제 IMO 가치가 있습니다.
Tony Chan

5
@Fraggle ADT 도구의 proguard-android.txt에서 : "최적화를 활성화하려면 자신의 프로젝트 구성 파일에 최적화 플래그를 포함시킬 수 없으며 대신"proguard-android-optimize "를 가리켜 야합니다. # project.properties 파일에서이 파일 대신 txt "파일을 사용하십시오.
Raanan

3
espinchi가 아래 답변에서 말했듯이. "이 방법의 유일한 문제점은 Log.d ("tag ","Processed : "+ new ItemCounter (blabla) +"items ")를 수행하면이 로그 메시지가 출시 된 버전에 나타나지 않더라도 StringBuilder를 사용하여 메시지를 작성하는데 비용이 많이들 수 있습니다. "Timber의 경우에도 마찬가지입니까?
Chitrang

117

좋은 답변이지만 개발이 끝나면 모든 Log 호출에 if 문을 사용하거나 외부 도구를 사용하고 싶지 않았습니다.

그래서 내가 사용하는 솔루션은 android.util.Log 클래스를 내 자신의 Log 클래스로 바꾸는 것입니다.

public class Log {
    static final boolean LOG = BuildConfig.DEBUG;

    public static void i(String tag, String string) {
        if (LOG) android.util.Log.i(tag, string);
    }
    public static void e(String tag, String string) {
        if (LOG) android.util.Log.e(tag, string);
    }
    public static void d(String tag, String string) {
        if (LOG) android.util.Log.d(tag, string);
    }
    public static void v(String tag, String string) {
        if (LOG) android.util.Log.v(tag, string);
    }
    public static void w(String tag, String string) {
        if (LOG) android.util.Log.w(tag, string);
    }
}

모든 소스 파일에서해야 할 유일한 일은 android.util.Log 가져 오기를 내 클래스로 바꾸는 것입니다.


143
이 방법의 유일한 문제점은 Log.d ( "tag", "Processed :"+ new ItemCounter (blabla) + "items")를 수행하면이 로그 메시지가 릴리스 된 버전에 나타나지 않더라도 StringBuilder는 메시지를 작성하는 데 사용되며 작성 비용이 많이들 수 있습니다.
espinchi

9
이 솔루션에는 큰 문제가 있습니다. espinchi는 빙산의 일각을 언급했습니다. 문제는 호출 할 때 Log.d("tag", someValue.toString());null이 아닌 someValue를 확인하는 것을 잊어 버리는 것이 매우 쉽다는 것 NullPointerException입니다. 이는 생산에 던져 질 수 있음을 의미합니다 . 안전한 솔루션을 제안하지만 당신을 속일 것입니다. 우리는 a private static boolean DEBUG그리고 그때if(DEBUG)Log.d(TAG, msg);
philipp

2
@espinchi 귀하의 관심사는 this answer stackoverflow.com/a/15452492/433718 (Slf4j, backlog, ...) 에서 논의 된 것처럼 모든 로깅 라이브러리에 적용되는 것 같습니다 . 사용하지 않는 것이 좋습니까?
OneWorld

1
@espinchi가 첫 번째 의견에서 언급 한 오버 헤드를 최소화하는 유일한 방법은 varargs 대신 로깅 방법을 변경하는 것입니다 String. 완전한 솔루션은 여기 에 설명되어 있습니다 . 여기에는 또 다른 단점이 있습니다. 모든 통화를 편집해야합니다 (하나의 가져 오기 회선 만이 아님).
Stan

21
참고로 Android Studio 및 gradle 빌드 시스템을 사용 static final boolean LOG = BuildConfig.DEBUG하는 경우이 파일을 사용 하고 수정할 필요가 없습니다.
ashishduh

61

로깅 여부를 나타내는 어딘가에 정적 부울을 갖는 것이 좋습니다.

MyDebug 클래스 {
  정적 최종 부울 LOG = true;
}

그런 다음 코드에 로그인하려는 위치에 다음을 수행하십시오.

if (MyDebug.LOG) {
  if (조건) Log.i (...);
}

이제 MyDebug.LOG를 false로 설정하면 컴파일러는 그러한 검사 내부의 모든 코드를 제거합니다 (정적 최종이므로 컴파일 타임에 코드가 사용되지 않음을 알고 있음).

대규모 프로젝트의 경우 필요에 따라 로깅을 쉽게 활성화 또는 비활성화 할 수 있도록 개별 파일에 부울을 갖기를 시작할 수 있습니다. 예를 들어, 창 관리자에있는 다양한 로깅 상수는 다음과 같습니다.

static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_FOCUS = false;
static final boolean DEBUG_ANIM = false;
static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_RESIZE = false;
static final boolean DEBUG_LAYERS = false;
static final boolean DEBUG_INPUT = false;
static final boolean DEBUG_INPUT_METHOD = false;
static final boolean DEBUG_VISIBILITY = false;
static final boolean DEBUG_WINDOW_MOVEMENT = false;
static final boolean DEBUG_ORIENTATION = false;
static final boolean DEBUG_APP_TRANSITIONS = false;
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
static final boolean DEBUG_WALLPAPER = false;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean HIDE_STACK_CRAWLS = true;
static final boolean MEASURE_LATENCY = false;

다음과 같은 해당 코드를 사용하십시오.

    if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
        TAG, "Adding window " + window + " at "
        + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");

1
나는 그런 접근 방식에도 투표 할 것입니다. 공식 Google 인앱 결제 샘플에서도 사용되었습니다.
LA_

4
조건을 첫 번째 매개 변수로 전달하는 것이 덜 장황하지 않습니까?
Snicolas

1
이것은 각 로그 명령문에 추가 코드가 필요하지만 최상의 솔루션으로 보입니다. 행 번호가 유지됩니다 (ProGuard 접근 방식의 약점), 로그 메시지를 작성하는 코드가 실행되지 않습니다 ( 래퍼 클래스 접근 방식의 약점 및 로깅 라이브러리 접근 방식의 약점 ) . @LA_에 따라 Google의 앱 청구 샘플에서이 방법을 사용하면 내 생각도 뒷받침됩니다.
OneWorld

2
@Snicolas 래퍼를 구현하지 않고 어떻게 조건을 첫 번째 매개 변수로 전달할 수 있습니까? 또한 매개 변수로 매개 변수를 추가하면 메서드를 입력하기 전에 모든 매개 변수, 즉 메시지 문자열을 평가해야합니다. 매개 변수를 빌드하기 전에 조건을 테스트해야합니다. 제안 된 솔루션은 외부 도구가없는 것이 가장 좋습니다.
type-a1pha

2
이진 코드 현명한, 이것이 가장 좋습니다. 그러나 이와 같은 코딩은 간단한 디버그 로그 출력에 많은 노력을 기울입니다. 코드 가독성이 크게 떨어집니다. 일부 승리 일부를 잃고, 나는 ... 생각
리처드 르 Mesurier

30

Christopher의 Proguard 솔루션이 가장 좋지만 어떤 이유로 든 Proguard가 마음에 들지 않으면 매우 낮은 기술 솔루션이 있습니다.

댓글 로그 :

find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/Log\./;\/\/ Log\./g'

주석 해제 로그 :

find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/;\/\/ Log\./Log\./g'

제한 사항은 로깅 명령이 여러 줄에 걸쳐 있지 않아야한다는 것입니다.

(프로젝트의 루트에있는 UNIX 쉘에서이 행을 실행하십시오. Windows를 사용하는 경우 UNIX 계층을 얻거나 동등한 Windows 명령을 사용하십시오)


1
는 ""Sed의에서 -i가 (에 따라 맥에서 실행되는 경우 이후에해야 할 ) 감사합니다.
Vishal

나는 이것이 내가 Guardguard와 함께하는 일이 그리 많지 않았기 때문에 내가하고있는 일에 사용하고있는 것이라고 생각한다
Joe Plante

첫 번째 게시물에서 제안한 것처럼 대괄호가 아닌 분기 이후에 로그가 있으면 어떻게됩니까?
type-a1pha

@ type-a1pha :이 솔루션을 채택하는 경우 대괄호 블록을 필수로 고려해야합니다.
니콜라스 라울

2
@NicolasRaoul 세미 콜론이이 문제를 해결합니다 ( //.;// )
알렉스 Gittemeier

18

최종 바이너리에서 로그 라인을 제거하는 데 많은 문제가 있었으므로 Android Studio 및 gradle과 함께 Proguard를 사용하는 것에 대한 정밀도를 추가하고 싶습니다.

assumenosideeffectsProguard 작품 을 만들기 위해서는 전제 조건이 있습니다.

gradle 파일에서 proguard-android-optimize.txt기본 파일 사용법을 지정해야 합니다.

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

        // With the file below, it does not work!
        //proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

실제로 기본 proguard-android.txt파일에서 두 플래그를 사용하여 최적화가 비활성화됩니다.

-dontoptimize
-dontpreverify

proguard-android-optimize.txt파일이 그 라인을 추가하지 않습니다, 이제 assumenosideeffects작업 할 수 있습니다.

그런 다음 개인적으로 SLF4J를 사용 합니다. 다른 라이브러리에 배포되는 라이브러리를 개발할 때 더 많이 사용됩니다. 장점은 기본적으로 출력이 없다는 것입니다. 통합자가 일부 로그 출력을 원하는 경우 Android 용 Logback을 사용하고 로그를 활성화하여 로그를 파일 또는 LogCat으로 경로 재 지정할 수 있습니다.

최종 라이브러리에서 로그를 제거해야하는 경우 파일을 활성화 한 후 Proguard 파일에 추가합니다 proguard-android-optimize.txt.

-assumenosideeffects class * implements org.slf4j.Logger {
    public *** trace(...);
    public *** debug(...);
    public *** info(...);
    public *** warn(...);
    public *** error(...);
}

새 Jack 컴파일러에서는 작동하지 않습니다. stackoverflow.com/questions/37932114/…
fattire

이것은 나를 도왔다; 모두 proguard-android-optimize.txt기본 Proguard와 파일로 및 -assumenosideeffects사용자 정의 Proguard와 파일이 필요했다! R8 shinker (현재 기본 설정)와 기본 Android 로깅을 사용하고 있습니다.
Jonik

10

Jake Wharton의 Timber를 사용하는 것이 좋습니다.

https://github.com/JakeWharton/timber

활성화 / 비활성화로 문제를 해결하고 자동으로 태그 클래스를 추가합니다.

다만

public class MyApp extends Application {

  public void onCreate() {
    super.onCreate();
    //Timber
    if (BuildConfig.DEBUG) {
      Timber.plant(new DebugTree());
    }
    ...

로그는 디버그 버전에서만 사용됩니다.

Timber.d("lol");

또는

Timber.i("lol says %s","lol");

인쇄

태그를 지정하지 않은 "귀하의 클래스 / msg"


2
목재는 매우 훌륭하지만 이미 기존 프로젝트가있는 경우 github.com/zserge/log를 사용해보십시오 . android.util.Log의 드롭 인 대체품이며 Timber의 기능과 그 밖의 기능을 대부분 갖추고 있습니다.
zserge

zserge, 로그 솔루션이 좋아 보입니다. 많은 기능. 목재와 같은 Lint 규칙 추가를 고려 했습니까?
jk7

8

Google IO 예제 응용 프로그램에서와 같이 LogUtils 클래스를 사용했습니다 . BuildConfig.DEBUG가 신뢰할 수 없기 때문에 BuildConfig.DEBUG 대신 응용 프로그램 특정 DEBUG 상수를 사용하도록 이것을 수정했습니다 . 그런 다음 내 수업에는 다음이 있습니다.

import static my.app.util.LogUtils.makeLogTag;
import static my.app.util.LogUtils.LOGV;

public class MyActivity extends FragmentActivity {
  private static final String TAG = makeLogTag(MyActivity.class);

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    LOGV(TAG, "my message");
  }
}

Build.DEBUG내가 사용한 버그 리포트에 +1 . 또한 다양한 "올바른"해결 방법을 포기하고 비슷한 스타일 솔루션을 사용합니다.
Richard Le Mesurier

7

roboguice의 로깅 기능 사용을 고려할 것 입니다내장 android.util.Log 대신 사용하는 것이 좋습니다.

이 기능은 릴리스 빌드에 대한 디버그 및 상세 로그를 자동으로 비활성화합니다. 또한 무료로 멋진 기능을 사용할 수 있습니다 (예 : 사용자 정의 가능한 로깅 동작, 모든 로그에 대한 추가 데이터 등)

난독 화를 사용하여 상당히 번거 로움이 될 수 있고, 내가 구성하고 만드는 문제를 통해 갈 것이다 일을 당신이 그에게 좋은 이유가없는 한 응용 프로그램과 함께 (로그를 비활성화하는 것은 좋은 하나되지 않습니다)


난독 화를 사용할 수 없을 때 아주 좋은 방법입니다. 특히 LOL을 지키기위한 roboguice 침입 때문에
Snicolas

1
robojuice의 로깅 기능에 대한 업데이트 된 링크 : github.com/roboguice/roboguice/wiki/Logging-via-Ln
RenniePet

7

Android Studio 사용자에게 특별히 적용되는이 솔루션을 게시하고 있습니다. 또한 최근에 Timber를 발견하고 다음을 수행하여 성공적으로 내 앱으로 가져 왔습니다.

최신 버전의 라이브러리를 build.gradle에 넣습니다.

compile 'com.jakewharton.timber:timber:4.1.1'

그런 다음 Android Studio에서 편집-> 찾기-> 경로에서 바꾸기 ...로 이동하십시오.

텍스트 상자에 Log.e(TAG,로그 메시지를 입력 하거나 정의하십시오 "Text to find". 그런 다음Timber.e(

여기에 이미지 설명을 입력하십시오

찾기를 클릭 한 다음 모두 바꿉니다.

이제 Android Studio는 프로젝트의 모든 파일을 검토하고 모든 로그를 팀버로 바꿉니다.

이 방법으로 내가 가진 유일한 문제는 gradle이 각 Java 파일의 가져 오기에서 "Timber"를 찾을 수 없기 때문에 나중에 백만 개의 오류 메시지가 발생한다는 것입니다. 오류를 클릭하면 Android Studio가 자동으로 "Timber"를 Java로 가져옵니다. 모든 오류 파일에 대해 작업을 완료하면 gradle이 다시 컴파일됩니다.

또한이 코드를 클래스 의 onCreate메소드에 넣어야합니다 Application.

    if (BuildConfig.DEBUG) {
        Timber.plant(new Timber.DebugTree());
    }

이로 인해 프로덕션 모드가 아닌 개발 모드에있을 때만 앱이 로깅됩니다. BuildConfig.RELEASE릴리스 모드로 로깅 할 수도 있습니다 .


3
가져 오기에 대해 동일한 작업을 수행하고 정규식 상자가 선택되어 있는지 확인하십시오. 텍스트 : import android\.util\.Log\;바꿀 내용 :import android\.util\.Log\;\nimport timber\.log\.Timber\;
Clark Wilson

또는 자신의 게시물 에 Chike Mgbemena 쇼처럼 구조적 검색을 사용 하고 바꿀 수 있습니다
Maksim Turaev

@MaksimTuraev 귀하의 링크는 더 이상 관련이 없습니다. 이제 헤어 스타일에 관한 블로그입니다.
Vadim Kotov

게시물이 삭제 된 것 같습니다 = (어디에서나 찾을 수 없습니다.
Maksim Turaev '

@MaksimTuraev 여기 뒤로 기계에서 복사본입니다,하지만 이미지가 깨진 - web.archive.org/web/20161004161318/http://chikemgbemena.com/...
바딤 Kotov

6

android.util.Log에 따라 로그를 활성화 / 비활성화하는 방법이 제공됩니다.

public static native boolean isLoggable(String tag, int level);

기본적으로 isLoggable (...) 메소드는 다음과 같이 장치에서 setprop를 설정 한 후에 만 ​​false를 리턴합니다.

adb shell setprop log.tag.MyAppTag DEBUG

DEBUG 레벨 이상의 로그를 인쇄 할 수 있음을 의미합니다. 안드로이드 문서 참조 :

지정된 태그의 로그를 지정된 레벨에서 로그 할 수 있는지 여부를 확인합니다. 태그의 기본 수준은 INFO로 설정되어 있습니다. 즉, INFO를 포함하여 위의 모든 수준이 기록됩니다. 로깅 방법을 호출하기 전에 태그를 기록해야하는지 확인해야합니다. 시스템 특성 'setprop log.tag'를 설정하여 기본 레벨을 변경할 수 있습니다. '레벨이 VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT 또는 SUPPRESS입니다. SUPPRESS는 태그에 대한 모든 로깅을 해제합니다. 'log.tag. ='에 local.prop 파일을 작성하여 /data/local.prop에 배치 할 수도 있습니다.

따라서 우리는 사용자 정의 로그 유틸리티를 사용할 수 있습니다 :

public final class Dlog 
{
    public static void v(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.VERBOSE))
            Log.v(tag, msg);
    }

    public static void d(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.DEBUG))
            Log.d(tag, msg);
    }

    public static void i(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.INFO))
            Log.i(tag, msg);
    }

    public static void w(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.WARN))
            Log.w(tag, msg);
    }

    public static void e(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.ERROR))
            Log.e(tag, msg);
    }
}

6

전역 바꾸기 (한 번)를 실행할 수 있고 그 후에 일부 코딩 규칙이 유지되면 Android 프레임 워크 에서 자주 사용되는 패턴을 따를 수 있습니다 .

쓰는 대신

Log.d(TAG, string1 + string2 + arg3.toString());

그대로

if (BuildConfig.DEBUG) Log.d(TAG, string1 + String.format("%.2f", arg2) + arg3.toString());

이제 proguard는 최적화 된 릴리스 DEX에서 StringBuilder와 사용중인 모든 문자열 및 메소드를 제거 할 수 있습니다. 사용 proguard-android-optimize.txt하면 android.util.Log 에 대해 걱정할 필요가 없습니다 proguard-rules.pro.

android {
  
  buildTypes {
    release {
      minifyEnabled true
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
  }
}

Android Studio gradle 플러그인을 사용하면 매우 안정적이므로 스트리핑을 제어하기 위해 추가 상수가 필요하지 않습니다.BuildConfig.DEBUG


4

여기에 이미지 설명을 입력하십시오

이것은 내 안드로이드 프로젝트에서 사용했던 것입니다 ..

Android Studio에서는 Ctrl + Shift + F를 사용하여 전체 프로젝트 (MacO의 경우 Command + Shift + F)와 Ctrl + Shift + R (대체 (MacO의 경우 Command + Shift + R))을 사용하여 비슷한 작업을 수행 할 수 있습니다


이것은 일식 프로젝트와 함께 일하는 것처럼 보입니다. 안드로이드 스튜디오에서는 검색 옵션을 사용할 수 없습니다.
Simon

2
안드로이드 스튜디오에서 Ctrl + Shift + F 단축키로 비슷한 검색을 할 수 있습니다
Lins Louis

질문의 예제 코드는 이것이 왜 신뢰할 수 없는지를 설명합니다.
Nicolas Raoul

로그에 포함 된 명령을 제거하는 데 문제가 발생할 수 있습니다. 예를 들어 chocolateLog.recipie ();
앤드류 S

Android Studio 2.1에서이 옵션을 찾을 수 없습니다. 또한 정상적인 검색 / 바꾸기로 한 번에 하나의 파일 에이 트릭을 사용할 수 있습니다.
VVB

3

매우 간단한 해결책이 있습니다. 개발에는 IntelliJ를 사용하므로 세부 사항은 다양하지만 아이디어는 모든 IDE에 적용되어야합니다.

소스 트리의 루트를 선택하고 마우스 오른쪽 단추를 클릭 한 후 "바꾸기"를 선택하십시오. 그런 다음 모든 "로그"를 바꾸도록 선택합니다. "// Log."와 함께. 모든 로그 문이 제거됩니다. 나중에 다시 넣으려면 동일한 바꾸기를 반복하지만 이번에는 모든 "// Log"를 바꾸십시오. "로그"와 함께.

나에게만 잘 작동합니다. "대화 상자"와 같은 사고를 피하기 위해 대소 문자를 구분하여 교체를 설정하십시오. 추가 보증을 위해 "로그"로 첫 단계를 수행 할 수도 있습니다. 검색 할 문자열로.

훌륭한.


2
내 질문에있는 "로그 라인에 주석을 달면" 단락을 읽으십시오 .
Nicolas Raoul

예, 답변을 탐색 한 후 더 자주 다시 읽어야합니다. :). 이러한 경우에는 모든 로그를 다른 인터페이스 뒤에 두는 것과 같이 이전에 제안한 것과 같은 다른 솔루션을 원할 수 있습니다. 사람들이 여분의 로깅 라이브러리의 오버 헤드를 피하고 사람들과 코드를 잘 알고있는 소규모 팀과 프로젝트에 제 제안이 더 효과적 일 것입니다.
kg_sYy

1
Log.d를; // Log.d로 바꾸면 "If"시나리오도 처리됩니다.
재스퍼

3

으로 zserge의 의견은 제안,

목재는 매우 훌륭하지만 이미 기존 프로젝트가있는 경우 github.com/zserge/log를 사용해보십시오. android.util.Log의 드롭 인 대체품이며 Timber의 기능과 그 밖의 기능을 대부분 갖추고 있습니다.

그의 로그 라이브러리 는 아래와 같이 간단한 활성화 / 비활성화 로그 인쇄 스위치를 제공합니다.

또한, 단지 변경을 요구 import선, 아무것도 에 대한 변화 요구를 Log.d(...);문.

if (!BuildConfig.DEBUG)
    Log.usePrinter(Log.ANDROID, false); // from now on Log.d etc do nothing and is likely to be optimized with JIT

각 코드를 각 활동 / 조각에 또는 한 곳에만 두어야합니까?
Noah Ternullo

@NoahTernullo // 파생 응용 프로그램 파일에서. DefaultApplication.java
영재

3

proguard-rules.txt 파일에 다음을 추가 하십시오.

-assumenosideeffects class android.util.Log {
  public static *** d(...);
  public static *** w(...);
  public static *** v(...);
  public static *** i(...);
}

1

다른 로그 수준을 지원하고 코드가 라이브 장치 또는 에뮬레이터에서 실행 중인지에 따라 로그 수준을 자동으로 변경하여 위의 솔루션을 개선했습니다.

public class Log {

final static int WARN = 1;
final static int INFO = 2;
final static int DEBUG = 3;
final static int VERB = 4;

static int LOG_LEVEL;

static
{
    if ("google_sdk".equals(Build.PRODUCT) || "sdk".equals(Build.PRODUCT)) {
        LOG_LEVEL = VERB;
    } else {
        LOG_LEVEL = INFO;
    }

}


/**
 *Error
 */
public static void e(String tag, String string)
{
        android.util.Log.e(tag, string);
}

/**
 * Warn
 */
public static void w(String tag, String string)
{
        android.util.Log.w(tag, string);
}

/**
 * Info
 */
public static void i(String tag, String string)
{
    if(LOG_LEVEL >= INFO)
    {
        android.util.Log.i(tag, string);
    }
}

/**
 * Debug
 */
public static void d(String tag, String string)
{
    if(LOG_LEVEL >= DEBUG)
    {
        android.util.Log.d(tag, string);
    }
}

/**
 * Verbose
 */
public static void v(String tag, String string)
{
    if(LOG_LEVEL >= VERB)
    {
        android.util.Log.v(tag, string);
    }
}


}

1
이전 솔루션과 동일한 문제입니다. string 매개 변수가 값 비싼 호출을 사용하여 빌드 된 경우 여전히 리소스를 낭비합니다. 전달 된 매개 변수를 빌드하기 전에 호출 확인을 수행해야합니다.
type-a1pha

1

ProGuard는 릴리스 빌드에서 당신을 위해 그것을 할 것이고 이제 android.com의 좋은 소식입니다.

http://developer.android.com/tools/help/proguard.html

ProGuard 도구는 사용되지 않는 코드를 제거하고 의미가 모호한 이름으로 클래스, 필드 및 메서드의 이름을 바꾸어 코드를 축소, 최적화 및 난독 처리합니다. 결과적으로 리버스 엔지니어링하기가 더 작은 작은 크기의 .apk 파일이 생성됩니다. ProGuard를 사용하면 응용 프로그램을 리버스 엔지니어링하기가 더 어려워 지므로 응용 프로그램에서 응용 프로그램을 라이센싱 할 때와 같이 보안에 민감한 기능을 응용 프로그램에서 사용할 때 사용하는 것이 중요합니다.

ProGuard는 Android 빌드 시스템에 통합되어 있으므로 수동으로 호출 할 필요가 없습니다. ProGuard는 릴리스 모드에서 응용 프로그램을 빌드 할 때만 실행되므로 디버그 모드에서 응용 프로그램을 빌드 할 때 난독 화 된 코드를 처리 할 필요가 없습니다. ProGuard를 실행하는 것은 완전히 선택 사항이지만 강력히 권장됩니다.

이 문서는 난독 처리 된 스택 추적을 디코딩하기 위해 ProGuard를 활성화 및 구성하는 방법과 retrace 도구를 사용하는 방법을 설명합니다


2
그러나 기본적으로 디버그 로깅은 제거하지 않는 것 같습니다. 그래서 Christopher의 답변이 더 좋습니다.
니콜라스 라울

0

Log.d (TAG, 일부 문자열, 종종 String.format ())를 사용하고 싶습니다.

TAG는 항상 클래스 이름입니다

클래스 텍스트에서 Log.d (TAG,-> Logd (

private void Logd(String str){
    if (MainClass.debug) Log.d(className, str);
}

이 방법으로 릴리스 버전을 만들 준비가되면 MainClass.debug를 false로 설정하십시오!


1
이것과 다른 솔루션을 보호하거나 주석 처리하는 것의 문제점은 코드에서 빠져 나와 많은 양의 문자열 빌드가 발생할 수 있다는 것입니다. 평균적인 앱에서는 문제가되지 않지만 최적화하려고하면 문제가됩니다.
Lassi Kinnunen

0

리눅스와 sed에서 bash를 사용하여 로그를 제거 할 수 있습니다.

find . -name "*\.java" | xargs sed -ri ':a; s%Log\.[ivdwe].*\);%;%; ta; /Log\.[ivdwe]/ !b; N; ba'

여러 줄 로그에서 작동합니다. 이 솔루션에서 프로덕션 코드에 로그가 없는지 확인할 수 있습니다.


0

나는 이것이 오래된 질문이라는 것을 알고 있지만 왜 모든 로그 호출을 Boolean logCallWasHere = true와 같은 것으로 바꾸지 않았습니까? // --- 여기서 로그의 나머지

그렇기 때문에 언제 다시 되돌릴 것인지 알고 if 문 호출에 영향을 미치지 않습니다. :)


흥미롭게도, 그런 줄은 컴파일러 / 최적화 프로그램에서 무시됩니다. 그러나 일부 메소드에는 여러 개의 로그 호출이 있으며 동일한 변수를 두 번 선언 할 수 없으므로 변수 이름은 고유해야합니다.
Nicolas Raoul

활동에서 변수를 맨 위에 선언하고이 줄에서 부울 선언을 제거 할 수 있습니다.)
masood elsad

0

왜 안 해?

if(BuildConfig.DEBUG)
  Log.d("tag","msg");

? 추가 라이브러리가 필요없고 프로젝트를 망치는 경향이있는 proguard 규칙이 없으며 Java 컴파일러는 릴리스 빌드를 할 때이 호출에 대한 바이트 코드를 남기지 않습니다.


불편한 점은 단순히 글을 쓰는 것보다 더 장황 Log.d("tag","msg");하고 if(BuildConfig.DEBUG)부분을 쓰는 것을 잊기 쉽다는 것입니다 .
Nicolas Raoul

1
이것에 대한 또 다른 문제는 문자열이 압축 릴리스에 남아 있다는 것입니다.
straya

0

추가 라이브러리를 엉망으로 만들거나 코드를 수동으로 편집하지 않으려는 경우 내 솔루션입니다. 이 Jupyter 노트북 을 만들어 모든 Java 파일을 살펴보고 모든 로그 메시지를 주석 처리했습니다. 완벽하지는 않지만 작업이 완료되었습니다.


0

내 길 :

1) 열 선택 모드 사용 (alt + shift + insert)

2) 하나의 Log.d (TAG, "text")를 선택하십시오. '로그'부분.

3) 그런 다음 Shift + Ctrl + Alt + J

4) 왼쪽 화살표를 클릭하십시오

5) 쉬프트 + 종료

6) 삭제를 누르십시오.

Java 파일에서 모든 LOG 호출을 한 번에 제거합니다.


0

이 간단한 기존 방법을 사용해보십시오.

Ctrl+ Shift+R

바꾸다

Log.e(

// Log.e(

질문에 주어진 예제 코드에서는 제대로 작동하지 않습니다.
니콜라스 라울

0

kotlin으로 쉽게 몇 가지 최상위 함수를 선언하십시오.

val isDebug: Boolean
    get() = BuildConfig.DEBUG

fun logE(tag: String, message: String) {
    if (isDebug) Log.e(tag, message)
}

fun logD(tag: String, message: String) {
    if (isDebug) Log.d(tag, message)
}

-1

가장 간단한 방법;

사용하다 DebugLog

앱이 출시되면 DebugLog에 의해 모든 로그가 비활성화됩니다.

https://github.com/MustafaFerhan/DebugLog


이것은 절대적으로 잘못입니다. 이로 인해 로그가 기록되지 않고 코드에서 제거되지 않으므로 사람들이 코드를 리버스 엔지니어링하는 데 도움이되고 여전히 모든 로그의 문자열을 형식화하는 비용이 있습니다.
Glenn Maynard
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.