• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 android.net.util;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.text.TextUtils;
22 import android.util.LocalLog;
23 import android.util.Log;
24 
25 import java.io.FileDescriptor;
26 import java.io.PrintWriter;
27 import java.util.StringJoiner;
28 
29 
30 /**
31  * Class to centralize logging functionality for tethering.
32  *
33  * All access to class methods other than dump() must be on the same thread.
34  *
35  * TODO: this is a copy of SharedLog in the NetworkStack. Remove after Tethering is migrated.
36  * @hide
37  */
38 public class SharedLog {
39     private static final int DEFAULT_MAX_RECORDS = 500;
40     private static final String COMPONENT_DELIMITER = ".";
41 
42     private enum Category {
43         NONE,
44         ERROR,
45         MARK,
46         WARN,
47     };
48 
49     private final LocalLog mLocalLog;
50     // The tag to use for output to the system log. This is not output to the
51     // LocalLog because that would be redundant.
52     private final String mTag;
53     // The component (or subcomponent) of a system that is sharing this log.
54     // This can grow in depth if components call forSubComponent() to obtain
55     // their SharedLog instance. The tag is not included in the component for
56     // brevity.
57     private final String mComponent;
58 
SharedLog(String tag)59     public SharedLog(String tag) {
60         this(DEFAULT_MAX_RECORDS, tag);
61     }
62 
SharedLog(int maxRecords, String tag)63     public SharedLog(int maxRecords, String tag) {
64         this(new LocalLog(maxRecords), tag, tag);
65     }
66 
SharedLog(LocalLog localLog, String tag, String component)67     private SharedLog(LocalLog localLog, String tag, String component) {
68         mLocalLog = localLog;
69         mTag = tag;
70         mComponent = component;
71     }
72 
getTag()73     public String getTag() {
74         return mTag;
75     }
76 
77     /**
78      * Create a SharedLog based on this log with an additional component prefix on each logged line.
79      */
forSubComponent(String component)80     public SharedLog forSubComponent(String component) {
81         if (!isRootLogInstance()) {
82             component = mComponent + COMPONENT_DELIMITER + component;
83         }
84         return new SharedLog(mLocalLog, mTag, component);
85     }
86 
87     /**
88      * Dump the contents of this log.
89      *
90      * <p>This method may be called on any thread.
91      */
dump(FileDescriptor fd, PrintWriter writer, String[] args)92     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
93         mLocalLog.readOnlyLocalLog().dump(fd, writer, args);
94     }
95 
96     //////
97     // Methods that both log an entry and emit it to the system log.
98     //////
99 
100     /**
101      * Log an error due to an exception. This does not include the exception stacktrace.
102      *
103      * <p>The log entry will be also added to the system log.
104      * @see #e(String, Throwable)
105      */
e(Exception e)106     public void e(Exception e) {
107         Log.e(mTag, record(Category.ERROR, e.toString()));
108     }
109 
110     /**
111      * Log an error message.
112      *
113      * <p>The log entry will be also added to the system log.
114      */
e(String msg)115     public void e(String msg) {
116         Log.e(mTag, record(Category.ERROR, msg));
117     }
118 
119     /**
120      * Log an error due to an exception, with the exception stacktrace if provided.
121      *
122      * <p>The error and exception message appear in the shared log, but the stacktrace is only
123      * logged in general log output (logcat). The log entry will be also added to the system log.
124      */
e(@onNull String msg, @Nullable Throwable exception)125     public void e(@NonNull String msg, @Nullable Throwable exception) {
126         if (exception == null) {
127             e(msg);
128             return;
129         }
130         Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception);
131     }
132 
133     /**
134      * Log an informational message.
135      *
136      * <p>The log entry will be also added to the system log.
137      */
i(String msg)138     public void i(String msg) {
139         Log.i(mTag, record(Category.NONE, msg));
140     }
141 
142     /**
143      * Log a warning message.
144      *
145      * <p>The log entry will be also added to the system log.
146      */
w(String msg)147     public void w(String msg) {
148         Log.w(mTag, record(Category.WARN, msg));
149     }
150 
151     //////
152     // Methods that only log an entry (and do NOT emit to the system log).
153     //////
154 
155     /**
156      * Log a general message to be only included in the in-memory log.
157      *
158      * <p>The log entry will *not* be added to the system log.
159      */
log(String msg)160     public void log(String msg) {
161         record(Category.NONE, msg);
162     }
163 
164     /**
165      * Log a general, formatted message to be only included in the in-memory log.
166      *
167      * <p>The log entry will *not* be added to the system log.
168      * @see String#format(String, Object...)
169      */
logf(String fmt, Object... args)170     public void logf(String fmt, Object... args) {
171         log(String.format(fmt, args));
172     }
173 
174     /**
175      * Log a message with MARK level.
176      *
177      * <p>The log entry will *not* be added to the system log.
178      */
mark(String msg)179     public void mark(String msg) {
180         record(Category.MARK, msg);
181     }
182 
record(Category category, String msg)183     private String record(Category category, String msg) {
184         final String entry = logLine(category, msg);
185         mLocalLog.log(entry);
186         return entry;
187     }
188 
logLine(Category category, String msg)189     private String logLine(Category category, String msg) {
190         final StringJoiner sj = new StringJoiner(" ");
191         if (!isRootLogInstance()) sj.add("[" + mComponent + "]");
192         if (category != Category.NONE) sj.add(category.toString());
193         return sj.add(msg).toString();
194     }
195 
196     // Check whether this SharedLog instance is nominally the top level in
197     // a potential hierarchy of shared logs (the root of a tree),
198     // or is a subcomponent within the hierarchy.
isRootLogInstance()199     private boolean isRootLogInstance() {
200         return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag);
201     }
202 }
203