android开发之自定义log工具

本文介绍了一种基于BuildConfig.DEBUG特性的日志管理方法,该方法能够在开发和生产环境中智能控制日志输出,有效防止敏感信息泄露。通过自定义Logger类及LogManager管理器实现日志的灵活控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

log日志输出在实际开发的过程中,使用频率是非常高的,每天都在用,那么问题容易出在哪个环节?体现在控制!因为log输出的往往都是项目的核心数据,也就是业务数据。当项目运行在生产环境下的时候,一旦产生数据泄漏,这就不叫bug了,那就是事故!所以,虽然log常用,但是能用到什么水平,那就是功底的问题。


原理剖析

eclipse下,随便生成一个android项目,基础文件生成出来之后,会有一个很特别的一级目录gen,这个目录下面有会一个二级目录,二级目录下面只有两个固定的文件,一个是R文件,这个文件里面是自动生成的,里面主要标识的是项目内所有资源的定位信息。另外一个文件就是BuildConfi.java,这个文件里面有一个静态的boolean值。具体定义是这个样子的,如下:

public final class BuildConfig {
    public final static boolean DEBUG = true;
}

不用疑惑,只要你在eclipse下创建新的android项目,这个目录就存在,而且它就是这个样子。它的特性在于,当项目在debug签名情况下是为true,但是当项目打上签名之后,这个值会自动变成false。那么就利用这个特性,控制log日志的输出。


Logger

public class Logger {

    public Logger() { }

    public void v(String format, Object... args)  { }

    public void d(String format, Object... args)  { }

    public void i(String format, Object... args)  { }

    public void w(String format, Object... args)  { }

    public void w(Throwable tr, String format, Object... args)  { }

    public void e(String format, Object... args)  { }

    public void e(Throwable tr, String format, Object... args)  { }

    public void wtf(String format, Object... args)  { }

    public void wtf(Throwable tr, String format, Object... args)  { }
}

LogManager

public class LogManager {
    public static final String Default_Tag = "TAGINFO";

    private static Logger Logger;
    private static HashMap<String,Logger> LoggerMap = null;

    public static Logger getLogger() {
        return getLogger(null);
    }

    public static Logger getLogger(String tag) {
        if(BuildConfig.DEBUG) {
            return getDebugLogger(tag);         
        } else {
            if (Logger == null) {
                Logger = new Logger();
            }
            return Logger;
        }
    }

    private static Logger getDebugLogger(String tag) {
        if(null == tag) tag = Default_Tag;

        Logger logger;
        if(null == LoggerMap) {
            synchronized (LogManager.class) {
                if(null == LoggerMap) LoggerMap = new HashMap<String,Logger>(); 
            }
        }

        if (LoggerMap.containsKey(tag))
            logger = LoggerMap.get(tag);
        else {
            logger = new DebugLogger(tag);
            LoggerMap.put(tag, logger);
        }
        return logger;
    }

    private static class DebugLogger extends Logger {
        private String tag;

        private DebugLogger(String tag) {    

            if(null != this.tag && tag == this.tag) return;     
            this.tag = null == tag? LogManager.Default_Tag:tag;
        }

        @Override
        public void v(String format, Object... args) {
            Log.v(tag, buildSimpleMessage(format, args));
        }

        @Override
        public void d(String format, Object... args) {
            Log.d(tag, buildSimpleMessage(format, args));
        }

        @Override
        public void i(String format, Object... args) {
            Log.i(tag, buildSimpleMessage(format, args));
        }

        @Override
        public void w(String format, Object... args) {
            Log.w(tag, buildMessage(format, args));
        }

        @Override
        public void w(Throwable tr, String format, Object... args) {
            Log.w(tag, buildMessage(format, args), tr);
        }

        @Override
        public void e(String format, Object... args) {
            Log.e(tag, buildMessage(format, args));
        }

        @Override
        public void e(Throwable tr, String format, Object... args) {
            Log.e(tag, buildMessage(format, args), tr);
        }

        @Override
        public void wtf(String format, Object... args) {
            Log.wtf(tag, buildMessage(format, args));
        }

        @Override
        public void wtf(Throwable tr, String format, Object... args) {
            Log.wtf(tag, buildMessage(format, args), tr);
        }

        private String buildSimpleMessage(String format, Object... args) {
            return (args == null) ? format : String.format(Locale.US, format, args);
        }
        private String buildMessage(String format, Object... args) {
            String msg = buildSimpleMessage(format, args);
            StackTraceElement[] trace = new Throwable().fillInStackTrace().getStackTrace();

            String caller = "<unknown>";
            for (int i = 2; i < trace.length; i++) {
                Class<?> clazz = trace[i].getClass();
                if (!clazz.equals(DebugLogger.class)) {
                    String callingClass = trace[i].getClassName();
                    callingClass = callingClass.substring(callingClass.lastIndexOf('.') + 1);
                    callingClass = callingClass.substring(callingClass.lastIndexOf('$') + 1);

                    caller = callingClass + "." + trace[i].getMethodName();
                    break;
                }
            }
            return String.format(Locale.US, "[%d] %s: %s",
                    Thread.currentThread().getId(), caller, msg);
        }
    }
}

使用

LogManager.getLogger().d("keyvalues: %s, keyvalues: %s",values, values);

上述中, %s 设置以字符串格式输出,keyvalues自定数据串标识,values表示和keyvalues对应的实体数据

总结

log日志如何使用直接决定了项目开发的效率,这个和注释是一个样子的。虽然很基础的东西,但是往往都是在项目开发过程中最重要的东西。以网络请求为例,请求的接口地址,参数,返回数据,等一系列数据,通过log输出后,不需要进行UI验证,直接通过数据就验证了业务的精准性。在logcat中,以自定义的TAG为自定义过滤的TAG,直接将数据输出出来,方便开发,方便维护。并且通过这种方式,在测试阶段日志正常输出,但是一旦签名之后,即便设备root之后,通过shell采集数据,这个也一样不会输出。

忠告

敬告各位同行,研发无小事,慎重对待每一个细节。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值