Log various properties at startup time for easier diagnosis

This commit is contained in:
Trustin Lee 2013-04-03 11:44:30 +09:00
parent bcb0b83b44
commit 0f3dc0409a
4 changed files with 165 additions and 58 deletions

View File

@ -33,10 +33,9 @@ public final class ResourceLeakDetector<T> {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ResourceLeakDetector.class); private static final InternalLogger logger = InternalLoggerFactory.getInstance(ResourceLeakDetector.class);
static { static {
if (ENABLED) { logger.debug("io.netty.resourceLeakDetection: {}", ENABLED);
logger.debug("Resource leak detection enabled.");
}
} }
private static final int DEFAULT_SAMPLING_INTERVAL = 113; private static final int DEFAULT_SAMPLING_INTERVAL = 113;
private static final ResourceLeak NOOP = new ResourceLeak() { private static final ResourceLeak NOOP = new ResourceLeak() {

View File

@ -15,10 +15,14 @@
*/ */
package io.netty.util.internal; package io.netty.util.internal;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.chmv8.ConcurrentHashMapV8; import io.netty.util.internal.chmv8.ConcurrentHashMapV8;
import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.InternalLoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
@ -41,6 +45,8 @@ import java.util.regex.Pattern;
*/ */
public final class PlatformDependent { public final class PlatformDependent {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent.class);
private static final boolean IS_ANDROID = isAndroid0(); private static final boolean IS_ANDROID = isAndroid0();
private static final boolean IS_WINDOWS = isWindows0(); private static final boolean IS_WINDOWS = isWindows0();
private static final boolean IS_ROOT = isRoot0(); private static final boolean IS_ROOT = isRoot0();
@ -59,12 +65,15 @@ public final class PlatformDependent {
private static final boolean HAS_JAVASSIST = hasJavassist0(); private static final boolean HAS_JAVASSIST = hasJavassist0();
static { static {
InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent.class); if (logger.isDebugEnabled()) {
logger.debug("io.netty.preferDirect: {}", DIRECT_BUFFER_PREFERRED);
}
if (!hasUnsafe()) { if (!hasUnsafe()) {
logger.warn( logger.warn(
"Your platform does not provide complete low-level API for accessing direct buffers reliably. " + "Your platform does not provide complete low-level API for accessing direct buffers reliably. " +
"Unless explicitly requested, heap buffer will always be preferred " + "Unless explicitly requested, heap buffer will always be preferred to avoid potential system " +
"to avoid potential risk of getting OutOfMemoryError."); "unstability.");
} }
} }
@ -277,80 +286,154 @@ public final class PlatformDependent {
} catch (Exception e) { } catch (Exception e) {
android = false; android = false;
} }
logger.debug("Platform: Android");
return android; return android;
} }
private static boolean isWindows0() { private static boolean isWindows0() {
return SystemPropertyUtil.get("os.name", "").toLowerCase(Locale.US).contains("win"); boolean windows = SystemPropertyUtil.get("os.name", "").toLowerCase(Locale.US).contains("win");
if (windows) {
logger.debug("Platform: Windows");
}
return windows;
} }
private static boolean isRoot0() { private static boolean isRoot0() {
Pattern PERMISSION_DENIED = Pattern.compile(".*permission.*denied.*"); if (isWindows()) {
boolean root = false; return false;
if (!isWindows()) { }
for (int i = 1023; i > 0; i --) {
ServerSocket ss = null; String[] ID_COMMANDS = { "/usr/bin/id", "/bin/id", "id" };
try { Pattern UID_PATTERN = Pattern.compile("^(?:0|[1-9][0-9]*)$");
ss = new ServerSocket(); for (String idCmd: ID_COMMANDS) {
ss.setReuseAddress(true); Process p = null;
ss.bind(new InetSocketAddress(i)); BufferedReader in = null;
root = true; String uid = null;
break; try {
} catch (Exception e) { p = Runtime.getRuntime().exec(new String[] { idCmd, "-u" });
// Failed to bind. in = new BufferedReader(new InputStreamReader(p.getInputStream(), CharsetUtil.US_ASCII));
// Check the error message so that we don't always need to bind 1023 times. uid = in.readLine();
String message = e.getMessage(); in.close();
if (message == null) {
message = ""; for (;;) {
} try {
message = message.toLowerCase(); int exitCode = p.waitFor();
if (PERMISSION_DENIED.matcher(message).matches()) { if (exitCode != 0) {
break; uid = null;
}
} finally {
if (ss != null) {
try {
ss.close();
} catch (Exception e) {
// Ignore.
} }
break;
} catch (InterruptedException e) {
// Ignore
}
}
} catch (Exception e) {
uid = null;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// Ignore
}
}
if (p != null) {
p.destroy();
}
}
if (uid != null && UID_PATTERN.matcher(uid).matches()) {
logger.debug("UID: {}", uid);
return "0".equals(uid);
}
}
logger.debug("Could not determine the current UID using /usr/bin/id; attempting to bind at privileged ports.");
Pattern PERMISSION_DENIED = Pattern.compile(".*(?:denied|not.*permitted).*");
for (int i = 1023; i > 0; i --) {
ServerSocket ss = null;
try {
ss = new ServerSocket();
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(i));
if (logger.isDebugEnabled()) {
logger.debug("UID: 0 (succeded to bind at port {})", i);
}
return true;
} catch (Exception e) {
// Failed to bind.
// Check the error message so that we don't always need to bind 1023 times.
String message = e.getMessage();
if (message == null) {
message = "";
}
message = message.toLowerCase();
if (PERMISSION_DENIED.matcher(message).matches()) {
break;
}
} finally {
if (ss != null) {
try {
ss.close();
} catch (Exception e) {
// Ignore.
} }
} }
} }
} }
return root;
logger.debug("UID: non-root (failed to bind at any privileged ports)");
return false;
} }
@SuppressWarnings("LoopStatementThatDoesntLoop")
private static int javaVersion0() { private static int javaVersion0() {
// Android int javaVersion;
if (isAndroid()) {
return 6; // Not really a loop
for (;;) {
// Android
if (isAndroid()) {
javaVersion = 6;
break;
}
try {
Class.forName("java.time.Clock", false, Object.class.getClassLoader());
javaVersion = 8;
break;
} catch (Exception e) {
// Ignore
}
try {
Class.forName("java.util.concurrent.LinkedTransferQueue", false, BlockingQueue.class.getClassLoader());
javaVersion = 7;
break;
} catch (Exception e) {
// Ignore
}
javaVersion = 6;
break;
} }
try { if (logger.isDebugEnabled()) {
Class.forName("java.time.Clock", false, Object.class.getClassLoader()); logger.debug("Java version: {}", javaVersion);
return 8;
} catch (Exception e) {
// Ignore
} }
return javaVersion;
try {
Class.forName("java.util.concurrent.LinkedTransferQueue", false, BlockingQueue.class.getClassLoader());
return 7;
} catch (Exception e) {
// Ignore
}
return 6;
} }
private static boolean hasUnsafe0() { private static boolean hasUnsafe0() {
if (isAndroid()) { if (isAndroid()) {
logger.debug("sun.misc.Unsafe: unavailable (Android)");
return false; return false;
} }
boolean noUnsafe = SystemPropertyUtil.getBoolean("io.netty.noUnsafe", false); boolean noUnsafe = SystemPropertyUtil.getBoolean("io.netty.noUnsafe", false);
if (noUnsafe) { if (noUnsafe) {
logger.debug("sun.misc.Unsafe: unavailable (io.netty.noUnsafe)");
return false; return false;
} }
@ -363,11 +446,14 @@ public final class PlatformDependent {
} }
if (!tryUnsafe) { if (!tryUnsafe) {
logger.debug("sun.misc.Unsafe: unavailable (io.netty.tryUnsafe/org.jboss.netty.tryUnsafe)");
return false; return false;
} }
try { try {
return PlatformDependent0.hasUnsafe(); boolean hasUnsafe = PlatformDependent0.hasUnsafe();
logger.debug("sun.misc.Unsafe: {}", hasUnsafe ? "available" : "unavailable");
return hasUnsafe;
} catch (Throwable t) { } catch (Throwable t) {
return false; return false;
} }
@ -384,13 +470,19 @@ public final class PlatformDependent {
private static boolean hasJavassist0() { private static boolean hasJavassist0() {
boolean noJavassist = SystemPropertyUtil.getBoolean("io.netty.noJavassist", false); boolean noJavassist = SystemPropertyUtil.getBoolean("io.netty.noJavassist", false);
if (noJavassist) { if (noJavassist) {
logger.debug("Javassist: unavailable (io.netty.noJavassist)");
return false; return false;
} }
try { try {
JavassistTypeParameterMatcherGenerator.generate(Object.class, PlatformDependent.class.getClassLoader()); JavassistTypeParameterMatcherGenerator.generate(Object.class, PlatformDependent.class.getClassLoader());
logger.debug("Javassist: available");
return true; return true;
} catch (Throwable t) { } catch (Throwable t) {
logger.debug("Javassist: unavailable");
logger.warn(
"You don't have Javassist in your class path or you don't have enough permission " +
"to load dynamically generated classes. Please check the configuration for better performance.");
return false; return false;
} }
} }

View File

@ -15,6 +15,8 @@
*/ */
package io.netty.util.internal; package io.netty.util.internal;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import sun.misc.Cleaner; import sun.misc.Cleaner;
import sun.misc.Unsafe; import sun.misc.Unsafe;
@ -28,6 +30,7 @@ import java.nio.ByteBuffer;
*/ */
final class PlatformDependent0 { final class PlatformDependent0 {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent0.class);
private static final Unsafe UNSAFE; private static final Unsafe UNSAFE;
private static final long CLEANER_FIELD_OFFSET; private static final long CLEANER_FIELD_OFFSET;
private static final long ADDRESS_FIELD_OFFSET; private static final long ADDRESS_FIELD_OFFSET;
@ -50,6 +53,7 @@ final class PlatformDependent0 {
} catch (Throwable t) { } catch (Throwable t) {
cleanerField = null; cleanerField = null;
} }
logger.debug("java.nio.ByteBuffer.cleaner: {}", cleanerField != null? "available" : "unavailable");
Field addressField; Field addressField;
try { try {
@ -68,6 +72,7 @@ final class PlatformDependent0 {
} catch (Throwable t) { } catch (Throwable t) {
addressField = null; addressField = null;
} }
logger.debug("java.nio.Buffer.address: {}", addressField != null? "available" : "unavailable");
Unsafe unsafe; Unsafe unsafe;
if (addressField != null && cleanerField != null) { if (addressField != null && cleanerField != null) {
@ -75,12 +80,21 @@ final class PlatformDependent0 {
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true); unsafeField.setAccessible(true);
unsafe = (Unsafe) unsafeField.get(null); unsafe = (Unsafe) unsafeField.get(null);
logger.debug("sun.misc.Unsafe.theUnsafe: {}", unsafe != null? "available" : "unavailable");
// Ensure the unsafe supports all necessary methods to work around the mistake in the latest OpenJDK. // Ensure the unsafe supports all necessary methods to work around the mistake in the latest OpenJDK.
// https://github.com/netty/netty/issues/1061 // https://github.com/netty/netty/issues/1061
// http://www.mail-archive.com/jdk6-dev@openjdk.java.net/msg00698.html // http://www.mail-archive.com/jdk6-dev@openjdk.java.net/msg00698.html
unsafe.getClass().getDeclaredMethod( try {
"copyMemory", new Class[] { Object.class, long.class, Object.class, long.class, long.class }); unsafe.getClass().getDeclaredMethod(
"copyMemory",
new Class[] { Object.class, long.class, Object.class, long.class, long.class });
logger.debug("sun.misc.Unsafe.copyMemory(Object, long, Object, long, long): available");
} catch (NoSuchMethodError t) {
logger.debug("sun.misc.Unsafe.copyMemory(Object, long, Object, long, long): unavailable");
throw t;
}
} catch (Throwable cause) { } catch (Throwable cause) {
unsafe = null; unsafe = null;
} }
@ -111,7 +125,9 @@ final class PlatformDependent0 {
//noinspection DynamicRegexReplaceableByCompiledPattern //noinspection DynamicRegexReplaceableByCompiledPattern
unaligned = arch.matches("^(i[3-6]86|x86(_64)?|x64|amd64)$"); unaligned = arch.matches("^(i[3-6]86|x86(_64)?|x64|amd64)$");
} }
UNALIGNED = unaligned; UNALIGNED = unaligned;
logger.debug("java.nio.Bits.unaligned: {}", UNALIGNED);
} }
} }

View File

@ -73,7 +73,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
} }
} catch (SecurityException e) { } catch (SecurityException e) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Unable to get/set System Property '" + key + '\'', e); logger.debug("Unable to get/set System Property: {}", key, e);
} }
} }
@ -85,7 +85,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
SELECTOR_AUTO_REBUILD_THRESHOLD = selectorAutoRebuildThreshold; SELECTOR_AUTO_REBUILD_THRESHOLD = selectorAutoRebuildThreshold;
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Selector auto-rebuild threshold: {}", SELECTOR_AUTO_REBUILD_THRESHOLD); logger.debug("io.netty.selectorAutoRebuildThreshold: {}", SELECTOR_AUTO_REBUILD_THRESHOLD);
} }
} }