How can I match the android.util.Log with crashlytics? - android

I want to create a new class in my android app to use crashlytics logging. That I want to do is create some methods that match the android.util.Log and I want to call the crashlytics method within ( Crashlytics.getInstance().core.log). But I don't have clear how can I do it... Someone can help me?
For example, I can do something like this?
Copy all Log.class in a new class and do
private Log() {
Crashlytics.getInstance().core.log
}
public static int v(String tag, String msg) {
return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
}
.
.
.
And in another class.
Log.v(tag, message);
This could work?

You could do something like:
private CrashlyticsCore getCrashlytics() {
return Crashlytics.getInstance().core;
}
public void logDebug(String tag, String message) {
getCrashlytics().log(Log.DEBUG, tag, message);
}
Then in another part of the app just call
logDebug(TAG, "This is a log message");

Related

How can I monitor android.util.log or override it?

I'm using log.d/v/w/e everywhere in the project.
Now, I want to save all the logs to the device local file.
However, the android.util.Log class in the final class.
That means I can't extend from it.
Is there a way to take over control for android.util.Log, so that I don't need to change log.d/v/w/e everywhere in the project?
I'm looking for a simple way to know if log.d/v/w/e is getting called and so that I can write the info to the local file.
When you need to add to the functionality of a final class, a common option is to use the decorator (wrapper) pattern:
public class LogUtils {
public static void LOGE(String tag, String message) {
Log.e(tag, message);
doSomethingElse();
}
...
}
This sort of implementation for logging is pretty popular.
However, there's another option to writing your own wrapper. Jake Wharton's library Timber already handles all the utility, and adds some other niceties like automatic tags and use of String.format for Java.
You can add your own functionality to handle your own diagnostic logic kind of like so:
public class MyLoggingClass extends DebugTree {
#Override
public void log(int priority, String tag, String message, Throwable t) {
if (BuildConfig.DEBUG) {
super.log(priority, tag, message, t);
}
doSomethingElse();
}
}
Remove any 'import android.util.Log' from a file and you can include your own log class:
// log.java
package com.my.package;
public class Log {
public static int v(String tag, String msg) { return println(android.util.Log.VERBOSE, tag, msg); }
public static int d(String tag, String msg) { return println(android.util.Log.DEBUG, tag, msg); }
public static int i(String tag, String msg) { return println(android.util.Log.INFO, tag, msg); }
public static int w(String tag, String msg) { return println(android.util.Log.WARN, tag, msg); }
public static int e(String tag, String msg) { return println(android.util.Log.ERROR, tag, msg); }
public static int println(int priority, String tag, String msg) {
// Do another thing
return android.util.Log.println(priority, tag, msg);
}
}
Then you can leave all your 'Log.e' lines undisturbed, but still intercept the logging lines.
This isn't a complete replacement/implementation of the android.util.Log class, but it's got all the functions I use and it's easy to extend if you need to.

Log statement during unit test

I am currently starting to unit test my android application. I am having problems when the unit test exercise code that has log statements in it. Here is a specific case. I have a class called ServiceManager that has a setSystemPause() and a getSystemPause() method. I just want a simple unit test that exercise that logic
ServiceManager class:
public class ServiceManager implements IServiceManager {
private final static String TAG = "ServiceManager";
private boolean mSystemPauseStatus = false;
public boolean getSystemPause () {
Log.i ("TAG", "getSystemPause: " + mSystemPauseStatus);
return mSystemPauseStatus;
}
public void setSystemPause (boolean pauseStatus){
Log.i ("TAG", "setSystemPause: " + pauseStatus);
mSystemPauseStatus = pauseStatus;
}
}
The unit test:
public class ServiceManagerTest {
#Test
public void testSystemPause() throws Exception {
ServiceManager serviceManager = new ServiceManager();
serviceManager.setSystemPause(false);
assert (! serviceManager.getSystemPause());
serviceManager.setSystemPause(true);
assert (serviceManager.getSystemPause());
}
}
The problem are the "Log.i" statements in my code. That causes the following error:
java.lang.RuntimeException: Method i in android.util.Log not mocked.
I understand what is happening, during unit test the android.jar library that is used does not contain the real code and I need to mock that call to "Log.i".
But the code base that I am going to test contains a lot of Log statements. I don't want to mock each usage of the Log facility.
My question is how do people do unit testing in Android while having Log statements in their code. Is there another log facility that I can use in my code instead of the Log class.
I also read the page here:
https://developer.android.com/training/testing/unit-testing/local-unit-tests.html
They suggest doing this in my build.gradle file:
android {
...
testOptions {
unitTests.returnDefaultValues = true
}
}
I don't want to resort to that because I just want the Log to appear. I want to properly mock all other facilities I will use in Android.
But will the Log statement affect the outcome of your unit tests? Problem is that Log is an Android-specific class, and can't be used as part of a JUnit 4 test as it's not part of the Java JDK. If you need Log statements to work as intended, either mock the behaviour out with Mockito, use returnDefaultValues = true, or run the test as a Connected Android Test (/androidTest folder instead of /test).
I personally use returnDefaultValues = true as you mention as Logging is something I'm not usually interested in when Unit Testing, only when I'm trying to track down specific bugs.
You could create a package level method in ServiceManager class which calls Log.i method.
public class ServiceManager implements IServiceManager {
private final static String TAG = "ServiceManager";
private boolean mSystemPauseStatus = false;
public boolean getSystemPause () {
log("TAG", "getSystemPause: " + pauseStmSystemPauseStatusatus);
return mSystemPauseStatus;
}
public void setSystemPause (boolean pauseStatus){
log("TAG", "setSystemPause: " + pauseStatus);
mSystemPauseStatus = pauseStatus;
}
void log(String tag, String message) {
Log.i (tag, message);
}
Then you can override this method in ServiceManagerTest to provide no implementation.
public class ServiceManagerTest {
#Test
public void testSystemPause() throws Exception {
ServiceManager serviceManager = createServiceManager();
serviceManager.setSystemPause(false);
assert (! serviceManager.getSystemPause());
serviceManager.setSystemPause(true);
assert (serviceManager.getSystemPause());
}
private ServiceManager createServiceManager() {
return new ServiceManager() {
#Override
void log(String tag, String message) {
//Do nothing or you could test that this method was called.
}
}
}
}

Disable printing to console (logcat) [duplicate]

I am having lots of logging statements to debug for example.
Log.v(TAG, "Message here");
Log.w(TAG, " WARNING HERE");
while deploying this application on device phone i want to turn off the verbose logging from where i can enable/disable logging.
The Android Documentation says the following about Log Levels:
Verbose should never be compiled into an application except during development. Debug logs are compiled in but stripped at runtime. Error, warning and info logs are always kept.
So you may want to consider stripping the log Verbose logging statements out, possibly using ProGuard as suggested in another answer.
According to the documentation, you can configure logging on a development device using System Properties. The property to set is log.tag.<YourTag> and it should be set to one of the following values: VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. More information on this is available in the documentation for the isLoggable() method.
You can set properties temporarily using the setprop command. For example:
C:\android>adb shell setprop log.tag.MyAppTag WARN
C:\android>adb shell getprop log.tag.MyAppTag
WARN
Alternatively, you can specify them in the file '/data/local.prop' as follows:
log.tag.MyAppTag=WARN
Later versions of Android appear to require that /data/local.prop be read only. This file is read at boot time so you'll need to restart after updating it. If /data/local.prop is world writable, it will likely be ignored.
Finally, you can set them programmatically using the System.setProperty() method.
The easiest way is probably to run your compiled JAR through ProGuard before deployment, with a config like:
-assumenosideeffects class android.util.Log {
public static int v(...);
}
That will — aside from all the other ProGuard optimisations — remove any verbose log statements directly from the bytecode.
A common way is to make an int named loglevel, and define its debug level based on loglevel.
public static int LOGLEVEL = 2;
public static boolean ERROR = LOGLEVEL > 0;
public static boolean WARN = LOGLEVEL > 1;
...
public static boolean VERBOSE = LOGLEVEL > 4;
if (VERBOSE) Log.v(TAG, "Message here"); // Won't be shown
if (WARN) Log.w(TAG, "WARNING HERE"); // Still goes through
Later, you can just change the LOGLEVEL for all debug output level.
I took a simple route - creating a wrapper class that also makes use of variable parameter lists.
public class Log{
public static int LEVEL = android.util.Log.WARN;
static public void d(String tag, String msgFormat, Object...args)
{
if (LEVEL<=android.util.Log.DEBUG)
{
android.util.Log.d(tag, String.format(msgFormat, args));
}
}
static public void d(String tag, Throwable t, String msgFormat, Object...args)
{
if (LEVEL<=android.util.Log.DEBUG)
{
android.util.Log.d(tag, String.format(msgFormat, args), t);
}
}
//...other level logging functions snipped
The better way is to use SLF4J API + some of its implementation.
For Android applications you can use the following:
Android Logger is the lightweight but easy-to-configure SLF4J implementation (< 50 Kb).
LOGBack is the most powerful and optimized implementation but its size is about 1 Mb.
Any other by your taste: slf4j-android, slf4android.
You should use
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "my log message");
}
Stripping out the logging with proguard (see answer from #Christopher ) was easy and fast, but it caused stack traces from production to mismatch the source if there was any debug logging in the file.
Instead, here's a technique that uses different logging levels in development vs. production, assuming that proguard is used only in production. It recognizes production by seeing if proguard has renamed a given class name (in the example, I use "com.foo.Bar"--you would replace this with a fully-qualified class name that you know will be renamed by proguard).
This technique makes use of commons logging.
private void initLogging() {
Level level = Level.WARNING;
try {
// in production, the shrinker/obfuscator proguard will change the
// name of this class (and many others) so in development, this
// class WILL exist as named, and we will have debug level
Class.forName("com.foo.Bar");
level = Level.FINE;
} catch (Throwable t) {
// no problem, we are in production mode
}
Handler[] handlers = Logger.getLogger("").getHandlers();
for (Handler handler : handlers) {
Log.d("log init", "handler: " + handler.getClass().getName());
handler.setLevel(level);
}
}
Log4j or slf4j can also be used as logging frameworks in Android together with logcat. See the project android-logging-log4j or log4j support in android
There is a tiny drop-in replacement for the standard android Log class - https://github.com/zserge/log
Basically all you have to do is to replace imports from android.util.Log to trikita.log.Log. Then in your Application.onCreate() or in some static initalizer check for the BuilConfig.DEBUG or any other flag and use Log.level(Log.D) or Log.level(Log.E) to change the minimal log level. You can use Log.useLog(false) to disable logging at all.
May be you can see this Log extension class: https://github.com/dbauduin/Android-Tools/tree/master/logs.
It enables you to have a fine control on logs.
You can for example disable all logs or just the logs of some packages or classes.
Moreover, it adds some useful functionalities (for instance you don't have to pass a tag for each log).
I created a Utility/Wrapper which solves this problem + other common problems around Logging.
A Debugging utility with the following features:
The usual features provided by Log class wrapped around by LogMode s.
Method Entry-Exit logs: Can be turned off by a switch
Selective Debugging: Debug specific classes.
Method Execution-Time Measurement: Measure Execution time for individual methods as well as collective time spent on all methods of a class.
How To Use?
Include the class in your project.
Use it like you use android.util.Log methods, to start with.
Use the Entry-Exit logs feature by placing calls to entry_log()-exit_log() methods at the beginning and ending of methods in your app.
I have tried to make the documentation self suffiecient.
Suggestions to improve this Utility are welcome.
Free to use/share.
Download it from GitHub.
Here is a more complex solution. You will get full stack trace and the method toString() will be called only if needed(Performance). The attribute BuildConfig.DEBUG will be false in the production mode so all trace and debug logs will be removed. The hot spot compiler has the chance to remove the calls because off final static properties.
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import android.util.Log;
public class Logger {
public enum Level {
error, warn, info, debug, trace
}
private static final String DEFAULT_TAG = "Project";
private static final Level CURRENT_LEVEL = BuildConfig.DEBUG ? Level.trace : Level.info;
private static boolean isEnabled(Level l) {
return CURRENT_LEVEL.compareTo(l) >= 0;
}
static {
Log.i(DEFAULT_TAG, "log level: " + CURRENT_LEVEL.name());
}
private String classname = DEFAULT_TAG;
public void setClassName(Class<?> c) {
classname = c.getSimpleName();
}
public String getClassname() {
return classname;
}
public boolean isError() {
return isEnabled(Level.error);
}
public boolean isWarn() {
return isEnabled(Level.warn);
}
public boolean isInfo() {
return isEnabled(Level.info);
}
public boolean isDebug() {
return isEnabled(Level.debug);
}
public boolean isTrace() {
return isEnabled(Level.trace);
}
public void error(Object... args) {
if (isError()) Log.e(buildTag(), build(args));
}
public void warn(Object... args) {
if (isWarn()) Log.w(buildTag(), build(args));
}
public void info(Object... args) {
if (isInfo()) Log.i(buildTag(), build(args));
}
public void debug(Object... args) {
if (isDebug()) Log.d(buildTag(), build(args));
}
public void trace(Object... args) {
if (isTrace()) Log.v(buildTag(), build(args));
}
public void error(String msg, Throwable t) {
if (isError()) error(buildTag(), msg, stackToString(t));
}
public void warn(String msg, Throwable t) {
if (isWarn()) warn(buildTag(), msg, stackToString(t));
}
public void info(String msg, Throwable t) {
if (isInfo()) info(buildTag(), msg, stackToString(t));
}
public void debug(String msg, Throwable t) {
if (isDebug()) debug(buildTag(), msg, stackToString(t));
}
public void trace(String msg, Throwable t) {
if (isTrace()) trace(buildTag(), msg, stackToString(t));
}
private String buildTag() {
String tag ;
if (BuildConfig.DEBUG) {
StringBuilder b = new StringBuilder(20);
b.append(getClassname());
StackTraceElement stackEntry = Thread.currentThread().getStackTrace()[4];
if (stackEntry != null) {
b.append('.');
b.append(stackEntry.getMethodName());
b.append(':');
b.append(stackEntry.getLineNumber());
}
tag = b.toString();
} else {
tag = DEFAULT_TAG;
}
}
private String build(Object... args) {
if (args == null) {
return "null";
} else {
StringBuilder b = new StringBuilder(args.length * 10);
for (Object arg : args) {
if (arg == null) {
b.append("null");
} else {
b.append(arg);
}
}
return b.toString();
}
}
private String stackToString(Throwable t) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(500);
baos.toString();
t.printStackTrace(new PrintStream(baos));
return baos.toString();
}
}
use like this:
Loggor log = new Logger();
Map foo = ...
List bar = ...
log.error("Foo:", foo, "bar:", bar);
// bad example (avoid something like this)
// log.error("Foo:" + " foo.toString() + "bar:" + bar);
In a very simple logging scenario, where you're literally just trying to write to console during development for debugging purposes, it might be easiest to just do a search and replace before your production build and comment out all the calls to Log or System.out.println.
For example, assuming you didn't use the "Log." anywhere outside of a call to Log.d or Log.e, etc, you could simply do a find and replace across the entire solution to replace "Log." with "//Log." to comment out all your logging calls, or in my case I'm just using System.out.println everywhere, so before going to production I'll simply do a full search and replace for "System.out.println" and replace with "//System.out.println".
I know this isn't ideal, and it would be nice if the ability to find and comment out calls to Log and System.out.println were built into Eclipse, but until that happens the easiest and fastest and best way to do this is to comment out by search and replace. If you do this, you don't have to worry about mismatching stack trace line numbers, because you're editing your source code, and you're not adding any overhead by checking some log level configuration, etc.
In my apps I have a class which wraps the Log class which has a static boolean var called "state". Throughout my code I check the value of the "state" variable using a static method before actually writing to the Log. I then have a static method to set the "state" variable which ensures the value is common across all instances created by the app. This means I can enable or disable all logging for the App in one call - even when the App is running. Useful for support calls... It does mean that you have to stick to your guns when debugging and not regress to using the standard Log class though...
It's also useful (convenient) that Java interprets a boolean var as false if it hasn't been assigned a value, which means it can be left as false until you need to turn on logging :-)
We can use class Log in our local component and define the methods as v/i/e/d.
Based on the need of we can make call further.
example is shown below.
public class Log{
private static boolean TAG = false;
public static void d(String enable_tag, String message,Object...args){
if(TAG)
android.util.Log.d(enable_tag, message+args);
}
public static void e(String enable_tag, String message,Object...args){
if(TAG)
android.util.Log.e(enable_tag, message+args);
}
public static void v(String enable_tag, String message,Object...args){
if(TAG)
android.util.Log.v(enable_tag, message+args);
}
}
if we do not need any print(s), at-all make TAG as false for all else
remove the check for type of Log (say Log.d).
as
public static void i(String enable_tag, String message,Object...args){
// if(TAG)
android.util.Log.i(enable_tag, message+args);
}
here message is for string and and args is the value you want to print.
For me it is often useful being able to set different log levels for each TAG.
I am using this very simple wrapper class:
public class Log2 {
public enum LogLevels {
VERBOSE(android.util.Log.VERBOSE), DEBUG(android.util.Log.DEBUG), INFO(android.util.Log.INFO), WARN(
android.util.Log.WARN), ERROR(android.util.Log.ERROR);
int level;
private LogLevels(int logLevel) {
level = logLevel;
}
public int getLevel() {
return level;
}
};
static private HashMap<String, Integer> logLevels = new HashMap<String, Integer>();
public static void setLogLevel(String tag, LogLevels level) {
logLevels.put(tag, level.getLevel());
}
public static int v(String tag, String msg) {
return Log2.v(tag, msg, null);
}
public static int v(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.VERBOSE) {
return -1;
}
}
return Log.v(tag, msg, tr);
}
public static int d(String tag, String msg) {
return Log2.d(tag, msg, null);
}
public static int d(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.DEBUG) {
return -1;
}
}
return Log.d(tag, msg);
}
public static int i(String tag, String msg) {
return Log2.i(tag, msg, null);
}
public static int i(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.INFO) {
return -1;
}
}
return Log.i(tag, msg);
}
public static int w(String tag, String msg) {
return Log2.w(tag, msg, null);
}
public static int w(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.WARN) {
return -1;
}
}
return Log.w(tag, msg, tr);
}
public static int e(String tag, String msg) {
return Log2.e(tag, msg, null);
}
public static int e(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.ERROR) {
return -1;
}
}
return Log.e(tag, msg, tr);
}
}
Now just set the log level per TAG at the beginning of each class:
Log2.setLogLevel(TAG, LogLevels.INFO);
Another way is to use a logging platform that has the capabilities of opening and closing logs. This can give much of flexibility sometimes even on a production app which logs should be open and which closed depending on which issues you have
for example:
LumberJack
Shipbook (disclaimer: I'm the author of this package)
https://limxtop.blogspot.com/2019/05/app-log.html
Read this article please, where provides complete implement:
For debug version, all the logs will be output;
For release version, only the logs whose level is above DEBUG (exclude) will be output by default. In the meanwhile, the DEBUG and VERBOSE log can be enable through setprop log.tag.<YOUR_LOG_TAG> <LEVEL> in running time.

Android logs printed in both debug and release mode [duplicate]

I am having lots of logging statements to debug for example.
Log.v(TAG, "Message here");
Log.w(TAG, " WARNING HERE");
while deploying this application on device phone i want to turn off the verbose logging from where i can enable/disable logging.
The Android Documentation says the following about Log Levels:
Verbose should never be compiled into an application except during development. Debug logs are compiled in but stripped at runtime. Error, warning and info logs are always kept.
So you may want to consider stripping the log Verbose logging statements out, possibly using ProGuard as suggested in another answer.
According to the documentation, you can configure logging on a development device using System Properties. The property to set is log.tag.<YourTag> and it should be set to one of the following values: VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. More information on this is available in the documentation for the isLoggable() method.
You can set properties temporarily using the setprop command. For example:
C:\android>adb shell setprop log.tag.MyAppTag WARN
C:\android>adb shell getprop log.tag.MyAppTag
WARN
Alternatively, you can specify them in the file '/data/local.prop' as follows:
log.tag.MyAppTag=WARN
Later versions of Android appear to require that /data/local.prop be read only. This file is read at boot time so you'll need to restart after updating it. If /data/local.prop is world writable, it will likely be ignored.
Finally, you can set them programmatically using the System.setProperty() method.
The easiest way is probably to run your compiled JAR through ProGuard before deployment, with a config like:
-assumenosideeffects class android.util.Log {
public static int v(...);
}
That will — aside from all the other ProGuard optimisations — remove any verbose log statements directly from the bytecode.
A common way is to make an int named loglevel, and define its debug level based on loglevel.
public static int LOGLEVEL = 2;
public static boolean ERROR = LOGLEVEL > 0;
public static boolean WARN = LOGLEVEL > 1;
...
public static boolean VERBOSE = LOGLEVEL > 4;
if (VERBOSE) Log.v(TAG, "Message here"); // Won't be shown
if (WARN) Log.w(TAG, "WARNING HERE"); // Still goes through
Later, you can just change the LOGLEVEL for all debug output level.
I took a simple route - creating a wrapper class that also makes use of variable parameter lists.
public class Log{
public static int LEVEL = android.util.Log.WARN;
static public void d(String tag, String msgFormat, Object...args)
{
if (LEVEL<=android.util.Log.DEBUG)
{
android.util.Log.d(tag, String.format(msgFormat, args));
}
}
static public void d(String tag, Throwable t, String msgFormat, Object...args)
{
if (LEVEL<=android.util.Log.DEBUG)
{
android.util.Log.d(tag, String.format(msgFormat, args), t);
}
}
//...other level logging functions snipped
The better way is to use SLF4J API + some of its implementation.
For Android applications you can use the following:
Android Logger is the lightweight but easy-to-configure SLF4J implementation (< 50 Kb).
LOGBack is the most powerful and optimized implementation but its size is about 1 Mb.
Any other by your taste: slf4j-android, slf4android.
You should use
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "my log message");
}
Stripping out the logging with proguard (see answer from #Christopher ) was easy and fast, but it caused stack traces from production to mismatch the source if there was any debug logging in the file.
Instead, here's a technique that uses different logging levels in development vs. production, assuming that proguard is used only in production. It recognizes production by seeing if proguard has renamed a given class name (in the example, I use "com.foo.Bar"--you would replace this with a fully-qualified class name that you know will be renamed by proguard).
This technique makes use of commons logging.
private void initLogging() {
Level level = Level.WARNING;
try {
// in production, the shrinker/obfuscator proguard will change the
// name of this class (and many others) so in development, this
// class WILL exist as named, and we will have debug level
Class.forName("com.foo.Bar");
level = Level.FINE;
} catch (Throwable t) {
// no problem, we are in production mode
}
Handler[] handlers = Logger.getLogger("").getHandlers();
for (Handler handler : handlers) {
Log.d("log init", "handler: " + handler.getClass().getName());
handler.setLevel(level);
}
}
Log4j or slf4j can also be used as logging frameworks in Android together with logcat. See the project android-logging-log4j or log4j support in android
There is a tiny drop-in replacement for the standard android Log class - https://github.com/zserge/log
Basically all you have to do is to replace imports from android.util.Log to trikita.log.Log. Then in your Application.onCreate() or in some static initalizer check for the BuilConfig.DEBUG or any other flag and use Log.level(Log.D) or Log.level(Log.E) to change the minimal log level. You can use Log.useLog(false) to disable logging at all.
May be you can see this Log extension class: https://github.com/dbauduin/Android-Tools/tree/master/logs.
It enables you to have a fine control on logs.
You can for example disable all logs or just the logs of some packages or classes.
Moreover, it adds some useful functionalities (for instance you don't have to pass a tag for each log).
I created a Utility/Wrapper which solves this problem + other common problems around Logging.
A Debugging utility with the following features:
The usual features provided by Log class wrapped around by LogMode s.
Method Entry-Exit logs: Can be turned off by a switch
Selective Debugging: Debug specific classes.
Method Execution-Time Measurement: Measure Execution time for individual methods as well as collective time spent on all methods of a class.
How To Use?
Include the class in your project.
Use it like you use android.util.Log methods, to start with.
Use the Entry-Exit logs feature by placing calls to entry_log()-exit_log() methods at the beginning and ending of methods in your app.
I have tried to make the documentation self suffiecient.
Suggestions to improve this Utility are welcome.
Free to use/share.
Download it from GitHub.
Here is a more complex solution. You will get full stack trace and the method toString() will be called only if needed(Performance). The attribute BuildConfig.DEBUG will be false in the production mode so all trace and debug logs will be removed. The hot spot compiler has the chance to remove the calls because off final static properties.
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import android.util.Log;
public class Logger {
public enum Level {
error, warn, info, debug, trace
}
private static final String DEFAULT_TAG = "Project";
private static final Level CURRENT_LEVEL = BuildConfig.DEBUG ? Level.trace : Level.info;
private static boolean isEnabled(Level l) {
return CURRENT_LEVEL.compareTo(l) >= 0;
}
static {
Log.i(DEFAULT_TAG, "log level: " + CURRENT_LEVEL.name());
}
private String classname = DEFAULT_TAG;
public void setClassName(Class<?> c) {
classname = c.getSimpleName();
}
public String getClassname() {
return classname;
}
public boolean isError() {
return isEnabled(Level.error);
}
public boolean isWarn() {
return isEnabled(Level.warn);
}
public boolean isInfo() {
return isEnabled(Level.info);
}
public boolean isDebug() {
return isEnabled(Level.debug);
}
public boolean isTrace() {
return isEnabled(Level.trace);
}
public void error(Object... args) {
if (isError()) Log.e(buildTag(), build(args));
}
public void warn(Object... args) {
if (isWarn()) Log.w(buildTag(), build(args));
}
public void info(Object... args) {
if (isInfo()) Log.i(buildTag(), build(args));
}
public void debug(Object... args) {
if (isDebug()) Log.d(buildTag(), build(args));
}
public void trace(Object... args) {
if (isTrace()) Log.v(buildTag(), build(args));
}
public void error(String msg, Throwable t) {
if (isError()) error(buildTag(), msg, stackToString(t));
}
public void warn(String msg, Throwable t) {
if (isWarn()) warn(buildTag(), msg, stackToString(t));
}
public void info(String msg, Throwable t) {
if (isInfo()) info(buildTag(), msg, stackToString(t));
}
public void debug(String msg, Throwable t) {
if (isDebug()) debug(buildTag(), msg, stackToString(t));
}
public void trace(String msg, Throwable t) {
if (isTrace()) trace(buildTag(), msg, stackToString(t));
}
private String buildTag() {
String tag ;
if (BuildConfig.DEBUG) {
StringBuilder b = new StringBuilder(20);
b.append(getClassname());
StackTraceElement stackEntry = Thread.currentThread().getStackTrace()[4];
if (stackEntry != null) {
b.append('.');
b.append(stackEntry.getMethodName());
b.append(':');
b.append(stackEntry.getLineNumber());
}
tag = b.toString();
} else {
tag = DEFAULT_TAG;
}
}
private String build(Object... args) {
if (args == null) {
return "null";
} else {
StringBuilder b = new StringBuilder(args.length * 10);
for (Object arg : args) {
if (arg == null) {
b.append("null");
} else {
b.append(arg);
}
}
return b.toString();
}
}
private String stackToString(Throwable t) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(500);
baos.toString();
t.printStackTrace(new PrintStream(baos));
return baos.toString();
}
}
use like this:
Loggor log = new Logger();
Map foo = ...
List bar = ...
log.error("Foo:", foo, "bar:", bar);
// bad example (avoid something like this)
// log.error("Foo:" + " foo.toString() + "bar:" + bar);
In a very simple logging scenario, where you're literally just trying to write to console during development for debugging purposes, it might be easiest to just do a search and replace before your production build and comment out all the calls to Log or System.out.println.
For example, assuming you didn't use the "Log." anywhere outside of a call to Log.d or Log.e, etc, you could simply do a find and replace across the entire solution to replace "Log." with "//Log." to comment out all your logging calls, or in my case I'm just using System.out.println everywhere, so before going to production I'll simply do a full search and replace for "System.out.println" and replace with "//System.out.println".
I know this isn't ideal, and it would be nice if the ability to find and comment out calls to Log and System.out.println were built into Eclipse, but until that happens the easiest and fastest and best way to do this is to comment out by search and replace. If you do this, you don't have to worry about mismatching stack trace line numbers, because you're editing your source code, and you're not adding any overhead by checking some log level configuration, etc.
In my apps I have a class which wraps the Log class which has a static boolean var called "state". Throughout my code I check the value of the "state" variable using a static method before actually writing to the Log. I then have a static method to set the "state" variable which ensures the value is common across all instances created by the app. This means I can enable or disable all logging for the App in one call - even when the App is running. Useful for support calls... It does mean that you have to stick to your guns when debugging and not regress to using the standard Log class though...
It's also useful (convenient) that Java interprets a boolean var as false if it hasn't been assigned a value, which means it can be left as false until you need to turn on logging :-)
We can use class Log in our local component and define the methods as v/i/e/d.
Based on the need of we can make call further.
example is shown below.
public class Log{
private static boolean TAG = false;
public static void d(String enable_tag, String message,Object...args){
if(TAG)
android.util.Log.d(enable_tag, message+args);
}
public static void e(String enable_tag, String message,Object...args){
if(TAG)
android.util.Log.e(enable_tag, message+args);
}
public static void v(String enable_tag, String message,Object...args){
if(TAG)
android.util.Log.v(enable_tag, message+args);
}
}
if we do not need any print(s), at-all make TAG as false for all else
remove the check for type of Log (say Log.d).
as
public static void i(String enable_tag, String message,Object...args){
// if(TAG)
android.util.Log.i(enable_tag, message+args);
}
here message is for string and and args is the value you want to print.
For me it is often useful being able to set different log levels for each TAG.
I am using this very simple wrapper class:
public class Log2 {
public enum LogLevels {
VERBOSE(android.util.Log.VERBOSE), DEBUG(android.util.Log.DEBUG), INFO(android.util.Log.INFO), WARN(
android.util.Log.WARN), ERROR(android.util.Log.ERROR);
int level;
private LogLevels(int logLevel) {
level = logLevel;
}
public int getLevel() {
return level;
}
};
static private HashMap<String, Integer> logLevels = new HashMap<String, Integer>();
public static void setLogLevel(String tag, LogLevels level) {
logLevels.put(tag, level.getLevel());
}
public static int v(String tag, String msg) {
return Log2.v(tag, msg, null);
}
public static int v(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.VERBOSE) {
return -1;
}
}
return Log.v(tag, msg, tr);
}
public static int d(String tag, String msg) {
return Log2.d(tag, msg, null);
}
public static int d(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.DEBUG) {
return -1;
}
}
return Log.d(tag, msg);
}
public static int i(String tag, String msg) {
return Log2.i(tag, msg, null);
}
public static int i(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.INFO) {
return -1;
}
}
return Log.i(tag, msg);
}
public static int w(String tag, String msg) {
return Log2.w(tag, msg, null);
}
public static int w(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.WARN) {
return -1;
}
}
return Log.w(tag, msg, tr);
}
public static int e(String tag, String msg) {
return Log2.e(tag, msg, null);
}
public static int e(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.ERROR) {
return -1;
}
}
return Log.e(tag, msg, tr);
}
}
Now just set the log level per TAG at the beginning of each class:
Log2.setLogLevel(TAG, LogLevels.INFO);
Another way is to use a logging platform that has the capabilities of opening and closing logs. This can give much of flexibility sometimes even on a production app which logs should be open and which closed depending on which issues you have
for example:
LumberJack
Shipbook (disclaimer: I'm the author of this package)
https://limxtop.blogspot.com/2019/05/app-log.html
Read this article please, where provides complete implement:
For debug version, all the logs will be output;
For release version, only the logs whose level is above DEBUG (exclude) will be output by default. In the meanwhile, the DEBUG and VERBOSE log can be enable through setprop log.tag.<YOUR_LOG_TAG> <LEVEL> in running time.

How do I enable/disable log levels in Android?

I am having lots of logging statements to debug for example.
Log.v(TAG, "Message here");
Log.w(TAG, " WARNING HERE");
while deploying this application on device phone i want to turn off the verbose logging from where i can enable/disable logging.
The Android Documentation says the following about Log Levels:
Verbose should never be compiled into an application except during development. Debug logs are compiled in but stripped at runtime. Error, warning and info logs are always kept.
So you may want to consider stripping the log Verbose logging statements out, possibly using ProGuard as suggested in another answer.
According to the documentation, you can configure logging on a development device using System Properties. The property to set is log.tag.<YourTag> and it should be set to one of the following values: VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. More information on this is available in the documentation for the isLoggable() method.
You can set properties temporarily using the setprop command. For example:
C:\android>adb shell setprop log.tag.MyAppTag WARN
C:\android>adb shell getprop log.tag.MyAppTag
WARN
Alternatively, you can specify them in the file '/data/local.prop' as follows:
log.tag.MyAppTag=WARN
Later versions of Android appear to require that /data/local.prop be read only. This file is read at boot time so you'll need to restart after updating it. If /data/local.prop is world writable, it will likely be ignored.
Finally, you can set them programmatically using the System.setProperty() method.
The easiest way is probably to run your compiled JAR through ProGuard before deployment, with a config like:
-assumenosideeffects class android.util.Log {
public static int v(...);
}
That will — aside from all the other ProGuard optimisations — remove any verbose log statements directly from the bytecode.
A common way is to make an int named loglevel, and define its debug level based on loglevel.
public static int LOGLEVEL = 2;
public static boolean ERROR = LOGLEVEL > 0;
public static boolean WARN = LOGLEVEL > 1;
...
public static boolean VERBOSE = LOGLEVEL > 4;
if (VERBOSE) Log.v(TAG, "Message here"); // Won't be shown
if (WARN) Log.w(TAG, "WARNING HERE"); // Still goes through
Later, you can just change the LOGLEVEL for all debug output level.
I took a simple route - creating a wrapper class that also makes use of variable parameter lists.
public class Log{
public static int LEVEL = android.util.Log.WARN;
static public void d(String tag, String msgFormat, Object...args)
{
if (LEVEL<=android.util.Log.DEBUG)
{
android.util.Log.d(tag, String.format(msgFormat, args));
}
}
static public void d(String tag, Throwable t, String msgFormat, Object...args)
{
if (LEVEL<=android.util.Log.DEBUG)
{
android.util.Log.d(tag, String.format(msgFormat, args), t);
}
}
//...other level logging functions snipped
The better way is to use SLF4J API + some of its implementation.
For Android applications you can use the following:
Android Logger is the lightweight but easy-to-configure SLF4J implementation (< 50 Kb).
LOGBack is the most powerful and optimized implementation but its size is about 1 Mb.
Any other by your taste: slf4j-android, slf4android.
You should use
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "my log message");
}
Stripping out the logging with proguard (see answer from #Christopher ) was easy and fast, but it caused stack traces from production to mismatch the source if there was any debug logging in the file.
Instead, here's a technique that uses different logging levels in development vs. production, assuming that proguard is used only in production. It recognizes production by seeing if proguard has renamed a given class name (in the example, I use "com.foo.Bar"--you would replace this with a fully-qualified class name that you know will be renamed by proguard).
This technique makes use of commons logging.
private void initLogging() {
Level level = Level.WARNING;
try {
// in production, the shrinker/obfuscator proguard will change the
// name of this class (and many others) so in development, this
// class WILL exist as named, and we will have debug level
Class.forName("com.foo.Bar");
level = Level.FINE;
} catch (Throwable t) {
// no problem, we are in production mode
}
Handler[] handlers = Logger.getLogger("").getHandlers();
for (Handler handler : handlers) {
Log.d("log init", "handler: " + handler.getClass().getName());
handler.setLevel(level);
}
}
Log4j or slf4j can also be used as logging frameworks in Android together with logcat. See the project android-logging-log4j or log4j support in android
There is a tiny drop-in replacement for the standard android Log class - https://github.com/zserge/log
Basically all you have to do is to replace imports from android.util.Log to trikita.log.Log. Then in your Application.onCreate() or in some static initalizer check for the BuilConfig.DEBUG or any other flag and use Log.level(Log.D) or Log.level(Log.E) to change the minimal log level. You can use Log.useLog(false) to disable logging at all.
May be you can see this Log extension class: https://github.com/dbauduin/Android-Tools/tree/master/logs.
It enables you to have a fine control on logs.
You can for example disable all logs or just the logs of some packages or classes.
Moreover, it adds some useful functionalities (for instance you don't have to pass a tag for each log).
I created a Utility/Wrapper which solves this problem + other common problems around Logging.
A Debugging utility with the following features:
The usual features provided by Log class wrapped around by LogMode s.
Method Entry-Exit logs: Can be turned off by a switch
Selective Debugging: Debug specific classes.
Method Execution-Time Measurement: Measure Execution time for individual methods as well as collective time spent on all methods of a class.
How To Use?
Include the class in your project.
Use it like you use android.util.Log methods, to start with.
Use the Entry-Exit logs feature by placing calls to entry_log()-exit_log() methods at the beginning and ending of methods in your app.
I have tried to make the documentation self suffiecient.
Suggestions to improve this Utility are welcome.
Free to use/share.
Download it from GitHub.
Here is a more complex solution. You will get full stack trace and the method toString() will be called only if needed(Performance). The attribute BuildConfig.DEBUG will be false in the production mode so all trace and debug logs will be removed. The hot spot compiler has the chance to remove the calls because off final static properties.
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import android.util.Log;
public class Logger {
public enum Level {
error, warn, info, debug, trace
}
private static final String DEFAULT_TAG = "Project";
private static final Level CURRENT_LEVEL = BuildConfig.DEBUG ? Level.trace : Level.info;
private static boolean isEnabled(Level l) {
return CURRENT_LEVEL.compareTo(l) >= 0;
}
static {
Log.i(DEFAULT_TAG, "log level: " + CURRENT_LEVEL.name());
}
private String classname = DEFAULT_TAG;
public void setClassName(Class<?> c) {
classname = c.getSimpleName();
}
public String getClassname() {
return classname;
}
public boolean isError() {
return isEnabled(Level.error);
}
public boolean isWarn() {
return isEnabled(Level.warn);
}
public boolean isInfo() {
return isEnabled(Level.info);
}
public boolean isDebug() {
return isEnabled(Level.debug);
}
public boolean isTrace() {
return isEnabled(Level.trace);
}
public void error(Object... args) {
if (isError()) Log.e(buildTag(), build(args));
}
public void warn(Object... args) {
if (isWarn()) Log.w(buildTag(), build(args));
}
public void info(Object... args) {
if (isInfo()) Log.i(buildTag(), build(args));
}
public void debug(Object... args) {
if (isDebug()) Log.d(buildTag(), build(args));
}
public void trace(Object... args) {
if (isTrace()) Log.v(buildTag(), build(args));
}
public void error(String msg, Throwable t) {
if (isError()) error(buildTag(), msg, stackToString(t));
}
public void warn(String msg, Throwable t) {
if (isWarn()) warn(buildTag(), msg, stackToString(t));
}
public void info(String msg, Throwable t) {
if (isInfo()) info(buildTag(), msg, stackToString(t));
}
public void debug(String msg, Throwable t) {
if (isDebug()) debug(buildTag(), msg, stackToString(t));
}
public void trace(String msg, Throwable t) {
if (isTrace()) trace(buildTag(), msg, stackToString(t));
}
private String buildTag() {
String tag ;
if (BuildConfig.DEBUG) {
StringBuilder b = new StringBuilder(20);
b.append(getClassname());
StackTraceElement stackEntry = Thread.currentThread().getStackTrace()[4];
if (stackEntry != null) {
b.append('.');
b.append(stackEntry.getMethodName());
b.append(':');
b.append(stackEntry.getLineNumber());
}
tag = b.toString();
} else {
tag = DEFAULT_TAG;
}
}
private String build(Object... args) {
if (args == null) {
return "null";
} else {
StringBuilder b = new StringBuilder(args.length * 10);
for (Object arg : args) {
if (arg == null) {
b.append("null");
} else {
b.append(arg);
}
}
return b.toString();
}
}
private String stackToString(Throwable t) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(500);
baos.toString();
t.printStackTrace(new PrintStream(baos));
return baos.toString();
}
}
use like this:
Loggor log = new Logger();
Map foo = ...
List bar = ...
log.error("Foo:", foo, "bar:", bar);
// bad example (avoid something like this)
// log.error("Foo:" + " foo.toString() + "bar:" + bar);
In a very simple logging scenario, where you're literally just trying to write to console during development for debugging purposes, it might be easiest to just do a search and replace before your production build and comment out all the calls to Log or System.out.println.
For example, assuming you didn't use the "Log." anywhere outside of a call to Log.d or Log.e, etc, you could simply do a find and replace across the entire solution to replace "Log." with "//Log." to comment out all your logging calls, or in my case I'm just using System.out.println everywhere, so before going to production I'll simply do a full search and replace for "System.out.println" and replace with "//System.out.println".
I know this isn't ideal, and it would be nice if the ability to find and comment out calls to Log and System.out.println were built into Eclipse, but until that happens the easiest and fastest and best way to do this is to comment out by search and replace. If you do this, you don't have to worry about mismatching stack trace line numbers, because you're editing your source code, and you're not adding any overhead by checking some log level configuration, etc.
In my apps I have a class which wraps the Log class which has a static boolean var called "state". Throughout my code I check the value of the "state" variable using a static method before actually writing to the Log. I then have a static method to set the "state" variable which ensures the value is common across all instances created by the app. This means I can enable or disable all logging for the App in one call - even when the App is running. Useful for support calls... It does mean that you have to stick to your guns when debugging and not regress to using the standard Log class though...
It's also useful (convenient) that Java interprets a boolean var as false if it hasn't been assigned a value, which means it can be left as false until you need to turn on logging :-)
We can use class Log in our local component and define the methods as v/i/e/d.
Based on the need of we can make call further.
example is shown below.
public class Log{
private static boolean TAG = false;
public static void d(String enable_tag, String message,Object...args){
if(TAG)
android.util.Log.d(enable_tag, message+args);
}
public static void e(String enable_tag, String message,Object...args){
if(TAG)
android.util.Log.e(enable_tag, message+args);
}
public static void v(String enable_tag, String message,Object...args){
if(TAG)
android.util.Log.v(enable_tag, message+args);
}
}
if we do not need any print(s), at-all make TAG as false for all else
remove the check for type of Log (say Log.d).
as
public static void i(String enable_tag, String message,Object...args){
// if(TAG)
android.util.Log.i(enable_tag, message+args);
}
here message is for string and and args is the value you want to print.
For me it is often useful being able to set different log levels for each TAG.
I am using this very simple wrapper class:
public class Log2 {
public enum LogLevels {
VERBOSE(android.util.Log.VERBOSE), DEBUG(android.util.Log.DEBUG), INFO(android.util.Log.INFO), WARN(
android.util.Log.WARN), ERROR(android.util.Log.ERROR);
int level;
private LogLevels(int logLevel) {
level = logLevel;
}
public int getLevel() {
return level;
}
};
static private HashMap<String, Integer> logLevels = new HashMap<String, Integer>();
public static void setLogLevel(String tag, LogLevels level) {
logLevels.put(tag, level.getLevel());
}
public static int v(String tag, String msg) {
return Log2.v(tag, msg, null);
}
public static int v(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.VERBOSE) {
return -1;
}
}
return Log.v(tag, msg, tr);
}
public static int d(String tag, String msg) {
return Log2.d(tag, msg, null);
}
public static int d(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.DEBUG) {
return -1;
}
}
return Log.d(tag, msg);
}
public static int i(String tag, String msg) {
return Log2.i(tag, msg, null);
}
public static int i(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.INFO) {
return -1;
}
}
return Log.i(tag, msg);
}
public static int w(String tag, String msg) {
return Log2.w(tag, msg, null);
}
public static int w(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.WARN) {
return -1;
}
}
return Log.w(tag, msg, tr);
}
public static int e(String tag, String msg) {
return Log2.e(tag, msg, null);
}
public static int e(String tag, String msg, Throwable tr) {
if (logLevels.containsKey(tag)) {
if (logLevels.get(tag) > android.util.Log.ERROR) {
return -1;
}
}
return Log.e(tag, msg, tr);
}
}
Now just set the log level per TAG at the beginning of each class:
Log2.setLogLevel(TAG, LogLevels.INFO);
Another way is to use a logging platform that has the capabilities of opening and closing logs. This can give much of flexibility sometimes even on a production app which logs should be open and which closed depending on which issues you have
for example:
LumberJack
Shipbook (disclaimer: I'm the author of this package)
https://limxtop.blogspot.com/2019/05/app-log.html
Read this article please, where provides complete implement:
For debug version, all the logs will be output;
For release version, only the logs whose level is above DEBUG (exclude) will be output by default. In the meanwhile, the DEBUG and VERBOSE log can be enable through setprop log.tag.<YOUR_LOG_TAG> <LEVEL> in running time.

Categories

Resources