android Log File LogUtils Instance

  • 2021-12-05 07:23:32
  • OfStack

Background

This is a long time ago in the network to find a common class, has forgotten the original link, but feel very good to use 1 straight in use, can log written to file inside can also locate you in which class which 1 line print log, save to the file path is android/data/your package name/files/directory, and then we can find problems happily


import android.text.TextUtils;
import android.util.Log;
import com.smartlink.suixing.App;
import com.smartlink.suixing.BuildConfig;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Formatter;
import java.util.Locale;

public class LogUtils {

	public static String			customTagPrefix	= "log";	//  Customize Tag The prefix of, which can be the author name 

	private static final boolean	isSaveLog		= true;		//  Do you want to save the log to SD Card 

	private static String			cacheDirPath;

	private LogUtils() {

	}

	//  The type of log allowed to be printed, the default is true Is set to false Do not print 
	public static boolean	allowD		= BuildConfig.DEBUG;
	public static boolean	allowE		= BuildConfig.DEBUG;
	public static boolean	allowI		= BuildConfig.DEBUG;
	public static boolean	allowV		= BuildConfig.DEBUG;
	public static boolean	allowW		= BuildConfig.DEBUG;
	public static boolean	allowWtf	= BuildConfig.DEBUG;

	// public static boolean allowD = true;
	// public static boolean allowE = true;
	// public static boolean allowI = true;
	// public static boolean allowV = true;
	// public static boolean allowW = true;
	// public static boolean allowWtf = true;

	private static String generateTag(StackTraceElement caller) {
		String tag = "%s.%s(Line:%d)"; //  Placeholder 
		String callerClazzName = caller.getClassName(); //  Get to the class name 
		callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1);
		tag = String.format(tag, callerClazzName, caller.getMethodName(), caller.getLineNumber()); //  Replace 
		tag = TextUtils.isEmpty(customTagPrefix) ? tag : customTagPrefix + ":" + tag;
		return tag;
	}

	/***
	 *  The print console can't display that long log problem 
	 * 
	 * @param msg
	 */
	public static void logE(String msg) { //  The message is too long , Sectional printing 
		if (!allowE) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);
		//  Because String Adj. length The number of characters is not the number of bytes, so in order to prevent too many Chinese characters, 
		//  Put 4*1024 Adj. MAX Byte print length changed to 2001 Number of characters 
		int max_str_length = 2001 - tag.length();
		//  Greater than 4000 Hour 
		while (msg.length() > max_str_length) {
			// Log.e(tag, msg.substring(0, max_str_length));
			LogUtils.e(msg.substring(0, max_str_length));
			msg = msg.substring(max_str_length);
		}
		//  The remainder 
		// Log.e(tag, msg);
		LogUtils.e(msg);
	}

	/**
	 *  Custom logger
	 */
	public static CustomLogger customLogger;

	public interface CustomLogger {

		void d(String tag, String content);

		void d(String tag, String content, Throwable tr);

		void e(String tag, String content);

		void e(String tag, String content, Throwable tr);

		void i(String tag, String content);

		void i(String tag, String content, Throwable tr);

		void v(String tag, String content);

		void v(String tag, String content, Throwable tr);

		void w(String tag, String content);

		void w(String tag, String content, Throwable tr);

		void w(String tag, Throwable tr);

		void wtf(String tag, String content);

		void wtf(String tag, String content, Throwable tr);

		void wtf(String tag, Throwable tr);
	}

	public static void d(String content) {
		if (!allowD) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.d(tag, content);
		} else {
			Log.d(tag, content);
		}
	}

	public static void d(String content, Throwable tr) {
		if (!allowD) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.d(tag, content, tr);
		} else {
			Log.d(tag, content, tr);
		}
	}

	public static void e(String content) {
		if (!allowE) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.e(tag, content);
		} else {
			Log.e(tag, content);
		}
		if (isSaveLog) {
			point(cacheDirPath, tag, content);
		}
	}

	public static void e(String content, Throwable tr) {
		if (!allowE) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.e(tag, content, tr);
		} else {
			Log.e(tag, content, tr);
		}
		if (isSaveLog) {
			point(cacheDirPath, tag, tr.getMessage());
		}
	}

	public static void e(Throwable tr) {
		if (!allowE) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.e(tag, "", tr);
		} else {
			Log.e(tag, "", tr);
		}
		if (isSaveLog) {
			point(cacheDirPath, tag, tr.getMessage());
		}
	}

	public static void i(String content) {
		if (!allowI) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.i(tag, content);
		} else {
			Log.i(tag, content);
		}

	}

	public static void i(String content, Throwable tr) {
		if (!allowI) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.i(tag, content, tr);
		} else {
			Log.i(tag, content, tr);
		}

	}

	public static void v(String content) {
		if (!allowV) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.v(tag, content);
		} else {
			Log.v(tag, content);
		}
	}

	public static void v(String content, Throwable tr) {
		if (!allowV) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.v(tag, content, tr);
		} else {
			Log.v(tag, content, tr);
		}
	}

	public static void w(String content) {
		if (!allowW) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.w(tag, content);
		} else {
			Log.w(tag, content);
		}
	}

	public static void w(String content, Throwable tr) {
		if (!allowW) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.w(tag, content, tr);
		} else {
			Log.w(tag, content, tr);
		}
	}

	public static void w(Throwable tr) {
		if (!allowW) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.w(tag, tr);
		} else {
			Log.w(tag, tr);
		}
	}

	public static void wtf(String content) {
		if (!allowWtf) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.wtf(tag, content);
		} else {
			Log.wtf(tag, content);
		}
	}

	public static void wtf(String content, Throwable tr) {
		if (!allowWtf) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.wtf(tag, content, tr);
		} else {
			Log.wtf(tag, content, tr);
		}
	}

	public static void wtf(Throwable tr) {
		if (!allowWtf) return;
		StackTraceElement caller = getCallerStackTraceElement();
		String tag = generateTag(caller);

		if (customLogger != null) {
			customLogger.wtf(tag, tr);
		} else {
			Log.wtf(tag, tr);
		}
	}

	private static StackTraceElement getCallerStackTraceElement() {
		return Thread.currentThread().getStackTrace()[4];
	}

	public static void point(String path, String tag, String msg) {
		if (isSDAva()) {
			path = cacheDirPath;
			Date date = new Date();
			SimpleDateFormat dateFormat = new SimpleDateFormat("", Locale.SIMPLIFIED_CHINESE);
			dateFormat.applyPattern("yyyy");
			path = path + dateFormat.format(date) + "/";
			dateFormat.applyPattern("MM");
			path += dateFormat.format(date) + "/";
			dateFormat.applyPattern("dd");
			path += dateFormat.format(date) + ".log";
			dateFormat.applyPattern("[yyyy-MM-dd HH:mm:ss]");
			String time = dateFormat.format(date);
			File file = new File(path);
			if (!file.exists()) createDipPath(path);
			BufferedWriter out = null;
			try {
				out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true)));
				out.write(time + " " + tag + " " + msg + "\r\n");
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					if (out != null) {
						out.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 *  According to the file path   Recursive file creation 
	 * 
	 * @param file
	 */
	public static void createDipPath(String file) {
		String parentFile = file.substring(0, file.lastIndexOf("/"));
		File file1 = new File(file);
		File parent = new File(parentFile);
		if (!file1.exists()) {
			parent.mkdirs();
			try {
				file1.createNewFile();
				LogUtils.e(" The path to the log file is " + file1.getAbsolutePath());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * A little trick to reuse a formatter in the same thread
	 */
	private static class ReusableFormatter {

		private Formatter		formatter;

		private StringBuilder	builder;

		public ReusableFormatter() {
			builder = new StringBuilder();
			formatter = new Formatter(builder);
		}

		public String format(String msg, Object... args) {
			formatter.format(msg, args);
			String s = builder.toString();
			builder.setLength(0);
			return s;
		}
	}

	private static final ThreadLocal<ReusableFormatter> thread_local_formatter = new ThreadLocal<ReusableFormatter>() {

		protected ReusableFormatter initialValue() {
			return new ReusableFormatter();
		}
	};

	public static String format(String msg, Object... args) {
		ReusableFormatter formatter = thread_local_formatter.get();
		return formatter.format(msg, args);
	}

	public static boolean isSDAva() {
		if (cacheDirPath == null) cacheDirPath = App.getAppContext().getExternalFilesDir("log").getAbsolutePath();

		if (!TextUtils.isEmpty(cacheDirPath)) {
			return true;
		} else {
			return false;
		}
	}
}

Additional knowledge: Android log printing class LogUtils can navigate the class name, method name and the number of lines with errors and save the log file

In development, we often debug our application by printing log. In Java we often use the methods System. out. println () to print logs on the console for our debugging. In Android, there is a special class Log to realize the log printing under Android system, which is more convenient for us to locate the program where there are problems.   

However, the Log class officially provided by Android is not very convenient in actual project use. When an error occurs in the program, what we hope most is that this Log class can help us locate which method of which class, and even then there is an error in that line. This can bring great convenience to our debugging.   

At the same time, we should also think that for the sake of application security, before app is officially launched, we should turn off the function of printing logs to prevent others from cracking your application through Log. When printing Log in production mode, the function of printing log is turned off in formal mode. To close and open Log flexibly, it is also necessary to encapsulate it on the native Log class.   

There is another time, when our program crashes due to problems, we hope to collect the causes of exceptions for analysis, so we can save the Log log to a file and put it in the directory created by the SD card program. You can also upload the abnormal Log log file to the server in the background of the program when the user is networked, which is convenient for programmers to analyze and solve bug.   

Today, I will share with you a very practical Log class LogUtils, this class is extracted from xUtils, slightly modified, there are comments.   

Example:

We call a few methods in LogUtils in MainActivity, paying attention to the number of lines. 1

Then see if the log printed by the console is like that called by MainActivity. Log has the name of this class and the method name of oncreate, and the current number of lines; 2

See the Log log in the above figure is not very convenient to locate the problems in the program, and the exception can be located quickly. Then set the following Log type to false anywhere in the program, so it will not print logs, which is quite convenient to use.  


   //  The type of log allowed to be printed, the default is true Is set to false Do not print 
 public static boolean allowD = true;
 public static boolean allowE = true;
 public static boolean allowI = true;
 public static boolean allowV = true;
 public static boolean allowW = true;
 public static boolean allowWtf = true;

The code is posted below:


package com.finddreams.log;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Formatter;
import java.util.Locale;

import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;

/**
 * Log Tools, similar to android.util.Log .  tag Automatically generated, formatted :
 * customTagPrefix:className.methodName(Line:lineNumber),
 * customTagPrefix Output only when empty: className.methodName(Line:lineNumber) . 
 */
public class LogUtils {

 public static String customTagPrefix = "finddreams"; //  Customize Tag The prefix of, which can be the author name 
 private static final boolean isSaveLog = false; //  Do you want to save the log to SD Card 
 public static final String ROOT = Environment.getExternalStorageDirectory()
   .getPath() + "/finddreams/"; // SD Root directory in card 
 private static final String PATH_LOG_INFO = ROOT + "info/";

 private LogUtils() {
 }

 //  The type of log allowed to be printed, the default is true Is set to false Do not print 
 public static boolean allowD = true;
 public static boolean allowE = true;
 public static boolean allowI = true;
 public static boolean allowV = true;
 public static boolean allowW = true;
 public static boolean allowWtf = true;

 private static String generateTag(StackTraceElement caller) {
  String tag = "%s.%s(Line:%d)"; //  Placeholder 
  String callerClazzName = caller.getClassName(); //  Get to the class name 
  callerClazzName = callerClazzName.substring(callerClazzName
    .lastIndexOf(".") + 1);
  tag = String.format(tag, callerClazzName, caller.getMethodName(),
    caller.getLineNumber()); //  Replace 
  tag = TextUtils.isEmpty(customTagPrefix) ? tag : customTagPrefix + ":"
    + tag;
  return tag;
 }

 /**
  *  Custom logger
  */
 public static CustomLogger customLogger;

 public interface CustomLogger {
  void d(String tag, String content);

  void d(String tag, String content, Throwable tr);

  void e(String tag, String content);

  void e(String tag, String content, Throwable tr);

  void i(String tag, String content);

  void i(String tag, String content, Throwable tr);

  void v(String tag, String content);

  void v(String tag, String content, Throwable tr);

  void w(String tag, String content);

  void w(String tag, String content, Throwable tr);

  void w(String tag, Throwable tr);

  void wtf(String tag, String content);

  void wtf(String tag, String content, Throwable tr);

  void wtf(String tag, Throwable tr);
 }

 public static void d(String content) {
  if (!allowD)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.d(tag, content);
  } else {
   Log.d(tag, content);
  }
 }

 public static void d(String content, Throwable tr) {
  if (!allowD)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.d(tag, content, tr);
  } else {
   Log.d(tag, content, tr);
  }
 }

 public static void e(String content) {
  if (!allowE)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.e(tag, content);
  } else {
   Log.e(tag, content);
  }
  if (isSaveLog) {
   point(PATH_LOG_INFO, tag, content);
  }
 }

 public static void e(String content, Throwable tr) {
  if (!allowE)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.e(tag, content, tr);
  } else {
   Log.e(tag, content, tr);
  }
  if (isSaveLog) {
   point(PATH_LOG_INFO, tag, tr.getMessage());
  }
 }

 public static void i(String content) {
  if (!allowI)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.i(tag, content);
  } else {
   Log.i(tag, content);
  }

 }

 public static void i(String content, Throwable tr) {
  if (!allowI)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.i(tag, content, tr);
  } else {
   Log.i(tag, content, tr);
  }

 }

 public static void v(String content) {
  if (!allowV)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.v(tag, content);
  } else {
   Log.v(tag, content);
  }
 }

 public static void v(String content, Throwable tr) {
  if (!allowV)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.v(tag, content, tr);
  } else {
   Log.v(tag, content, tr);
  }
 }

 public static void w(String content) {
  if (!allowW)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.w(tag, content);
  } else {
   Log.w(tag, content);
  }
 }

 public static void w(String content, Throwable tr) {
  if (!allowW)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.w(tag, content, tr);
  } else {
   Log.w(tag, content, tr);
  }
 }

 public static void w(Throwable tr) {
  if (!allowW)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.w(tag, tr);
  } else {
   Log.w(tag, tr);
  }
 }

 public static void wtf(String content) {
  if (!allowWtf)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.wtf(tag, content);
  } else {
   Log.wtf(tag, content);
  }
 }

 public static void wtf(String content, Throwable tr) {
  if (!allowWtf)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.wtf(tag, content, tr);
  } else {
   Log.wtf(tag, content, tr);
  }
 }

 public static void wtf(Throwable tr) {
  if (!allowWtf)
   return;
  StackTraceElement caller = getCallerStackTraceElement();
  String tag = generateTag(caller);

  if (customLogger != null) {
   customLogger.wtf(tag, tr);
  } else {
   Log.wtf(tag, tr);
  }
 }

 private static StackTraceElement getCallerStackTraceElement() {
  return Thread.currentThread().getStackTrace()[4];
 }

 public static void point(String path, String tag, String msg) {
  if (isSDAva()) {
   Date date = new Date();
   SimpleDateFormat dateFormat = new SimpleDateFormat("",
     Locale.SIMPLIFIED_CHINESE);
   dateFormat.applyPattern("yyyy");
   path = path + dateFormat.format(date) + "/";
   dateFormat.applyPattern("MM");
   path += dateFormat.format(date) + "/";
   dateFormat.applyPattern("dd");
   path += dateFormat.format(date) + ".log";
   dateFormat.applyPattern("[yyyy-MM-dd HH:mm:ss]");
   String time = dateFormat.format(date);
   File file = new File(path);
   if (!file.exists())
    createDipPath(path);
   BufferedWriter out = null;
   try {
    out = new BufferedWriter(new OutputStreamWriter(
      new FileOutputStream(file, true)));
    out.write(time + " " + tag + " " + msg + "\r\n");
   } catch (Exception e) {
    e.printStackTrace();
   } finally {
    try {
     if (out != null) {
      out.close();
     }
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }
 }

 /**
  *  According to the file path   Recursive file creation 
  * 
  * @param file
  */
 public static void createDipPath(String file) {
  String parentFile = file.substring(0, file.lastIndexOf("/"));
  File file1 = new File(file);
  File parent = new File(parentFile);
  if (!file1.exists()) {
   parent.mkdirs();
   try {
    file1.createNewFile();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }

 /**
  * A little trick to reuse a formatter in the same thread
  */
 private static class ReusableFormatter {

  private Formatter formatter;
  private StringBuilder builder;

  public ReusableFormatter() {
   builder = new StringBuilder();
   formatter = new Formatter(builder);
  }

  public String format(String msg, Object... args) {
   formatter.format(msg, args);
   String s = builder.toString();
   builder.setLength(0);
   return s;
  }
 }

 private static final ThreadLocal<ReusableFormatter> thread_local_formatter = new ThreadLocal<ReusableFormatter>() {
  protected ReusableFormatter initialValue() {
   return new ReusableFormatter();
  }
 };

 public static String format(String msg, Object... args) {
  ReusableFormatter formatter = thread_local_formatter.get();
  return formatter.format(msg, args);
 }

 public static boolean isSDAva() {
  if (Environment.getExternalStorageState().equals(
    Environment.MEDIA_MOUNTED)
    || Environment.getExternalStorageDirectory().exists()) {
   return true;
  } else {
   return false;
  }
 }
}

Related articles: