Logging best practices and thoughts

Logs only needed to debug applications during development, to ensure that the feature works as expected and produces desired results. The best practice is, I believe, to do logging in any way which is most convenient to you and allows to find and resolve issues as quickly and efficiently as possible

I mentioned earlier that the log entry isn't logged into a file. Why isn't this a built in feature in Android?

Who (except a programmer on the development stage) would want an application to waste limited storage space on one's device with useless data? Users don't see, don't read, don't use logs. They don't need this garbage. Application in production must not produce any logs and, of course, must not save them to files.

The only logging which should be implemented in released application is unhandled exceptions logging. Moreover, it's application's responsibility to handle these logs if it suggests sending crash reports, and removing them after the report has been sent.

Another reason logs should not be created by released apps is that they may contain sensitive data and output which requires user authorization, thus introducing security flaws.

I believe the best practice is to remove all logs as soon as the module or feature is fully implemented and thoroughly tested, before deployment to production. Introducing if (BuildConfig.DEBUG) condition helps to ensure this has been achieved.


This will generate clean debug tags with this format ClasssName[MethodName] - LineNumber with reflection.

Complete code with inline comments is available as a gist here.

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();
    }
}