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);
static {
if (ENABLED) {
logger.debug("Resource leak detection enabled.");
}
logger.debug("io.netty.resourceLeakDetection: {}", ENABLED);
}
private static final int DEFAULT_SAMPLING_INTERVAL = 113;
private static final ResourceLeak NOOP = new ResourceLeak() {

View File

@ -15,10 +15,14 @@
*/
package io.netty.util.internal;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.chmv8.ConcurrentHashMapV8;
import io.netty.util.internal.logging.InternalLogger;
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.net.InetSocketAddress;
import java.net.ServerSocket;
@ -41,6 +45,8 @@ import java.util.regex.Pattern;
*/
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_WINDOWS = isWindows0();
private static final boolean IS_ROOT = isRoot0();
@ -59,12 +65,15 @@ public final class PlatformDependent {
private static final boolean HAS_JAVASSIST = hasJavassist0();
static {
InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent.class);
if (logger.isDebugEnabled()) {
logger.debug("io.netty.preferDirect: {}", DIRECT_BUFFER_PREFERRED);
}
if (!hasUnsafe()) {
logger.warn(
"Your platform does not provide complete low-level API for accessing direct buffers reliably. " +
"Unless explicitly requested, heap buffer will always be preferred " +
"to avoid potential risk of getting OutOfMemoryError.");
"Unless explicitly requested, heap buffer will always be preferred to avoid potential system " +
"unstability.");
}
}
@ -277,80 +286,154 @@ public final class PlatformDependent {
} catch (Exception e) {
android = false;
}
logger.debug("Platform: Android");
return android;
}
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() {
Pattern PERMISSION_DENIED = Pattern.compile(".*permission.*denied.*");
boolean root = false;
if (!isWindows()) {
for (int i = 1023; i > 0; i --) {
ServerSocket ss = null;
try {
ss = new ServerSocket();
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(i));
root = true;
break;
} 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.
if (isWindows()) {
return false;
}
String[] ID_COMMANDS = { "/usr/bin/id", "/bin/id", "id" };
Pattern UID_PATTERN = Pattern.compile("^(?:0|[1-9][0-9]*)$");
for (String idCmd: ID_COMMANDS) {
Process p = null;
BufferedReader in = null;
String uid = null;
try {
p = Runtime.getRuntime().exec(new String[] { idCmd, "-u" });
in = new BufferedReader(new InputStreamReader(p.getInputStream(), CharsetUtil.US_ASCII));
uid = in.readLine();
in.close();
for (;;) {
try {
int exitCode = p.waitFor();
if (exitCode != 0) {
uid = null;
}
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() {
// Android
if (isAndroid()) {
return 6;
int javaVersion;
// 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 {
Class.forName("java.time.Clock", false, Object.class.getClassLoader());
return 8;
} catch (Exception e) {
// Ignore
if (logger.isDebugEnabled()) {
logger.debug("Java version: {}", javaVersion);
}
try {
Class.forName("java.util.concurrent.LinkedTransferQueue", false, BlockingQueue.class.getClassLoader());
return 7;
} catch (Exception e) {
// Ignore
}
return 6;
return javaVersion;
}
private static boolean hasUnsafe0() {
if (isAndroid()) {
logger.debug("sun.misc.Unsafe: unavailable (Android)");
return false;
}
boolean noUnsafe = SystemPropertyUtil.getBoolean("io.netty.noUnsafe", false);
if (noUnsafe) {
logger.debug("sun.misc.Unsafe: unavailable (io.netty.noUnsafe)");
return false;
}
@ -363,11 +446,14 @@ public final class PlatformDependent {
}
if (!tryUnsafe) {
logger.debug("sun.misc.Unsafe: unavailable (io.netty.tryUnsafe/org.jboss.netty.tryUnsafe)");
return false;
}
try {
return PlatformDependent0.hasUnsafe();
boolean hasUnsafe = PlatformDependent0.hasUnsafe();
logger.debug("sun.misc.Unsafe: {}", hasUnsafe ? "available" : "unavailable");
return hasUnsafe;
} catch (Throwable t) {
return false;
}
@ -384,13 +470,19 @@ public final class PlatformDependent {
private static boolean hasJavassist0() {
boolean noJavassist = SystemPropertyUtil.getBoolean("io.netty.noJavassist", false);
if (noJavassist) {
logger.debug("Javassist: unavailable (io.netty.noJavassist)");
return false;
}
try {
JavassistTypeParameterMatcherGenerator.generate(Object.class, PlatformDependent.class.getClassLoader());
logger.debug("Javassist: available");
return true;
} 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;
}
}

View File

@ -15,6 +15,8 @@
*/
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.Unsafe;
@ -28,6 +30,7 @@ import java.nio.ByteBuffer;
*/
final class PlatformDependent0 {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent0.class);
private static final Unsafe UNSAFE;
private static final long CLEANER_FIELD_OFFSET;
private static final long ADDRESS_FIELD_OFFSET;
@ -50,6 +53,7 @@ final class PlatformDependent0 {
} catch (Throwable t) {
cleanerField = null;
}
logger.debug("java.nio.ByteBuffer.cleaner: {}", cleanerField != null? "available" : "unavailable");
Field addressField;
try {
@ -68,6 +72,7 @@ final class PlatformDependent0 {
} catch (Throwable t) {
addressField = null;
}
logger.debug("java.nio.Buffer.address: {}", addressField != null? "available" : "unavailable");
Unsafe unsafe;
if (addressField != null && cleanerField != null) {
@ -75,12 +80,21 @@ final class PlatformDependent0 {
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
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.
// https://github.com/netty/netty/issues/1061
// http://www.mail-archive.com/jdk6-dev@openjdk.java.net/msg00698.html
unsafe.getClass().getDeclaredMethod(
"copyMemory", new Class[] { Object.class, long.class, Object.class, long.class, long.class });
try {
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) {
unsafe = null;
}
@ -111,7 +125,9 @@ final class PlatformDependent0 {
//noinspection DynamicRegexReplaceableByCompiledPattern
unaligned = arch.matches("^(i[3-6]86|x86(_64)?|x64|amd64)$");
}
UNALIGNED = unaligned;
logger.debug("java.nio.Bits.unaligned: {}", UNALIGNED);
}
}

View File

@ -73,7 +73,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
}
} catch (SecurityException e) {
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;
if (logger.isDebugEnabled()) {
logger.debug("Selector auto-rebuild threshold: {}", SELECTOR_AUTO_REBUILD_THRESHOLD);
logger.debug("io.netty.selectorAutoRebuildThreshold: {}", SELECTOR_AUTO_REBUILD_THRESHOLD);
}
}