DebugFilter.java revision 12651:6ef01bd40ce2
1230592Sken/* 2281564Sslm * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 3281564Sslm * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4230592Sken * 5230592Sken * This code is free software; you can redistribute it and/or modify it 6230592Sken * under the terms of the GNU General Public License version 2 only, as 7230592Sken * published by the Free Software Foundation. 8230592Sken * 9230592Sken * This code is distributed in the hope that it will be useful, but WITHOUT 10230592Sken * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11230592Sken * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12230592Sken * version 2 for more details (a copy is included in the LICENSE file that 13230592Sken * accompanied this code). 14230592Sken * 15230592Sken * You should have received a copy of the GNU General Public License version 16230592Sken * 2 along with this work; if not, write to the Free Software Foundation, 17230592Sken * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18230592Sken * 19230592Sken * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20230592Sken * or visit www.oracle.com if you need additional information or have any 21230592Sken * questions. 22230592Sken */ 23230592Skenpackage org.graalvm.compiler.debug; 24230592Sken 25230592Skenimport java.util.Arrays; 26230592Skenimport java.util.regex.Pattern; 27281564Sslm 28230592Skenimport org.graalvm.compiler.debug.GraalDebugConfig.Options; 29230592Skenimport org.graalvm.compiler.debug.internal.DebugScope; 30230592Sken 31230592Sken/** 32212420Sken * Implements the filter specified by the {@link Options#Dump}, {@link Options#Log}, 33281564Sslm * {@link Options#Count},{@link Options#MethodMeter} and {@link Options#Time} options. 34281564Sslm * <p> 35212420Sken * These options enable the associated debug facility if their filter matches the 36212420Sken * {@linkplain DebugScope#getQualifiedName() name} of the {@linkplain Debug#currentScope() current 37212420Sken * scope}. For the {@link Options#Dump} and {@link Options#Log} options, the log or dump level is 38212420Sken * set. The {@link Options#Count},{@link Options#MethodMeter} and {@link Options#Time} options don't 39212420Sken * have a level, for them {@code level = 0} means disabled and a {@code level > 0} means enabled. 40212420Sken * <p> 41230592Sken * A filter is a list of comma-separated terms of the form {@code <pattern>[:<level>]}. {@code 42212420Sken * <pattern>} is interpreted as a glob pattern if it contains a "*" or "?" character. Otherwise, it 43212420Sken * is interpreted as a substring. If {@code <pattern>} is empty, it matches every scope. If {@code : 44212420Sken * <level>} is omitted, it defaults to {@link Debug#BASIC_LOG_LEVEL}. The term {@code ~<pattern>} is 45212420Sken * a shorthand for {@code <pattern>:0} to disable a debug facility for a pattern. 46212420Sken * <p> 47212420Sken * The resulting log level of a scope is determined by the <em>last</em> matching term. If no term 48212420Sken * matches, the log level is 0 (disabled). A filter with no terms matches every scope with a log 49212420Sken * level of {@link Debug#BASIC_LOG_LEVEL}. 50212420Sken * 51212420Sken * <h2>Examples of filters</h2> 52212420Sken * 53212420Sken * <ul> 54212420Sken * <li>(empty string)<br> 55212420Sken * Matches any scope with log level {@link Debug#BASIC_LOG_LEVEL}. 56212420Sken * 57212420Sken * <li>{@code :1}<br> 58212420Sken * Matches any scope with log level 1. 59212420Sken * 60212420Sken * <li>{@code *}<br> 61212420Sken * Matches any scope with log level {@link Debug#BASIC_LOG_LEVEL}. 62212420Sken * 63212420Sken * <li>{@code CodeGen,CodeInstall}<br> 64212420Sken * Matches scopes containing "CodeGen" or "CodeInstall", both with log level 65212420Sken * {@link Debug#BASIC_LOG_LEVEL}. 66212420Sken * 67212420Sken * <li>{@code CodeGen:2,CodeInstall:1}<br> 68212420Sken * Matches scopes containing "CodeGen" with log level 2, or "CodeInstall" with log level 1. 69212420Sken * 70212420Sken * <li>{@code :1,Dead:2}<br> 71212420Sken * Matches scopes containing "Dead" with log level 2, and all other scopes with log level 1. 72212420Sken * 73212420Sken * <li>{@code :1,Dead:0}<br> 74212420Sken * Matches all scopes with log level 1, except those containing "Dead". 75212420Sken * 76212420Sken * <li>{@code Code*}<br> 77212420Sken * Matches scopes starting with "Code" with log level {@link Debug#BASIC_LOG_LEVEL}. 78212420Sken * 79212420Sken * <li>{@code Code,~Dead}<br> 80212420Sken * Matches scopes containing "Code" but not "Dead", with log level {@link Debug#BASIC_LOG_LEVEL}. 81212420Sken * </ul> 82212420Sken */ 83212420Skenfinal class DebugFilter { 84212420Sken 85212420Sken public static DebugFilter parse(String spec) { 86212420Sken if (spec == null) { 87212420Sken return null; 88212420Sken } 89212420Sken return new DebugFilter(spec.split(",")); 90212420Sken } 91212420Sken 92212420Sken private final Term[] terms; 93212420Sken 94212420Sken private DebugFilter(String[] terms) { 95212420Sken if (terms.length == 0) { 96212420Sken this.terms = null; 97212420Sken } else { 98212420Sken this.terms = new Term[terms.length]; 99212420Sken for (int i = 0; i < terms.length; i++) { 100212420Sken String t = terms[i]; 101212420Sken int idx = t.indexOf(':'); 102212420Sken 103212420Sken String pattern; 104212420Sken int level; 105212420Sken if (idx < 0) { 106212420Sken if (t.startsWith("~")) { 107212420Sken pattern = t.substring(1); 108212420Sken level = 0; 109212420Sken } else { 110212420Sken pattern = t; 111212420Sken level = Debug.BASIC_LOG_LEVEL; 112212420Sken } 113212420Sken } else { 114212420Sken pattern = t.substring(0, idx); 115212420Sken if (idx + 1 < t.length()) { 116212420Sken String levelString = t.substring(idx + 1); 117212420Sken try { 118212420Sken level = Integer.parseInt(levelString); 119212420Sken } catch (NumberFormatException e) { 120212420Sken switch (levelString) { 121212420Sken case "basic": 122212420Sken level = Debug.BASIC_LOG_LEVEL; 123212420Sken break; 124212420Sken case "info": 125212420Sken level = Debug.INFO_LOG_LEVEL; 126212420Sken break; 127212420Sken case "verbose": 128212420Sken level = Debug.VERBOSE_LOG_LEVEL; 129212420Sken break; 130212420Sken default: 131212420Sken throw new IllegalArgumentException("Unknown dump level: \"" + levelString + "\" expected basic, info, verbose or an integer"); 132212420Sken } 133230592Sken } 134230592Sken 135230592Sken } else { 136230592Sken level = Debug.BASIC_LOG_LEVEL; 137230592Sken } 138230592Sken } 139212420Sken 140212420Sken this.terms[i] = new Term(pattern, level); 141212420Sken } 142212420Sken } 143212420Sken } 144212420Sken 145212420Sken /** 146212420Sken * Check whether a given input is matched by this filter, and determine the log level. 147212420Sken */ 148212420Sken public int matchLevel(String input) { 149212420Sken if (terms == null) { 150212420Sken return Debug.BASIC_LOG_LEVEL; 151212420Sken } else { 152212420Sken int level = 0; 153212420Sken for (Term t : terms) { 154212420Sken if (t.matches(input)) { 155212420Sken level = t.level; 156212420Sken } 157212420Sken } 158212420Sken return level; 159212420Sken } 160212420Sken } 161212420Sken 162212420Sken @Override 163212420Sken public String toString() { 164212420Sken StringBuilder buf = new StringBuilder("DebugFilter"); 165212420Sken if (terms != null) { 166212420Sken buf.append(Arrays.toString(terms)); 167212420Sken } else { 168212420Sken buf.append("[]"); 169212420Sken } 170212420Sken return buf.toString(); 171212420Sken } 172212420Sken 173212420Sken private static class Term { 174212420Sken 175212420Sken private final Pattern pattern; 176212420Sken public final int level; 177212420Sken 178212420Sken Term(String filter, int level) { 179212420Sken this.level = level; 180212420Sken if (filter.isEmpty()) { 181212420Sken this.pattern = null; 182212420Sken } else if (filter.contains("*") || filter.contains("?")) { 183212420Sken this.pattern = Pattern.compile(MethodFilter.createGlobString(filter)); 184212420Sken } else { 185212420Sken this.pattern = Pattern.compile(".*" + MethodFilter.createGlobString(filter) + ".*"); 186212420Sken } 187212420Sken } 188212420Sken 189212420Sken /** 190212420Sken * Determines if a given input is matched by this filter. 191212420Sken */ 192212420Sken public boolean matches(String input) { 193212420Sken return pattern == null || pattern.matcher(input).matches(); 194212420Sken } 195212420Sken 196212420Sken @Override 197212420Sken public String toString() { 198212420Sken return (pattern == null ? ".*" : pattern.toString()) + ":" + level; 199212420Sken } 200212420Sken } 201212420Sken} 202212420Sken