All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.android.logcat.AndroidLogcatReceiver Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition android library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * 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.IDevice;
import com.android.ddmlib.Log;
import com.android.tools.idea.logcat.StackTraceExpander;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.android.util.AndroidOutputReceiver;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by IntelliJ IDEA.
 * User: Eugene.Kudelevsky
 * Date: Sep 12, 2009
 * Time: 9:01:05 PM
 */
public class AndroidLogcatReceiver extends AndroidOutputReceiver {
  private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.logcat.AndroidLogcatReceiver");
  private static Pattern LOG_PATTERN =
    Pattern.compile("^\\[\\s(\\d\\d-\\d\\d\\s\\d\\d:\\d\\d:\\d\\d\\.\\d+)\\s+(\\d*):\\s*(\\S+)\\s([VDIWEAF])/(.*)\\]$", Pattern.DOTALL);

  /** Prefix to use for all lines without a header. */
  public static final String CONTINUATION_LINE_PREFIX = StringUtil.repeatSymbol(' ', 4);

  /** Prefix to use for stack trace lines. */
  public static final String STACK_TRACE_LINE_PREFIX = CONTINUATION_LINE_PREFIX + StringUtil.repeatSymbol(' ', 8);

  /**
   * Prefix to use for stack trace lines that were expanded in by {@link StackTraceExpander}.
   * The only reason this is different from {@link #STACK_TRACE_LINE_PREFIX} is that we want {@link ExceptionFolding}
   * class to be able to determine and fold just the expanded lines.
   */
  public static final String EXPANDED_STACK_TRACE_LINE_PREFIX = STACK_TRACE_LINE_PREFIX.replace(' ', '\u00A0');

  /** Prefix to use for the stack trace "Caused by:" lines. */
  public static final String STACK_TRACE_CAUSE_LINE_PREFIX = CONTINUATION_LINE_PREFIX + Character.toString(' ');

  private LogMessageHeader myLastMessageHeader;
  private volatile boolean myCanceled = false;
  private Log.LogLevel myPrevLogLevel;
  private final Writer myWriter;
  private final IDevice myDevice;

  private final StackTraceExpander myStackTraceExpander = new StackTraceExpander(CONTINUATION_LINE_PREFIX,
                                                                                 STACK_TRACE_LINE_PREFIX,
                                                                                 EXPANDED_STACK_TRACE_LINE_PREFIX,
                                                                                 STACK_TRACE_CAUSE_LINE_PREFIX);

  public AndroidLogcatReceiver(IDevice device, Writer writer) {
    myDevice = device;
    myWriter = new PrintWriter(writer);
  }

  @Override
  public void processNewLine(String line) {
    Matcher matcher = LOG_PATTERN.matcher(line);
    if (myLastMessageHeader == null && matcher.matches()) {
      myLastMessageHeader = new LogMessageHeader();
      myLastMessageHeader.myTime = matcher.group(1);
      myLastMessageHeader.myPid = Integer.valueOf(matcher.group(2));

      String tid = matcher.group(3).trim();
      long tidValue;
      try {
        // Thread id's may be in hex on some platforms.
        // Decode and store them in radix 10.
        tidValue = Long.decode(tid.trim());
      } catch (NumberFormatException e) {
        tidValue = -1;
      }
      myLastMessageHeader.myTid = Long.toString(tidValue);

      myLastMessageHeader.myAppPackage =
        myDevice == null ? "" : myDevice.getClientName(myLastMessageHeader.myPid);
      myLastMessageHeader.myLogLevel = getByLetterString(matcher.group(4));
      myLastMessageHeader.myTag = matcher.group(5).trim();
    }
    else {
      if (line.length() == 0) return;
      String text;
      if (myLastMessageHeader == null) {
        text = myStackTraceExpander.expand(line);
      } else {
        text = getFullMessage(line, myLastMessageHeader);
      }
      try {
        myWriter.write(text + '\n');
      }
      catch (IOException ignored) {
        LOG.info(ignored);
      }
      myLastMessageHeader = null;
    }
  }

  @Nullable
  private static Log.LogLevel getByLetterString(@Nullable String s) {
    if (s == null) {
      return null;
    }
    final Log.LogLevel logLevel = Log.LogLevel.getByLetterString(s);

    /* LogLevel doesn't support messages with severity "F". Log.wtf() is supposed
     * to generate "A", but generates "F" */
    if (logLevel == null && s.equals("F")) {
      return Log.LogLevel.ASSERT;
    }
    return logLevel;
  }

  @Override
  public boolean isCancelled() {
    return myCanceled;
  }

  static class LogMessageHeader {
    String myTime;
    Log.LogLevel myLogLevel;
    int myPid;
    String myTid;
    String myAppPackage;
    String myTag;
  }

  private static String getFullMessage(String message, LogMessageHeader header) {
    return AndroidLogcatFormatter.formatMessage(message, header);
  }

  public void cancel() {
    myCanceled = true;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy