Android之日志管理(Log)(原创)
##文章大纲
一、为什么要使用日志管理工具
二、日志管理工具实战
三、项目源码下载

##一、为什么要使用日志管理工具
###1. 对IT安全至关重要
  当您使用强大的日志管理软件自动触发以保护您的系统时,您已经赢得了一半的战斗,以确保您的IT基础设施安全。某些日志管理工具具有阻止可疑IP地址,删除帐户,甚至完全关闭显示受感染迹象的计算机的内置功能。
  此外,有效的日志管理工具可以实现并简化您的入侵检测系统。因此,当您的入侵检测系统发出恶意活动信号时,您可以快速检查由日志管理工具生成和维护的日志文件。日志文件可以进一步提供重要线索,便于故障排除以帮助您。
###2. 帮助企业更有效地运营
  使用日志管理工具的直接好处之一是它可以最大限度地减少生产中的停机时间。日志管理工具是解决方案带中的主要力量,可以使您智能地掌握与生产相关的可能问题。它允许您知道什么时候重要的事情已经改变或改变。反过来,这会对您的技术平稳运行以及整个业务流程产生重大影响。
  此外,有效的日志管理对于满足合规性也很重要。某些合规性要求您监控和记录每个应用程序以及IT基础架构中的系统的事件。
###3. 找到问题的根源
  使用复杂的日志管理工具维护日志文件允许进行根本原因分析,稍后便于调试。你可以避免艰苦的手工努力,试图弄清楚什么是轨道,以及究竟是什么导致了一个可能的问题。这进一步使您在处理所有类型的问题时越来越有效。
  您可以浏览日志文件,甚至可以使用该工具发现任何违规行为。这有助于使系统恢复正常工作。日志管理工具可帮助您更深入地识别现代组织遇到的威胁。
##二、日志管理工具实战
  在此次项目实战过程中,我们重点关注于两个点,第一个是团队开发过程中的问题定位,比如日志打印包含类名、接口编写人、错误信息等内容,方便问题快速定位,第二个是项目上线后的优化,我们可以将手机机型、版本号、项目版本、错误信息等以文件存在手机中,定期将数据传送到服务器。
###1. 获取手机相关信息
  该模块信息在团队协作开发中无需体现出来,在项目上线后,错误日志的上传才需要用到,用于问题快速定位,相关源码如下所示:
```
package com.example.administrator.mylogger;
import android.content.Context;
import android.os.Build;
/**
 * 手机相关信息获取
 */
public class PhoneMessage {
    //获取设备的屏幕宽度
    public static int getDeviceWidth(Context context) {
        return context.getResources().getDisplayMetrics().widthPixels;
    }
    //获取设备的屏幕高度
    public static int getDeviceHeight(Context context) {
        return context.getResources().getDisplayMetrics().heightPixels;
    }
    //获取厂商名
    public static String getDeviceManufacturer() {
        return Build.MANUFACTURER;
    }
    //获取手机品牌
    public static String getDeviceBrand() {
        return Build.BRAND;
    }
    //获取手机型号
    public static String getDeviceModel() {
        return android.os.Build.MODEL;
    }
    //获取手机Android系统SDK
    public static int getDeviceSDK() {
        return android.os.Build.VERSION.SDK_INT;
    }
    //获取手机Android版本
    public static String getDeviceAndroidVersion() {
        return android.os.Build.VERSION.RELEASE;
    }
    public static String getPhoneMessage(Context context)
    {
String phoneMessage = "屏幕宽度:" + getDeviceWidth(context) + "\n" + "屏幕高度:" + getDeviceHeight(context) + "\n" + "手机厂商名:" + getDeviceManufacturer()
+ "\n" + "手机品牌:" + getDeviceBrand() + "\n" + "手机型号:" + getDeviceModel() + "\n" + "Android系统SDK:" + getDeviceSDK()
+ "\n" + "手机Android版本:" + getDeviceAndroidVersion() ;
return phoneMessage;
    }
}
```
###2. 获取app相关信息
  该模块获取的信息包括app名称、版本号、包名、类名、开发人等信息,在团队开发过程中,只需要体现包名、类型和开发人信息即可,而在错误日志上传到服务器时,则需全部上传,具体获取app信息代码如下:
```
package com.example.administrator.mylogger;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
/**
 * 获取app相关信息
 */
public class AppUtils {
    /**
     * 获取应用程序名称
     */
    private static synchronized String getAppName(Context context) {
        try {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageInfo(
                    context.getPackageName(), 0);
            int labelRes = packageInfo.applicationInfo.labelRes;
            return context.getResources().getString(labelRes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * [获取应用程序版本名称信息]
     * @param context
     * @return 当前应用的版本名称
     */
    private static synchronized String getVersionName(Context context) {
        try {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageInfo(
                    context.getPackageName(), 0);
            return packageInfo.versionName;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * [获取应用程序版本号]
     * @param context
     * @return 当前应用的版本号
     */
    private static synchronized int getVersionCode(Context context) {
        try {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageInfo(
                    context.getPackageName(), 0);
            return packageInfo.versionCode;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
    //获取当前的activity的完整路径
    public static String getRunningActivityName(Context context){
        ActivityManager activityManager=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        String runningActivity=activityManager.getRunningTasks(1).get(0).topActivity.getClassName();
        return runningActivity;
    }
    //用于错误日志存进手机中使用
    public static String getAppMessage(Context context)
    {
        String message = "\n App名称:"+getAppName(context) + "\n 版本名称:"+getVersionName(context) + "\n 版本号:" + getVersionCode(context) + "\n 类名:" + getRunningActivityName(context);
        return message;
    }
}
```
###3. 开发人员信息管理封装类
```
package com.example.administrator.mylogger;
/**
 * 管理开发人员的姓名,用于日志打印 方便问题定位
 */
public class NameManager {
    public static String wxc = "吴晓畅";
}
```
###4. 日志输出封装类
```
package com.example.administrator.mylogger;
import android.app.ActivityManager;
import android.content.Context;
import android.util.Log;
import java.util.Date;
import java.text.SimpleDateFormat;
/**
 * 关于操作中的日志信息输出
 * 
 * @author 吴晓畅
 * 
 */
public final class Logger {
private static final boolean isinput = true;// 用于判断是否输出日志 可以控制整个应用的输出 调试模式 true 上线模式 false
	//Android的Log等级通常有五类,按照日志级别由低到高分别是Verbose、Debug、Info、Warning、Error  等级逐步增大
	private final static int logLevel = Log.VERBOSE; //日志级别,大于或者等于logLevel才会被打印
	/**
	 * 输出故障的日志信息
	 * 
	 * @param context
	 *            系统名称模块名称接口名称
	 * @param msg
	 *            详细描述
	 *
	 * @param userName
	 *            接口编写人
	 */
	public static void d(Context context, String msg, String userName) {
if (isinput) {
			if(logLevel <= Log.DEBUG)
			{
				Log.d(AppUtils.getRunningActivityName(context), "\n 接口编写人:" + userName + "\n 日志信息:" + msg);
			}
}
}
	/**
	 * 输出错误的日志信息
	 * 
	 * @param context
	 *            系统名称模块名称接口名称
	 * @param msg
	 *            详细描述
	 * @param userName
	 *            接口编写人
	 */
	public static void e(Context context, String msg, String userName) {
if (isinput) {
			if(logLevel <= Log.ERROR)
			{
Log.e(AppUtils.getRunningActivityName(context), "\n 接口编写人:" + userName + "\n 日志信息:" + msg);
}
		}
	}
	/**
	 * 输出程序的日志信息
	 * 
	 * @param context
	 *            系统名称模块名称接口名称
	 * @param msg
	 *            详细描述
	 * @param userName
	 *            接口编写人
	 */
	public static void i(Context context, String msg, String userName) {
if (isinput) {
			if(logLevel <= Log.INFO)
			{
Log.i(AppUtils.getRunningActivityName(context), "\n 接口编写人:" + userName + "\n 日志信息:" + msg);
}
}
}
	/**
	 * 输出冗余的日志信息
	 * 
	 * @param context
	 *            系统名称模块名称接口名称
	 * @param msg
	 *            详细描述
	 * @param userName
	 *            接口编写人
	 */
	public static void v(Context context, String msg, String userName) {
		if (isinput) {
			if(logLevel <= Log.VERBOSE)
			{
Log.v(AppUtils.getRunningActivityName(context), "\n 接口编写人:" + userName + "\n 日志信息:" + msg);
			}
		}
	}
	/**
	 * 输出警告的日志信息
	 * 
	 * @param context
	 *            系统名称模块名称接口名称
	 * @param msg
	 *            详细描述
	 * @param userName
	 *            接口编写人
	 */
	public static void w(Context context, String msg, String userName) {
	    //获取手机相关信息
		String phoneMessage = PhoneMessage.getPhoneMessage(context);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
		//获取错误日志信息
		String errorMessage = "\n 接口信息:" + AppUtils.getAppMessage(context) + "\n" + "接口编写人:" + userName + "\n" + "错误信息为:" + msg + "\n" +
				"错误时间:" + df.format(new Date());
//将手机信息、错误信息缓存进手机
//
if (isinput) {
			if(logLevel <= Log.WARN)
			{
				Log.w(AppUtils.getRunningActivityName(context), "\n 接口编写人:" + userName + "\n 日志信息:" + msg);
			}
		}
	}
}
```
温馨提示:
(1) isinput变量用于判断是否输出日志 可以控制整个应用的输出 调试模式 true  上线模式 false
(2)Android的Log等级通常有五类,按照日志级别由低到高分别是Verbose、Debug、Info、Warning、Error, 等级逐步增大,在该项目中,我们用logLevel变量控制日志输出,当日志级别大于或者等于logLevel才会被打印
###5. 测试工具使用
**新建activity_main.xml**
```
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
```
**MainActivity代码**
```
package com.example.administrator.mylogger;
        import android.support.v7.app.AppCompatActivity;
        import android.os.Bundle;
        import android.widget.TextView;
        import java.text.SimpleDateFormat;
        import java.util.Date;
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
TextView textView = findViewById(R.id.textView);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
        textView.setText(PhoneMessage.getPhoneMessage(MainActivity.this) + "\n 接口信息:" + AppUtils.getAppMessage(MainActivity.this) + "\n" + "接口编写人:" + NameManager.wxc + "\n" + "错误信息为:" + "测试错误" + "\n" +
                "错误时间:" + df.format(new Date()));
        Logger.e(MainActivity.this, "测试错误", NameManager.wxc);
    }
}
```
**运行结果如下所示**


##三、项目源码下载
链接:https://pan.baidu.com/s/1OMwtwbjMV9BI-tfCceTErQ 
提取码:ybhu 
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号