| /* |
| * 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); |
| } |
| } |