1 /*
2  * Copyright (C) 2008 The Android Open Source Project
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.android.internal.logging;
18 
19 import android.util.Log;
20 import com.android.internal.util.FastPrintWriter;
21 import dalvik.system.DalvikLogging;
22 import dalvik.system.DalvikLogHandler;
23 
24 import java.io.PrintWriter;
25 import java.io.StringWriter;
26 import java.util.logging.Formatter;
27 import java.util.logging.Handler;
28 import java.util.logging.Level;
29 import java.util.logging.LogRecord;
30 import java.util.logging.Logger;
31 
32 /**
33  * Implements a {@link java.util.logging.Logger} handler that writes to the Android log. The
34  * implementation is rather straightforward. The name of the logger serves as
35  * the log tag. Only the log levels need to be converted appropriately. For
36  * this purpose, the following mapping is being used:
37  *
38  * <table>
39  *   <tr>
40  *     <th>logger level</th>
41  *     <th>Android level</th>
42  *   </tr>
43  *   <tr>
44  *     <td>
45  *       SEVERE
46  *     </td>
47  *     <td>
48  *       ERROR
49  *     </td>
50  *   </tr>
51  *   <tr>
52  *     <td>
53  *       WARNING
54  *     </td>
55  *     <td>
56  *       WARN
57  *     </td>
58  *   </tr>
59  *   <tr>
60  *     <td>
61  *       INFO
62  *     </td>
63  *     <td>
64  *       INFO
65  *     </td>
66  *   </tr>
67  *   <tr>
68  *     <td>
69  *       CONFIG
70  *     </td>
71  *     <td>
72  *       DEBUG
73  *     </td>
74  *   </tr>
75  *   <tr>
76  *     <td>
77  *       FINE, FINER, FINEST
78  *     </td>
79  *     <td>
80  *       VERBOSE
81  *     </td>
82  *   </tr>
83  * </table>
84  */
85 public class AndroidHandler extends Handler implements DalvikLogHandler {
86     /**
87      * Holds the formatter for all Android log handlers.
88      */
89     private static final Formatter THE_FORMATTER = new Formatter() {
90         @Override
91         public String format(LogRecord r) {
92             Throwable thrown = r.getThrown();
93             if (thrown != null) {
94                 StringWriter sw = new StringWriter();
95                 PrintWriter pw = new FastPrintWriter(sw, false, 256);
96                 sw.write(r.getMessage());
97                 sw.write("\n");
98                 thrown.printStackTrace(pw);
99                 pw.flush();
100                 return sw.toString();
101             } else {
102                 return r.getMessage();
103             }
104         }
105     };
106 
107     /**
108      * Constructs a new instance of the Android log handler.
109      */
AndroidHandler()110     public AndroidHandler() {
111         setFormatter(THE_FORMATTER);
112     }
113 
114     @Override
close()115     public void close() {
116         // No need to close, but must implement abstract method.
117     }
118 
119     @Override
flush()120     public void flush() {
121         // No need to flush, but must implement abstract method.
122     }
123 
124     @Override
publish(LogRecord record)125     public void publish(LogRecord record) {
126         int level = getAndroidLevel(record.getLevel());
127         String tag = DalvikLogging.loggerNameToTag(record.getLoggerName());
128         if (!Log.isLoggable(tag, level)) {
129             return;
130         }
131 
132         try {
133             String message = getFormatter().format(record);
134             Log.println(level, tag, message);
135         } catch (RuntimeException e) {
136             Log.e("AndroidHandler", "Error logging message.", e);
137         }
138     }
139 
publish(Logger source, String tag, Level level, String message)140     public void publish(Logger source, String tag, Level level, String message) {
141         // TODO: avoid ducking into native 2x; we aren't saving any formatter calls
142         int priority = getAndroidLevel(level);
143         if (!Log.isLoggable(tag, priority)) {
144             return;
145         }
146 
147         try {
148             Log.println(priority, tag, message);
149         } catch (RuntimeException e) {
150             Log.e("AndroidHandler", "Error logging message.", e);
151         }
152     }
153 
154     /**
155      * Converts a {@link java.util.logging.Logger} logging level into an Android one.
156      *
157      * @param level The {@link java.util.logging.Logger} logging level.
158      *
159      * @return The resulting Android logging level.
160      */
getAndroidLevel(Level level)161     static int getAndroidLevel(Level level) {
162         int value = level.intValue();
163         if (value >= 1000) { // SEVERE
164             return Log.ERROR;
165         } else if (value >= 900) { // WARNING
166             return Log.WARN;
167         } else if (value >= 800) { // INFO
168             return Log.INFO;
169         } else {
170             return Log.DEBUG;
171         }
172     }
173 }
174