Use java.util.logging

This commit is contained in:
yushijinhun 2018-07-08 14:48:53 +08:00
parent 6fe53b6993
commit e4cc4dd8aa
No known key found for this signature in database
GPG key ID: 5BC167F73EA558E4
8 changed files with 126 additions and 82 deletions

View file

@ -6,9 +6,6 @@ import static java.util.Optional.of;
import static moe.yushi.authlibinjector.util.IOUtils.asString;
import static moe.yushi.authlibinjector.util.IOUtils.getURL;
import static moe.yushi.authlibinjector.util.IOUtils.removeNewLines;
import static moe.yushi.authlibinjector.util.LoggingUtils.debug;
import static moe.yushi.authlibinjector.util.LoggingUtils.info;
import static moe.yushi.authlibinjector.util.LoggingUtils.isDebugOn;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.instrument.ClassFileTransformer;
@ -21,6 +18,7 @@ import moe.yushi.authlibinjector.transform.ClassTransformer;
import moe.yushi.authlibinjector.transform.SkinWhitelistTransformUnit;
import moe.yushi.authlibinjector.transform.YggdrasilApiTransformUnit;
import moe.yushi.authlibinjector.transform.YggdrasilKeyTransformUnit;
import moe.yushi.authlibinjector.util.Logging;
public final class AuthlibInjector {
@ -65,17 +63,17 @@ public final class AuthlibInjector {
public static void bootstrap(Consumer<ClassFileTransformer> transformerRegistry) {
if (!booted.compareAndSet(false, true)) {
info("already booted, skipping");
Logging.ROOT.info("already booted, skipping");
return;
}
info("version: " + getVersion());
Logging.ROOT.info("version: " + getVersion());
Optional<YggdrasilConfiguration> optionalConfig = configure();
if (optionalConfig.isPresent()) {
transformerRegistry.accept(createTransformer(optionalConfig.get()));
} else {
info("no config available");
Logging.ROOT.warning("no config available");
}
}
@ -84,7 +82,7 @@ public final class AuthlibInjector {
if (prefetched == null) {
prefetched = System.getProperty(PROP_PREFETCHED_DATA_OLD);
if (prefetched != null) {
info("warning: org.to2mbn.authlibinjector.config.prefetched option is deprecated and will be removed in a future release.");
Logging.ROOT.warning("org.to2mbn.authlibinjector.config.prefetched option is deprecated and will be removed in a future release.");
}
}
return Optional.ofNullable(prefetched);
@ -93,51 +91,50 @@ public final class AuthlibInjector {
private static Optional<YggdrasilConfiguration> configure() {
String apiRoot = System.getProperty(PROP_API_ROOT);
if (apiRoot == null) return empty();
info("api root: {0}", apiRoot);
Logging.ROOT.info("api root: " + apiRoot);
String metadataResponse;
Optional<String> prefetched = getPrefetchedResponse();
if (!prefetched.isPresent()) {
info("fetching metadata");
Logging.ROOT.info("fetching metadata");
try {
metadataResponse = asString(getURL(apiRoot));
} catch (IOException e) {
info("unable to fetch metadata: {0}", e);
Logging.ROOT.severe("unable to fetch metadata: " + e);
throw new UncheckedIOException(e);
}
} else {
info("prefetched metadata detected");
Logging.ROOT.info("prefetched metadata detected");
try {
metadataResponse = new String(Base64.getDecoder().decode(removeNewLines(prefetched.get())), UTF_8);
} catch (IllegalArgumentException e) {
info("unable to decode metadata: {0}\n"
Logging.ROOT.severe("unable to decode metadata: " + e + "\n"
+ "metadata to decode:\n"
+ "{1}", e, prefetched.get());
+ prefetched.get());
throw e;
}
}
debug("metadata: {0}", metadataResponse);
Logging.ROOT.fine("metadata: " + metadataResponse);
YggdrasilConfiguration configuration;
try {
configuration = YggdrasilConfiguration.parse(apiRoot, metadataResponse);
} catch (UncheckedIOException e) {
info("unable to parse metadata: {0}\n"
Logging.ROOT.severe("unable to parse metadata: " + e + "\n"
+ "metadata to parse:\n"
+ "{1}",
e, metadataResponse);
+ metadataResponse);
throw e;
}
debug("parsed metadata: {0}", configuration);
Logging.ROOT.fine("parsed metadata: " + configuration);
return of(configuration);
}
private static ClassTransformer createTransformer(YggdrasilConfiguration config) {
ClassTransformer transformer = new ClassTransformer();
transformer.debugSaveClass = isDebugOn();
transformer.debugSaveClass = false; // TODO: add an option?
for (String ignore : nonTransformablePackages)
transformer.ignores.add(ignore);

View file

@ -1,10 +1,10 @@
package moe.yushi.authlibinjector.httpd;
import static moe.yushi.authlibinjector.util.LoggingUtils.info;
import java.io.IOException;
import moe.yushi.authlibinjector.YggdrasilConfiguration;
import moe.yushi.authlibinjector.transform.DeprecatedApiTransformUnit;
import moe.yushi.authlibinjector.transform.TransformUnit;
import moe.yushi.authlibinjector.util.Logging;
public class DeprecatedApiHandle {
@ -40,7 +40,7 @@ public class DeprecatedApiHandle {
} catch (IOException e) {
throw new IllegalStateException("httpd failed to start");
}
info("httpd is running on port {0,number,#}", getLocalApiPort());
Logging.HTTPD.info("httpd is running on port " + getLocalApiPort());
started = true;
}
}

View file

@ -13,13 +13,12 @@ import static moe.yushi.authlibinjector.util.JsonUtils.asJsonArray;
import static moe.yushi.authlibinjector.util.JsonUtils.asJsonObject;
import static moe.yushi.authlibinjector.util.JsonUtils.asJsonString;
import static moe.yushi.authlibinjector.util.JsonUtils.parseJson;
import static moe.yushi.authlibinjector.util.LoggingUtils.debug;
import static moe.yushi.authlibinjector.util.LoggingUtils.info;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Base64;
import java.util.Optional;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import fi.iki.elonen.NanoHTTPD;
@ -28,6 +27,7 @@ import moe.yushi.authlibinjector.YggdrasilConfiguration;
import moe.yushi.authlibinjector.internal.org.json.simple.JSONArray;
import moe.yushi.authlibinjector.internal.org.json.simple.JSONObject;
import moe.yushi.authlibinjector.util.JsonUtils;
import moe.yushi.authlibinjector.util.Logging;
public class DeprecatedApiHttpd extends NanoHTTPD {
@ -61,25 +61,25 @@ public class DeprecatedApiHttpd extends NanoHTTPD {
.map(encoded -> asString(Base64.getDecoder().decode(encoded)))
.flatMap(texturesPayload -> obtainTextureUrl(texturesPayload, "SKIN"));
} catch (UncheckedIOException e) {
info("[httpd] unable to fetch skin for {0}: {1}", username, e);
Logging.HTTPD.log(Level.WARNING, "unable to fetch skin for " + username, e);
return of(newFixedLengthResponse(Status.INTERNAL_ERROR, null, null));
}
if (skinUrl.isPresent()) {
String url = skinUrl.get();
debug("[httpd] retrieving skin for {0} from {1}", username, url);
Logging.HTTPD.fine("retrieving skin for " + username + " from " + url);
byte[] data;
try {
data = getURL(url);
} catch (IOException e) {
info("[httpd] unable to retrieve skin from {0}: {1}", url, e);
return of(newFixedLengthResponse(Status.NOT_FOUND, null, null));
Logging.HTTPD.log(Level.WARNING, "unable to retrieve skin from " + url, e);
return of(newFixedLengthResponse(Status.INTERNAL_ERROR, null, null));
}
info("[httpd] retrieved skin for {0} from {1}, {2} bytes", username, url, data.length);
Logging.HTTPD.info("retrieved skin for " + username + " from " + url + ", " + data.length + " bytes");
return of(newFixedLengthResponse(Status.OK, "image/png", new ByteArrayInputStream(data), data.length));
} else {
info("[httpd] no skin found for {0}", username);
Logging.HTTPD.info("no skin found for " + username);
return of(newFixedLengthResponse(Status.NOT_FOUND, null, null));
}
}
@ -94,7 +94,7 @@ public class DeprecatedApiHttpd extends NanoHTTPD {
} catch (IOException e) {
throw new UncheckedIOException(e);
}
debug("[httpd] query uuid of username {0}, response: {1}", username, responseText);
Logging.HTTPD.fine("query uuid of username " + username + ", response: " + responseText);
JSONArray response = asJsonArray(parseJson(responseText));
if (response.size() == 0) {
@ -116,10 +116,10 @@ public class DeprecatedApiHttpd extends NanoHTTPD {
throw new UncheckedIOException(e);
}
if (responseText.isEmpty()) {
debug("[httpd] query profile of {0}, not found", uuid);
Logging.HTTPD.fine("query profile of " + uuid + ", not found");
return empty();
}
debug("[httpd] query profile of {0}, response: {1}", uuid, responseText);
Logging.HTTPD.fine("query profile of " + uuid + ", response: " + responseText);
JSONObject response = asJsonObject(parseJson(responseText));
return asJsonArray(response.get("properties")).stream()

View file

@ -3,32 +3,33 @@ package moe.yushi.authlibinjector.javaagent;
import static moe.yushi.authlibinjector.AuthlibInjector.PROP_API_ROOT;
import static moe.yushi.authlibinjector.AuthlibInjector.bootstrap;
import static moe.yushi.authlibinjector.AuthlibInjector.nonTransformablePackages;
import static moe.yushi.authlibinjector.util.LoggingUtils.debug;
import static moe.yushi.authlibinjector.util.LoggingUtils.info;
import java.lang.instrument.Instrumentation;
import java.util.Arrays;
import java.util.logging.Level;
import moe.yushi.authlibinjector.util.Logging;
public class AuthlibInjectorPremain {
static {
Logging.init();
}
public static void premain(String arg, Instrumentation instrumentation) {
try {
info("launched from premain");
Logging.ROOT.info("launched from premain");
initInjector(arg, instrumentation, false);
} catch (Throwable e) {
// prevent the exception being thrown to VM
e.printStackTrace();
info("an exception has been caught, exiting");
Logging.ROOT.log(Level.SEVERE, "an exception has been caught, exiting", e);
System.exit(1);
}
}
public static void agentmain(String arg, Instrumentation instrumentation) {
try {
info("launched from agentmain");
Logging.ROOT.info("launched from agentmain");
initInjector(arg, instrumentation, true);
} catch (Throwable e) {
// prevent the exception being thrown to VM
e.printStackTrace();
Logging.ROOT.log(Level.SEVERE, "an exception has been caught", e);
}
}
@ -41,10 +42,10 @@ public class AuthlibInjectorPremain {
if (needsRetransform) {
if (retransformSupported) {
info("start retransforming");
Logging.TRANSFORM.info("start retransforming");
doRetransform(instrumentation);
} else {
info("retransforming is not supported");
Logging.TRANSFORM.warning("retransforming is not supported");
}
}
}
@ -63,10 +64,9 @@ public class AuthlibInjectorPremain {
instrumentation.retransformClasses(classToRetransform);
}
long t1 = System.currentTimeMillis();
info("retransforming finished in {0}ms", t1 - t0);
Logging.TRANSFORM.info("retransforming finished in " + (t1 - t0) + "ms");
} catch (Throwable e) {
info("unable to retransform");
e.printStackTrace();
Logging.TRANSFORM.log(Level.SEVERE, "unable to retransform", e);
}
}
@ -88,7 +88,7 @@ public class AuthlibInjectorPremain {
}
}
}
debug("loaded {0} classes, {1} to retransform", loadedClasses.length, idx);
Logging.TRANSFORM.fine("loaded " + loadedClasses.length + " classes, " + idx + " to retransform");
return Arrays.copyOf(dest, idx);
}

View file

@ -1,7 +1,5 @@
package moe.yushi.authlibinjector.transform;
import static moe.yushi.authlibinjector.util.LoggingUtils.debug;
import static moe.yushi.authlibinjector.util.LoggingUtils.info;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
@ -14,9 +12,11 @@ import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import moe.yushi.authlibinjector.util.Logging;
public class ClassTransformer implements ClassFileTransformer {
@ -52,7 +52,7 @@ public class ClassTransformer implements ClassFileTransformer {
ClassReader reader = new ClassReader(classBuffer);
reader.accept(optionalVisitor.get(), 0);
if (currentModified) {
info("transform {0} using {1}", className, unit);
Logging.TRANSFORM.info("transform " + className + " using " + unit);
modified = true;
classBuffer = writer.toByteArray();
}
@ -88,12 +88,11 @@ public class ClassTransformer implements ClassFileTransformer {
}
return classBuffer;
} else {
debug("no transform performed on {0}", className);
Logging.TRANSFORM.fine("no transform performed on " + className);
return null;
}
} catch (Throwable e) {
info("unable to transform {0}: {1}", internalClassName, e);
e.printStackTrace();
Logging.TRANSFORM.log(Level.WARNING, "unable to transform: " + internalClassName, e);
}
}
return null;
@ -103,8 +102,7 @@ public class ClassTransformer implements ClassFileTransformer {
try {
Files.write(Paths.get(className + "_dump.class"), classBuffer, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
} catch (IOException e) {
info("unable to dump class {0}: {1}", className, e);
e.printStackTrace();
Logging.TRANSFORM.log(Level.WARNING, "unable to dump class " + className, e);
}
}

View file

@ -1,11 +1,11 @@
package moe.yushi.authlibinjector.transform;
import static moe.yushi.authlibinjector.util.LoggingUtils.info;
import static org.objectweb.asm.Opcodes.ASM6;
import java.util.Optional;
import java.util.function.Function;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import moe.yushi.authlibinjector.util.Logging;
public class LdcTransformUnit implements TransformUnit {
@ -29,7 +29,7 @@ public class LdcTransformUnit implements TransformUnit {
Optional<String> transformed = ldcMapper.apply((String) cst);
if (transformed.isPresent() && !transformed.get().equals(cst)) {
modifiedCallback.run();
info("transform [{0}] to [{1}]", cst, transformed.get());
Logging.TRANSFORM.info("transform [" + cst + "] to [" + transformed.get() + "]");
super.visitLdcInsn(transformed.get());
} else {
super.visitLdcInsn(cst);

View file

@ -0,0 +1,74 @@
package moe.yushi.authlibinjector.util;
import static moe.yushi.authlibinjector.AuthlibInjector.PROP_DEBUG;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.StreamHandler;
public final class Logging {
private Logging() {}
public static final Logger ROOT = Logger.getLogger("moe.yushi.authlibinjector");
public static final Logger TRANSFORM = Logger.getLogger("moe.yushi.authlibinjector.transform");
public static final Logger HTTPD = Logger.getLogger("moe.yushi.authlibinjector.httpd");
public static void init() {
initRootLogger();
initLoggingLevels();
}
private static void initRootLogger() {
ROOT.setLevel(Level.INFO);
ROOT.setUseParentHandlers(false);
StreamHandler handler = new StreamHandler(System.err, new Formatter() {
private String convertLoggerName(String loggerName) {
final String prefix = "moe.yushi.authlibinjector";
if (loggerName.startsWith(prefix)) {
return "authlib-injector" + loggerName.substring(prefix.length());
} else {
return loggerName;
}
}
@Override
public String format(LogRecord record) {
String exception = "";
if (record.getThrown() != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println();
record.getThrown().printStackTrace(pw);
pw.close();
exception = sw.toString();
}
return MessageFormat.format("[{0}] [{1}] {2}{3}\n",
convertLoggerName(record.getLoggerName()),
record.getLevel().getName(),
record.getMessage(),
exception);
}
}) {
@Override
public synchronized void publish(LogRecord record) {
super.publish(record);
flush();
}
};
handler.setLevel(Level.ALL);
handler.setFilter(null);
ROOT.addHandler(handler);
}
private static void initLoggingLevels() {
if ("true".equals(System.getProperty(PROP_DEBUG))) {
ROOT.setLevel(Level.ALL);
}
}
}

View file

@ -1,25 +0,0 @@
package moe.yushi.authlibinjector.util;
import static moe.yushi.authlibinjector.AuthlibInjector.PROP_DEBUG;
import java.text.MessageFormat;
public final class LoggingUtils {
private static boolean debug = "true".equals(System.getProperty(PROP_DEBUG));
public static void info(String message, Object... args) {
System.err.println("[authlib-injector] " + MessageFormat.format(message, args));
}
public static void debug(String message, Object... args) {
if (debug) {
info(message, args);
}
}
public static boolean isDebugOn() {
return debug;
}
private LoggingUtils() {}
}