1 /* 2 * Copyright (c) 2012, 2015, 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. 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 24 25 package org.graalvm.compiler.debug; 26 27 import java.util.Arrays; 28 import java.util.regex.Pattern; 29 30 import org.graalvm.compiler.debug.DebugContext.Scope; 31 32 /** 33 * Implements the filter specified by options such as {@link DebugOptions#Dump}, 34 * {@link DebugOptions#Log}, {@link DebugOptions#Count} and {@link DebugOptions#Time}. 35 * 36 * See <a href="DumpHelp.txt">here</a> for a description of the filter syntax. 37 * 38 * <p> 39 * These options enable the associated debug facility if their filter matches the 40 * {@linkplain Scope#getQualifiedName() name} of the current scope. For the 41 * {@link DebugOptions#Dump} and {@link DebugOptions#Log} options, the log or dump level is set. The 42 * {@link DebugOptions#Count} and {@link DebugOptions#Time} options don't have a level, for them 43 * {@code level = 0} means disabled and a {@code level > 0} means enabled. 44 * <p> 45 * The syntax for a filter is explained <a href="file:doc-files/DumpHelp.txt">here</a>. 46 */ 47 final class DebugFilter { 48 49 public static DebugFilter parse(String spec) { 50 if (spec == null) { 51 return null; 52 } 53 return new DebugFilter(spec.split(",")); 54 } 55 56 private final Term[] terms; 57 58 private DebugFilter(String[] terms) { 59 if (terms.length == 0) { 60 this.terms = null; 61 } else { 62 this.terms = new Term[terms.length]; 63 for (int i = 0; i < terms.length; i++) { 64 String t = terms[i]; 65 int idx = t.indexOf(':'); 66 67 String pattern; 68 int level; 69 if (idx < 0) { 70 if (t.startsWith("~")) { 71 pattern = t.substring(1); 72 level = 0; 73 } else { 74 pattern = t; 75 level = DebugContext.BASIC_LEVEL; 76 } 77 } else { 78 pattern = t.substring(0, idx); 79 if (idx + 1 < t.length()) { 80 String levelString = t.substring(idx + 1); 81 try { 82 level = Integer.parseInt(levelString); 83 } catch (NumberFormatException e) { 84 switch (levelString) { 85 case "basic": 86 level = DebugContext.BASIC_LEVEL; 87 break; 88 case "info": 89 level = DebugContext.INFO_LEVEL; 90 break; 91 case "verbose": 92 level = DebugContext.VERBOSE_LEVEL; 93 break; 94 default: 95 throw new IllegalArgumentException("Unknown dump level: \"" + levelString + "\" expected basic, info, verbose or an integer"); 96 } 97 } 98 99 } else { 100 level = DebugContext.BASIC_LEVEL; 101 } 102 } 103 104 this.terms[i] = new Term(pattern, level); 105 } 106 } 107 } 108 109 /** 110 * Check whether a given input is matched by this filter, and determine the log level. 111 */ 112 public int matchLevel(String input) { 113 if (terms == null) { 114 return DebugContext.BASIC_LEVEL; 115 } else { 116 int defaultLevel = 0; 117 int level = -1; 118 for (Term t : terms) { 119 if (t.isMatchAny()) { 120 defaultLevel = t.level; 121 } else if (t.matches(input)) { 122 level = t.level; 123 } 124 } 125 return level == -1 ? defaultLevel : level; 126 } 127 } 128 129 @Override 130 public String toString() { 131 StringBuilder buf = new StringBuilder("DebugFilter"); 132 if (terms != null) { 133 buf.append(Arrays.toString(terms)); 134 } else { 135 buf.append("[]"); 136 } 137 return buf.toString(); 138 } 139 140 private static class Term { 141 142 private final Pattern pattern; 143 public final int level; 144 145 Term(String filter, int level) { 146 this.level = level; 147 if (filter.isEmpty() || filter.equals("*")) { 148 this.pattern = null; 149 } else if (filter.contains("*") || filter.contains("?")) { 150 this.pattern = Pattern.compile(MethodFilter.createGlobString(filter)); 151 } else { 152 this.pattern = Pattern.compile(".*" + MethodFilter.createGlobString(filter) + ".*"); 153 } 154 } 155 156 /** 157 * Determines if a given input is matched by this filter. 158 */ 159 public boolean matches(String input) { 160 return pattern == null || pattern.matcher(input).matches(); 161 } 162 163 public boolean isMatchAny() { 164 return pattern == null; 165 } 166 167 @Override 168 public String toString() { 169 return (pattern == null ? ".*" : pattern.toString()) + ":" + level; 170 } 171 } 172 }