1、新建Android项目
Project: AndroidLog4j
Package:cn.darkranger.log
Activity:MainActivity
2、在libs中添加log4j-1.2.17.jar包
3、添加android-logging-log4j-1.0.3.jar
我看了一下,这里面只有两个类,我就用反编译工具反编译成了java文件,写入代码中了
LogCatAppender.java(主要作用是将log在控制台的输出转化为Android中的LogCat输出)
package cn.darkranger.log.log4j; import org.apache.log4j.AppenderSkeleton; import org.apache.log4j.Layout; import org.apache.log4j.PatternLayout; import org.apache.log4j.spi.LoggingEvent; import android.util.Log; /** * 源自 android-logging-log4j-1.0.3.jar * * @author Administrator */ public class LogCatAppender extends AppenderSkeleton { protected Layout tagLayout; public LogCatAppender(Layout messageLayout, Layout tagLayout) { this.tagLayout = tagLayout; setLayout(messageLayout); } public LogCatAppender(Layout messageLayout) { this(messageLayout, new PatternLayout("%c")); } public LogCatAppender() { this(new PatternLayout("%m%n")); } protected void append(LoggingEvent le) { switch (le.getLevel().toInt()) { case 5000: if (le.getThrowableInformation() != null) { Log.v(getTagLayout().format(le), getLayout().format(le), le.getThrowableInformation().getThrowable()); } else { Log.v(getTagLayout().format(le), getLayout().format(le)); } break; case 10000: if (le.getThrowableInformation() != null) { Log.d(getTagLayout().format(le), getLayout().format(le), le.getThrowableInformation().getThrowable()); } else { Log.d(getTagLayout().format(le), getLayout().format(le)); } break; case 20000: if (le.getThrowableInformation() != null) { Log.i(getTagLayout().format(le), getLayout().format(le), le.getThrowableInformation().getThrowable()); } else { Log.i(getTagLayout().format(le), getLayout().format(le)); } break; case 30000: if (le.getThrowableInformation() != null) { Log.w(getTagLayout().format(le), getLayout().format(le), le.getThrowableInformation().getThrowable()); } else { Log.w(getTagLayout().format(le), getLayout().format(le)); } break; case 40000: if (le.getThrowableInformation() != null) { Log.e(getTagLayout().format(le), getLayout().format(le), le.getThrowableInformation().getThrowable()); } else { Log.e(getTagLayout().format(le), getLayout().format(le)); } break; case 50000: if (le.getThrowableInformation() != null) { Log.wtf(getTagLayout().format(le), getLayout().format(le), le.getThrowableInformation().getThrowable()); } else Log.wtf(getTagLayout().format(le), getLayout().format(le)); break; } } public void close() { } public boolean requiresLayout() { return true; } public Layout getTagLayout() { return this.tagLayout; } public void setTagLayout(Layout tagLayout) { this.tagLayout = tagLayout; } }
LogConfig.java(主要作用是配置一些基本的信息)
package cn.darkranger.log.log4j; import java.io.IOException; import org.apache.log4j.Layout; import org.apache.log4j.Level; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; import org.apache.log4j.RollingFileAppender; import org.apache.log4j.helpers.LogLog; /** * 源自 android-logging-log4j-1.0.3.jar * * @author Administrator */ public class LogConfig { private Level rootLevel = Level.DEBUG; private String filePattern = "%d - [%p::%c::%C] - %m%n"; private String logCatPattern = "%m%n"; private String fileName = "android-log4j.log"; private int maxBackupSize = 5; private long maxFileSize = 1024 * 1024 * 5L; private boolean immediateFlush = true; private boolean useLogCatAppender = true; private boolean useFileAppender = true; private boolean resetConfiguration = true; private boolean internalDebugging = false; public LogConfig() { } public LogConfig(String fileName) { setFileName(fileName); } public LogConfig(String fileName, Level rootLevel) { this(fileName); setRootLevel(rootLevel); } public LogConfig(String fileName, Level rootLevel, String filePattern) { this(fileName); setRootLevel(rootLevel); setFilePattern(filePattern); } public LogConfig(String fileName, int maxBackupSize, long maxFileSize, String filePattern, Level rootLevel) { this(fileName, rootLevel, filePattern); setMaxBackupSize(maxBackupSize); setMaxFileSize(maxFileSize); } public void configure() { Logger root = Logger.getRootLogger(); if (isResetConfiguration()) { LogManager.getLoggerRepository().resetConfiguration(); } LogLog.setInternalDebugging(isInternalDebugging()); if (isUseFileAppender()) { configureFileAppender(); } if (isUseLogCatAppender()) { configureLogCatAppender(); } root.setLevel(getRootLevel()); } public void setLevel(String loggerName, Level level) { Logger.getLogger(loggerName).setLevel(level); } private void configureFileAppender() { Logger root = Logger.getRootLogger(); Layout fileLayout = new PatternLayout(getFilePattern()); RollingFileAppender rollingFileAppender; try { rollingFileAppender = new RollingFileAppender(fileLayout, getFileName()); } catch (IOException e) { throw new RuntimeException("Exception configuring log system", e); } rollingFileAppender.setMaxBackupIndex(getMaxBackupSize()); rollingFileAppender.setMaximumFileSize(getMaxFileSize()); rollingFileAppender.setImmediateFlush(isImmediateFlush()); root.addAppender(rollingFileAppender); } private void configureLogCatAppender() { Logger root = Logger.getRootLogger(); Layout logCatLayout = new PatternLayout(getLogCatPattern()); LogCatAppender logCatAppender = new LogCatAppender(logCatLayout); root.addAppender(logCatAppender); } public Level getRootLevel() { return this.rootLevel; } public void setRootLevel(Level level) { this.rootLevel = level; } public String getFilePattern() { return this.filePattern; } public void setFilePattern(String filePattern) { this.filePattern = filePattern; } public String getLogCatPattern() { return this.logCatPattern; } public void setLogCatPattern(String logCatPattern) { this.logCatPattern = logCatPattern; } public String getFileName() { return this.fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public int getMaxBackupSize() { return this.maxBackupSize; } public void setMaxBackupSize(int maxBackupSize) { this.maxBackupSize = maxBackupSize; } public long getMaxFileSize() { return this.maxFileSize; } public void setMaxFileSize(long maxFileSize) { this.maxFileSize = maxFileSize; } public boolean isImmediateFlush() { return this.immediateFlush; } public void setImmediateFlush(boolean immediateFlush) { this.immediateFlush = immediateFlush; } public boolean isUseFileAppender() { return this.useFileAppender; } public void setUseFileAppender(boolean useFileAppender) { this.useFileAppender = useFileAppender; } public boolean isUseLogCatAppender() { return this.useLogCatAppender; } public void setUseLogCatAppender(boolean useLogCatAppender) { this.useLogCatAppender = useLogCatAppender; } public void setResetConfiguration(boolean resetConfiguration) { this.resetConfiguration = resetConfiguration; } public boolean isResetConfiguration() { return this.resetConfiguration; } public void setInternalDebugging(boolean internalDebugging) { this.internalDebugging = internalDebugging; } public boolean isInternalDebugging() { return this.internalDebugging; } }
4、编写LogUtil.java工具类(主要作用是重新配置Log4j的一些参数,设置成为合适自己项目的log,在这里我们通过调用LogUtil.configLog()就可以了,简洁)
LogUtil.java
package cn.darkranger.log.log4j; import java.io.File; import java.util.Locale; import org.apache.log4j.Level; import android.os.Environment; /** * LogUtil 工具类 * * @author Administrator * */ @SuppressWarnings("all") public class LogUtil { /** 这里的AppName决定log的文件位置和名称 **/ private static final String APP_NAME = "MyApp"; /** 设置log文件全路径,这里是 MyApp/Log/myapp.log **/ private static final String LOG_FILE_PATH = Environment.getExternalStorageDirectory() + File.separator + APP_NAME + File.separator + "Log" + File.separator + APP_NAME.toLowerCase(Locale.CHINA) + ".log"; /** * ### log文件的格式 * * ### 输出格式解释: * ### [%-d{yyyy-MM-dd HH:mm:ss}][Class: %c.%M(%F:%L)] %n[Level: %-5p] - Msg: %m%n * * ### %d{yyyy-MM-dd HH:mm:ss}: 时间,大括号内是时间格式 * ### %c: 全类名 * ### %M: 调用的方法名称 * ### %F:%L 类名:行号(在控制台可以追踪代码) * ### %n: 换行 * ### %p: 日志级别,这里%-5p是指定的5个字符的日志名称,为的是格式整齐 * ### %m: 日志信息 * ### 输出的信息大概如下: * ### [时间{时间格式}][信息所在的class.method(className:lineNumber)] 换行 * ### [Level: 5个字符的等级名称] - Msg: 输出信息 换行 */ private static final String LOG_FILE_PATTERN = "[%-d{yyyy-MM-dd HH:mm:ss}][Class: %c.%M(%F:%L)] %n[Level: %-5p] - Msg: %m%n"; /** 生产环境下的log等级 **/ private static final Level LOG_LEVEL_PRODUCE = Level.ALL; /** 发布以后的log等级 **/ private static final Level LOG_LEVEL_RELEASE = Level.INFO; /** * 配置log4j参数 */ public static void configLog(){ LogConfig logConfig = new LogConfig(); /** 设置Log等级,生产环境下调用setLogToProduce(),发布后调用setLogToRelease() **/ setLogToProduce(logConfig); logConfig.setFileName(LOG_FILE_PATH); logConfig.setLevel("org.apache", Level.ERROR); logConfig.setFilePattern(LOG_FILE_PATTERN); logConfig.setMaxFileSize(1024 * 1024 * 5); logConfig.setImmediateFlush(true); logConfig.configure(); } /** * 将log设置为生产环境 * * @param logConfig */ private static void setLogToProduce(LogConfig logConfig) { logConfig.setRootLevel(LOG_LEVEL_PRODUCE); } /** * 将log设置为发布以后的环境 * * @param logConfig */ private static void setLogToRelease(LogConfig logConfig) { logConfig.setRootLevel(LOG_LEVEL_RELEASE); } }
5、编写MyApplication.java(继承Application,然后在onCreate()中调用LogUtil.configLog()方法来配置Log4j,这样程序一开始就相当于初始化了Log4j的配置)
package cn.darkranger.log.application; import org.apache.log4j.Logger; import android.app.Application; import cn.darkranger.log.log4j.LogUtil; public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); //配置log4j基本参数 LogUtil.configLog(); //获取Application Log Logger log = Logger.getLogger(MyApplication.class); //输出MyApplication的信息 log.info("Log4j Is Ready and My Application Was Created Successfully! "); } }
6、修改AndroidManifest.xml(主要有两个地方,一是添加读取存储的权限,二是指定Application为我们刚刚写的MyApplication)
有下划线的地方就是我们添加的xml代码
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.darkranger.log" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="22" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:name="cn.darkranger.log.application.MyApplication" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="cn.darkranger.log.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
7、使用Log4j
(1)创建Logger实例
private static Logger log = Logger.getLogger(YourClassName.class);
(2)在代码中用log记录信息
log.info("onCreate()");
log.fatal("this is fatal!");
log.error("this is error!");
log.warn("this is warn!");
log.info("this is info!");
log.debug("this is debug!");
log.trace("this is trace!");
(3)MainActivity.java中的示例(红色的部分就是log的记录)
package cn.darkranger.log; import org.apache.log4j.Logger; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; public class MainActivity extends AppCompatActivity { private static Logger log = Logger.getLogger(MainActivity.class); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); log.info("onCreate()"); log.fatal("this is fatal!"); log.error("this is error!"); log.warn("this is warn!"); log.info("this is info!"); log.debug("this is debug!"); log.trace("this is trace!"); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); log.info("onCreateOptionsMenu()"); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
8、结果展示:
控制台输出:
平板中的Log位置:计算机\Galaxy Tab A\Tablet\MyApp\Log\myapp.log(相对于计算机)
设备存储\MyApp\Log\myapp.log(相对于平板)
[2016-06-16 17:14:54][Class: cn.darkranger.log.application.MyApplication.onCreate(MyApplication.java:21)] [Level: INFO ] - Msg: Log4j Is Ready and My Application Was Created Successfully! [2016-06-16 17:14:54][Class: cn.darkranger.log.MainActivity.onCreate(MainActivity.java:17)] [Level: INFO ] - Msg: onCreate() [2016-06-16 17:14:54][Class: cn.darkranger.log.MainActivity.onCreate(MainActivity.java:18)] [Level: FATAL] - Msg: this is fatal! [2016-06-16 17:14:54][Class: cn.darkranger.log.MainActivity.onCreate(MainActivity.java:19)] [Level: ERROR] - Msg: this is error! [2016-06-16 17:14:54][Class: cn.darkranger.log.MainActivity.onCreate(MainActivity.java:20)] [Level: WARN ] - Msg: this is warn! [2016-06-16 17:14:54][Class: cn.darkranger.log.MainActivity.onCreate(MainActivity.java:21)] [Level: INFO ] - Msg: this is info! [2016-06-16 17:14:54][Class: cn.darkranger.log.MainActivity.onCreate(MainActivity.java:22)] [Level: DEBUG] - Msg: this is debug! [2016-06-16 17:14:54][Class: cn.darkranger.log.MainActivity.onCreate(MainActivity.java:23)] [Level: TRACE] - Msg: this is trace! [2016-06-16 17:14:54][Class: cn.darkranger.log.MainActivity.onCreateOptionsMenu(MainActivity.java:30)] [Level: INFO ] - Msg: onCreateOptionsMenu()