org.tinylog.runtime.RuntimeProvider Maven / Gradle / Ivy
/*
* Copyright 2016 Martin Winandy
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.tinylog.runtime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import org.tinylog.Level;
import org.tinylog.provider.InternalLogger;
/**
* Provider for getting runtime specific data from Virtual Machine.
*/
public final class RuntimeProvider {
private static final int MINIMUM_VERSION_MODERN_JAVA = 9;
private static final RuntimeDialect dialect = resolveDialect();
/** */
private RuntimeProvider() {
}
/**
* Checks if running on Android.
*
* @return {@code true} if running on Android, otherwise {@code false}
*/
public static boolean isAndroid() {
return dialect.isAndroid();
}
/**
* Gets valid and available class loaders.
*
* @return Valid class loader instances
*/
public static List getClassLoaders() {
ClassLoader threadClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader classClassLoader = RuntimeProvider.class.getClassLoader();
if (threadClassLoader == null || threadClassLoader == classClassLoader) {
return Collections.singletonList(classClassLoader);
} else {
List classLoaders = new ArrayList();
classLoaders.add(threadClassLoader);
classLoaders.add(classClassLoader);
return classLoaders;
}
}
/**
* Gets the name of the default writer.
*
* @return Name of default writer
*/
public static String getDefaultWriter() {
return dialect.getDefaultWriter();
}
/**
* Gets the ID of the current process (pid).
*
* @return ID of the current process
*/
public static long getProcessId() {
return dialect.getProcessId();
}
/**
* Gets the start time of the Java virtual machine or tinylog.
*
* @return Start time
*/
public static Timestamp getStartTime() {
return dialect.getStartTime();
}
/**
* Gets the class name of a caller from stack trace. Any anonymous part will be stripped from class name.
*
* @param depth
* Position of caller in stack trace
* @return Fully-qualified class name of caller
*/
public static String getCallerClassName(final int depth) {
return stripAnonymousPart(dialect.getCallerClassName(depth + 1));
}
/**
* Gets the class name of a caller from stack trace. Any anonymous part will be stripped from class name.
*
* @param loggerClassName
* Logger class name that should appear before the real caller
* @return Fully-qualified class name of caller
*/
public static String getCallerClassName(final String loggerClassName) {
String callerClassName = dialect.getCallerClassName(loggerClassName);
if (callerClassName == null) {
InternalLogger.log(Level.ERROR, "Logger class \"" + loggerClassName + "\" is missing in stack trace");
return "";
} else {
return stripAnonymousPart(callerClassName);
}
}
/**
* Gets the complete stack trace element of a caller from stack trace. Any anonymous part will be stripped from
* class name.
*
* @param depth
* Position of caller in stack trace
* @return Stack trace element of a caller
*/
public static StackTraceElement getCallerStackTraceElement(final int depth) {
return normalizeClassName(dialect.getCallerStackTraceElement(depth + 1));
}
/**
* Gets the complete stack trace element of a caller from stack trace. Any anonymous part will be stripped from
* class name.
*
* @param loggerClassName
* Logger class name that should appear before the real caller
* @return Stack trace element of a caller
*/
public static StackTraceElement getCallerStackTraceElement(final String loggerClassName) {
StackTraceElement element = dialect.getCallerStackTraceElement(loggerClassName);
if (element == null) {
InternalLogger.log(Level.ERROR, "Logger class \"" + loggerClassName + "\" is missing in stack trace");
return new StackTraceElement("", "", "", -1);
} else {
return normalizeClassName(element);
}
}
/**
* Creates a timestamp with the current date and time.
*
* @return Timestamp with current date and time
*/
public static Timestamp createTimestamp() {
return dialect.createTimestamp();
}
/**
* Creates a formatter for {@link Timestamp Timestamps}.
*
* @param pattern
* Format pattern that is compatible with {@link DateTimeFormatter}
* @param locale
* Locale for formatting
* @return Formatter for formatting timestamps
*/
public static TimestampFormatter createTimestampFormatter(final String pattern, final Locale locale) {
return dialect.createTimestampFormatter(pattern, locale);
}
/**
* Resolves the runtime dialect for the current VM.
*
* @return Resolved runtime dialect
*/
private static RuntimeDialect resolveDialect() {
if (getJavaVersion() >= MINIMUM_VERSION_MODERN_JAVA) {
return new ModernJavaRuntime();
} else if ("Android Runtime".equalsIgnoreCase(System.getProperty("java.runtime.name"))) {
return new AndroidRuntime();
} else {
return new LegacyJavaRuntime();
}
}
/**
* Gets the major version number of Java.
*
* @return Major version number of Java or -1 if unknown
*/
private static int getJavaVersion() {
String version = System.getProperty("java.version");
if (version == null) {
return -1;
} else {
int index = version.indexOf('.');
if (index > 0) {
version = version.substring(0, index);
}
try {
return Integer.parseInt(version);
} catch (NumberFormatException ex) {
return -1;
}
}
}
/**
* Strips the the anonymous part from a class name.
*
* @param className
* Fully-qualified class name
* @return Human-readable class name without any anonymous part
*/
private static String stripAnonymousPart(final String className) {
for (int index = className.indexOf("$", 0); index != -1; index = className.indexOf('$', index + 2)) {
/* Trailing dollar sign */
if (index >= className.length() - 1) {
return className.substring(0, index);
}
char firstLetter = className.charAt(index + 1);
/* First letter after dollar sign is not a capital letter of a named inner class */
if (firstLetter < 'A' || firstLetter > 'Z') {
return className.substring(0, index);
}
}
return className;
}
/**
* Strips the the anonymous part from a class name of stack trace element.
*
* @param element
* Original stack trace element
* @return New or same stack trace element with an human-readable class name without any anonymous part
*/
private static StackTraceElement normalizeClassName(final StackTraceElement element) {
String className = element.getClassName();
int dollarIndex = className.indexOf("$");
if (dollarIndex == -1) {
return element;
} else {
className = stripAnonymousPart(className);
return new StackTraceElement(className, element.getMethodName(), element.getFileName(), element.getLineNumber());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy