blob: 0e8b03c2d36995a96b3a28d7ea57cb0ff826562a [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* 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 com.android.ddmlib.logcat;
import com.android.annotations.NonNull;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.Log.LogLevel;
import com.google.common.primitives.Ints;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class to parse raw output of {@code adb logcat -v long} to {@link LogCatMessage} objects.
*/
public final class LogCatMessageParser {
private LogLevel mCurLogLevel = LogLevel.WARN;
private String mCurPid = "?";
private String mCurTid = "?";
private String mCurTag = "?";
private String mCurTime = "?:??";
/**
* This pattern is meant to parse the first line of a log message with the option
* 'logcat -v long'. The first line represents the date, tag, severity, etc.. while the
* following lines are the message (can be several lines).<br>
* This first line looks something like:<br>
* {@code "[ 00-00 00:00:00.000 <pid>:0x<???> <severity>/<tag>]"}
* <br>
* Note: severity is one of V, D, I, W, E, A? or F. However, there doesn't seem to be
* a way to actually generate an A (assert) message. Log.wtf is supposed to generate
* a message with severity A, however it generates the undocumented F level. In
* such a case, the parser will change the level from F to A.<br>
* Note: the fraction of second value can have any number of digit.<br>
* Note: the tag should be trimmed as it may have spaces at the end.
*/
private static final Pattern sLogHeaderPattern = Pattern.compile(
"^\\[\\s(\\d\\d-\\d\\d\\s\\d\\d:\\d\\d:\\d\\d\\.\\d+)"
+ "\\s+(\\d*):\\s*(\\S+)\\s([VDIWEAF])/(.*)\\]$");
/**
* Parse a list of strings into {@link LogCatMessage} objects. This method
* maintains state from previous calls regarding the last seen header of
* logcat messages.
* @param lines list of raw strings obtained from logcat -v long
* @param device device from which these log messages have been received
* @return list of LogMessage objects parsed from the input
*/
@NonNull
public List<LogCatMessage> processLogLines(String[] lines, IDevice device) {
List<LogCatMessage> messages = new ArrayList<LogCatMessage>(lines.length);
for (String line : lines) {
if (line.isEmpty()) {
continue;
}
Matcher matcher = sLogHeaderPattern.matcher(line);
if (matcher.matches()) {
mCurTime = matcher.group(1);
mCurPid = matcher.group(2);
mCurTid = matcher.group(3);
mCurLogLevel = LogLevel.getByLetterString(matcher.group(4));
mCurTag = matcher.group(5).trim();
/* LogLevel doesn't support messages with severity "F". Log.wtf() is supposed
* to generate "A", but generates "F". */
if (mCurLogLevel == null && matcher.group(4).equals("F")) {
mCurLogLevel = LogLevel.ASSERT;
}
} else {
String pkgName = ""; //$NON-NLS-1$
Integer pid = Ints.tryParse(mCurPid);
if (pid != null && device != null) {
pkgName = device.getClientName(pid);
}
LogCatMessage m = new LogCatMessage(mCurLogLevel, mCurPid, mCurTid,
pkgName, mCurTag, mCurTime, line);
messages.add(m);
}
}
return messages;
}
}