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