1/* Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2 3Licensed under the Apache License, Version 2.0 (the "License"); 4you may not use this file except in compliance with the License. 5You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9Unless required by applicable law or agreed to in writing, software 10distributed under the License is distributed on an "AS IS" BASIS, 11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12See the License for the specific language governing permissions and 13limitations under the License. 14==============================================================================*/ 15 16package org.tensorflow.demo.env; 17 18import android.util.Log; 19 20import java.util.HashSet; 21import java.util.Set; 22 23/** 24 * Wrapper for the platform log function, allows convenient message prefixing and log disabling. 25 */ 26public final class Logger { 27 private static final String DEFAULT_TAG = "tensorflow"; 28 private static final int DEFAULT_MIN_LOG_LEVEL = Log.DEBUG; 29 30 // Classes to be ignored when examining the stack trace 31 private static final Set<String> IGNORED_CLASS_NAMES; 32 33 static { 34 IGNORED_CLASS_NAMES = new HashSet<String>(3); 35 IGNORED_CLASS_NAMES.add("dalvik.system.VMStack"); 36 IGNORED_CLASS_NAMES.add("java.lang.Thread"); 37 IGNORED_CLASS_NAMES.add(Logger.class.getCanonicalName()); 38 } 39 40 private final String tag; 41 private final String messagePrefix; 42 private int minLogLevel = DEFAULT_MIN_LOG_LEVEL; 43 44 /** 45 * Creates a Logger using the class name as the message prefix. 46 * 47 * @param clazz the simple name of this class is used as the message prefix. 48 */ 49 public Logger(final Class<?> clazz) { 50 this(clazz.getSimpleName()); 51 } 52 53 /** 54 * Creates a Logger using the specified message prefix. 55 * 56 * @param messagePrefix is prepended to the text of every message. 57 */ 58 public Logger(final String messagePrefix) { 59 this(DEFAULT_TAG, messagePrefix); 60 } 61 62 /** 63 * Creates a Logger with a custom tag and a custom message prefix. If the message prefix 64 * is set to <pre>null</pre>, the caller's class name is used as the prefix. 65 * 66 * @param tag identifies the source of a log message. 67 * @param messagePrefix prepended to every message if non-null. If null, the name of the caller is 68 * being used 69 */ 70 public Logger(final String tag, final String messagePrefix) { 71 this.tag = tag; 72 final String prefix = messagePrefix == null ? getCallerSimpleName() : messagePrefix; 73 this.messagePrefix = (prefix.length() > 0) ? prefix + ": " : prefix; 74 } 75 76 /** 77 * Creates a Logger using the caller's class name as the message prefix. 78 */ 79 public Logger() { 80 this(DEFAULT_TAG, null); 81 } 82 83 /** 84 * Creates a Logger using the caller's class name as the message prefix. 85 */ 86 public Logger(final int minLogLevel) { 87 this(DEFAULT_TAG, null); 88 this.minLogLevel = minLogLevel; 89 } 90 91 public void setMinLogLevel(final int minLogLevel) { 92 this.minLogLevel = minLogLevel; 93 } 94 95 public boolean isLoggable(final int logLevel) { 96 return logLevel >= minLogLevel || Log.isLoggable(tag, logLevel); 97 } 98 99 /** 100 * Return caller's simple name. 101 * 102 * Android getStackTrace() returns an array that looks like this: 103 * stackTrace[0]: dalvik.system.VMStack 104 * stackTrace[1]: java.lang.Thread 105 * stackTrace[2]: com.google.android.apps.unveil.env.UnveilLogger 106 * stackTrace[3]: com.google.android.apps.unveil.BaseApplication 107 * 108 * This function returns the simple version of the first non-filtered name. 109 * 110 * @return caller's simple name 111 */ 112 private static String getCallerSimpleName() { 113 // Get the current callstack so we can pull the class of the caller off of it. 114 final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); 115 116 for (final StackTraceElement elem : stackTrace) { 117 final String className = elem.getClassName(); 118 if (!IGNORED_CLASS_NAMES.contains(className)) { 119 // We're only interested in the simple name of the class, not the complete package. 120 final String[] classParts = className.split("\\."); 121 return classParts[classParts.length - 1]; 122 } 123 } 124 125 return Logger.class.getSimpleName(); 126 } 127 128 private String toMessage(final String format, final Object... args) { 129 return messagePrefix + (args.length > 0 ? String.format(format, args) : format); 130 } 131 132 public void v(final String format, final Object... args) { 133 if (isLoggable(Log.VERBOSE)) { 134 Log.v(tag, toMessage(format, args)); 135 } 136 } 137 138 public void v(final Throwable t, final String format, final Object... args) { 139 if (isLoggable(Log.VERBOSE)) { 140 Log.v(tag, toMessage(format, args), t); 141 } 142 } 143 144 public void d(final String format, final Object... args) { 145 if (isLoggable(Log.DEBUG)) { 146 Log.d(tag, toMessage(format, args)); 147 } 148 } 149 150 public void d(final Throwable t, final String format, final Object... args) { 151 if (isLoggable(Log.DEBUG)) { 152 Log.d(tag, toMessage(format, args), t); 153 } 154 } 155 156 public void i(final String format, final Object... args) { 157 if (isLoggable(Log.INFO)) { 158 Log.i(tag, toMessage(format, args)); 159 } 160 } 161 162 public void i(final Throwable t, final String format, final Object... args) { 163 if (isLoggable(Log.INFO)) { 164 Log.i(tag, toMessage(format, args), t); 165 } 166 } 167 168 public void w(final String format, final Object... args) { 169 if (isLoggable(Log.WARN)) { 170 Log.w(tag, toMessage(format, args)); 171 } 172 } 173 174 public void w(final Throwable t, final String format, final Object... args) { 175 if (isLoggable(Log.WARN)) { 176 Log.w(tag, toMessage(format, args), t); 177 } 178 } 179 180 public void e(final String format, final Object... args) { 181 if (isLoggable(Log.ERROR)) { 182 Log.e(tag, toMessage(format, args)); 183 } 184 } 185 186 public void e(final Throwable t, final String format, final Object... args) { 187 if (isLoggable(Log.ERROR)) { 188 Log.e(tag, toMessage(format, args), t); 189 } 190 } 191} 192