1 /* 2 * Copyright (C) 2011 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 com.android.ddmuilib.logcat; 18 19 import com.android.ddmlib.Log.LogLevel; 20 21 import java.util.ArrayList; 22 import java.util.List; 23 import java.util.regex.Matcher; 24 import java.util.regex.Pattern; 25 26 /** 27 * Class to parse raw output of {@code adb logcat -v long} to {@link LogCatMessage} objects. 28 */ 29 public final class LogCatMessageParser { 30 private LogLevel mCurLogLevel = LogLevel.WARN; 31 private String mCurPid = "?"; 32 private String mCurTag = "?"; 33 private String mCurTime = "?:??"; 34 35 /** 36 * This pattern is meant to parse the first line of a log message with the option 37 * 'logcat -v long'. The first line represents the date, tag, severity, etc.. while the 38 * following lines are the message (can be several lines).<br> 39 * This first line looks something like:<br> 40 * {@code "[ 00-00 00:00:00.000 <pid>:0x<???> <severity>/<tag>]"} 41 * <br> 42 * Note: severity is one of V, D, I, W, E, A? or F. However, there doesn't seem to be 43 * a way to actually generate an A (assert) message. Log.wtf is supposed to generate 44 * a message with severity A, however it generates the undocumented F level. In 45 * such a case, the parser will change the level from F to A.<br> 46 * Note: the fraction of second value can have any number of digit.<br> 47 * Note: the tag should be trimmed as it may have spaces at the end. 48 */ 49 private static Pattern sLogHeaderPattern = Pattern.compile( 50 "^\\[\\s(\\d\\d-\\d\\d\\s\\d\\d:\\d\\d:\\d\\d\\.\\d+)" 51 + "\\s+(\\d*):(0x[0-9a-fA-F]+)\\s([VDIWEAF])/(.*)\\]$"); 52 53 /** 54 * Parse a list of strings into {@link LogCatMessage} objects. This method 55 * maintains state from previous calls regarding the last seen header of 56 * logcat messages. 57 * @param lines list of raw strings obtained from logcat -v long 58 * @param pidToNameMapper mapper to obtain the app name given a pid 59 * @return list of LogMessage objects parsed from the input 60 */ processLogLines(String[] lines, LogCatPidToNameMapper pidToNameMapper)61 public List<LogCatMessage> processLogLines(String[] lines, 62 LogCatPidToNameMapper pidToNameMapper) { 63 List<LogCatMessage> messages = new ArrayList<LogCatMessage>(lines.length); 64 65 for (String line : lines) { 66 if (line.length() == 0) { 67 continue; 68 } 69 70 Matcher matcher = sLogHeaderPattern.matcher(line); 71 if (matcher.matches()) { 72 mCurTime = matcher.group(1); 73 mCurPid = matcher.group(2); 74 mCurLogLevel = LogLevel.getByLetterString(matcher.group(4)); 75 mCurTag = matcher.group(5).trim(); 76 77 /* LogLevel doesn't support messages with severity "F". Log.wtf() is supposed 78 * to generate "A", but generates "F". */ 79 if (mCurLogLevel == null && matcher.group(4).equals("F")) { 80 mCurLogLevel = LogLevel.ASSERT; 81 } 82 } else { 83 LogCatMessage m = new LogCatMessage(mCurLogLevel, mCurPid, 84 pidToNameMapper.getName(mCurPid), 85 mCurTag, mCurTime, line); 86 messages.add(m); 87 } 88 } 89 90 return messages; 91 } 92 } 93