记录最佳实践和想法

Rob*_*ert 19 logging android logcat

我即将对我的应用程序进行一些重构,然后我开始思考这个简单而复杂的主题,日志记录,如何做到干净,有效和信息丰富的日志记录......

当您阅读有关日志记录的文档时,您经常会看到此代码段

if (BuildConfig.DEBUG) {
    Log.d(TAG + "message");
}
Run Code Online (Sandbox Code Playgroud)

它让我想知道它的目的是什么?根据文档Android Developer - Log,调试日志消息被编译但在运行时被剥离,因此您不需要在该if语句中进行日志调用.还是我想知道什么?

然后我也想知道使用除调试之外的任何其他Log.x()调用的真正好处是什么,因为用户不会看到日志条目或登录到某些错误文件,因此它们将被编译并执行在生产环境中没有任何目的?这可能是之前if语句的用例?

我之前提到过,日志条目没有记录到文件中.为什么这不是Android的内置功能?是因为性能问题,不必要的权限使用还是别的?我已经在我自己的日志类中实现了这个功能,但现在我想知道这是不好的做法?但是拥有重要日志条目的日志也很好吗?

因此,要在开发和生产过程中实现清洁,有效和信息丰富的日志记录.什么是最佳做法?

Ale*_*hak 12

仅在开发期间调试应用程序所需的日志,以确保该功能按预期工作并产生所需的结果.我相信,最佳做法是以最方便的方式进行日志记录,并尽可能快速有效地查找和解决问题

我之前提到过,日志条目没有记录到文件中.为什么这不是Android的内置功能?

谁(开发阶段的程序员除外)希望应用程序在一个设备上浪费有限的存储空间和无用的数据?用户看不到,不看,不使用日志.他们不需要这种垃圾.生产中的应用程序不得生成任何日志,当然,不得将它们保存到文件中.

应该在已发布的应用程序中实现的唯一日志记录是未处理的异常日志记录.此外,应用程序负责处理这些日志,如果它建议发送崩溃报告,并在报告发送后删除它们.

发布的应用程序不应创建日志的另一个原因是它们可能包含需要用户授权的敏感数据和输出,从而引入安全漏洞.

我相信最佳做法是在部署到生产之前,在模块或功能完全实施并进行全面测试后立即删除所有日志.引入if (BuildConfig.DEBUG)条件有助于确保实现这一目标.

  • 如果它是一个与外部设备连接以执行一些复杂事务并需要收集应发送给支持团队的诊断信息的应用程序,该怎么办?收到一些客户支持请求声称“此连接无法正常工作”并且无法在其设备上找到原因,这很糟糕。 (2认同)

Eef*_*ret 8

这将使用这种ClasssName[MethodName] - LineNumber带反射的格式生成干净的调试标记.

这里提供了带有内联注释的完整代码.

import android.util.Log;

public class Logger {

    public enum LOGGER_DEPTH {
        ACTUAL_METHOD(4),
        LOGGER_METHOD(3),
        STACK_TRACE_METHOD(1),
        JVM_METHOD(0);

        private final int value;

        private LOGGER_DEPTH(final int newValue) {
            value = newValue;
        }

        public int getValue() {
            return value;
        }
    }

    private static final String personalTAG = "Logger";

    private StringBuilder sb;

    private Logger() {
        if (LoggerLoader.instance != null) {
            Log.e(personalTAG, "Error: Logger already instantiated");
            throw new IllegalStateException("Already Instantiated");
        } else {
            this.sb = new StringBuilder(255);
        }
    }

    public static Logger getLogger() {
        return LoggerLoader.instance;
    }

    private String getTag(LOGGER_DEPTH depth) {
        try {
            String className = Thread.currentThread().getStackTrace()[depth.getValue()].getClassName();
            sb.append(className.substring(className.lastIndexOf(".") + 1));
            sb.append("[");
            sb.append(Thread.currentThread().getStackTrace()[depth.getValue()].getMethodName());
            sb.append("] - ");
            sb.append(Thread.currentThread().getStackTrace()[depth.getValue()].getLineNumber());
            return sb.toString();
        } catch (Exception ex) {
            ex.printStackTrace();
            Log.d(personalTAG, ex.getMessage());
        } finally {
            sb.setLength(0);
        }
        return null;
    }

    public void d(String msg) {
        try {
            Log.d(getTag(LOGGER_DEPTH.ACTUAL_METHOD), msg);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void d(String msg, LOGGER_DEPTH depth) {
        try {
            Log.d(getTag(depth), msg);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void d(String msg, Throwable t, LOGGER_DEPTH depth) {
        try {
            Log.d(getTag(depth), msg, t);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void e(String msg) {
        try {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), msg);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void e(String msg, LOGGER_DEPTH depth) {
        try {
            Log.e(getTag(depth), msg);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void e(String msg, Throwable t, LOGGER_DEPTH depth) {
        try {
            Log.e(getTag(depth), msg, t);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void w(String msg) {
        try {
            Log.w(getTag(LOGGER_DEPTH.ACTUAL_METHOD), msg);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void w(String msg, LOGGER_DEPTH depth) {
        try {
            Log.w(getTag(depth), msg);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void w(String msg, Throwable t, LOGGER_DEPTH depth) {
        try {
            Log.w(getTag(depth), msg, t);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void v(String msg) {
        try {
            Log.v(getTag(LOGGER_DEPTH.ACTUAL_METHOD), msg);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void v(String msg, LOGGER_DEPTH depth) {
        try {
            Log.v(getTag(depth), msg);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void v(String msg, Throwable t, LOGGER_DEPTH depth) {
        try {
            Log.v(getTag(depth), msg, t);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void i(String msg) {
        try {
            Log.i(getTag(LOGGER_DEPTH.ACTUAL_METHOD), msg);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void i(String msg, LOGGER_DEPTH depth) {
        try {
            Log.i(getTag(depth), msg);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void i(String msg, Throwable t, LOGGER_DEPTH depth) {
        try {
            Log.i(getTag(depth), msg, t);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void wtf(String msg) {
        try {
            Log.wtf(getTag(LOGGER_DEPTH.ACTUAL_METHOD), msg);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void wtf(String msg, LOGGER_DEPTH depth) {
        try {
            Log.wtf(getTag(depth), msg);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    public void wtf(String msg, Throwable t, LOGGER_DEPTH depth) {
        try {
            Log.wtf(getTag(depth), msg, t);
        } catch (Exception exception) {
            Log.e(getTag(LOGGER_DEPTH.ACTUAL_METHOD), "Logger failed, exception: " + exception.getMessage());
        }
    }

    private static class LoggerLoader {
        private static final Logger instance = new Logger();
    }
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*res 5

自从我开始在Android中工作以来,我就遇到了同样的问题,并且创建了这个开源项目(Android Studio宏),该项目允许您通过使用“ // <#DEBUG_AREA>和// <#/ DEBUG_AREA>“代码中的标记,基本思想是,当您更改构建变体时,这些标记中的任何内容都会被注释,例如,如果在for循环中有类似的内容:

       //=========This piece of code is only for logging purposes...=========
        Log.e("LogUserInfo", "Name: " + name);
        Log.e("LogUserInfo", "Id: " + user.getId());
        Log.e("LogUserInfo", "Id: " + user.getDistance());
        //====================================================================
Run Code Online (Sandbox Code Playgroud)

代替这样做:

if(DEBUG){
      Log.e("LogginUserInfo", "Name: " + name);
      Log.e("LogginUserInfo", "Id: " + user.getId());
      Log.e("LogginUserInfo", "Id: " + user.getDistance());
 }
Run Code Online (Sandbox Code Playgroud)

使用此宏,您可以执行以下操作(完整方法):

private List<String> getNamesOfUsersNearMe(String zipCode){
    List<User> users = mBusinessLogic.getUsersByZipcode(zipCode);
    if(users == null || users.size() < 1){
        return null;
    }

    List<String> names = new ArrayList<String>();
    int totalUsers = users.size();
    for(int i = 0; i < totalUsers; i++){
        User user = users.get(i);
        String name = user.getName();
        names.add(name);
        //<#DEBUG_AREA>
        Log.e("LogginUserInfo", "Name: " + name);
        Log.e("LogginUserInfo", "Id: " + user.getId());
        Log.e("LogginUserInfo", "Id: " + user.getDistance());
        //</#DEBUG_AREA>
    }
    return names;
}
Run Code Online (Sandbox Code Playgroud)

当您更改构建版本以将其发布时,它将变成这样:

private List<String> getNamesOfUsersNearMe(String zipCode){
    List<User> users = mBusinessLogic.getUsersByZipcode(zipCode);
    if(users == null || users.size() < 1){
        return null;
    }

    List<String> names = new ArrayList<String>();
    int totalUsers = users.size();
    for(int i = 0; i < totalUsers; i++){
        User user = users.get(i);
        String name = user.getName();
        names.add(name);
        /*<#DEBUG_OFF>
            Log.e("LogginUserInfo", "Name: " + name);
            Log.e("LogginUserInfo", "Id: " + user.getId());
            Log.e("LogginUserInfo", "Id: " + user.getDistance());
        </#DEBUG_OFF>*/
    }

    return names;
}
Run Code Online (Sandbox Code Playgroud)

长循环的性能更好,并且可以通过在“发布”模式下摆脱不必要的代码来使代码更整洁,当然,如果返回“调试”,它将取消注释该区域并使其保持原来的方式带有“ <#DEBUG_AREA>”标签...

还要尝试适应最常见的情况,似乎有时候您不需要一个完整的区域就可以摆脱,而只需要一个Log,因此在这种情况下,该项目还有一个Log wrapper类,您可以将其用作如下:

if(users == null || users.size() < 1){
    ASDebuggerMacroLog.e("LogUserInfo", "There's no users available near me...");
    return null;
}
Run Code Online (Sandbox Code Playgroud)

在Android Studio中更改为“发布”模式后,将注释“ ASDebuggerMacroLog”类使用的代码行。

希望能帮助到你!

问候!