Log various properties at startup time for easier diagnosis
This commit is contained in:
parent
bcb0b83b44
commit
0f3dc0409a
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user