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);
|
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() {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user