Bug: b/112869080 Test: atest FrameworksNetTests NetworkStackTests Change-Id: I1b8b6a3f4390adbabf92fb9e48da61c47b08b2ec
203 lines
5.9 KiB
Java
203 lines
5.9 KiB
Java
/*
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.net.util;
|
|
|
|
import android.annotation.NonNull;
|
|
import android.annotation.Nullable;
|
|
import android.text.TextUtils;
|
|
import android.util.LocalLog;
|
|
import android.util.Log;
|
|
|
|
import java.io.FileDescriptor;
|
|
import java.io.PrintWriter;
|
|
import java.util.StringJoiner;
|
|
|
|
|
|
/**
|
|
* Class to centralize logging functionality for tethering.
|
|
*
|
|
* All access to class methods other than dump() must be on the same thread.
|
|
*
|
|
* TODO: this is a copy of SharedLog in the NetworkStack. Remove after Tethering is migrated.
|
|
* @hide
|
|
*/
|
|
public class SharedLog {
|
|
private static final int DEFAULT_MAX_RECORDS = 500;
|
|
private static final String COMPONENT_DELIMITER = ".";
|
|
|
|
private enum Category {
|
|
NONE,
|
|
ERROR,
|
|
MARK,
|
|
WARN,
|
|
};
|
|
|
|
private final LocalLog mLocalLog;
|
|
// The tag to use for output to the system log. This is not output to the
|
|
// LocalLog because that would be redundant.
|
|
private final String mTag;
|
|
// The component (or subcomponent) of a system that is sharing this log.
|
|
// This can grow in depth if components call forSubComponent() to obtain
|
|
// their SharedLog instance. The tag is not included in the component for
|
|
// brevity.
|
|
private final String mComponent;
|
|
|
|
public SharedLog(String tag) {
|
|
this(DEFAULT_MAX_RECORDS, tag);
|
|
}
|
|
|
|
public SharedLog(int maxRecords, String tag) {
|
|
this(new LocalLog(maxRecords), tag, tag);
|
|
}
|
|
|
|
private SharedLog(LocalLog localLog, String tag, String component) {
|
|
mLocalLog = localLog;
|
|
mTag = tag;
|
|
mComponent = component;
|
|
}
|
|
|
|
public String getTag() {
|
|
return mTag;
|
|
}
|
|
|
|
/**
|
|
* Create a SharedLog based on this log with an additional component prefix on each logged line.
|
|
*/
|
|
public SharedLog forSubComponent(String component) {
|
|
if (!isRootLogInstance()) {
|
|
component = mComponent + COMPONENT_DELIMITER + component;
|
|
}
|
|
return new SharedLog(mLocalLog, mTag, component);
|
|
}
|
|
|
|
/**
|
|
* Dump the contents of this log.
|
|
*
|
|
* <p>This method may be called on any thread.
|
|
*/
|
|
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
|
|
mLocalLog.readOnlyLocalLog().dump(fd, writer, args);
|
|
}
|
|
|
|
//////
|
|
// Methods that both log an entry and emit it to the system log.
|
|
//////
|
|
|
|
/**
|
|
* Log an error due to an exception. This does not include the exception stacktrace.
|
|
*
|
|
* <p>The log entry will be also added to the system log.
|
|
* @see #e(String, Throwable)
|
|
*/
|
|
public void e(Exception e) {
|
|
Log.e(mTag, record(Category.ERROR, e.toString()));
|
|
}
|
|
|
|
/**
|
|
* Log an error message.
|
|
*
|
|
* <p>The log entry will be also added to the system log.
|
|
*/
|
|
public void e(String msg) {
|
|
Log.e(mTag, record(Category.ERROR, msg));
|
|
}
|
|
|
|
/**
|
|
* Log an error due to an exception, with the exception stacktrace if provided.
|
|
*
|
|
* <p>The error and exception message appear in the shared log, but the stacktrace is only
|
|
* logged in general log output (logcat). The log entry will be also added to the system log.
|
|
*/
|
|
public void e(@NonNull String msg, @Nullable Throwable exception) {
|
|
if (exception == null) {
|
|
e(msg);
|
|
return;
|
|
}
|
|
Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception);
|
|
}
|
|
|
|
/**
|
|
* Log an informational message.
|
|
*
|
|
* <p>The log entry will be also added to the system log.
|
|
*/
|
|
public void i(String msg) {
|
|
Log.i(mTag, record(Category.NONE, msg));
|
|
}
|
|
|
|
/**
|
|
* Log a warning message.
|
|
*
|
|
* <p>The log entry will be also added to the system log.
|
|
*/
|
|
public void w(String msg) {
|
|
Log.w(mTag, record(Category.WARN, msg));
|
|
}
|
|
|
|
//////
|
|
// Methods that only log an entry (and do NOT emit to the system log).
|
|
//////
|
|
|
|
/**
|
|
* Log a general message to be only included in the in-memory log.
|
|
*
|
|
* <p>The log entry will *not* be added to the system log.
|
|
*/
|
|
public void log(String msg) {
|
|
record(Category.NONE, msg);
|
|
}
|
|
|
|
/**
|
|
* Log a general, formatted message to be only included in the in-memory log.
|
|
*
|
|
* <p>The log entry will *not* be added to the system log.
|
|
* @see String#format(String, Object...)
|
|
*/
|
|
public void logf(String fmt, Object... args) {
|
|
log(String.format(fmt, args));
|
|
}
|
|
|
|
/**
|
|
* Log a message with MARK level.
|
|
*
|
|
* <p>The log entry will *not* be added to the system log.
|
|
*/
|
|
public void mark(String msg) {
|
|
record(Category.MARK, msg);
|
|
}
|
|
|
|
private String record(Category category, String msg) {
|
|
final String entry = logLine(category, msg);
|
|
mLocalLog.log(entry);
|
|
return entry;
|
|
}
|
|
|
|
private String logLine(Category category, String msg) {
|
|
final StringJoiner sj = new StringJoiner(" ");
|
|
if (!isRootLogInstance()) sj.add("[" + mComponent + "]");
|
|
if (category != Category.NONE) sj.add(category.toString());
|
|
return sj.add(msg).toString();
|
|
}
|
|
|
|
// Check whether this SharedLog instance is nominally the top level in
|
|
// a potential hierarchy of shared logs (the root of a tree),
|
|
// or is a subcomponent within the hierarchy.
|
|
private boolean isRootLogInstance() {
|
|
return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag);
|
|
}
|
|
}
|