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