1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.incubator.http.internal.hpack; 26 27 import jdk.incubator.http.internal.common.Utils; 28 import jdk.incubator.http.internal.hpack.HPACK.Logger.Level; 29 30 import java.security.AccessController; 31 import java.security.PrivilegedAction; 32 import java.util.Map; 33 import java.util.ResourceBundle; 34 import java.util.function.Supplier; 35 36 import static java.lang.String.format; 37 import static java.util.stream.Collectors.joining; 38 import static jdk.incubator.http.internal.hpack.HPACK.Logger.Level.EXTRA; 39 import static jdk.incubator.http.internal.hpack.HPACK.Logger.Level.NONE; 40 import static jdk.incubator.http.internal.hpack.HPACK.Logger.Level.NORMAL; 41 42 /** 43 * Internal utilities and stuff. 44 */ 45 public final class HPACK { 46 47 private static final RootLogger LOGGER; 48 private static final Map<String, Level> logLevels = 49 Map.of("NORMAL", NORMAL, "EXTRA", EXTRA); 50 51 static { 52 String PROPERTY = "jdk.internal.httpclient.hpack.log.level"; 53 54 String value = AccessController.doPrivileged( 55 (PrivilegedAction<String>) () -> System.getProperty(PROPERTY)); 56 57 if (value == null) { 58 LOGGER = new RootLogger(NONE); 59 } else { 60 String upperCasedValue = value.toUpperCase(); 61 Level l = logLevels.get(upperCasedValue); 62 if (l == null) { 63 LOGGER = new RootLogger(NONE); 64 LOGGER.log(System.Logger.Level.INFO, 65 () -> format("%s value '%s' not recognized (use %s); logging disabled", 66 PROPERTY, value, logLevels.keySet().stream().collect(joining(", ")))); 67 } else { 68 LOGGER = new RootLogger(l); 69 LOGGER.log(System.Logger.Level.DEBUG, 70 () -> format("logging level %s", l)); 71 } 72 } 73 } 74 75 public static Logger getLogger() { 76 return LOGGER; 77 } 78 79 private HPACK() { } 80 81 /** 82 * The purpose of this logger is to provide means of diagnosing issues _in 83 * the HPACK implementation_. It's not a general purpose logger. 84 */ 85 // implements System.Logger to make it possible to skip this class 86 // when looking for the Caller. 87 public static class Logger implements System.Logger { 88 89 /** 90 * Log detail level. 91 */ 92 public enum Level { 93 94 NONE(0, System.Logger.Level.OFF), 95 NORMAL(1, System.Logger.Level.DEBUG), 96 EXTRA(2, System.Logger.Level.TRACE); 97 98 private final int level; 99 final System.Logger.Level systemLevel; 100 101 Level(int i, System.Logger.Level system) { 102 level = i; 103 systemLevel = system; 104 } 105 106 public final boolean implies(Level other) { 107 return this.level >= other.level; 108 } 109 } 110 111 private final String name; 112 private final Level level; 113 private final String path; 114 private final System.Logger logger; 115 116 private Logger(String path, String name, Level level) { 117 this(path, name, level, null); 118 } 119 120 private Logger(String p, String name, Level level, System.Logger logger) { 121 this.path = p; 122 this.name = name; 123 this.level = level; 124 this.logger = Utils.getHpackLogger(path::toString, level.systemLevel); 125 } 126 127 public final String getName() { 128 return name; 129 } 130 131 @Override 132 public boolean isLoggable(System.Logger.Level level) { 133 return logger.isLoggable(level); 134 } 135 136 @Override 137 public void log(System.Logger.Level level, ResourceBundle bundle, String msg, Throwable thrown) { 138 logger.log(level, bundle, msg,thrown); 139 } 140 141 @Override 142 public void log(System.Logger.Level level, ResourceBundle bundle, String format, Object... params) { 143 logger.log(level, bundle, format, params); 144 } 145 146 /* 147 * Usual performance trick for logging, reducing performance overhead in 148 * the case where logging with the specified level is a NOP. 149 */ 150 151 public boolean isLoggable(Level level) { 152 return this.level.implies(level); 153 } 154 155 public void log(Level level, Supplier<String> s) { 156 if (this.level.implies(level)) { 157 logger.log(level.systemLevel, s); 158 } 159 } 160 161 public Logger subLogger(String name) { 162 return new Logger(path + "/" + name, name, level); 163 } 164 165 } 166 167 private static final class RootLogger extends Logger { 168 169 protected RootLogger(Level level) { 170 super("hpack", "hpack", level); 171 } 172 173 } 174 }