How to enable logging for apache commons HttpClient on Android
To enable logging for apache commons HttpClient in normal Java application I used:
System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire", "debug");
System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient", "debug");
开发者_JAVA百科
But on android I don't see logs in LogCat.
Am I missing some thing?
Ignore my earlier comment. I found the solution on the org.apache.http logging page. Your original answer was referring to httpclient-3.x logging, and the working code for recent versions comes from http-components logging
java.util.logging.Logger.getLogger("org.apache.http.wire").setLevel(java.util.logging.Level.FINEST);
java.util.logging.Logger.getLogger("org.apache.http.headers").setLevel(java.util.logging.Level.FINEST);
System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire", "debug");
System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http", "debug");
System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http.headers", "debug");
and properties:
adb shell setprop log.tag.org.apache.http VERBOSE
adb shell setprop log.tag.org.apache.http.wire VERBOSE
adb shell setprop log.tag.org.apache.http.headers VERBOSE
The difference is in the logging tag names.
Here is a solution (without digging into details)
Console:
adb shell setprop log.tag.httpclient.wire.header VERBOSE
adb shell setprop log.tag.httpclient.wire.content VERBOSE
Code:
java.util.logging.Logger.getLogger("httpclient.wire.header").setLevel(java.util.logging.Level.FINEST);
java.util.logging.Logger.getLogger("httpclient.wire.content").setLevel(java.util.logging.Level.FINEST);
Test:
java.util.logging.Logger.getLogger("httpclient.wire.content").log(java.util.logging.Level.CONFIG, "hola");
The devil is in the details. I'm running the 2.3.3 emulator and got it working with:
java.util.logging.Logger.getLogger("org.apache.http.wire").setLevel(java.util.logging.Level.FINEST);
java.util.logging.Logger.getLogger("org.apache.http.headers").setLevel(java.util.logging.Level.FINEST);
and in the adb shell
# setprop log.tag.org.apache.http.wire VERBOSE
# setprop log.tag.org.apache.http.headers VERBOSE
Thus it seems the log specifiers are different.
You just need to use
java.util.logging.Logger.getLogger(yourFullClassName).setLevel(java.util.logging.Level.All);
and
adb shell setprop log.tag.correspondingTag VERBOSE
Android use this function to get correspondingTag from class full name:
public static String loggerNameToTag(String loggerName)
{
if (loggerName == null) {
return "null";
}
int length = loggerName.length();
if (length <= 23) {
return loggerName;
}
int lastPeriod = loggerName.lastIndexOf(".");
return length - (lastPeriod + 1) <= 23 ? loggerName.substring(lastPeriod + 1) : loggerName.substring(loggerName.length() - 23);
}
so for example,I want to enable logging for “org.apache.http.impl.client.DefaultRequestDirector” class,do such things below:
String clzName = "org.apache.http.impl.client.DefaultRequestDirector";
String newClzName = loggerNameToTag(clzName);
System.out.println("className:" + clzName + " tagName is " + newClzName); //get tagName from class full name,and then it will be used in setprop
Logger jdkLogger = Logger.getLogger(clzName);
jdkLogger.setLevel(Level.ALL);
if (jdkLogger.isLoggable(Level.FINE))
{
jdkLogger.log(Level.FINE, "jdk log msg");
jdkLogger.log(Level.Fine,"tagName is")
}
And then in adb shell
setprop log.tag.DefaultRequestDirector VERBOSE
For Apache Http Components version 5.x, you need to use slf4j
logging Facade e.g. JUL
(Jakarta Common Logging) to bind a logging backend at compile time.
implementation 'org.slf4j:slf4j-jdk14:2.0.0-alpha7'
Retrieve the root
logger via
final Logger rootLogger = java.util.logging.Logger.getLogger("");
or
final Logger rootLogger = java.util.logging.LogManager.getLogManager().getLogger("")
Set the logging level to proper level, otherwise messages are discarded
rootLogger.setLevel(Level.ALL);
Implement your own java.util.logging.Handler
for receiving messages
public static class LogHandler extends Handler {
@Override
public void close() {
// do nothing
}
@Override
public void flush() {
// do nothing
}
@Override
public void publish(LogRecord record) {
final Level level = record.getLevel();
if (level == Level.INFO) {
Log.i(record.getLoggerName(), record.getMessage());
} else if (level == Level.WARNING) {
Log.w(record.getLoggerName(), record.getMessage());
} else if (level == Level.SEVERE) {
Log.e(record.getLoggerName(), record.getMessage());
} else if (level == Level.FINE) {
Log.d(record.getLoggerName(), record.getMessage());
} else {
Log.v(record.getLoggerName(), record.getMessage());
}
}
}
Set the handler
final LogHandler logHandler = new LogHandler();
rootLogger.addHandler(logHandler);
And for goodies a setLevel
function for modules. A container is required to keep strong reference to uninitialized external loggers, otherwise garbage collector will deallocate and level
parameter will be set to default.
private static HashMap<String, Logger> sLoggerMap = new HashMap<>();
Class to hold modules
public static class Module {
final String mModule;
public static final Module APACHE_HTTP = new Module("org.apache.hc.client5.http");
public static final Module APACHE_HTTP_WIRE = new Module("org.apache.hc.client5.http.wire");
public static final Module APACHE_HTTP_HEADERS = new Module("org.apache.hc.client5.http.headers");
Module(final String module) {
mModule = module;
}
}
With function
public static void setLogging(final Module module, final Level level) {
Logger logger = sLoggerMap.get(module.mModule);
if (logger == null) {
logger = Logger.getLogger(module.mModule);
sLoggerMap.put(module.mModule, logger);
}
logger.setLevel(level);
}
And use it like so (I'm encapsulating everything inside Logging
class)
Logging.setLogging(Logging.Module.APACHE_HTTP_WIRE, Level.FINE);
It has its own drawbacks when requests are async. Switching log level will affect all the in progress request.
For release build, add following to proguard-rules.pro
-keep class org.apache.hc.client5.http.** {
<fields>;
<methods>;
}
精彩评论