8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.debug; 24 25 import java.util.Arrays; 26 import java.util.regex.Pattern; 27 28 import org.graalvm.compiler.debug.GraalDebugConfig.Options; 29 import org.graalvm.compiler.debug.internal.DebugScope; 30 31 /** 32 * Implements the filter specified by the {@link Options#Dump}, {@link Options#Log}, 33 * {@link Options#Count},{@link Options#MethodMeter} and {@link Options#Time} options. 34 * <p> 35 * These options enable the associated debug facility if their filter matches the 36 * {@linkplain DebugScope#getQualifiedName() name} of the {@linkplain Debug#currentScope() current 37 * scope}. For the {@link Options#Dump} and {@link Options#Log} options, the log or dump level is 38 * set. The {@link Options#Count},{@link Options#MethodMeter} and {@link Options#Time} options don't 39 * have a level, for them {@code level = 0} means disabled and a {@code level > 0} means enabled. 40 * <p> 41 * A filter is a list of comma-separated terms of the form {@code <pattern>[:<level>]}. {@code 42 * <pattern>} is interpreted as a glob pattern if it contains a "*" or "?" character. Otherwise, it 43 * is interpreted as a substring. If {@code <pattern>} is empty, it matches every scope. If {@code : 44 * <level>} is omitted, it defaults to {@link Debug#BASIC_LEVEL}. The term {@code ~<pattern>} is a 45 * shorthand for {@code <pattern>:0} to disable a debug facility for a pattern. 46 * <p> 47 * The resulting log level of a scope is determined by the <em>last</em> matching term. If no term 48 * matches, the log level is 0 (disabled). A filter with no terms matches every scope with a log 49 * level of {@link Debug#BASIC_LEVEL}. 50 * 51 * <h2>Examples of filters</h2> 52 * 53 * <ul> 54 * <li>(empty string)<br> 55 * Matches any scope with log level {@link Debug#BASIC_LEVEL}. 56 * 57 * <li>{@code :1}<br> 58 * Matches any scope with log level 1. 59 * 60 * <li>{@code *}<br> 61 * Matches any scope with log level {@link Debug#BASIC_LEVEL}. 62 * 63 * <li>{@code CodeGen,CodeInstall}<br> 64 * Matches scopes containing "CodeGen" or "CodeInstall", both with log level 65 * {@link Debug#BASIC_LEVEL}. 66 * 67 * <li>{@code CodeGen:2,CodeInstall:1}<br> 68 * Matches scopes containing "CodeGen" with log level 2, or "CodeInstall" with log level 1. 69 * 70 * <li>{@code :1,Dead:2}<br> 71 * Matches scopes containing "Dead" with log level 2, and all other scopes with log level 1. 72 * 73 * <li>{@code :1,Dead:0}<br> 74 * Matches all scopes with log level 1, except those containing "Dead". 75 * 76 * <li>{@code Code*}<br> 77 * Matches scopes starting with "Code" with log level {@link Debug#BASIC_LEVEL}. 78 * 79 * <li>{@code Code,~Dead}<br> 80 * Matches scopes containing "Code" but not "Dead", with log level {@link Debug#BASIC_LEVEL}. 81 * </ul> 82 */ 83 final class DebugFilter { 84 85 public static DebugFilter parse(String spec) { 86 if (spec == null) { 87 return null; 88 } 89 return new DebugFilter(spec.split(",")); 90 } 91 92 private final Term[] terms; 93 94 private DebugFilter(String[] terms) { 95 if (terms.length == 0) { 96 this.terms = null; 97 } else { 98 this.terms = new Term[terms.length]; 99 for (int i = 0; i < terms.length; i++) { 100 String t = terms[i]; 101 int idx = t.indexOf(':'); 102 103 String pattern; 104 int level; 105 if (idx < 0) { 106 if (t.startsWith("~")) { 107 pattern = t.substring(1); 108 level = 0; 109 } else { 110 pattern = t; 111 level = Debug.BASIC_LEVEL; 112 } 113 } else { 114 pattern = t.substring(0, idx); 115 if (idx + 1 < t.length()) { 116 String levelString = t.substring(idx + 1); 117 try { 118 level = Integer.parseInt(levelString); 119 } catch (NumberFormatException e) { 120 switch (levelString) { 121 case "basic": 122 level = Debug.BASIC_LEVEL; 123 break; 124 case "info": 125 level = Debug.INFO_LEVEL; 126 break; 127 case "verbose": 128 level = Debug.VERBOSE_LEVEL; 129 break; 130 default: 131 throw new IllegalArgumentException("Unknown dump level: \"" + levelString + "\" expected basic, info, verbose or an integer"); 132 } 133 } 134 135 } else { 136 level = Debug.BASIC_LEVEL; 137 } 138 } 139 140 this.terms[i] = new Term(pattern, level); 141 } 142 } 143 } 144 145 /** 146 * Check whether a given input is matched by this filter, and determine the log level. 147 */ 148 public int matchLevel(String input) { 149 if (terms == null) { 150 return Debug.BASIC_LEVEL; 151 } else { 152 int level = 0; 153 for (Term t : terms) { 154 if (t.matches(input)) { 155 level = t.level; 156 } 157 } 158 return level; 159 } 160 } 161 162 @Override 163 public String toString() { 164 StringBuilder buf = new StringBuilder("DebugFilter"); 165 if (terms != null) { 166 buf.append(Arrays.toString(terms)); 167 } else { 168 buf.append("[]"); 169 } 170 return buf.toString(); | 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.debug; 24 25 import java.util.Arrays; 26 import java.util.regex.Pattern; 27 28 import org.graalvm.compiler.debug.DebugContext.Scope; 29 30 /** 31 * Implements the filter specified by the {@link DebugOptions#Dump}, {@link DebugOptions#Log}, 32 * {@link DebugOptions#Count} and {@link DebugOptions#Time} options. 33 * <p> 34 * These options enable the associated debug facility if their filter matches the 35 * {@linkplain Scope#getQualifiedName() name} of the current scope. For the 36 * {@link DebugOptions#Dump} and {@link DebugOptions#Log} options, the log or dump level is set. The 37 * {@link DebugOptions#Count} and {@link DebugOptions#Time} options don't have a level, for them 38 * {@code level = 0} means disabled and a {@code level > 0} means enabled. 39 * <p> 40 * A filter is a list of comma-separated terms of the form {@code <pattern>[:<level>]}. {@code 41 * <pattern>} is interpreted as a glob pattern if it contains a "*" or "?" character. Otherwise, it 42 * is interpreted as a substring. If {@code <pattern>} is empty, it matches every scope. If {@code : 43 * <level>} is omitted, it defaults to {@link DebugContext#BASIC_LEVEL}. The term {@code ~<pattern>} 44 * is a shorthand for {@code <pattern>:0} to disable a debug facility for a pattern. 45 * <p> 46 * The resulting log level of a scope is determined by the <em>last</em> matching term. If no term 47 * matches, the log level is 0 (disabled). A filter with no terms matches every scope with a log 48 * level of {@link DebugContext#BASIC_LEVEL}. 49 * 50 * <h2>Examples of filters</h2> 51 * 52 * <ul> 53 * <li>(empty string)<br> 54 * Matches any scope with log level {@link DebugContext#BASIC_LEVEL}. 55 * 56 * <li>{@code :1}<br> 57 * Matches any scope with log level 1. 58 * 59 * <li>{@code *}<br> 60 * Matches any scope with log level {@link DebugContext#BASIC_LEVEL}. 61 * 62 * <li>{@code CodeGen,CodeInstall}<br> 63 * Matches scopes containing "CodeGen" or "CodeInstall", both with log level 64 * {@link DebugContext#BASIC_LEVEL}. 65 * 66 * <li>{@code CodeGen:2,CodeInstall:1}<br> 67 * Matches scopes containing "CodeGen" with log level 2, or "CodeInstall" with log level 1. 68 * 69 * <li>{@code :1,Dead:2}<br> 70 * Matches scopes containing "Dead" with log level 2, and all other scopes with log level 1. 71 * 72 * <li>{@code :1,Dead:0}<br> 73 * Matches all scopes with log level 1, except those containing "Dead". 74 * 75 * <li>{@code Code*}<br> 76 * Matches scopes starting with "Code" with log level {@link DebugContext#BASIC_LEVEL}. 77 * 78 * <li>{@code Code,~Dead}<br> 79 * Matches scopes containing "Code" but not "Dead", with log level {@link DebugContext#BASIC_LEVEL}. 80 * </ul> 81 */ 82 final class DebugFilter { 83 84 public static DebugFilter parse(String spec) { 85 if (spec == null) { 86 return null; 87 } 88 return new DebugFilter(spec.split(",")); 89 } 90 91 private final Term[] terms; 92 93 private DebugFilter(String[] terms) { 94 if (terms.length == 0) { 95 this.terms = null; 96 } else { 97 this.terms = new Term[terms.length]; 98 for (int i = 0; i < terms.length; i++) { 99 String t = terms[i]; 100 int idx = t.indexOf(':'); 101 102 String pattern; 103 int level; 104 if (idx < 0) { 105 if (t.startsWith("~")) { 106 pattern = t.substring(1); 107 level = 0; 108 } else { 109 pattern = t; 110 level = DebugContext.BASIC_LEVEL; 111 } 112 } else { 113 pattern = t.substring(0, idx); 114 if (idx + 1 < t.length()) { 115 String levelString = t.substring(idx + 1); 116 try { 117 level = Integer.parseInt(levelString); 118 } catch (NumberFormatException e) { 119 switch (levelString) { 120 case "basic": 121 level = DebugContext.BASIC_LEVEL; 122 break; 123 case "info": 124 level = DebugContext.INFO_LEVEL; 125 break; 126 case "verbose": 127 level = DebugContext.VERBOSE_LEVEL; 128 break; 129 default: 130 throw new IllegalArgumentException("Unknown dump level: \"" + levelString + "\" expected basic, info, verbose or an integer"); 131 } 132 } 133 134 } else { 135 level = DebugContext.BASIC_LEVEL; 136 } 137 } 138 139 this.terms[i] = new Term(pattern, level); 140 } 141 } 142 } 143 144 /** 145 * Check whether a given input is matched by this filter, and determine the log level. 146 */ 147 public int matchLevel(String input) { 148 if (terms == null) { 149 return DebugContext.BASIC_LEVEL; 150 } else { 151 int level = 0; 152 for (Term t : terms) { 153 if (t.matches(input)) { 154 level = t.level; 155 } 156 } 157 return level; 158 } 159 } 160 161 @Override 162 public String toString() { 163 StringBuilder buf = new StringBuilder("DebugFilter"); 164 if (terms != null) { 165 buf.append(Arrays.toString(terms)); 166 } else { 167 buf.append("[]"); 168 } 169 return buf.toString(); |