Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / cacheinvalidation / src / java / com / google / ipc / invalidation / external / client / android / service / AndroidLogger.java
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.ipc.invalidation.external.client.android.service;
18
19 import com.google.ipc.invalidation.external.client.SystemResources;
20 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
21 import com.google.ipc.invalidation.util.Formatter;
22
23 import android.util.Log;
24
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.logging.Level;
28
29
30 /**
31  * Provides the implementation of {@link Logger} for Android. The logging tag will be based upon the
32  * top-level class name containing the code invoking the logger (the outer class, not an inner or
33  * anonymous class name).   For severe and warning level messages, the Android logger will also
34  * dump the stack trace of the first argument if it is a throwable.
35  */
36 public class AndroidLogger implements Logger {
37
38   /** Creates a new AndroidLogger that uses the provided value as the Android logging tag */
39   public static AndroidLogger forTag(String tag) {
40     return new AndroidLogger(tag, null);
41   }
42
43   /** Creates a new AndroidLogger that will compute a tag value dynamically based upon the class
44    * that calls into the logger and will prepend the provided prefix (if any) on all
45    * logged messages.
46    */
47   public static AndroidLogger forPrefix(String prefix) {
48     return new AndroidLogger(null, prefix);
49   }
50
51   /**
52    * If {@code false}, then Log.isLoggable() is called to filter log messages
53    */
54   private static boolean filteringDisabled = false;
55
56   /**
57    * Maps from a Java {@link Level} to the android {@link Log} priority value used to log
58    * messages at that level.
59    */
60   private static Map<Level, Integer> levelToPriority = new HashMap<Level, Integer>();
61
62   static {
63     // Define the mappings for Java log levels to the associated Android log priorities
64     levelToPriority.put(Level.INFO, Log.INFO);
65     levelToPriority.put(Level.WARNING, Log.WARN);
66     levelToPriority.put(Level.SEVERE, Log.ERROR);
67     levelToPriority.put(Level.FINE, Log.DEBUG);
68     levelToPriority.put(Level.FINER, Log.VERBOSE);
69     levelToPriority.put(Level.FINEST, Log.VERBOSE);
70     levelToPriority.put(Level.CONFIG, Log.INFO);
71   }
72
73   /**
74    * Disables log filtering so all logged messages will be captured.
75    */
76   public static void disableFilteringForTest() {
77     filteringDisabled = true;
78   }
79
80   /**
81    * The default minimum Android log level. We default to 0 to ensure everything is logged.
82    * This should be a value from the {@link Log} constants.
83    */
84   private static int minimumLogLevel = 0;
85
86   /**
87    * The maximum length of an Android logging tag. There's no formal constants but the constraint is
88    * mentioned in the Log javadoc
89    */
90   private static final int MAX_TAG_LENGTH = 23;
91
92   /** Constant tag to use for logged messages (or {@code null} to use topmost class on stack */
93   private final String tag;
94
95   /** Prefix added to Android logging messages */
96   private final String logPrefix;
97
98   /** Creates a logger that prefixes every logging stmt with {@code logPrefix}. */
99   private AndroidLogger(String tag, String logPrefix) {
100     this.tag = tag;
101     this.logPrefix = logPrefix;
102   }
103
104   @Override
105   public boolean isLoggable(Level level) {
106     return isLoggable(getTag(), levelToPriority(level));
107   }
108
109   @Override
110   public void log(Level level, String template, Object... args) {
111     int androidLevel = levelToPriority(level);
112     String tag = getTag();
113     if (isLoggable(tag, androidLevel)) {
114       Log.println(androidLevel, tag, format(template, args));
115     }
116   }
117
118   @Override
119   public void severe(String template, Object...args) {
120     String tag = getTag();
121     if (isLoggable(tag, Log.ERROR)) {
122       // If the first argument is an exception, use the form of Log that will dump a stack trace
123       if ((args.length > 0) && (args[0] instanceof Throwable)) {
124         Log.e(tag, format(template, args), (Throwable) args[0]);
125       } else {
126         Log.e(tag, format(template, args));
127       }
128     }
129   }
130
131   @Override
132   public void warning(String template, Object...args) {
133     String tag = getTag();
134     if (isLoggable(tag, Log.WARN)){
135       // If the first argument is an exception, use the form of Log that will dump a stack trace
136       if ((args.length > 0) && (args[0] instanceof Throwable)) {
137         Log.w(tag, format(template, args), (Throwable) args[0]);
138       } else {
139         Log.w(tag, format(template, args));
140       }
141     }
142   }
143
144   @Override
145   public void info(String template, Object...args) {
146     String tag = getTag();
147     if (isLoggable(tag, Log.INFO)) {
148       Log.i(tag, format(template, args));
149     }
150   }
151
152   @Override
153   public void fine(String template, Object...args) {
154     String tag = getTag();
155     if (isLoggable(tag, Log.DEBUG)) {
156       Log.d(tag, format(template, args));
157     }
158   }
159
160   @Override
161   public void setSystemResources(SystemResources resources) {
162     // No-op.
163   }
164
165   /** Given a Java logging level, returns the corresponding Android log priority. */
166   private static int levelToPriority(Level level) {
167     Integer priority = levelToPriority.get(level);
168     if (priority != null) {
169       return priority;
170     }
171     throw new IllegalArgumentException("Unsupported level: " + level);
172   }
173
174   /** Formats the content of a logged messages for output, prepending the log prefix if any. */
175   private String format(String template, Object...args) {
176     return (logPrefix != null) ?
177         ("[" + logPrefix + "] " + Formatter.format(template, args)) :
178         Formatter.format(template, args);
179   }
180
181   /** Returns the Android logging tag that should be placed on logged messages */
182   private String getTag() {
183     if (tag != null) {
184       return tag;
185     }
186
187     StackTraceElement[] stackTrace = new Throwable().getStackTrace();
188     String className = null;
189     for (int i = 0; i < stackTrace.length; i++) {
190       className = stackTrace[i].getClassName();
191
192       // Skip over this class's methods
193       if (!className.equals(AndroidLogger.class.getName())) {
194         break;
195       }
196     }
197
198     // Compute the unqualified class name w/out any inner class, then truncate to the
199     // maximum tag length.
200     int unqualBegin = className.lastIndexOf('.') + 1;
201     if (unqualBegin < 0) { // should never happen, but be safe
202       unqualBegin = 0;
203     }
204     int unqualEnd = className.indexOf('$', unqualBegin);
205     if (unqualEnd < 0) {
206       unqualEnd = className.length();
207     }
208     if ((unqualEnd - unqualBegin) > MAX_TAG_LENGTH) {
209       unqualEnd = unqualBegin + MAX_TAG_LENGTH;
210     }
211     return className.substring(unqualBegin, unqualEnd);
212   }
213
214   /**
215    * Add additional constraint on logging. In addition to the normal check of
216    * {@link Log#isLoggable(String, int)} for logging, this also requires a minimum
217    * log level of the given value. This should be a value from the {@link Log} constants.
218    */
219   public static void setMinimumAndroidLogLevel(int logLevel) {
220     minimumLogLevel = logLevel;
221   }
222
223   /**
224    * Returns {@code true} is the provided tag/level will produce logged output.
225    */
226   
227   boolean isLoggable(String tag, int priority) {
228     return filteringDisabled || (priority >= minimumLogLevel && Log.isLoggable(tag, priority));
229   }
230 }