blob: cb655d29f124f50e1c516cc0fbbf0b95ebe17dd6 [file] [log] [blame]
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* 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 org.jetbrains.android.logcat;
import com.android.ddmlib.Log;
import com.intellij.diagnostic.logging.LogFilter;
import com.intellij.diagnostic.logging.LogFilterListener;
import com.intellij.diagnostic.logging.LogFilterModel;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.android.logcat.AndroidLogcatReceiver.LogMessageHeader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* @author Eugene.Kudelevsky
*/
public abstract class AndroidLogFilterModel extends LogFilterModel {
private final List<LogFilterListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private Log.LogLevel myPrevMessageLogLevel;
private String myPrevTag;
private String myPrevPkg;
private String myPrevPid;
private boolean myFullMessageApplicable = false;
private boolean myFullMessageApplicableByCustomFilter = false;
private StringBuilder myMessageBuilder = new StringBuilder();
protected List<AndroidLogFilter> myLogFilters = new ArrayList<AndroidLogFilter>();
public AndroidLogFilterModel() {
for (Log.LogLevel logLevel : Log.LogLevel.values()) {
myLogFilters.add(new AndroidLogFilter(logLevel));
}
}
@Override
public void updateCustomFilter(String filter) {
super.updateCustomFilter(filter);
setCustomFilter(filter);
fireTextFilterChange();
}
public void updateConfiguredFilter(@Nullable ConfiguredFilter filter) {
setConfiguredFilter(filter);
fireTextFilterChange();
}
protected abstract void setCustomFilter(String filter);
protected void setConfiguredFilter(@Nullable ConfiguredFilter filter) {
}
@Nullable
protected ConfiguredFilter getConfiguredFilter() {
return null;
}
protected abstract void saveLogLevel(String logLevelName);
@Override
public void addFilterListener(LogFilterListener listener) {
myListeners.add(listener);
}
@Override
public void removeFilterListener(LogFilterListener listener) {
myListeners.remove(listener);
}
private void fireTextFilterChange() {
for (LogFilterListener listener : myListeners) {
listener.onTextFilterChange();
}
}
private void fireFilterChange(LogFilter filter) {
for (LogFilterListener listener : myListeners) {
listener.onFilterStateChange(filter);
}
}
private static Key getProcessOutputType(@NotNull Log.LogLevel level) {
switch (level) {
case VERBOSE:
return AndroidLogcatConstants.VERBOSE;
case INFO:
return AndroidLogcatConstants.INFO;
case DEBUG:
return AndroidLogcatConstants.DEBUG;
case WARN:
return AndroidLogcatConstants.WARNING;
case ERROR:
return AndroidLogcatConstants.ERROR;
case ASSERT:
return AndroidLogcatConstants.ASSERT;
}
return ProcessOutputTypes.STDOUT;
}
@Override
public boolean isApplicable(String text) {
if (!super.isApplicable(text)) return false;
final LogFilter selectedLogLevelFilter = getSelectedLogLevelFilter();
return selectedLogLevelFilter == null || selectedLogLevelFilter.isAcceptable(text);
}
public boolean isApplicableByCustomFilter(String text) {
final ConfiguredFilter configuredFilterName = getConfiguredFilter();
if (configuredFilterName == null) {
return true;
}
Log.LogLevel logLevel = null;
String tag = null;
String pkg = null;
String pid = null;
String message = text;
Pair<LogMessageHeader, String> result = AndroidLogcatFormatter.parseMessage(text);
if (result.getFirst() != null) {
LogMessageHeader header = result.getFirst();
logLevel = header.myLogLevel;
tag = header.myTag;
pkg = header.myAppPackage;
pid = Integer.toString(header.myPid);
if (result.getSecond() != null) {
message = result.getSecond();
}
}
if (tag == null) {
tag = myPrevTag;
}
if (pkg == null) {
pkg = myPrevPkg;
}
if (pid == null) {
pid = myPrevPid;
}
if (logLevel == null) {
logLevel = myPrevMessageLogLevel;
}
return configuredFilterName.isApplicable(message, tag, pkg, pid, logLevel);
}
@Override
public List<? extends LogFilter> getLogFilters() {
return myLogFilters;
}
private class AndroidLogFilter extends LogFilter {
final Log.LogLevel myLogLevel;
private AndroidLogFilter(Log.LogLevel logLevel) {
super(StringUtil.capitalize(logLevel.name().toLowerCase()));
myLogLevel = logLevel;
}
@Override
public boolean isAcceptable(String line) {
Log.LogLevel logLevel = null;
Pair<LogMessageHeader, String> result = AndroidLogcatFormatter.parseMessage(line);
if (result.getFirst() != null) {
logLevel = result.getFirst().myLogLevel;
}
if (logLevel == null) {
logLevel = myPrevMessageLogLevel;
}
return logLevel != null && logLevel.getPriority() >= myLogLevel.getPriority();
}
}
public abstract String getSelectedLogLevelName();
@Nullable
private LogFilter getSelectedLogLevelFilter() {
final String filterName = getSelectedLogLevelName();
if (filterName != null) {
for (AndroidLogFilter logFilter : myLogFilters) {
if (filterName.equals(logFilter.myLogLevel.name())) {
return logFilter;
}
}
}
return null;
}
@Override
public boolean isFilterSelected(LogFilter filter) {
return filter == getSelectedLogLevelFilter();
}
@Override
public void selectFilter(LogFilter filter) {
if (!(filter instanceof AndroidLogFilter)) {
return;
}
String newFilterName = ((AndroidLogFilter)filter).myLogLevel.name();
if (!Comparing.equal(newFilterName, getSelectedLogLevelName())) {
saveLogLevel(newFilterName);
fireFilterChange(filter);
}
}
@Override
public void processingStarted() {
myPrevMessageLogLevel = null;
myPrevTag = null;
myPrevPkg = null;
myPrevPid = null;
myFullMessageApplicable = false;
myFullMessageApplicableByCustomFilter = false;
myMessageBuilder = new StringBuilder();
}
@Override
@NotNull
public MyProcessingResult processLine(String line) {
Pair<LogMessageHeader, String> result = AndroidLogcatFormatter.parseMessage(line);
final boolean messageHeader = result.getFirst() != null;
if (messageHeader) {
LogMessageHeader header = result.getFirst();
if (header.myLogLevel != null) {
myPrevMessageLogLevel = header.myLogLevel;
}
if (!header.myTag.isEmpty()) {
myPrevTag = header.myTag;
}
if (!header.myAppPackage.isEmpty()) {
myPrevPkg = header.myAppPackage;
}
if (header.myPid != 0) {
myPrevPid = Integer.toString(header.myPid);
}
}
final boolean applicable = isApplicable(line);
final boolean applicableByCustomFilter = isApplicableByCustomFilter(line);
String messagePrefix;
if (messageHeader) {
messagePrefix = null;
myMessageBuilder = new StringBuilder(line);
myMessageBuilder.append('\n');
myFullMessageApplicable = applicable;
myFullMessageApplicableByCustomFilter = applicableByCustomFilter;
}
else {
messagePrefix = (myFullMessageApplicable || applicable) &&
(myFullMessageApplicableByCustomFilter || applicableByCustomFilter) &&
!(myFullMessageApplicable && myFullMessageApplicableByCustomFilter)
? myMessageBuilder.toString()
: null;
myMessageBuilder.append(line).append('\n');
myFullMessageApplicable = myFullMessageApplicable || applicable;
myFullMessageApplicableByCustomFilter = myFullMessageApplicableByCustomFilter || applicableByCustomFilter;
}
final Key key = myPrevMessageLogLevel != null ? getProcessOutputType(myPrevMessageLogLevel) : ProcessOutputTypes.STDOUT;
return new MyProcessingResult(key,
myFullMessageApplicable && myFullMessageApplicableByCustomFilter,
messagePrefix);
}
}