【问题标题】:Flexible enable/disable logging in Android app在 Android 应用中灵活启用/禁用日志记录
【发布时间】:2012-07-21 01:59:50
【问题描述】:

出于性能方面的考虑,有些人建议使用以下方法,例如

public class MyActivity extends Activity {  

 private static final String TAG = "MyApp";  
 private static final boolean D = true;

 @Override  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if(D) Log.e(TAG, "MyActivity.onCreate debug message");  }

但是在做一个大项目的时候这是不合理的,因为当你调试的时候,你需要为debug标志更新很多文件,有没有更好的方法?

【问题讨论】:

  • 如果您还考虑节省资源,调用前的布尔测试是最好的解决方案。您可以使用静态类将布尔值仅保存在一个位置。按照建议使用 BuildCondig.DEBUG。

标签: java android


【解决方案1】:

您可以在 BuildConfig 中检查 DEBUG 布尔值:

if (BuildConfig.DEBUG) {
    // Do what you need
}

或者,您可以有一个调试变量,但或者将其保留在每个活动中,在您的应用程序类中声明它,并在需要时检查它的值。

如果您使用该变量的目的是进行日志记录,那么最好将您的日志记录包装到另一个类中,该类会检查 DEBUG 变量:

public class LogUtils {
    public static void LOGD(final String tag, String message) {
        if (BuildConfig.DEBUG) {
            Log.d(tag, message);
        }
    }

    public static void LOGV(final String tag, String message) {
        if (BuildConfig.DEBUG) {
            Log.v(tag, message);
        }
    }

    public static void LOGI(final String tag, String message) {
        if (BuildConfig.DEBUG) {
            Log.i(tag, message);
        }
    }

    public static void LOGW(final String tag, String message) {
        if (BuildConfig.DEBUG) {
            Log.w(tag, message);
        }
    }

    public static void LOGE(final String tag, String message) {
        if (BuildConfig.DEBUG) {
            Log.e(tag, message);
        }
    }

}

然后,对这个类进行日志调用:

LogUtils.LOGD(TAG, "MyActivity.onCreate debug message");

【讨论】:

  • 似乎BuildConfig 是我需要的,但我的项目是旧的(2.2)所以如何使用Eclipse(使用最新的SDK)生成BuildConfig?谢谢。首先。
  • 你无法导入这个类吗?:your.package.name.BuildConfig
  • 我可以在gen 文件夹中找到,但似乎ADT (code.google.com/p/android/issues/detail?id=27940) 中存在错误,因此不推荐使用此方法。
  • 为了避免可能出现的错误:项目 -> 自动构建 |项目 -> 清洁 |项目 -> 构建项目 |导出安卓应用
  • LogUtils 无法避免因字符串求值而导致的过载。
【解决方案2】:

我强烈推荐 Google 开发人员在他们的开源应用程序 iosched 上开发的内容。除其他原因外,它牢记BuildConfig 并检查指定标签的日志是否可在指定级别使用isLoggable 记录。这对我的项目来说是必须的。

/*
 * Copyright 2012 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.android.apps.iosched.util;

import com.google.android.apps.iosched.BuildConfig;

import android.util.Log;

/**
 * Helper methods that make logging more consistent throughout the app.
 */
public class LogUtils {
    private static final String LOG_PREFIX = "iosched_";
    private static final int LOG_PREFIX_LENGTH = LOG_PREFIX.length();
    private static final int MAX_LOG_TAG_LENGTH = 23;

    public static String makeLogTag(String str) {
        if (str.length() > MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH) {
            return LOG_PREFIX + str.substring(0, MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH - 1);
        }

        return LOG_PREFIX + str;
    }

    /**
     * WARNING: Don't use this when obfuscating class names with Proguard!
     */
    public static String makeLogTag(Class cls) {
        return makeLogTag(cls.getSimpleName());
    }

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

    public static void LOGD(final String tag, String message, Throwable cause) {
        if (Log.isLoggable(tag, Log.DEBUG)) {
            Log.d(tag, message, cause);
        }
    }

    public static void LOGV(final String tag, String message) {
        //noinspection PointlessBooleanExpression,ConstantConditions
        if (BuildConfig.DEBUG && Log.isLoggable(tag, Log.VERBOSE)) {
            Log.v(tag, message);
        }
    }

    public static void LOGV(final String tag, String message, Throwable cause) {
        //noinspection PointlessBooleanExpression,ConstantConditions
        if (BuildConfig.DEBUG && Log.isLoggable(tag, Log.VERBOSE)) {
            Log.v(tag, message, cause);
        }
    }

    public static void LOGI(final String tag, String message) {
        Log.i(tag, message);
    }

    public static void LOGI(final String tag, String message, Throwable cause) {
        Log.i(tag, message, cause);
    }

    public static void LOGW(final String tag, String message) {
        Log.w(tag, message);
    }

    public static void LOGW(final String tag, String message, Throwable cause) {
        Log.w(tag, message, cause);
    }

    public static void LOGE(final String tag, String message) {
        Log.e(tag, message);
    }

    public static void LOGE(final String tag, String message, Throwable cause) {
        Log.e(tag, message, cause);
    }

    private LogUtils() {
    }
}

【讨论】:

    【解决方案3】:

    this 一些相关问题的答案之一中找到了另一种解决方案。您可以像这样覆盖 Log 类:

    public class Log {
        static final boolean LOG = false;
    
        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);
        }
    }
    

    这样,你就不需要每次使用 log 时都使用 if 语句了。只需更改覆盖的 Log 类中的布尔值。当您准备好发布时,您可以使用 ProGuard 之类的工具剥离所有对 Log 的引用以提高性能。

    【讨论】:

    • 不会避免因字符串求值而导致的过载。
    【解决方案4】:

    使用 ProGuard 去除 Log.v 和 Log.d 消息

    另一种使用更少代码的替代方法是使用 ProGuard 将这些内容剥离出来以用于最终发布的应用程序。

    基本上,在app\proguard-rules.pro 文件中,定义您要剥离的android.util.Log 类的方法。 proguard-rules.pro 文件中的以下添加将导致在构建时剥离 v(详细)和 d(调试)方法:

    # This tell Proguard to assume Log.v and Log.d have no side effects (even
    # though they do since they write to the logs) and thus can be removed
    # during optimization:
    -assumenosideeffects class android.util.Log {
        public static int v(...);
        public static int d(...);
    }
    

    这避免了对贯穿整个代码的if (BuildConfig.DEBUG) 样式检查的需要。

    另见:Disable LogCat Output COMPLETELY in release Android app?

    【讨论】:

      【解决方案5】:

      我编写了一个LogWrapper 类,它很简单,看起来像这样:

      public class LogWrapper {
          private static final String DEBUG_TAG = "some-tag"
          private static boolean logsEnabled;
      
          public static void e(String msg) {
            if (logsEnabled) {      
              Log.e(DEBUG_TAG, msg);
            }
          }
      
          // other Log methods
      }
      

      您可以使用它来代替 Log 类,在一个地方随意修改布尔变量。希望这会有所帮助。

      【讨论】:

      • 包装器无法避免因字符串求值而导致的过载。
      【解决方案6】:

      我最近遇到了同样的问题,我认为用 Proguard 剥离类并不是禁用日志的好主意。所以我最终为标准的 Android Log 类编写了一个简单的替代品

      https://github.com/zserge/log

      它允许您控制日志级别。它还为您提供了很多“糖”来记录多个值、日志标签等等,而且 Maven Central/JCenter 上只有 200 行代码可用。

      【讨论】:

        猜你喜欢
        • 2021-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-01
        • 1970-01-01
        • 2015-06-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多